aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-04-27 22:08:56 -0400
committerBob Zeleznik <zzzman@gmail.com>2020-04-27 22:08:56 -0400
commit1f0d326a6c8735f67c6e37b19f4656e645e38c43 (patch)
tree65605e4183c7d79f1d193b9c7d6b32940d7ee8db /src
parent26e683056cddcbe8f90547c77519daa15c37518d (diff)
parent2f371a09f7305cbc44e9358af310078ce0cb4b3c (diff)
Merge branch 'master' into richTextSchemaS
Diffstat (limited to 'src')
-rw-r--r--src/Utils.ts52
-rw-r--r--src/client/apis/google_docs/GoogleApiClientUtils.ts2
-rw-r--r--src/client/apis/google_docs/GooglePhotosClientUtils.ts21
-rw-r--r--src/client/apis/youtube/YoutubeBox.tsx10
-rw-r--r--src/client/cognitive_services/CognitiveServices.ts5
-rw-r--r--src/client/documents/DocumentTypes.ts62
-rw-r--r--src/client/documents/Documents.ts327
-rw-r--r--src/client/goldenLayout.js4
-rw-r--r--src/client/northstar/core/BaseObject.ts12
-rw-r--r--src/client/northstar/core/attribute/AttributeModel.ts111
-rw-r--r--src/client/northstar/core/attribute/AttributeTransformationModel.ts52
-rw-r--r--src/client/northstar/core/attribute/CalculatedAttributeModel.ts42
-rw-r--r--src/client/northstar/core/brusher/IBaseBrushable.ts13
-rw-r--r--src/client/northstar/core/brusher/IBaseBrusher.ts11
-rw-r--r--src/client/northstar/core/filter/FilterModel.ts83
-rw-r--r--src/client/northstar/core/filter/FilterOperand.ts5
-rw-r--r--src/client/northstar/core/filter/FilterType.ts6
-rw-r--r--src/client/northstar/core/filter/IBaseFilterConsumer.ts12
-rw-r--r--src/client/northstar/core/filter/IBaseFilterProvider.ts8
-rw-r--r--src/client/northstar/core/filter/ValueComparision.ts78
-rw-r--r--src/client/northstar/dash-fields/HistogramField.ts66
-rw-r--r--src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts240
-rw-r--r--src/client/northstar/dash-nodes/HistogramBox.scss40
-rw-r--r--src/client/northstar/dash-nodes/HistogramBox.tsx175
-rw-r--r--src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss42
-rw-r--r--src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx122
-rw-r--r--src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss13
-rw-r--r--src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx80
-rw-r--r--src/client/northstar/manager/Gateway.ts299
-rw-r--r--src/client/northstar/model/ModelExtensions.ts48
-rw-r--r--src/client/northstar/model/ModelHelpers.ts220
-rw-r--r--src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts52
-rw-r--r--src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts105
-rw-r--r--src/client/northstar/model/binRanges/NominalVisualBinRange.ts52
-rw-r--r--src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts90
-rw-r--r--src/client/northstar/model/binRanges/VisualBinRange.ts32
-rw-r--r--src/client/northstar/model/binRanges/VisualBinRangeHelper.ts70
-rw-r--r--src/client/northstar/model/idea/MetricTypeMapping.ts30
-rw-r--r--src/client/northstar/model/idea/idea.ts8557
-rw-r--r--src/client/northstar/operations/BaseOperation.ts162
-rw-r--r--src/client/northstar/operations/HistogramOperation.ts158
-rw-r--r--src/client/northstar/utils/ArrayUtil.ts90
-rw-r--r--src/client/northstar/utils/Extensions.ts29
-rw-r--r--src/client/northstar/utils/GeometryUtil.ts133
-rw-r--r--src/client/northstar/utils/IDisposable.ts3
-rw-r--r--src/client/northstar/utils/IEquatable.ts3
-rw-r--r--src/client/northstar/utils/KeyCodes.ts137
-rw-r--r--src/client/northstar/utils/LABColor.ts90
-rw-r--r--src/client/northstar/utils/MathUtil.ts249
-rw-r--r--src/client/northstar/utils/PartialClass.ts7
-rw-r--r--src/client/northstar/utils/SizeConverter.ts101
-rw-r--r--src/client/northstar/utils/StyleContants.ts95
-rw-r--r--src/client/northstar/utils/Utils.ts75
-rw-r--r--src/client/util/DictationManager.ts6
-rw-r--r--src/client/util/DocumentManager.ts16
-rw-r--r--src/client/util/DragManager.ts49
-rw-r--r--src/client/util/DropConverter.ts16
-rw-r--r--src/client/util/History.ts6
-rw-r--r--src/client/util/Import & Export/DirectoryImportBox.tsx2
-rw-r--r--src/client/util/Import & Export/ImageUtils.ts3
-rw-r--r--src/client/util/InteractionUtils.tsx22
-rw-r--r--src/client/util/KeyCodes.ts136
-rw-r--r--src/client/util/LinkManager.ts4
-rw-r--r--src/client/util/ProsemirrorExampleTransfer.ts18
-rw-r--r--src/client/util/RichTextMenu.tsx8
-rw-r--r--src/client/util/RichTextRules.ts34
-rw-r--r--src/client/util/RichTextSchema.tsx35
-rw-r--r--src/client/util/Scripting.ts16
-rw-r--r--src/client/util/SearchUtil.ts2
-rw-r--r--src/client/util/SelectionManager.ts6
-rw-r--r--src/client/util/SharingManager.tsx2
-rw-r--r--src/client/util/type_decls.d1
-rw-r--r--src/client/views/AntimodeMenu.tsx21
-rw-r--r--src/client/views/ContextMenu.scss47
-rw-r--r--src/client/views/ContextMenu.tsx9
-rw-r--r--src/client/views/ContextMenuItem.tsx16
-rw-r--r--src/client/views/DocComponent.tsx56
-rw-r--r--src/client/views/DocumentButtonBar.tsx68
-rw-r--r--src/client/views/DocumentDecorations.scss2
-rw-r--r--src/client/views/DocumentDecorations.tsx118
-rw-r--r--src/client/views/EditableView.tsx2
-rw-r--r--src/client/views/GestureOverlay.tsx194
-rw-r--r--src/client/views/GlobalKeyHandler.ts42
-rw-r--r--src/client/views/InkingControl.tsx18
-rw-r--r--src/client/views/InkingStroke.scss8
-rw-r--r--src/client/views/InkingStroke.tsx30
-rw-r--r--src/client/views/Main.scss1
-rw-r--r--src/client/views/Main.tsx1
-rw-r--r--src/client/views/MainView.scss3
-rw-r--r--src/client/views/MainView.tsx53
-rw-r--r--src/client/views/OverlayView.tsx29
-rw-r--r--src/client/views/PreviewCursor.tsx17
-rw-r--r--src/client/views/ScriptBox.tsx11
-rw-r--r--src/client/views/SearchDocBox.tsx2
-rw-r--r--src/client/views/TemplateMenu.tsx33
-rw-r--r--src/client/views/Templates.tsx45
-rw-r--r--src/client/views/Touchable.tsx7
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx15
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx54
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx2
-rw-r--r--src/client/views/collections/CollectionMapView.scss30
-rw-r--r--src/client/views/collections/CollectionMapView.tsx263
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx168
-rw-r--r--src/client/views/collections/CollectionPileView.scss8
-rw-r--r--src/client/views/collections/CollectionPileView.tsx127
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx5
-rw-r--r--src/client/views/collections/CollectionSchemaMovableTableHOC.tsx2
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx24
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx21
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx7
-rw-r--r--src/client/views/collections/CollectionSubView.tsx24
-rw-r--r--src/client/views/collections/CollectionTimeView.tsx60
-rw-r--r--src/client/views/collections/CollectionTreeView.scss32
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx237
-rw-r--r--src/client/views/collections/CollectionView.scss5
-rw-r--r--src/client/views/collections/CollectionView.tsx218
-rw-r--r--src/client/views/collections/CollectionViewChromes.scss9
-rw-r--r--src/client/views/collections/CollectionViewChromes.tsx368
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx28
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx167
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx28
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx62
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss14
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx348
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.scss1
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx51
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx38
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx39
-rw-r--r--src/client/views/nodes/AudioBox.scss4
-rw-r--r--src/client/views/nodes/AudioBox.tsx50
-rw-r--r--src/client/views/nodes/ButtonBox.tsx97
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx31
-rw-r--r--src/client/views/nodes/ColorBox.scss1
-rw-r--r--src/client/views/nodes/ColorBox.tsx8
-rw-r--r--src/client/views/nodes/DocumentBox.tsx20
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx123
-rw-r--r--src/client/views/nodes/DocumentView.scss18
-rw-r--r--src/client/views/nodes/DocumentView.tsx468
-rw-r--r--src/client/views/nodes/FontIconBox.scss12
-rw-r--r--src/client/views/nodes/FontIconBox.tsx3
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss2
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx184
-rw-r--r--src/client/views/nodes/FormattedTextBoxComment.tsx26
-rw-r--r--src/client/views/nodes/ImageBox.scss10
-rw-r--r--src/client/views/nodes/ImageBox.tsx160
-rw-r--r--src/client/views/nodes/KeyValueBox.scss1
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx23
-rw-r--r--src/client/views/nodes/LabelBox.scss (renamed from src/client/views/nodes/ButtonBox.scss)13
-rw-r--r--src/client/views/nodes/LabelBox.tsx96
-rw-r--r--src/client/views/nodes/LinkAnchorBox.scss (renamed from src/client/views/nodes/DocuLinkBox.scss)8
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx (renamed from src/client/views/nodes/DocuLinkBox.tsx)69
-rw-r--r--src/client/views/nodes/LinkBox.tsx5
-rw-r--r--src/client/views/nodes/PDFBox.scss3
-rw-r--r--src/client/views/nodes/PDFBox.tsx11
-rw-r--r--src/client/views/nodes/PresBox.scss6
-rw-r--r--src/client/views/nodes/PresBox.tsx116
-rw-r--r--src/client/views/nodes/QueryBox.scss1
-rw-r--r--src/client/views/nodes/QueryBox.tsx17
-rw-r--r--src/client/views/nodes/RadialMenu.scss13
-rw-r--r--src/client/views/nodes/RadialMenu.tsx9
-rw-r--r--src/client/views/nodes/ScreenshotBox.scss5
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx42
-rw-r--r--src/client/views/nodes/ScriptingBox.scss35
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx98
-rw-r--r--src/client/views/nodes/SliderBox.scss1
-rw-r--r--src/client/views/nodes/SliderBox.tsx53
-rw-r--r--src/client/views/nodes/VideoBox.scss7
-rw-r--r--src/client/views/nodes/VideoBox.tsx79
-rw-r--r--src/client/views/nodes/WebBox.scss38
-rw-r--r--src/client/views/nodes/WebBox.tsx219
-rw-r--r--src/client/views/pdf/Annotation.tsx3
-rw-r--r--src/client/views/pdf/PDFViewer.scss9
-rw-r--r--src/client/views/pdf/PDFViewer.tsx66
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx10
-rw-r--r--src/client/views/search/FilterBox.tsx2
-rw-r--r--src/client/views/search/IconBar.tsx14
-rw-r--r--src/client/views/search/IconButton.tsx8
-rw-r--r--src/client/views/search/SearchBox.scss3
-rw-r--r--src/client/views/search/SearchBox.tsx62
-rw-r--r--src/client/views/search/SearchItem.tsx9
-rw-r--r--src/client/views/webcam/DashWebRTCVideo.tsx2
-rw-r--r--src/mobile/ImageUpload.tsx2
-rw-r--r--src/mobile/MobileInterface.tsx53
-rw-r--r--src/new_fields/Doc.ts178
-rw-r--r--src/new_fields/RichTextField.ts7
-rw-r--r--src/new_fields/RichTextUtils.ts26
-rw-r--r--src/new_fields/ScriptField.ts5
-rw-r--r--src/new_fields/Types.ts1
-rw-r--r--src/new_fields/documentSchemas.ts14
-rw-r--r--src/pen-gestures/GestureUtils.ts8
-rw-r--r--src/pen-gestures/ndollar.ts3
-rw-r--r--src/scraping/buxton/final/BuxtonImporter.ts43
-rw-r--r--src/server/ApiManagers/SearchManager.ts24
-rw-r--r--src/server/ApiManagers/UtilManager.ts13
-rw-r--r--src/server/DashUploadUtils.ts38
-rw-r--r--src/server/Message.ts2
-rw-r--r--src/server/RouteManager.ts1
-rw-r--r--src/server/SharedMediaTypes.ts1
-rw-r--r--src/server/Websocket/Websocket.ts3
-rw-r--r--src/server/authentication/models/current_user_utils.ts804
-rw-r--r--src/server/database.ts16
-rw-r--r--src/server/index.ts12
-rw-r--r--src/server/server_Initialization.ts1
-rw-r--r--src/server/updateProtos.ts3
205 files changed, 4560 insertions, 15323 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index e3ec10dcd..ad12c68a1 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -63,11 +63,6 @@ export namespace Utils {
return prepend("/corsProxy/") + encodeURIComponent(url);
}
- export async function getApiKey(target: string): Promise<string> {
- const response = await fetch(prepend(`/environment/${target.toUpperCase()}`));
- return response.text();
- }
-
export function CopyText(text: string) {
const textArea = document.createElement("textarea");
textArea.value = text;
@@ -475,12 +470,44 @@ export function clearStyleSheetRules(sheet: any) {
return false;
}
+export function simulateMouseClick(element: Element, x: number, y: number, sx: number, sy: number) {
+ ["pointerdown", "pointerup"].map(event => element.dispatchEvent(
+ new PointerEvent(event, {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ button: 2,
+ pointerType: "mouse",
+ clientX: x,
+ clientY: y,
+ screenX: sx,
+ screenY: sy,
+ })));
+
+ element.dispatchEvent(
+ new MouseEvent("contextmenu", {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ button: 2,
+ clientX: x,
+ clientY: y,
+ movementX: 0,
+ movementY: 0,
+ screenX: sx,
+ screenY: sy,
+ }));
+}
+
export function setupMoveUpEvents(
target: object,
e: React.PointerEvent,
moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean,
upEvent: (e: PointerEvent) => void,
- clickEvent: (e: PointerEvent) => void) {
+ clickEvent: (e: PointerEvent, doubleTap?: boolean) => void,
+ stopPropagation: boolean = true,
+ stopMovePropagation: boolean = true
+) {
(target as any)._downX = (target as any)._lastX = e.clientX;
(target as any)._downY = (target as any)._lastY = e.clientY;
@@ -494,18 +521,23 @@ export function setupMoveUpEvents(
}
(target as any)._lastX = e.clientX;
(target as any)._lastY = e.clientY;
- e.stopPropagation();
+ stopMovePropagation && e.stopPropagation();
};
+ (target as any)._doubleTap = false;
const _upEvent = (e: PointerEvent): void => {
+ (target as any)._doubleTap = (Date.now() - (target as any)._lastTap < 300);
+ (target as any)._lastTap = Date.now();
upEvent(e);
if (Math.abs(e.clientX - (target as any)._downX) < 4 && Math.abs(e.clientY - (target as any)._downY) < 4) {
- clickEvent(e);
+ clickEvent(e, (target as any)._doubleTap);
}
document.removeEventListener("pointermove", _moveEvent);
document.removeEventListener("pointerup", _upEvent);
};
- e.stopPropagation();
- e.preventDefault();
+ if (stopPropagation) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
document.removeEventListener("pointermove", _moveEvent);
document.removeEventListener("pointerup", _upEvent);
document.addEventListener("pointermove", _moveEvent);
diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 0d44ee8e0..fa67ddbef 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -97,7 +97,7 @@ export namespace GoogleApiClientUtils {
const paragraphs = extractParagraphs(document);
let text = paragraphs.map(paragraph => paragraph.contents.filter(content => !("inlineObjectId" in content)).map(run => run as docs_v1.Schema$TextRun).join("")).join("");
text = text.substring(0, text.length - 1);
- removeNewlines && text.ReplaceAll("\n", "");
+ removeNewlines && text.replace(/\n/g, "");
return { text, paragraphs };
};
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
index 7c4137f59..8c0149a89 100644
--- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts
+++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts
@@ -1,19 +1,18 @@
-import { Utils } from "../../../Utils";
-import { ImageField } from "../../../new_fields/URLField";
-import { Cast, StrCast } from "../../../new_fields/Types";
-import { Doc, Opt, DocListCastAsync } from "../../../new_fields/Doc";
+import { AssertionError } from "assert";
+import { EditorState } from "prosemirror-state";
+import { Doc, DocListCastAsync, Opt } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
-import Photos = require('googlephotos');
import { RichTextField } from "../../../new_fields/RichTextField";
import { RichTextUtils } from "../../../new_fields/RichTextUtils";
-import { EditorState } from "prosemirror-state";
-import { FormattedTextBox } from "../../views/nodes/FormattedTextBox";
+import { Cast, StrCast } from "../../../new_fields/Types";
+import { ImageField } from "../../../new_fields/URLField";
+import { MediaItem, NewMediaItemResult } from "../../../server/apis/google/SharedTypes";
+import { Utils } from "../../../Utils";
import { Docs, DocumentOptions } from "../../documents/Documents";
-import { NewMediaItemResult, MediaItem } from "../../../server/apis/google/SharedTypes";
-import { AssertionError } from "assert";
-import { DocumentView } from "../../views/nodes/DocumentView";
import { Networking } from "../../Network";
+import { FormattedTextBox } from "../../views/nodes/FormattedTextBox";
import GoogleAuthenticationManager from "../GoogleAuthenticationManager";
+import Photos = require('googlephotos');
export namespace GooglePhotos {
@@ -340,7 +339,7 @@ export namespace GooglePhotos {
const url = data.url.href;
const target = Doc.MakeAlias(source);
const description = parseDescription(target, descriptionKey);
- await DocumentView.makeCustomViewClicked(target, Docs.Create.FreeformDocument);
+ await Doc.makeCustomViewClicked(target, Docs.Create.FreeformDocument);
media.push({ url, description });
}
if (media.length) {
diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx
index c940bba43..1575e53fc 100644
--- a/src/client/apis/youtube/YoutubeBox.tsx
+++ b/src/client/apis/youtube/YoutubeBox.tsx
@@ -156,14 +156,14 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
@action
processVideoDetails = (videoDetails: any[]) => {
this.videoDetails = videoDetails;
- this.props.Document.cachedDetails = Docs.Get.DocumentHierarchyFromJson(videoDetails, "detailBackUp");
+ this.props.Document.cachedDetails = Docs.Get.FromJson({ data: videoDetails, title: "detailBackUp" });
}
/**
* The function that stores the search results in the props document.
*/
backUpSearchResults = (videos: any[]) => {
- this.props.Document.cachedSearchResults = Docs.Get.DocumentHierarchyFromJson(videos, "videosBackUp");
+ this.props.Document.cachedSearchResults = Docs.Get.FromJson({ data: videos, title: "videosBackUp" });
}
/**
@@ -171,9 +171,9 @@ export class YoutubeBox extends React.Component<FieldViewProps> {
* in the title of the videos.
*/
filterYoutubeTitleResult = (resultTitle: string) => {
- let processedTitle: string = resultTitle.ReplaceAll("&amp;", "&");
- processedTitle = processedTitle.ReplaceAll("&#39;", "'");
- processedTitle = processedTitle.ReplaceAll("&quot;", "\"");
+ let processedTitle: string = resultTitle.replace(/&amp;/g, "&");//.ReplaceAll("&amp;", "&");
+ processedTitle = processedTitle.replace(/"&#39;/g, "'");
+ processedTitle = processedTitle.replace(/&quot;/g, "\"");
return processedTitle;
}
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index 3f3726621..8c63ae906 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -8,7 +8,6 @@ import { UndoManager } from "../util/UndoManager";
import requestPromise = require("request-promise");
import { List } from "../../new_fields/List";
import { ClientRecommender } from "../ClientRecommender";
-import { ImageBox } from "../views/nodes/ImageBox";
type APIManager<D> = { converter: BodyConverter<D>, requester: RequestExecutor };
type RequestExecutor = (apiKey: string, body: string, service: Service) => Promise<string>;
@@ -46,7 +45,7 @@ export enum Confidence {
export namespace CognitiveServices {
const ExecuteQuery = async <D>(service: Service, manager: APIManager<D>, data: D): Promise<any> => {
- const apiKey = await Utils.getApiKey(service);
+ const apiKey = process.env[service.toUpperCase()];
if (!apiKey) {
console.log(`No API key found for ${service}: ensure index.ts has access to a .env file in your root directory.`);
return undefined;
@@ -192,7 +191,7 @@ export namespace CognitiveServices {
let results = await ExecuteQuery(Service.Handwriting, Manager, inkData);
if (results) {
results.recognitionUnits && (results = results.recognitionUnits);
- target[keys[0]] = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis");
+ target[keys[0]] = Docs.Get.FromJson({ data: results, title: "Ink Analysis" });
const recognizedText = results.map((item: any) => item.recognizedText);
const recognizedObjects = results.map((item: any) => item.recognizedObject);
const individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1);
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index b6a6cc75a..de366763b 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -1,31 +1,37 @@
export enum DocumentType {
NONE = "none",
- TEXT = "text",
- HIST = "histogram",
- IMG = "image",
- WEB = "web",
- COL = "collection",
- KVP = "kvp",
- VID = "video",
- AUDIO = "audio",
- PDF = "pdf",
- IMPORT = "import",
- LINK = "link",
- LINKDB = "linkdb",
- BUTTON = "button",
- SLIDER = "slider",
- YOUTUBE = "youtube",
- WEBCAM = "webcam",
- FONTICON = "fonticonbox",
- PRES = "presentation",
- RECOMMENDATION = "recommendation",
- LINKFOLLOW = "linkfollow",
- PRESELEMENT = "preselement",
- QUERY = "query",
- COLOR = "color",
- DOCULINK = "doculink",
- PDFANNO = "pdfanno",
- INK = "ink",
- DOCUMENT = "document",
- SCREENSHOT = "screenshot",
+
+ // core data types
+ RTF = "rtf", // rich text
+ IMG = "image", // image box
+ WEB = "web", // web page or html clipping
+ COL = "collection", // collection
+ KVP = "kvp", // key value pane
+ VID = "video", // video
+ AUDIO = "audio", // audio
+ PDF = "pdf", // pdf
+ INK = "ink", // ink stroke
+ SCREENSHOT = "screenshot", // view of a desktop application
+ FONTICON = "fonticonbox", // font icon
+ QUERY = "query", // search query
+ LABEL = "label", // simple text label
+ BUTTON = "button", // onClick button
+ WEBCAM = "webcam", // webcam
+ PDFANNO = "pdfanno", // pdf text selection (could be just a collection?)
+ DATE = "date", // calendar view of a date
+ SCRIPTING = "script", // script editor
+
+ // special purpose wrappers that either take no data or are compositions of lower level types
+ LINK = "link", // link (view of a document that acts as a link)
+ LINKANCHOR = "linkanchor", // blue dot link anchor (view of a link document's anchor)
+ IMPORT = "import", // directory import box (file system directory)
+ SLIDER = "slider", // number slider (view of a number)
+ PRES = "presentation", // presentation (view of a collection) --- shouldn't this be a view type? technically requires a special view in which documents must have their aliasOf fields filled in
+ PRESELEMENT = "preselement",// presentation item (view of a document in a collection)
+ COLOR = "color", // color picker (view of a color picker for a color string)
+ YOUTUBE = "youtube", // youtube directory (view of you tube search results)
+ DOCHOLDER = "docholder", // nested document (view of a document)
+
+ LINKDB = "linkdb", // database of links ??? why do we have this
+ RECOMMENDATION = "recommendation", // view of a recommendation
} \ No newline at end of file
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index cca0e7bc6..c64916897 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,6 +1,3 @@
-import { HistogramField } from "../northstar/dash-fields/HistogramField";
-import { HistogramBox } from "../northstar/dash-nodes/HistogramBox";
-import { HistogramOperation } from "../northstar/operations/HistogramOperation";
import { CollectionView } from "../views/collections/CollectionView";
import { CollectionViewType } from "../views/collections/CollectionView";
import { AudioBox } from "../views/nodes/AudioBox";
@@ -8,21 +5,15 @@ import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
import { ImageBox } from "../views/nodes/ImageBox";
import { KeyValueBox } from "../views/nodes/KeyValueBox";
import { PDFBox } from "../views/nodes/PDFBox";
+import { ScriptingBox } from "../views/nodes/ScriptingBox";
import { VideoBox } from "../views/nodes/VideoBox";
import { WebBox } from "../views/nodes/WebBox";
-import { Gateway } from "../northstar/manager/Gateway";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
-import { action } from "mobx";
-import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel";
-import { AggregateFunction } from "../northstar/model/idea/idea";
import { OmitKeys, JSONUtils, Utils } from "../../Utils";
import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../new_fields/Doc";
import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField";
import { HtmlField } from "../../new_fields/HtmlField";
import { List } from "../../new_fields/List";
import { Cast, NumCast, StrCast } from "../../new_fields/Types";
-import { listSpec } from "../../new_fields/Schema";
import { DocServer } from "../DocServer";
import { dropActionType } from "../util/DragManager";
import { DateField } from "../../new_fields/DateField";
@@ -32,7 +23,7 @@ import { LinkManager } from "../util/LinkManager";
import { DocumentManager } from "../util/DocumentManager";
import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox";
import { Scripting } from "../util/Scripting";
-import { ButtonBox } from "../views/nodes/ButtonBox";
+import { LabelBox } from "../views/nodes/LabelBox";
import { SliderBox } from "../views/nodes/SliderBox";
import { FontIconBox } from "../views/nodes/FontIconBox";
import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
@@ -41,16 +32,12 @@ import { ComputedField, ScriptField } from "../../new_fields/ScriptField";
import { ProxyField } from "../../new_fields/Proxy";
import { DocumentType } from "./DocumentTypes";
import { RecommendationsBox } from "../views/RecommendationsBox";
-import { SearchBox } from "../views/search/SearchBox";
-
-//import { PresBox } from "../views/nodes/PresBox";
-//import { PresField } from "../../new_fields/PresField";
import { PresElementBox } from "../views/presentationview/PresElementBox";
import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
import { QueryBox } from "../views/nodes/QueryBox";
import { ColorBox } from "../views/nodes/ColorBox";
-import { DocuLinkBox } from "../views/nodes/DocuLinkBox";
-import { DocumentBox } from "../views/nodes/DocumentBox";
+import { LinkAnchorBox } from "../views/nodes/LinkAnchorBox";
+import { DocHolderBox } from "../views/nodes/DocumentBox";
import { InkingStroke } from "../views/InkingStroke";
import { InkField } from "../../new_fields/InkField";
import { InkingControl } from "../views/InkingControl";
@@ -61,7 +48,6 @@ import { ContextMenuProps } from "../views/ContextMenuItem";
import { ContextMenu } from "../views/ContextMenu";
import { LinkBox } from "../views/nodes/LinkBox";
import { ScreenshotBox } from "../views/nodes/ScreenshotBox";
-const requestImageSize = require('../util/request-image-size');
const path = require('path');
export interface DocumentOptions {
@@ -80,7 +66,7 @@ export interface DocumentOptions {
_showCaption?: string; // which field to display in the caption area. leave empty to have no caption
_scrollTop?: number; // scroll location for pdfs
_chromeStatus?: string;
- _viewType?: number;
+ _viewType?: string; // sub type of a collection
_gridGap?: number; // gap between items in masonry view
_xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
_yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts
@@ -92,11 +78,13 @@ export interface DocumentOptions {
x?: number;
y?: number;
z?: number;
+ author?: string;
dropAction?: dropActionType;
childDropAction?: dropActionType;
layoutKey?: string;
type?: string;
title?: string;
+ label?: string; // short form of title for use as an icon label
style?: string;
page?: number;
scale?: number;
@@ -116,18 +104,23 @@ export interface DocumentOptions {
ignoreClick?: boolean;
lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
+ isAnnotating?: boolean; // whether we web document is annotation mode where links can't be clicked to allow annotations to be created
opacity?: number;
defaultBackgroundColor?: string;
isBackground?: boolean;
- isButton?: boolean;
+ isLinkButton?: boolean;
columnWidth?: number;
- fontSize?: number;
+ _fontSize?: number;
+ _fontFamily?: string;
curPage?: number;
currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds
displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
borderRounding?: string;
boxShadow?: string;
dontRegisterChildren?: boolean;
+ "onClick-rawScript"?: string; // onClick script in raw text form
+ "onCheckedClick-rawScript"?: string; // onChecked script in raw text form
+ "onCheckedClick-params"?: List<string>; // parameter list for onChecked treeview functions
_pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
schemaColumns?: List<SchemaHeaderField>;
dockingConfig?: string;
@@ -148,13 +141,14 @@ export interface DocumentOptions {
icon?: string;
sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
+ searchFileTypes?: List<string>; // file types allowed in a search query
strokeWidth?: number;
treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view
treeViewHideTitle?: boolean; // whether to hide the title of a tree view
treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
treeViewOpen?: boolean; // whether this document is expanded in a tree view
+ treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
- isFacetFilter?: boolean; // whether document functions as a facet filter in a tree view
limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
// [key: string]: Opt<Field>;
pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown
@@ -189,105 +183,106 @@ export namespace Docs {
};
type TemplateMap = Map<DocumentType, PrototypeTemplate>;
type PrototypeMap = Map<DocumentType, Doc>;
- const data = "data";
+ const defaultDataKey = "data";
const TemplateMap: TemplateMap = new Map([
- [DocumentType.TEXT, {
+ [DocumentType.RTF, {
layout: { view: FormattedTextBox, dataField: "text" },
options: { _height: 150, _xMargin: 10, _yMargin: 10 }
}],
- [DocumentType.HIST, {
- layout: { view: HistogramBox, dataField: data },
- options: { _height: 300, backgroundColor: "black" }
- }],
[DocumentType.QUERY, {
- layout: { view: QueryBox, dataField: data },
+ layout: { view: QueryBox, dataField: defaultDataKey },
options: { _width: 400 }
}],
[DocumentType.COLOR, {
- layout: { view: ColorBox, dataField: data },
+ layout: { view: ColorBox, dataField: defaultDataKey },
options: { _nativeWidth: 220, _nativeHeight: 300 }
}],
[DocumentType.IMG, {
- layout: { view: ImageBox, dataField: data },
+ layout: { view: ImageBox, dataField: defaultDataKey },
options: {}
}],
[DocumentType.WEB, {
- layout: { view: WebBox, dataField: data },
+ layout: { view: WebBox, dataField: defaultDataKey },
options: { _height: 300 }
}],
[DocumentType.COL, {
- layout: { view: CollectionView, dataField: data },
+ layout: { view: CollectionView, dataField: defaultDataKey },
options: { _panX: 0, _panY: 0, scale: 1 } // , _width: 500, _height: 500 }
}],
[DocumentType.KVP, {
- layout: { view: KeyValueBox, dataField: data },
+ layout: { view: KeyValueBox, dataField: defaultDataKey },
options: { _height: 150 }
}],
- [DocumentType.DOCUMENT, {
- layout: { view: DocumentBox, dataField: data },
+ [DocumentType.DOCHOLDER, {
+ layout: { view: DocHolderBox, dataField: defaultDataKey },
options: { _height: 250 }
}],
[DocumentType.VID, {
- layout: { view: VideoBox, dataField: data },
+ layout: { view: VideoBox, dataField: defaultDataKey },
options: { currentTimecode: 0 },
}],
[DocumentType.AUDIO, {
- layout: { view: AudioBox, dataField: data },
+ layout: { view: AudioBox, dataField: defaultDataKey },
options: { _height: 35, backgroundColor: "lightGray" }
}],
[DocumentType.PDF, {
- layout: { view: PDFBox, dataField: data },
+ layout: { view: PDFBox, dataField: defaultDataKey },
options: { curPage: 1 }
}],
[DocumentType.IMPORT, {
- layout: { view: DirectoryImportBox, dataField: data },
+ layout: { view: DirectoryImportBox, dataField: defaultDataKey },
options: { _height: 150 }
}],
[DocumentType.LINK, {
- layout: { view: LinkBox, dataField: data },
+ layout: { view: LinkBox, dataField: defaultDataKey },
options: { _height: 150 }
}],
[DocumentType.LINKDB, {
data: new List<Doc>(),
- layout: { view: EmptyBox, dataField: data },
- options: { childDropAction: "alias", title: "LINK DB" }
+ layout: { view: EmptyBox, dataField: defaultDataKey },
+ options: { childDropAction: "alias", title: "Global Link Database" }
+ }],
+ [DocumentType.SCRIPTING, {
+ layout: { view: ScriptingBox, dataField: defaultDataKey }
}],
[DocumentType.YOUTUBE, {
- layout: { view: YoutubeBox, dataField: data }
+ layout: { view: YoutubeBox, dataField: defaultDataKey }
+ }],
+ [DocumentType.LABEL, {
+ layout: { view: LabelBox, dataField: defaultDataKey },
}],
[DocumentType.BUTTON, {
- layout: { view: ButtonBox, dataField: data },
+ layout: { view: LabelBox, dataField: "onClick" },
}],
[DocumentType.SLIDER, {
- layout: { view: SliderBox, dataField: data },
+ layout: { view: SliderBox, dataField: defaultDataKey },
}],
[DocumentType.PRES, {
- layout: { view: PresBox, dataField: data },
+ layout: { view: PresBox, dataField: defaultDataKey },
options: {}
}],
[DocumentType.FONTICON, {
- layout: { view: FontIconBox, dataField: data },
+ layout: { view: FontIconBox, dataField: defaultDataKey },
options: { _width: 40, _height: 40, borderRounding: "100%" },
}],
[DocumentType.RECOMMENDATION, {
- layout: { view: RecommendationsBox, dataField: data },
- options: { width: 200, height: 200 },
+ layout: { view: RecommendationsBox, dataField: defaultDataKey },
+ options: { _width: 200, _height: 200 },
}],
[DocumentType.WEBCAM, {
- layout: { view: DashWebRTCVideo, dataField: data }
+ layout: { view: DashWebRTCVideo, dataField: defaultDataKey }
}],
[DocumentType.PRESELEMENT, {
- layout: { view: PresElementBox, dataField: data }
+ layout: { view: PresElementBox, dataField: defaultDataKey }
}],
[DocumentType.INK, {
- layout: { view: InkingStroke, dataField: data },
+ layout: { view: InkingStroke, dataField: defaultDataKey },
options: { backgroundColor: "transparent" }
}],
[DocumentType.SCREENSHOT, {
- layout: { view: ScreenshotBox, dataField: data },
- options: {}
- }]
+ layout: { view: ScreenshotBox, dataField: defaultDataKey },
+ }],
]);
// All document prototypes are initialized with at least these values
@@ -414,7 +409,7 @@ export namespace Docs {
const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true });
const deviceProto = Doc.GetProto(doc);
deviceProto.hero = new ImageField(constructed[0].url);
- Docs.Get.DocumentHierarchyFromJson(device, undefined, deviceProto);
+ Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } });
Doc.AddDocToList(parentProto, "data", doc);
} else if (errors) {
console.log(errors);
@@ -437,7 +432,7 @@ export namespace Docs {
const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn",
"_chromeStatus", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
"_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", "_scrollTop",
- "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"];
+ "_color", "isLinkButton", "isBackground", "removeDropProperties", "treeViewOpen"];
/**
* This function receives the relevant document prototype and uses
@@ -504,23 +499,18 @@ export namespace Docs {
const extension = path.extname(target);
target = `${target.substring(0, target.length - extension.length)}_o${extension}`;
}
- requestImageSize(Utils.CorsProxy(target))
- .then((size: any) => {
- const aspect = size.height / size.width;
- if (!inst._nativeWidth) {
- inst._nativeWidth = size.width;
- }
- inst._nativeHeight = NumCast(inst._nativeWidth) * aspect;
- inst._height = NumCast(inst._width) * aspect;
- })
- .catch((err: any) => console.log(err));
- // }
return inst;
}
export function PresDocument(initial: List<Doc> = new List(), options: DocumentOptions = {}) {
return InstanceFromProto(Prototypes.get(DocumentType.PRES), initial, options);
}
+ export function ScriptingDocument(script: Opt<ScriptField>, options: DocumentOptions = {}, fieldKey?: string) {
+ const res = InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script, options);
+ fieldKey && res.proto instanceof Doc && (res.proto.layout = ScriptingBox.LayoutString(fieldKey));
+ return res;
+ }
+
export function VideoDocument(url: string, options: DocumentOptions = {}) {
return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(new URL(url)), options);
}
@@ -543,10 +533,6 @@ export namespace Docs {
return instance;
}
- export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.HIST), new HistogramField(histoOp), options);
- }
-
export function QueryDocument(options: DocumentOptions = {}) {
return InstanceFromProto(Prototypes.get(DocumentType.QUERY), "", options);
}
@@ -556,26 +542,28 @@ export namespace Docs {
}
export function TextDocument(text: string, options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.TEXT), text, options, undefined, "text");
+ return InstanceFromProto(Prototypes.get(DocumentType.RTF), text, options, undefined, "text");
}
export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) {
- const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, { isButton: true, treeViewHideTitle: true, treeViewOpen: false, removeDropProperties: new List(["isBackground", "isButton"]), ...options });
+ const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, { isLinkButton: true, treeViewHideTitle: true, treeViewOpen: false, removeDropProperties: new List(["isBackground", "isLinkButton"]), ...options });
const linkDocProto = Doc.GetProto(doc);
linkDocProto.anchor1 = source.doc;
linkDocProto.anchor2 = target.doc;
+ linkDocProto.anchor1_timecode = source.doc.currentTimecode || source.doc.displayTimecode;
+ linkDocProto.anchor2_timecode = target.doc.currentTimecode || target.doc.displayTimecode;
if (linkDocProto.layout_key1 === undefined) {
- Cast(linkDocProto.proto, Doc, null).layout_key1 = DocuLinkBox.LayoutString("anchor1");
- Cast(linkDocProto.proto, Doc, null).layout_key2 = DocuLinkBox.LayoutString("anchor2");
+ Cast(linkDocProto.proto, Doc, null).layout_key1 = LinkAnchorBox.LayoutString("anchor1");
+ Cast(linkDocProto.proto, Doc, null).layout_key2 = LinkAnchorBox.LayoutString("anchor2");
Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "lastOpened", "creationDate", "author"]);
Cast(linkDocProto.proto, Doc, null).layoutKey = undefined;
}
LinkManager.Instance.addLink(doc);
- Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(this)");
- Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(this)");
+ Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)");
+ Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)");
return doc;
}
@@ -589,6 +577,7 @@ export namespace Docs {
I.title = "ink";
I.x = options.x;
I.y = options.y;
+ I._backgroundColor = "transparent";
I._width = options._width;
I._height = options._height;
I.data = new InkField(points);
@@ -605,39 +594,8 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(new URL(url)), options);
}
- export async function DBDocument(url: string, options: DocumentOptions = {}, columnOptions: DocumentOptions = {}) {
- const schemaName = options.title ? options.title : "-no schema-";
- const ctlog = await Gateway.Instance.GetSchema(url, schemaName);
- if (ctlog && ctlog.schemas) {
- const schema = ctlog.schemas[0];
- const schemaDoc = Docs.Create.TreeDocument([], { ...options, _nativeWidth: undefined, _nativeHeight: undefined, _width: 150, _height: 100, title: schema.displayName! });
- const schemaDocuments = Cast(schemaDoc.data, listSpec(Doc), []);
- if (!schemaDocuments) {
- return;
- }
- CurrentUserUtils.AddNorthstarSchema(schema, schemaDoc);
- const docs = schemaDocuments;
- CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
- DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt<Field>) => {
- if (field instanceof Doc) {
- docs.push(field);
- } else {
- const atmod = new ColumnAttributeModel(attr);
- const histoOp = new HistogramOperation(schema.displayName!,
- new AttributeTransformationModel(atmod, AggregateFunction.None),
- new AttributeTransformationModel(atmod, AggregateFunction.Count),
- new AttributeTransformationModel(atmod, AggregateFunction.Count));
- docs.push(Docs.Create.HistogramDocument(histoOp, { ...columnOptions, _width: 200, _height: 200, title: attr.displayName! }));
- }
- }));
- });
- return schemaDoc;
- }
- return Docs.Create.TreeDocument([], { _width: 50, _height: 100, title: schemaName });
- }
-
export function WebDocument(url: string, options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.WEB), new WebField(new URL(url)), options);
+ return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(new URL(url)) : undefined, { _fitWidth: true, _chromeStatus: url ? "disabled" : "enabled", isAnnotating: true, lockedTransform: true, ...options });
}
export function HtmlDocument(html: string, options: DocumentOptions = {}) {
@@ -649,17 +607,25 @@ export namespace Docs {
}
export function DocumentDocument(document?: Doc, options: DocumentOptions = {}) {
- return InstanceFromProto(Prototypes.get(DocumentType.DOCUMENT), document, { title: document ? document.title + "" : "container", ...options });
+ return InstanceFromProto(Prototypes.get(DocumentType.DOCHOLDER), document, { title: document ? document.title + "" : "container", ...options });
}
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Freeform }, id);
}
+ export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Pile }, id);
+ }
+
export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Linear }, id);
}
+ export function MapDocument(documents: Array<Doc>, options: DocumentOptions = {}) {
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), options);
+ }
+
export function CarouselDocument(documents: Array<Doc>, options: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Carousel });
}
@@ -688,8 +654,12 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Masonry });
}
+ export function LabelDocument(options?: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.LABEL), undefined, { ...(options || {}) });
+ }
+
export function ButtonDocument(options?: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.BUTTON), undefined, { ...(options || {}) });
+ return InstanceFromProto(Prototypes.get(DocumentType.BUTTON), undefined, { ...(options || {}), "onClick-rawScript": "-script-" });
}
export function SliderDocument(options?: DocumentOptions) {
@@ -744,6 +714,15 @@ export namespace Docs {
const primitives = ["string", "number", "boolean"];
+ export interface JsonConversionOpts {
+ data: any;
+ title?: string;
+ appendToExisting?: { targetDoc: Doc, fieldKey?: string };
+ excludeEmptyObjects?: boolean;
+ }
+
+ const defaultKey = "json";
+
/**
* This function takes any valid JSON(-like) data, i.e. parsed or unparsed, and at arbitrarily
* deep levels of nesting, converts the data and structure into nested documents with the appropriate fields.
@@ -761,23 +740,54 @@ export namespace Docs {
* All TS/JS objects get converted directly to documents, directly preserving the key value structure. Everything else,
* lacking the key value structure, gets stored as a field in a wrapper document.
*
- * @param input for convenience and flexibility, either a valid JSON string to be parsed,
+ * @param data for convenience and flexibility, either a valid JSON string to be parsed,
* or the result of any JSON.parse() call.
- * @param title an optional title to give to the highest parent document in the hierarchy
+ * @param title an optional title to give to the highest parent document in the hierarchy.
+ * If whether this function creates a new document or appendToExisting is specified and that document already has a title,
+ * because this title field can be left undefined for the opposite behavior, including a title will overwrite the existing title.
+ * @param appendToExisting **if specified**, there are two cases, both of which return the target document:
+ *
+ * 1) the json to be converted can be represented as a document, in which case the target document will act as the root
+ * of the tree and receive all the conversion results as new fields on itself
+ * 2) the json can't be represented as a document, in which case the function will assign the field-level conversion
+ * results to either the specified key on the target document, or to its "json" key by default.
+ *
+ * If not specified, the function creates and returns a new entirely generic document (different from the Doc.Create calls)
+ * to act as the root of the tree.
+ *
+ * One might choose to specify this field if you want to write to a document returned from a Document.Create function call,
+ * say a TreeView document that will be rendered, not just an untyped, identityless doc that would otherwise be created
+ * from a default call to new Doc.
+ *
+ * @param excludeEmptyObjects whether non-primitive objects (TypeScript objects and arrays) should be converted even
+ * if they contain no data. By default, empty objects and arrays are ignored.
*/
- export function DocumentHierarchyFromJson(input: any, title?: string, appendToTarget?: Doc): Opt<Doc> {
- if (input === undefined || input === null || ![...primitives, "object"].includes(typeof input)) {
+ export function FromJson({ data, title, appendToExisting, excludeEmptyObjects }: JsonConversionOpts): Opt<Doc> {
+ if (excludeEmptyObjects === undefined) {
+ excludeEmptyObjects = true;
+ }
+ if (data === undefined || data === null || ![...primitives, "object"].includes(typeof data)) {
+ return undefined;
+ }
+ let resolved: any;
+ try {
+ resolved = JSON.parse(typeof data === "string" ? data : JSON.stringify(data));
+ } catch (e) {
return undefined;
}
- input = JSON.parse(typeof input === "string" ? input : JSON.stringify(input));
- let converted: Doc;
- if (typeof input === "object" && !(input instanceof Array)) {
- converted = convertObject(input, title, appendToTarget);
+ let output: Opt<Doc>;
+ if (typeof resolved === "object" && !(resolved instanceof Array)) {
+ output = convertObject(resolved, excludeEmptyObjects, title, appendToExisting?.targetDoc);
} else {
- (converted = new Doc).json = toField(input);
+ const result = toField(resolved, excludeEmptyObjects);
+ if (appendToExisting) {
+ (output = appendToExisting.targetDoc)[appendToExisting.fieldKey || defaultKey] = result;
+ } else {
+ (output = new Doc).json = result;
+ }
}
- title && (converted.title = title);
- return converted;
+ title && output && (output.title = title);
+ return output;
}
/**
@@ -787,12 +797,24 @@ export namespace Docs {
* @returns the object mapped from JSON to field values, where each mapping
* might involve arbitrary recursion (since toField might itself call convertObject)
*/
- const convertObject = (object: any, title?: string, target?: Doc): Doc => {
- const resolved = target ?? new Doc;
- let result: Opt<Field>;
- Object.keys(object).map(key => (result = toField(object[key], key)) && (resolved[key] = result));
- title && !resolved.title && (resolved.title = title);
- return resolved;
+ const convertObject = (object: any, excludeEmptyObjects: boolean, title?: string, target?: Doc): Opt<Doc> => {
+ const hasEntries = Object.keys(object).length;
+ if (hasEntries || !excludeEmptyObjects) {
+ const resolved = target ?? new Doc;
+ if (hasEntries) {
+ let result: Opt<Field>;
+ Object.keys(object).map(key => {
+ // if excludeEmptyObjects is true, any qualifying conversions from toField will
+ // be undefined, and thus the results that would have
+ // otherwise been empty (List or Doc)s will just not be written
+ if (result = toField(object[key], excludeEmptyObjects, key)) {
+ resolved[key] = result;
+ }
+ });
+ }
+ title && (resolved.title = title);
+ return resolved;
+ }
};
/**
@@ -802,15 +824,19 @@ export namespace Docs {
* @returns the list mapped from JSON to field values, where each mapping
* might involve arbitrary recursion (since toField might itself call convertList)
*/
- const convertList = (list: Array<any>): List<Field> => {
+ const convertList = (list: Array<any>, excludeEmptyObjects: boolean): Opt<List<Field>> => {
const target = new List();
let result: Opt<Field>;
- list.map(item => (result = toField(item)) && target.push(result));
- return target;
+ // if excludeEmptyObjects is true, any qualifying conversions from toField will
+ // be undefined, and thus the results that would have
+ // otherwise been empty (List or Doc)s will just not be written
+ list.map(item => (result = toField(item, excludeEmptyObjects)) && target.push(result));
+ if (target.length || !excludeEmptyObjects) {
+ return target;
+ }
};
-
- const toField = (data: any, title?: string): Opt<Field> => {
+ const toField = (data: any, excludeEmptyObjects: boolean, title?: string): Opt<Field> => {
if (data === null || data === undefined) {
return undefined;
}
@@ -818,7 +844,7 @@ export namespace Docs {
return data;
}
if (typeof data === "object") {
- return data instanceof Array ? convertList(data) : convertObject(data, title);
+ return data instanceof Array ? convertList(data, excludeEmptyObjects) : convertObject(data, excludeEmptyObjects, title, undefined);
}
throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`);
};
@@ -842,9 +868,6 @@ export namespace Docs {
} else if (field instanceof AudioField) {
created = Docs.Create.AudioDocument((field).url.href, resolved);
layout = AudioBox.LayoutString;
- } else if (field instanceof HistogramField) {
- created = Docs.Create.HistogramDocument((field).HistoOp, resolved);
- layout = HistogramBox.LayoutString;
} else if (field instanceof InkField) {
const { selectedColor, selectedWidth, selectedTool } = InkingControl.Instance;
created = Docs.Create.InkDocument(selectedColor, selectedTool, Number(selectedWidth), (field).inkData, resolved);
@@ -856,9 +879,11 @@ export namespace Docs {
created = Docs.Create.TextDocument("", { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved });
layout = FormattedTextBox.LayoutString;
}
- created.layout = layout?.(fieldKey);
- created.title = fieldKey;
- proto && (created.proto = Doc.GetProto(proto));
+ if (created) {
+ created.layout = layout?.(fieldKey);
+ created.title = fieldKey;
+ proto && created.proto && (created.proto = Doc.GetProto(proto));
+ }
return created;
}
@@ -881,10 +906,6 @@ export namespace Docs {
if (!options._width) options._width = 400;
if (!options._height) options._height = options._width * 1200 / 927;
}
- if (type.indexOf("excel") !== -1) {
- ctor = Docs.Create.DBDocument;
- options.dropAction = "copy";
- }
if (type.indexOf("html") !== -1) {
if (path.includes(window.location.hostname)) {
const s = path.split('/');
@@ -902,7 +923,7 @@ export namespace Docs {
});
}
ctor = Docs.Create.WebDocument;
- options = { _height: options._width, ...options, title: path, _nativeWidth: undefined };
+ options = { ...options, _nativeWidth: 850, _nativeHeight: 962, _width: 500, _height: 566, title: path, };
}
return ctor ? ctor(path, options) : undefined;
}
@@ -945,20 +966,20 @@ export namespace DocUtils {
export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", id?: string) {
const sv = DocumentManager.Instance.getDocumentView(source.doc);
if (sv && sv.props.ContainingCollectionDoc === target.doc) return;
- if (target.doc === CurrentUserUtils.UserDocument) return undefined;
+ if (target.doc === Doc.UserDoc()) return undefined;
const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship }, id);
- Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('this.anchor1.title +" (" + (this.linkRelationship||"to") +") " + this.anchor2.title');
+ Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2.title');
- Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(this)");
- Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(this)");
+ Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)");
+ Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)");
return linkDoc;
}
export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number): void {
ContextMenu.Instance.addItem({
description: "Add Note ...",
- subitems: DocListCast((Doc.UserDoc().noteTypes as Doc).data).map((note, i) => ({
+ subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({
description: ":" + StrCast(note.title),
event: (args: { x: number, y: number }) => {
const textDoc = Docs.Create.TextDocument("", {
@@ -975,7 +996,7 @@ export namespace DocUtils {
});
ContextMenu.Instance.addItem({
description: "Add Template Doc ...",
- subitems: DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({
+ subitems: DocListCast(Cast(Doc.UserDoc().dockedBtns, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({
description: ":" + StrCast(dragDoc.title),
event: (args: { x: number, y: number }) => {
const newDoc = Doc.ApplyTemplate(dragDoc);
diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js
index b510385ff..2d4283b02 100644
--- a/src/client/goldenLayout.js
+++ b/src/client/goldenLayout.js
@@ -1551,7 +1551,7 @@
},
dimensions: {
borderWidth: 5,
- borderGrabWidth: 15,
+ borderGrabWidth: 5,
minItemHeight: 10,
minItemWidth: 10,
headerHeight: 20,
@@ -2796,11 +2796,13 @@
if (this._isVertical) {
dragHandle.css('top', -handleExcessPos);
dragHandle.css('height', this._size + handleExcessSize);
+ element.css('cursor', 'row-resize');
element.addClass('lm_vertical');
element['height'](this._size);
} else {
dragHandle.css('left', -handleExcessPos);
dragHandle.css('width', this._size + handleExcessSize);
+ element.css('cursor', 'col-resize');
element.addClass('lm_horizontal');
element['width'](this._size);
}
diff --git a/src/client/northstar/core/BaseObject.ts b/src/client/northstar/core/BaseObject.ts
deleted file mode 100644
index ed3818071..000000000
--- a/src/client/northstar/core/BaseObject.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { IEquatable } from '../utils/IEquatable';
-import { IDisposable } from '../utils/IDisposable';
-
-export class BaseObject implements IEquatable, IDisposable {
-
- public Equals(other: Object): boolean {
- return this === other;
- }
-
- public Dispose(): void {
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/core/attribute/AttributeModel.ts b/src/client/northstar/core/attribute/AttributeModel.ts
deleted file mode 100644
index c89b1617c..000000000
--- a/src/client/northstar/core/attribute/AttributeModel.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea';
-import { BaseObject } from '../BaseObject';
-import { observable } from "mobx";
-
-export abstract class AttributeModel extends BaseObject {
- public abstract get DisplayName(): string;
- public abstract get CodeName(): string;
- public abstract get DataType(): DataType;
- public abstract get VisualizationHints(): VisualizationHint[];
-}
-
-export class ColumnAttributeModel extends AttributeModel {
- public Attribute: Attribute;
-
- constructor(attribute: Attribute) {
- super();
- this.Attribute = attribute;
- }
-
- public get DataType(): DataType {
- return this.Attribute.dataType ? this.Attribute.dataType : DataType.Undefined;
- }
-
- public get DisplayName(): string {
- return this.Attribute.displayName ? this.Attribute.displayName.ReplaceAll("_", " ") : "";
- }
-
- public get CodeName(): string {
- return this.Attribute.rawName ? this.Attribute.rawName : "";
- }
-
- public get VisualizationHints(): VisualizationHint[] {
- return this.Attribute.visualizationHints ? this.Attribute.visualizationHints : [];
- }
-
- public Equals(other: ColumnAttributeModel): boolean {
- return this.Attribute.rawName === other.Attribute.rawName;
- }
-}
-
-export class CodeAttributeModel extends AttributeModel {
- private _visualizationHints: VisualizationHint[];
-
- public CodeName: string;
-
- @observable
- public Code: string;
-
- constructor(code: string, codeName: string, displayName: string, visualizationHints: VisualizationHint[]) {
- super();
- this.Code = code;
- this.CodeName = codeName;
- this.DisplayName = displayName;
- this._visualizationHints = visualizationHints;
- }
-
- public get DataType(): DataType {
- return DataType.Undefined;
- }
-
- @observable
- public DisplayName: string;
-
- public get VisualizationHints(): VisualizationHint[] {
- return this._visualizationHints;
- }
-
- public Equals(other: CodeAttributeModel): boolean {
- return this.CodeName === other.CodeName;
- }
-
-}
-
-export class BackendAttributeModel extends AttributeModel {
- private _dataType: DataType;
- private _displayName: string;
- private _codeName: string;
- private _visualizationHints: VisualizationHint[];
-
- public Id: string;
-
- constructor(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]) {
- super();
- this.Id = id;
- this._dataType = dataType;
- this._displayName = displayName;
- this._codeName = codeName;
- this._visualizationHints = visualizationHints;
- }
-
- public get DataType(): DataType {
- return this._dataType;
- }
-
- public get DisplayName(): string {
- return this._displayName.ReplaceAll("_", " ");
- }
-
- public get CodeName(): string {
- return this._codeName;
- }
-
- public get VisualizationHints(): VisualizationHint[] {
- return this._visualizationHints;
- }
-
- public Equals(other: BackendAttributeModel): boolean {
- return this.Id === other.Id;
- }
-
-} \ No newline at end of file
diff --git a/src/client/northstar/core/attribute/AttributeTransformationModel.ts b/src/client/northstar/core/attribute/AttributeTransformationModel.ts
deleted file mode 100644
index 66485183b..000000000
--- a/src/client/northstar/core/attribute/AttributeTransformationModel.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-
-import { computed, observable } from "mobx";
-import { AggregateFunction } from "../../model/idea/idea";
-import { AttributeModel } from "./AttributeModel";
-import { IEquatable } from "../../utils/IEquatable";
-
-export class AttributeTransformationModel implements IEquatable {
-
- @observable public AggregateFunction: AggregateFunction;
- @observable public AttributeModel: AttributeModel;
-
- constructor(attributeModel: AttributeModel, aggregateFunction: AggregateFunction = AggregateFunction.None) {
- this.AttributeModel = attributeModel;
- this.AggregateFunction = aggregateFunction;
- }
-
- @computed
- public get PresentedName(): string {
- var displayName = this.AttributeModel.DisplayName;
- if (this.AggregateFunction === AggregateFunction.Count) {
- return "count";
- }
- if (this.AggregateFunction === AggregateFunction.Avg) {
- displayName = "avg(" + displayName + ")";
- }
- else if (this.AggregateFunction === AggregateFunction.Max) {
- displayName = "max(" + displayName + ")";
- }
- else if (this.AggregateFunction === AggregateFunction.Min) {
- displayName = "min(" + displayName + ")";
- }
- else if (this.AggregateFunction === AggregateFunction.Sum) {
- displayName = "sum(" + displayName + ")";
- }
- else if (this.AggregateFunction === AggregateFunction.SumE) {
- displayName = "sumE(" + displayName + ")";
- }
-
- return displayName;
- }
-
- public clone(): AttributeTransformationModel {
- var clone = new AttributeTransformationModel(this.AttributeModel);
- clone.AggregateFunction = this.AggregateFunction;
- return clone;
- }
-
- public Equals(other: AttributeTransformationModel): boolean {
- return this.AggregateFunction === other.AggregateFunction &&
- this.AttributeModel.Equals(other.AttributeModel);
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts
deleted file mode 100644
index a197c1305..000000000
--- a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { BackendAttributeModel, AttributeModel, CodeAttributeModel } from "./AttributeModel";
-import { DataType, VisualizationHint } from '../../model/idea/idea';
-
-export class CalculatedAttributeManager {
- public static AllCalculatedAttributes: Array<AttributeModel> = new Array<AttributeModel>();
-
- public static Clear() {
- this.AllCalculatedAttributes = new Array<AttributeModel>();
- }
-
- public static CreateBackendAttributeModel(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]): BackendAttributeModel {
- var filtered = this.AllCalculatedAttributes.filter(am => {
- if (am instanceof BackendAttributeModel &&
- am.Id === id) {
- return true;
- }
- return false;
- });
- if (filtered.length > 0) {
- return filtered[0] as BackendAttributeModel;
- }
- var newAttr = new BackendAttributeModel(id, dataType, displayName, codeName, visualizationHints);
- this.AllCalculatedAttributes.push(newAttr);
- return newAttr;
- }
-
- public static CreateCodeAttributeModel(code: string, codeName: string, visualizationHints: VisualizationHint[]): CodeAttributeModel {
- var filtered = this.AllCalculatedAttributes.filter(am => {
- if (am instanceof CodeAttributeModel &&
- am.CodeName === codeName) {
- return true;
- }
- return false;
- });
- if (filtered.length > 0) {
- return filtered[0] as CodeAttributeModel;
- }
- var newAttr = new CodeAttributeModel(code, codeName, codeName.ReplaceAll("_", " "), visualizationHints);
- this.AllCalculatedAttributes.push(newAttr);
- return newAttr;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts
deleted file mode 100644
index 87f4ba413..000000000
--- a/src/client/northstar/core/brusher/IBaseBrushable.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { PIXIPoint } from '../../utils/MathUtil';
-import { IEquatable } from '../../utils/IEquatable';
-import { Doc } from '../../../../new_fields/Doc';
-
-export interface IBaseBrushable<T> extends IEquatable {
- BrusherModels: Array<Doc>;
- BrushColors: Array<number>;
- Position: PIXIPoint;
- Size: PIXIPoint;
-}
-export function instanceOfIBaseBrushable<T>(object: any): object is IBaseBrushable<T> {
- return 'BrusherModels' in object;
-} \ No newline at end of file
diff --git a/src/client/northstar/core/brusher/IBaseBrusher.ts b/src/client/northstar/core/brusher/IBaseBrusher.ts
deleted file mode 100644
index d2de6ed62..000000000
--- a/src/client/northstar/core/brusher/IBaseBrusher.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { PIXIPoint } from '../../utils/MathUtil';
-import { IEquatable } from '../../utils/IEquatable';
-
-
-export interface IBaseBrusher<T> extends IEquatable {
- Position: PIXIPoint;
- Size: PIXIPoint;
-}
-export function instanceOfIBaseBrusher<T>(object: any): object is IBaseBrusher<T> {
- return 'BrushableModels' in object;
-} \ No newline at end of file
diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts
deleted file mode 100644
index 6ab96b33d..000000000
--- a/src/client/northstar/core/filter/FilterModel.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { ValueComparison } from "./ValueComparision";
-import { Utils } from "../../utils/Utils";
-import { IBaseFilterProvider } from "./IBaseFilterProvider";
-import { FilterOperand } from "./FilterOperand";
-import { HistogramField } from "../../dash-fields/HistogramField";
-import { Cast, FieldValue } from "../../../../new_fields/Types";
-import { Doc } from "../../../../new_fields/Doc";
-
-export class FilterModel {
- public ValueComparisons: ValueComparison[];
- constructor() {
- this.ValueComparisons = new Array<ValueComparison>();
- }
-
- public Equals(other: FilterModel): boolean {
- if (!Utils.EqualityHelper(this, other)) return false;
- if (!this.isSame(this.ValueComparisons, (other).ValueComparisons)) return false;
- return true;
- }
-
- private isSame(a: ValueComparison[], b: ValueComparison[]): boolean {
- if (a.length !== b.length) {
- return false;
- }
- for (let i = 0; i < a.length; i++) {
- let valueComp = a[i];
- if (!valueComp.Equals(b[i])) {
- return false;
- }
- }
- return true;
- }
-
- public ToPythonString(): string {
- return "(" + this.ValueComparisons.map(vc => vc.ToPythonString()).join("&&") + ")";
- }
-
- public static And(filters: string[]): string {
- let ret = filters.filter(f => f !== "").join(" && ");
- return ret;
- }
- public static GetFilterModelsRecursive(baseOperation: IBaseFilterProvider, visitedFilterProviders: Set<IBaseFilterProvider>, filterModels: FilterModel[], isFirst: boolean): string {
- let ret = "";
- visitedFilterProviders.add(baseOperation);
- let filtered = baseOperation.FilterModels.filter(fm => fm && fm.ValueComparisons.length > 0);
- if (!isFirst && filtered.length > 0) {
- filterModels.push(...filtered);
- ret = "(" + baseOperation.FilterModels.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")";
- }
- if (Utils.isBaseFilterConsumer(baseOperation) && baseOperation.Links) {
- let children = new Array<string>();
- let linkedGraphNodes = baseOperation.Links;
- linkedGraphNodes.map(linkVm => {
- let filterDoc = FieldValue(Cast(linkVm.linkedFrom, Doc));
- if (filterDoc) {
- let filterHistogram = Cast(filterDoc.data, HistogramField);
- if (filterHistogram) {
- if (!visitedFilterProviders.has(filterHistogram.HistoOp)) {
- let child = FilterModel.GetFilterModelsRecursive(filterHistogram.HistoOp, visitedFilterProviders, filterModels, false);
- if (child !== "") {
- // if (linkVm.IsInverted) {
- // child = "! " + child;
- // }
- children.push(child);
- }
- }
- }
- }
- });
-
- let childrenJoined = children.join(baseOperation.FilterOperand === FilterOperand.AND ? " && " : " || ");
- if (children.length > 0) {
- if (ret !== "") {
- ret = "(" + ret + " && (" + childrenJoined + "))";
- }
- else {
- ret = "(" + childrenJoined + ")";
- }
- }
- }
- return ret;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/core/filter/FilterOperand.ts b/src/client/northstar/core/filter/FilterOperand.ts
deleted file mode 100644
index 2e8e8d6a0..000000000
--- a/src/client/northstar/core/filter/FilterOperand.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export enum FilterOperand
-{
- AND,
- OR
-} \ No newline at end of file
diff --git a/src/client/northstar/core/filter/FilterType.ts b/src/client/northstar/core/filter/FilterType.ts
deleted file mode 100644
index 9adbc087f..000000000
--- a/src/client/northstar/core/filter/FilterType.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export enum FilterType
-{
- Filter,
- Brush,
- Slice
-} \ No newline at end of file
diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts
deleted file mode 100644
index e7549d113..000000000
--- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { FilterOperand } from '../filter/FilterOperand';
-import { IEquatable } from '../../utils/IEquatable';
-import { Doc } from '../../../../new_fields/Doc';
-
-export interface IBaseFilterConsumer extends IEquatable {
- FilterOperand: FilterOperand;
- Links: Doc[];
-}
-
-export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer {
- return 'FilterOperand' in object;
-} \ No newline at end of file
diff --git a/src/client/northstar/core/filter/IBaseFilterProvider.ts b/src/client/northstar/core/filter/IBaseFilterProvider.ts
deleted file mode 100644
index fc3301b11..000000000
--- a/src/client/northstar/core/filter/IBaseFilterProvider.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { FilterModel } from '../filter/FilterModel';
-
-export interface IBaseFilterProvider {
- FilterModels: Array<FilterModel>;
-}
-export function instanceOfIBaseFilterProvider(object: any): object is IBaseFilterProvider {
- return 'FilterModels' in object;
-} \ No newline at end of file
diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts
deleted file mode 100644
index 65687a82b..000000000
--- a/src/client/northstar/core/filter/ValueComparision.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { Predicate } from '../../model/idea/idea';
-import { Utils } from '../../utils/Utils';
-import { AttributeModel } from '../attribute/AttributeModel';
-
-export class ValueComparison {
-
- public attributeModel: AttributeModel;
- public Value: any;
- public Predicate: Predicate;
-
- public constructor(attributeModel: AttributeModel, predicate: Predicate, value: any) {
- this.attributeModel = attributeModel;
- this.Value = value;
- this.Predicate = predicate;
- }
-
- public Equals(other: Object): boolean {
- if (!Utils.EqualityHelper(this, other)) {
- return false;
- }
- if (this.Predicate !== (other as ValueComparison).Predicate) {
- return false;
- }
- let isComplex = (typeof this.Value === "object");
- if (!isComplex && this.Value !== (other as ValueComparison).Value) {
- return false;
- }
- if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) {
- return false;
- }
- return true;
- }
-
- public ToPythonString(): string {
- var op = "";
- switch (this.Predicate) {
- case Predicate.EQUALS:
- op = "==";
- break;
- case Predicate.GREATER_THAN:
- op = ">";
- break;
- case Predicate.GREATER_THAN_EQUAL:
- op = ">=";
- break;
- case Predicate.LESS_THAN:
- op = "<";
- break;
- case Predicate.LESS_THAN_EQUAL:
- op = "<=";
- break;
- default:
- op = "==";
- break;
- }
-
- var val = this.Value.toString();
- if (typeof this.Value === 'string' || this.Value instanceof String) {
- val = "\"" + val + "\"";
- }
- var ret = " ";
- var rawName = this.attributeModel.CodeName;
- switch (this.Predicate) {
- case Predicate.STARTS_WITH:
- ret += rawName + " != null && " + rawName + ".StartsWith(" + val + ") ";
- return ret;
- case Predicate.ENDS_WITH:
- ret += rawName + " != null && " + rawName + ".EndsWith(" + val + ") ";
- return ret;
- case Predicate.CONTAINS:
- ret += rawName + " != null && " + rawName + ".Contains(" + val + ") ";
- return ret;
- default:
- ret += rawName + " " + op + " " + val + " ";
- return ret;
- }
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
deleted file mode 100644
index 076516977..000000000
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { observable } from "mobx";
-import { custom, serializable } from "serializr";
-import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel";
-import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation";
-import { ObjectField } from "../../../new_fields/ObjectField";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { OmitKeys } from "../../../Utils";
-import { Deserializable } from "../../util/SerializationHelper";
-import { Copy, ToScriptString, ToString } from "../../../new_fields/FieldSymbols";
-
-function serialize(field: HistogramField) {
- const obj = OmitKeys(field, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit;
- return obj;
-}
-
-function deserialize(jp: any) {
- let X: AttributeTransformationModel | undefined;
- let Y: AttributeTransformationModel | undefined;
- let V: AttributeTransformationModel | undefined;
-
- const schema = CurrentUserUtils.GetNorthstarSchema(jp.SchemaName);
- if (schema) {
- CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
- if (attr.displayName === jp.X.AttributeModel.Attribute.DisplayName) {
- X = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.X.AggregateFunction);
- }
- if (attr.displayName === jp.Y.AttributeModel.Attribute.DisplayName) {
- Y = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.Y.AggregateFunction);
- }
- if (attr.displayName === jp.V.AttributeModel.Attribute.DisplayName) {
- V = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.V.AggregateFunction);
- }
- });
- if (X && Y && V) {
- return new HistogramOperation(jp.SchemaName, X, Y, V, jp.Normalization);
- }
- }
- return HistogramOperation.Empty;
-}
-
-@Deserializable("histogramField")
-export class HistogramField extends ObjectField {
- @serializable(custom(serialize, deserialize)) @observable public readonly HistoOp: HistogramOperation;
- constructor(data?: HistogramOperation) {
- super();
- this.HistoOp = data ? data : HistogramOperation.Empty;
- }
-
- toString(): string {
- return JSON.stringify(OmitKeys(this.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit);
- }
-
- [Copy]() {
- // const y = this.HistoOp;
- // const z = this.HistoOp.Copy;
- return new HistogramField(HistogramOperation.Duplicate(this.HistoOp));
- }
-
- [ToScriptString]() {
- return this.toString();
- }
- [ToString]() {
- return this.toString();
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
deleted file mode 100644
index 6b36ffc9e..000000000
--- a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-import React = require("react");
-import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
-import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
-import { AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { LABColor } from '../../northstar/utils/LABColor';
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBox } from "./HistogramBox";
-import "./HistogramBoxPrimitives.scss";
-
-export class HistogramBinPrimitive {
- constructor(init?: Partial<HistogramBinPrimitive>) {
- Object.assign(this, init);
- }
- public DataValue: number = 0;
- public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
- public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
- public MarginPercentage: number = 0;
- public Color: number = StyleConstants.WARNING_COLOR;
- public Opacity: number = 1;
- public BrushIndex: number = 0;
- public BarAxis: number = -1;
-}
-
-export class HistogramBinPrimitiveCollection {
- private static TOLERANCE: number = 0.0001;
-
- private _histoBox: HistogramBox;
- private get histoOp() { return this._histoBox.HistoOp; }
- private get histoResult() { return this.histoOp.Result as HistogramResult; }
- private get sizeConverter() { return this._histoBox.SizeConverter; }
- public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>();
- public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
-
- constructor(bin: Bin, histoBox: HistogramBox) {
- this._histoBox = histoBox;
- let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
-
- brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
- switch (histoBox.ChartType) {
- case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
- case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
- case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
- case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
- }
- }, 0);
-
- // adjust brush rects (stacking or not)
- var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
- var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex !== allBrushIndex && b.DataValue !== 0.0);
- filteredBinPrims.reduce((sum, fbp) => {
- if (histoBox.ChartType === ChartType.VerticalBar) {
- if (this.histoOp.Y.AggregateFunction === AggregateFunction.Count) {
- fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.height;
- }
- if (this.histoOp.Y.AggregateFunction === AggregateFunction.Avg) {
- var w = fbp.Rect.width / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.width;
- }
- }
- else if (histoBox.ChartType === ChartType.HorizontalBar) {
- if (this.histoOp.X.AggregateFunction === AggregateFunction.Count) {
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.width;
- }
- if (this.histoOp.X.AggregateFunction === AggregateFunction.Avg) {
- var h = fbp.Rect.height / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.height;
- }
- }
- return 0;
- }, 0);
- this.BinPrimitives = this.BinPrimitives.reverse();
- var f = this.BinPrimitives.filter(b => b.BrushIndex === allBrushIndex);
- this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
- }
-
- private setupBrushing(bin: Bin, normalization: number) {
- var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
- var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
- this.histoResult.brushes!.map(brush => brush.brushIndex !== 0 && brush.brushIndex !== overlapBrushIndex && orderedBrushes.push(brush));
- return {
- orderedBrushes,
- maxAxis: orderedBrushes.reduce((prev, Brush) => {
- let aggResult = this.getBinValue(normalization, bin, Brush.brushIndex!);
- return aggResult !== undefined && aggResult > prev ? aggResult : prev;
- }, Number.MIN_VALUE)
- };
- }
-
- private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
-
- let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
- if (unNormalizedValue === undefined) {
- return brushFactorSum;
- }
-
- var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
- unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
-
- let allUnNormalizedValue = this.getBinValue(2, bin, ModelHelpers.AllBrushIndex(this.histoResult));
-
- // bcz: are these calls needed?
- let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
- let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
- var returnBrushFactorSum = brushFactorSum;
- if (allUnNormalizedValue !== undefined) {
- var brushFactor = (unNormalizedValue / allUnNormalizedValue);
- returnBrushFactorSum += brushFactor;
- returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
-
- var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
- var ratio = (tempRect.width / tempRect.height);
- var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
- var newWidth = newHeight * ratio;
-
- xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
- yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
- xTo = (xFrom + newWidth);
- yFrom = (yTo + newHeight);
- }
- var alpha = 0.0;
- var color = this.baseColorFromBrush(brush);
- var lerpColor = LABColor.Lerp(
- LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
- LABColor.FromColor(color),
- (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
- var dataColor = LABColor.ToColor(lerpColor);
-
- this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
- return returnBrushFactorSum;
- }
-
- private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
- let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
- if (unNormalizedValue !== undefined) {
- let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
- let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
-
- if (xFrom !== undefined && yFrom !== undefined && xTo !== undefined && yTo !== undefined) {
- this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
- }
- }
- return 0;
- }
-
- private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
- let dataValue = this.getBinValue(1, bin, brush.brushIndex!);
- if (dataValue !== undefined) {
- let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
- let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-
- var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
- var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
- this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
- this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
-
- this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
- this.baseColorFromBrush(brush), normalization !== 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
- }
- return 0;
- }
-
- private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
- let dataValue = this.getBinValue(0, bin, brush.brushIndex!);
- if (dataValue !== undefined) {
- let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
- let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
- var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
- var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
- yTo + (yFrom - yTo) / 2.0 - 1,
- this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
- 2.0);
-
- this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
- this.baseColorFromBrush(brush), normalization !== 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
- }
- return 0;
- }
-
- public getBinValue(axis: number, bin: Bin, brushIndex: number) {
- var aggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis === 0 ? this.histoOp.X : axis === 1 ? this.histoOp.Y : this.histoOp.V, this.histoResult, brushIndex);
- let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
- return dataValue !== null && dataValue.hasResult ? dataValue.result : undefined;
- }
-
- private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
- var marginParams = new MarginAggregateParameters();
- marginParams.aggregateFunction = axis.AggregateFunction;
- var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
- let aggResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey);
- return aggResult instanceof MarginAggregateResult && aggResult.absolutMargin ? aggResult.absolutMargin : 0;
- }
-
- private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
- marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
- var binPrimitive = new HistogramBinPrimitive(
- {
- Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
- MarginRect: marginRect,
- MarginPercentage: marginPercentage,
- BrushIndex: brush.brushIndex,
- Color: color,
- Opacity: opacity,
- DataValue: dataValue,
- BarAxis: barAxis
- });
- this.BinPrimitives.push(binPrimitive);
- }
-
- private baseColorFromBrush(brush: Brush): number {
- let bc = StyleConstants.BRUSH_COLORS;
- if (brush.brushIndex === ModelHelpers.RestBrushIndex(this.histoResult)) {
- return StyleConstants.HIGHLIGHT_COLOR;
- }
- else if (brush.brushIndex === ModelHelpers.OverlapBrushIndex(this.histoResult)) {
- return StyleConstants.OVERLAP_COLOR;
- }
- else if (brush.brushIndex === ModelHelpers.AllBrushIndex(this.histoResult)) {
- return 0x00ff00;
- }
- else if (bc.length > 0) {
- return bc[brush.brushIndex! % bc.length];
- }
- // else if (this.histoOp.BrushColors.length > 0) {
- // return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
- // }
- return StyleConstants.HIGHLIGHT_COLOR;
- }
-}
diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss
deleted file mode 100644
index 06d781263..000000000
--- a/src/client/northstar/dash-nodes/HistogramBox.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-.histogrambox-container {
- padding: 0vw;
- position: absolute;
- top: -50%;
- left:-50%;
- text-align: center;
- width: 100%;
- height: 100%;
- background: black;
- }
- .histogrambox-xaxislabel {
- position:absolute;
- left:0;
- width:100%;
- text-align: center;
- bottom:0;
- background: lightgray;
- font-size: 14;
- font-weight: bold;
- }
- .histogrambox-yaxislabel {
- position:absolute;
- height:100%;
- width: 25px;
- left:0;
- bottom:0;
- background: lightgray;
- }
- .histogrambox-yaxislabel-text {
- position:absolute;
- left:0;
- width: 1000px;
- transform-origin: 10px 10px;
- transform: rotate(-90deg);
- text-align: left;
- font-size: 14;
- font-weight: bold;
- bottom: calc(50% - 25px);
- }
- \ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
deleted file mode 100644
index 8fee53fb9..000000000
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-import React = require("react");
-import { action, computed, observable, reaction, runInAction, trace } from "mobx";
-import { observer } from "mobx-react";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
-import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
-import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
-import { SizeConverter } from "../../northstar/utils/SizeConverter";
-import { DragManager } from "../../util/DragManager";
-import { FieldView, FieldViewProps } from "../../views/nodes/FieldView";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { HistogramField } from "../dash-fields/HistogramField";
-import "../utils/Extensions";
-import "./HistogramBox.scss";
-import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
-import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
-import { StyleConstants } from "../utils/StyleContants";
-import { Cast } from "../../../new_fields/Types";
-import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
-
-
-@observer
-export class HistogramBox extends React.Component<FieldViewProps> {
- public static LayoutString(fieldStr: string) { return FieldView.LayoutString(HistogramBox, fieldStr); }
- private _dropXRef = React.createRef<HTMLDivElement>();
- private _dropYRef = React.createRef<HTMLDivElement>();
- private _dropXDisposer?: DragManager.DragDropDisposer;
- private _dropYDisposer?: DragManager.DragDropDisposer;
-
- @observable public HistoOp: HistogramOperation = HistogramOperation.Empty;
- @observable public VisualBinRanges: VisualBinRange[] = [];
- @observable public ValueRange: number[] = [];
- @computed public get HistogramResult(): HistogramResult { return this.HistoOp.Result as HistogramResult; }
- @observable public SizeConverter: SizeConverter = new SizeConverter();
-
- @computed get createOperationParamsCache() { return this.HistoOp.CreateOperationParameters(); }
- @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
- @computed get ChartType() {
- return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
- (this.BinRanges[1] instanceof AggregateBinRange ? ChartType.SinglePoint : ChartType.HorizontalBar) :
- this.BinRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap;
- }
-
- @action
- dropX = (e: Event, de: DragManager.DropEvent) => {
- if (de.complete.docDragData) {
- let h = Cast(de.complete.docDragData.draggedDocuments[0].data, HistogramField);
- if (h) {
- this.HistoOp.X = h.HistoOp.X;
- }
- e.stopPropagation();
- e.preventDefault();
- }
- }
- @action
- dropY = (e: Event, de: DragManager.DropEvent) => {
- if (de.complete.docDragData) {
- let h = Cast(de.complete.docDragData.draggedDocuments[0].data, HistogramField);
- if (h) {
- this.HistoOp.Y = h.HistoOp.X;
- }
- e.stopPropagation();
- e.preventDefault();
- }
- }
-
- @action
- xLabelPointerDown = (e: React.PointerEvent) => {
- this.HistoOp.X = new AttributeTransformationModel(this.HistoOp.X.AttributeModel, this.HistoOp.X.AggregateFunction === AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
- }
- @action
- yLabelPointerDown = (e: React.PointerEvent) => {
- this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction === AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
- }
-
- componentDidMount() {
- if (this._dropXRef.current) {
- this._dropXDisposer = DragManager.MakeDropTarget(this._dropXRef.current, this.dropX.bind(this));
- }
- if (this._dropYRef.current) {
- this._dropYDisposer = DragManager.MakeDropTarget(this._dropYRef.current, this.dropY.bind(this));
- }
- reaction(() => CurrentUserUtils.NorthstarDBCatalog, (catalog?: Catalog) => this.activateHistogramOperation(catalog), { fireImmediately: true });
- reaction(() => [this.VisualBinRanges && this.VisualBinRanges.slice()], () => this.SizeConverter.SetVisualBinRanges(this.VisualBinRanges));
- reaction(() => [this.props.PanelWidth(), this.props.PanelHeight()], (size: number[]) => this.SizeConverter.SetIsSmall(size[0] < 40 && size[1] < 40));
- reaction(() => this.HistogramResult ? this.HistogramResult.binRanges : undefined,
- (binRanges: BinRange[] | undefined) => {
- if (binRanges) {
- this.VisualBinRanges.splice(0, this.VisualBinRanges.length, ...binRanges.map((br, ind) =>
- VisualBinRangeHelper.GetVisualBinRange(this.HistoOp.Schema!.distinctAttributeParameters, br, this.HistogramResult, ind ? this.HistoOp.Y : this.HistoOp.X, this.ChartType)));
-
- let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp.Schema!.distinctAttributeParameters, this.HistoOp.V, this.HistogramResult, ModelHelpers.AllBrushIndex(this.HistogramResult));
- this.ValueRange = Object.values(this.HistogramResult.bins!).reduce((prev, cur) => {
- let value = ModelHelpers.GetAggregateResult(cur, valueAggregateKey) as DoubleValueAggregateResult;
- return value && value.hasResult ? [Math.min(prev[0], value.result!), Math.max(prev[1], value.result!)] : prev;
- }, [Number.MAX_VALUE, Number.MIN_VALUE]);
- }
- });
- }
-
- componentWillUnmount() {
- if (this._dropXDisposer) {
- this._dropXDisposer();
- }
- if (this._dropYDisposer) {
- this._dropYDisposer();
- }
- }
-
- async activateHistogramOperation(catalog?: Catalog) {
- if (catalog) {
- let histoOp = await Cast(this.props.Document[this.props.fieldKey], HistogramField);
- runInAction(() => {
- this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty;
- if (this.HistoOp !== HistogramOperation.Empty) {
- reaction(() => DocListCast(this.props.Document.linkedFromDocs), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
- reaction(() => DocListCast(this.props.Document.brushingDocs).length,
- async () => {
- let brushingDocs = await DocListCastAsync(this.props.Document.brushingDocs);
- const proto = this.props.Document.proto;
- if (proto && brushingDocs) {
- let mapped = brushingDocs.map((brush, i) => {
- brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length];
- let brushed = DocListCast(brush.brushingDocs);
- if (!brushed.length) return null;
- return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] };
- });
- runInAction(() => this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped.filter(m => m) as { l: Doc, b: Doc }[]));
- }
- }, { fireImmediately: true });
- reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true });
- }
- });
- }
- }
-
- @action
- private onScrollWheel = (e: React.WheelEvent) => {
- this.HistoOp.DrillDown(e.deltaY > 0);
- e.stopPropagation();
- }
-
- render() {
- let labelY = this.HistoOp && this.HistoOp.Y ? this.HistoOp.Y.PresentedName : "<...>";
- let labelX = this.HistoOp && this.HistoOp.X ? this.HistoOp.X.PresentedName : "<...>";
- let loff = this.SizeConverter.LeftOffset;
- let toff = this.SizeConverter.TopOffset;
- let roff = this.SizeConverter.RightOffset;
- let boff = this.SizeConverter.BottomOffset;
- return (
- <div className="histogrambox-container" onWheel={this.onScrollWheel}>
- <div className="histogrambox-yaxislabel" onPointerDown={this.yLabelPointerDown} ref={this._dropYRef} >
- <span className="histogrambox-yaxislabel-text">
- {labelY}
- </span>
- </div>
- <div className="histogrambox-primitives" style={{
- transform: `translate(${loff + 25}px, ${toff}px)`,
- width: `calc(100% - ${loff + roff + 25}px)`,
- height: `calc(100% - ${toff + boff}px)`,
- }}>
- <HistogramLabelPrimitives HistoBox={this} />
- <HistogramBoxPrimitives HistoBox={this} />
- </div>
- <div className="histogrambox-xaxislabel" onPointerDown={this.xLabelPointerDown} ref={this._dropXRef} >
- {labelX}
- </div>
- </div>
- );
- }
-}
-
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
deleted file mode 100644
index 26203612a..000000000
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-.histogramboxprimitives-container {
- width: 100%;
- height: 100%;
-}
-.histogramboxprimitives-border {
- border: 3px;
- pointer-events: none;
- position: absolute;
- fill:"transparent";
- stroke: white;
- stroke-width: 1px;
-}
-.histogramboxprimitives-bar {
- position: absolute;
- border: 1px;
- border-style: solid;
- border-color: #282828;
- pointer-events: all;
-}
-
-.histogramboxprimitives-placer {
- position: absolute;
- pointer-events: none;
- width: 100%;
- height: 100%;
-}
-.histogramboxprimitives-svgContainer {
- position: absolute;
- top:0;
- left:0;
- width:100%;
- height: 100%;
-}
-.histogramboxprimitives-line {
- position: absolute;
- background: darkGray;
- stroke: darkGray;
- stroke-width: 1px;
- width:100%;
- height:100%;
- opacity: 0.4;
-} \ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
deleted file mode 100644
index 66d91cc1d..000000000
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import React = require("react");
-import { computed, observable, reaction, runInAction, trace, action } from "mobx";
-import { observer } from "mobx-react";
-import { Utils as DashUtils, emptyFunction } from '../../../Utils';
-import { FilterModel } from "../../northstar/core/filter/FilterModel";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
-import { LABColor } from '../../northstar/utils/LABColor';
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection";
-import { HistogramBox } from "./HistogramBox";
-import "./HistogramBoxPrimitives.scss";
-
-export interface HistogramPrimitivesProps {
- HistoBox: HistogramBox;
-}
-@observer
-export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesProps> {
- private get histoOp() { return this.props.HistoBox.HistoOp; }
- private get renderDimension() { return this.props.HistoBox.SizeConverter.RenderDimension; }
- @observable _selectedPrims: HistogramBinPrimitive[] = [];
- @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
- @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
- @computed get selectedPrimitives() { return this._selectedPrims.map(bp => this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); }
- @computed get barPrimitives() {
- let histoResult = this.props.HistoBox.HistogramResult;
- if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) {
- return (null);
- }
- let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult);
- return Object.keys(histoResult.bins).reduce((prims: JSX.Element[], key: string) => {
- let drawPrims = new HistogramBinPrimitiveCollection(histoResult.bins![key], this.props.HistoBox);
- let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex,
- ModelHelpers.GetBinFilterModel(histoResult.bins![key], allBrushIndex, histoResult, this.histoOp.X, this.histoOp.Y));
- drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp =>
- prims.push(...[{ r: bp.Rect, c: bp.Color }, { r: bp.MarginRect, c: StyleConstants.MARGIN_BARS_COLOR }].map(pair => this.drawRect(pair.r, bp.BarAxis, pair.c, "bar", toggle))));
- return prims;
- }, [] as JSX.Element[]);
- }
-
- componentDidMount() {
- reaction(() => this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
- }
-
- private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) {
- let rawAllBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex === allBrushIndex);
- if (!rawAllBrushPrim) {
- return emptyFunction;
- }
- let allBrushPrim = rawAllBrushPrim;
- return () => runInAction(() => {
- if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) {
- this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim), 1);
- this.histoOp.RemoveFilterModels([filterModel]);
- }
- else {
- this._selectedPrims.push(allBrushPrim);
- this.histoOp.AddFilterModels([filterModel]);
- }
- });
- }
-
- private renderGridLinesAndLabels(axis: number) {
- if (!this.props.HistoBox.SizeConverter.Initialized) {
- return (null);
- }
- let labels = this.props.HistoBox.VisualBinRanges[axis].GetLabels();
- return <svg className="histogramboxprimitives-svgContainer">
- {labels.reduce((prims, binLabel, i) => {
- let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
- prims.push(this.drawLine(r.xFrom, r.yFrom, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0));
- if (i === labels.length - 1) {
- prims.push(this.drawLine(axis === 0 ? r.xTo : r.xFrom, axis === 0 ? r.yFrom : r.yTo, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0));
- }
- return prims;
- }, [] as JSX.Element[])}
- </svg>;
- }
-
- drawLine(xFrom: number, yFrom: number, width: number, height: number) {
- if (height < 0) {
- yFrom += height;
- height = -height;
- }
- if (width < 0) {
- xFrom += width;
- width = -width;
- }
- let trans2Xpercent = `${(xFrom + width) / this.renderDimension * 100}%`;
- let trans2Ypercent = `${(yFrom + height) / this.renderDimension * 100}%`;
- let trans1Xpercent = `${xFrom / this.renderDimension * 100}%`;
- let trans1Ypercent = `${yFrom / this.renderDimension * 100}%`;
- return <line className="histogramboxprimitives-line" key={DashUtils.GenerateGuid()} x1={trans1Xpercent} x2={`${trans2Xpercent}`} y1={trans1Ypercent} y2={`${trans2Ypercent}`} />;
- }
- drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = emptyFunction) {
- if (r.height < 0) {
- r.y += r.height;
- r.height = -r.height;
- }
- if (r.width < 0) {
- r.x += r.width;
- r.width = -r.width;
- }
- let transXpercent = `${r.x / this.renderDimension * 100}%`;
- let transYpercent = `${r.y / this.renderDimension * 100}%`;
- let widthXpercent = `${r.width / this.renderDimension * 100}%`;
- let heightYpercent = `${r.height / this.renderDimension * 100}%`;
- return (<rect className={`histogramboxprimitives-${classExt}`} key={DashUtils.GenerateGuid()} onPointerDown={(e: React.PointerEvent) => { if (e.button === 0) tapHandler(); }}
- x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />);
- }
- render() {
- return <div className="histogramboxprimitives-container">
- {this.xaxislines}
- {this.yaxislines}
- <svg className="histogramboxprimitives-svgContainer">
- {this.barPrimitives}
- {this.selectedPrimitives}
- </svg>
- </div>;
- }
-}
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
deleted file mode 100644
index 304d33771..000000000
--- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-
- .histogramLabelPrimitives-gridlabel {
- position:absolute;
- transform-origin: left top;
- font-size: 11;
- color:white;
- }
- .histogramLabelPrimitives-placer {
- position:absolute;
- width:100%;
- height:100%;
- pointer-events: none;
- } \ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
deleted file mode 100644
index 62aebd3c6..000000000
--- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React = require("react");
-import { action, computed, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Utils as DashUtils } from '../../../Utils';
-import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
-import "../utils/Extensions";
-import { StyleConstants } from "../utils/StyleContants";
-import { HistogramBox } from "./HistogramBox";
-import "./HistogramLabelPrimitives.scss";
-import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives";
-
-@observer
-export class HistogramLabelPrimitives extends React.Component<HistogramPrimitivesProps> {
- componentDidMount() {
- reaction(() => [this.props.HistoBox.props.PanelWidth(), this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length],
- (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0], fields[1], this.props.HistoBox), { fireImmediately: true });
- }
-
- @action
- static computeLabelAngle(panelWidth: number, leftOffset: number, histoBox: HistogramBox) {
- const textWidth = 30;
- if (panelWidth > 0 && histoBox.VisualBinRanges.length && histoBox.VisualBinRanges[0] instanceof NominalVisualBinRange) {
- let space = (panelWidth - leftOffset * 2) / histoBox.VisualBinRanges[0].GetBins().length;
- histoBox.SizeConverter.SetLabelAngle(Math.min(Math.PI / 2, Math.max(Math.PI / 6, textWidth / space * Math.PI / 2)));
- } else if (histoBox.SizeConverter.LabelAngle) {
- histoBox.SizeConverter.SetLabelAngle(0);
- }
- }
- @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
- @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
-
- private renderGridLinesAndLabels(axis: number) {
- let sc = this.props.HistoBox.SizeConverter;
- let vb = this.props.HistoBox.VisualBinRanges;
- if (!vb.length || !sc.Initialized) {
- return (null);
- }
- let dim = (axis === 0 ? this.props.HistoBox.props.PanelWidth() : this.props.HistoBox.props.PanelHeight()) / ((axis === 0 && vb[axis] instanceof NominalVisualBinRange) ?
- (12 + 5) : // (<number>FontStyles.AxisLabel.fontSize + 5)));
- sc.MaxLabelSizes[axis].coords[axis] + 5);
-
- let labels = vb[axis].GetLabels();
- return labels.reduce((prims, binLabel, i) => {
- let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
- if (i % Math.ceil(labels.length / dim) === 0 && binLabel.label) {
- const label = binLabel.label.Truncate(StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS, "...");
- const textHeight = 14; const textWidth = 30;
- let xStart = (axis === 0 ? r.xFrom + (r.xTo - r.xFrom) / 2.0 : r.xFrom - 10 - textWidth);
- let yStart = (axis === 1 ? r.yFrom - textHeight / 2 : r.yFrom);
-
- if (axis === 0 && vb[axis] instanceof NominalVisualBinRange) {
- let space = (r.xTo - r.xFrom) / sc.RenderDimension * this.props.HistoBox.props.PanelWidth();
- xStart += Math.max(textWidth / 2, (1 - textWidth / space) * textWidth / 2) - textHeight / 2;
- }
-
- let xPercent = axis === 1 ? `${xStart}px` : `${xStart / sc.RenderDimension * 100}%`;
- let yPercent = axis === 0 ? `${this.props.HistoBox.props.PanelHeight() - sc.BottomOffset - textHeight}px` : `${yStart / sc.RenderDimension * 100}%`;
-
- prims.push(
- <div className="histogramLabelPrimitives-placer" key={DashUtils.GenerateGuid()} style={{ transform: `translate(${xPercent}, ${yPercent})` }}>
- <div className="histogramLabelPrimitives-gridlabel" style={{ transform: `rotate(${axis === 0 ? sc.LabelAngle : 0}rad)` }}>
- {label}
- </div>
- </div>
- );
- }
- return prims;
- }, [] as JSX.Element[]);
- }
-
- render() {
- let xaxislines = this.xaxislines;
- let yaxislines = this.yaxislines;
- return <div className="histogramLabelPrimitives-container">
- {xaxislines}
- {yaxislines}
- </div>;
- }
-
-} \ No newline at end of file
diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts
deleted file mode 100644
index c541cce6a..000000000
--- a/src/client/northstar/manager/Gateway.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea";
-import { computed, observable, action } from "mobx";
-
-export class Gateway {
-
- private static _instance: Gateway;
-
- private constructor() {
- }
-
- public static get Instance() {
- return this._instance || (this._instance = new this());
- }
-
- public async GetCatalog(): Promise<Catalog> {
- try {
- const json = await this.MakeGetRequest("catalog");
- const cat = Catalog.fromJS(json);
- return cat;
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async PostSchema(csvdata: string, schemaname: string): Promise<string> {
- try {
- const json = await this.MakePostJsonRequest("postSchema", { csv: csvdata, schema: schemaname });
- // const cat = Catalog.fromJS(json);
- // return cat;
- return json;
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async GetSchema(pathname: string, schemaname: string): Promise<Catalog> {
- try {
- const json = await this.MakeGetRequest("schema", undefined, { path: pathname, schema: schemaname });
- const cat = Catalog.fromJS(json);
- return cat;
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async ClearCatalog(): Promise<void> {
- try {
- await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {});
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async TerminateServer(): Promise<void> {
- try {
- const url = Gateway.ConstructUrl("terminateServer");
- const response = await fetch(url,
- {
- redirect: "follow",
- method: "POST",
- credentials: "include"
- });
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async Compile(data: any): Promise<CompileResults | undefined> {
- const json = await this.MakePostJsonRequest("compile", data);
- if (json !== null) {
- const cr = CompileResults.fromJS(json);
- return cr;
- }
- }
-
- public async SubmitResult(data: any): Promise<void> {
- try {
- console.log(data);
- const url = Gateway.ConstructUrl("submitProblem");
- const response = await fetch(url,
- {
- redirect: "follow",
- method: "POST",
- credentials: "include",
- body: JSON.stringify(data)
- });
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async SpecifyProblem(data: any): Promise<void> {
- try {
- console.log(data);
- const url = Gateway.ConstructUrl("specifyProblem");
- const response = await fetch(url,
- {
- redirect: "follow",
- method: "POST",
- credentials: "include",
- body: JSON.stringify(data)
- });
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
- public async ExportToScript(solutionId: string): Promise<string> {
- try {
- const url = Gateway.ConstructUrl("exportsolution/script/" + solutionId);
- const response = await fetch(url,
- {
- redirect: "follow",
- method: "GET",
- credentials: "include"
- });
- return await response.text();
- }
- catch (error) {
- throw new Error("can not reach northstar's backend");
- }
- }
-
-
- public async StartOperation(data: any): Promise<OperationReference | undefined> {
- const json = await this.MakePostJsonRequest("operation", data);
- if (json !== null) {
- const or = OperationReference.fromJS(json);
- return or;
- }
- }
-
- public async GetResult(data: any): Promise<Result | undefined> {
- const json = await this.MakePostJsonRequest("result", data);
- if (json !== null) {
- const res = Result.fromJS(json);
- return res;
- }
- }
-
- public async PauseOperation(data: any): Promise<void> {
- const url = Gateway.ConstructUrl("pause");
- await fetch(url,
- {
- redirect: "follow",
- method: "POST",
- credentials: "include",
- body: JSON.stringify(data)
- });
- }
-
- public async MakeGetRequest(endpoint: string, signal?: AbortSignal, params?: any): Promise<any> {
- let url = !params ? Gateway.ConstructUrl(endpoint) :
- (() => {
- let newUrl = new URL(Gateway.ConstructUrl(endpoint));
- Object.getOwnPropertyNames(params).map(prop =>
- newUrl.searchParams.append(prop, params[prop]));
- return Gateway.ConstructUrl(endpoint) + newUrl.search;
- })();
-
- const response = await fetch(url,
- {
- redirect: "follow",
- method: "GET",
- credentials: "include",
- signal
- });
- const json = await response.json();
- return json;
- }
-
- public async MakePostJsonRequest(endpoint: string, data: any, signal?: AbortSignal): Promise<any> {
- const url = Gateway.ConstructUrl(endpoint);
- const response = await fetch(url,
- {
- redirect: "follow",
- method: "POST",
- credentials: "include",
- body: JSON.stringify(data),
- signal
- });
- const json = await response.json();
- return json;
- }
-
-
- public static ConstructUrl(appendix: string): string {
- let base = NorthstarSettings.Instance.ServerUrl;
- if (base.slice(-1) === "/") {
- base = base.slice(0, -1);
- }
- let url = base + "/" + NorthstarSettings.Instance.ServerApiPath + "/" + appendix;
- return url;
- }
-}
-
-declare var ENV: any;
-
-export class NorthstarSettings {
- private _environment: any;
-
- @observable
- public ServerUrl: string = document.URL;
-
- @observable
- public ServerApiPath?: string;
-
- @observable
- public SampleSize?: number;
-
- @observable
- public XBins?: number;
-
- @observable
- public YBins?: number;
-
- @observable
- public SplashTimeInMS?: number;
-
- @observable
- public ShowFpsCounter?: boolean;
-
- @observable
- public IsMenuFixed?: boolean;
-
- @observable
- public ShowShutdownButton?: boolean;
-
- @observable
- public IsDarpa?: boolean;
-
- @observable
- public IsIGT?: boolean;
-
- @observable
- public DegreeOfParallelism?: number;
-
- @observable
- public ShowWarnings?: boolean;
-
- @computed
- public get IsDev(): boolean {
- return ENV.IsDev;
- }
-
- @computed
- public get TestDataFolderPath(): string {
- return this.Origin + "testdata/";
- }
-
- @computed
- public get Origin(): string {
- return window.location.origin + "/";
- }
-
- private static _instance: NorthstarSettings;
-
- @action
- public UpdateEnvironment(environment: any): void {
- /*let serverParam = new URL(document.URL).searchParams.get("serverUrl");
- if (serverParam) {
- if (serverParam === "debug") {
- this.ServerUrl = `http://${window.location.hostname}:1234`;
- }
- else {
- this.ServerUrl = serverParam;
- }
- }
- else {
- this.ServerUrl = environment["SERVER_URL"] ? environment["SERVER_URL"] : document.URL;
- }*/
- this.ServerUrl = environment.SERVER_URL ? environment.SERVER_URL : document.URL;
- this.ServerApiPath = environment.SERVER_API_PATH;
- this.SampleSize = environment.SAMPLE_SIZE;
- this.XBins = environment.X_BINS;
- this.YBins = environment.Y_BINS;
- this.SplashTimeInMS = environment.SPLASH_TIME_IN_MS;
- this.ShowFpsCounter = environment.SHOW_FPS_COUNTER;
- this.ShowShutdownButton = environment.SHOW_SHUTDOWN_BUTTON;
- this.IsMenuFixed = environment.IS_MENU_FIXED;
- this.IsDarpa = environment.IS_DARPA;
- this.IsIGT = environment.IS_IGT;
- this.DegreeOfParallelism = environment.DEGREE_OF_PARALLISM;
- }
-
- public static get Instance(): NorthstarSettings {
- if (!this._instance) {
- this._instance = new NorthstarSettings();
- }
- return this._instance;
- }
-}
diff --git a/src/client/northstar/model/ModelExtensions.ts b/src/client/northstar/model/ModelExtensions.ts
deleted file mode 100644
index 29f80d2d1..000000000
--- a/src/client/northstar/model/ModelExtensions.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea';
-import { Utils } from '../utils/Utils';
-
-import { FilterModel } from '../core/filter/FilterModel';
-
-(SingleDimensionAggregateParameters as any).prototype.Equals = function (other: Object) {
- if (!Utils.EqualityHelper(this, other)) return false;
- if (!Utils.EqualityHelper((this as SingleDimensionAggregateParameters).attributeParameters!,
- (other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
- if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters)) return false;
- return true;
-};
-
-{
- (AttributeParameters as any).prototype.Equals = function (other: AttributeParameters) {
- return (this).constructor.name === (<any>other).constructor.name &&
- this.rawName === other.rawName;
- };
-}
-
-{
- (Solution as any).prototype.Equals = function (other: Object) {
- if (!Utils.EqualityHelper(this, other)) return false;
- if ((this as Solution).solutionId !== (other as Solution).solutionId) return false;
- return true;
- };
-}
-
-{
- (MarginAggregateParameters as any).prototype.Equals = function (other: Object) {
- if (!Utils.EqualityHelper(this, other)) return false;
- if (!Utils.EqualityHelper((this as SingleDimensionAggregateParameters).attributeParameters!,
- (other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
- if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
-
- if ((this as MarginAggregateParameters).aggregateFunction !== (other as MarginAggregateParameters).aggregateFunction) return false;
- return true;
- };
-}
-
-{
- (Brush as any).prototype.Equals = function (other: Object) {
- if (!Utils.EqualityHelper(this, other)) return false;
- if ((this as Brush).brushEnum !== (other as Brush).brushEnum) return false;
- if ((this as Brush).brushIndex !== (other as Brush).brushIndex) return false;
- return true;
- };
-} \ No newline at end of file
diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts
deleted file mode 100644
index 88e6e72b8..000000000
--- a/src/client/northstar/model/ModelHelpers.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-
-import { action } from "mobx";
-import { AggregateFunction, AggregateKey, AggregateParameters, AttributeColumnParameters, AttributeParameters, AverageAggregateParameters, Bin, BinningParameters, Brush, BrushEnum, CountAggregateParameters, DataType, EquiWidthBinningParameters, HistogramResult, MarginAggregateParameters, SingleBinBinningParameters, SingleDimensionAggregateParameters, SumAggregateParameters, AggregateBinRange, NominalBinRange, AlphabeticBinRange, Predicate, Schema, Attribute, AttributeGroup, Exception, AttributeBackendParameters, AttributeCodeParameters } from '../model/idea/idea';
-import { ValueComparison } from "../core/filter/ValueComparision";
-import { ArrayUtil } from "../utils/ArrayUtil";
-import { AttributeModel, ColumnAttributeModel, BackendAttributeModel, CodeAttributeModel } from "../core/attribute/AttributeModel";
-import { FilterModel } from "../core/filter/FilterModel";
-import { AlphabeticVisualBinRange } from "./binRanges/AlphabeticVisualBinRange";
-import { NominalVisualBinRange } from "./binRanges/NominalVisualBinRange";
-import { VisualBinRangeHelper } from "./binRanges/VisualBinRangeHelper";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-
-export class ModelHelpers {
-
- public static CreateAggregateKey(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel, histogramResult: HistogramResult,
- brushIndex: number, aggParameters?: SingleDimensionAggregateParameters): AggregateKey {
- {
- if (aggParameters === undefined) {
- aggParameters = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, atm);
- }
- else {
- aggParameters.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- }
- return new AggregateKey(
- {
- aggregateParameterIndex: ModelHelpers.GetAggregateParametersIndex(histogramResult, aggParameters),
- brushIndex: brushIndex
- });
- }
- }
-
- public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number {
- return Array.from(histogramResult.aggregateParameters!).findIndex((value, i, set) => {
- if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) return true;
- if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) return true;
- if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) return true;
- return false;
- });
- }
-
- public static GetAggregateParameter(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel): AggregateParameters | undefined {
- var aggParam: AggregateParameters | undefined;
- if (atm.AggregateFunction === AggregateFunction.Avg) {
- var avg = new AverageAggregateParameters();
- avg.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- avg.distinctAttributeParameters = distinctAttributeParameters;
- aggParam = avg;
- }
- else if (atm.AggregateFunction === AggregateFunction.Count) {
- var cnt = new CountAggregateParameters();
- cnt.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- cnt.distinctAttributeParameters = distinctAttributeParameters;
- aggParam = cnt;
- }
- else if (atm.AggregateFunction === AggregateFunction.Sum) {
- var sum = new SumAggregateParameters();
- sum.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- sum.distinctAttributeParameters = distinctAttributeParameters;
- aggParam = sum;
- }
- return aggParam;
- }
-
- public static GetAggregateParametersWithMargins(distinctAttributeParameters: AttributeParameters | undefined, atms: Array<AttributeTransformationModel>): Array<AggregateParameters> {
- var aggregateParameters = new Array<AggregateParameters>();
- atms.forEach(agg => {
- var aggParams = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, agg);
- if (aggParams) {
- aggregateParameters.push(aggParams);
-
- var margin = new MarginAggregateParameters();
- margin.aggregateFunction = agg.AggregateFunction;
- margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel);
- margin.distinctAttributeParameters = distinctAttributeParameters;
- aggregateParameters.push(margin);
- }
- });
-
- return aggregateParameters;
- }
-
- public static GetBinningParameters(attr: AttributeTransformationModel, nrOfBins: number, minvalue?: number, maxvalue?: number): BinningParameters {
- if (attr.AggregateFunction === AggregateFunction.None) {
- return new EquiWidthBinningParameters(
- {
- attributeParameters: ModelHelpers.GetAttributeParameters(attr.AttributeModel),
- requestedNrOfBins: nrOfBins,
- minValue: minvalue,
- maxValue: maxvalue
- });
- }
- else {
- return new SingleBinBinningParameters(
- {
- attributeParameters: ModelHelpers.GetAttributeParameters(attr.AttributeModel)
- });
- }
- }
-
- public static GetAttributeParametersFromAttributeModel(am: AttributeModel): AttributeParameters {
- if (am instanceof ColumnAttributeModel) {
- return new AttributeColumnParameters(
- {
- rawName: am.CodeName,
- visualizationHints: am.VisualizationHints
- });
- }
- else if (am instanceof BackendAttributeModel) {
- return new AttributeBackendParameters(
- {
- rawName: am.CodeName,
- visualizationHints: am.VisualizationHints,
- id: (am).Id
- });
- }
- else if (am instanceof CodeAttributeModel) {
- return new AttributeCodeParameters(
- {
- rawName: am.CodeName,
- visualizationHints: am.VisualizationHints,
- code: (am).Code
- });
- }
- else {
- throw new Exception();
- }
- }
-
- public static GetAttributeParameters(am: AttributeModel): AttributeParameters {
- return this.GetAttributeParametersFromAttributeModel(am);
- }
-
- public static OverlapBrushIndex(histogramResult: HistogramResult): number {
- var brush = ArrayUtil.First(histogramResult.brushes!, (b: any) => b.brushEnum === BrushEnum.Overlap);
- return ModelHelpers.GetBrushIndex(histogramResult, brush);
- }
-
- public static AllBrushIndex(histogramResult: HistogramResult): number {
- var brush = ArrayUtil.First(histogramResult.brushes!, (b: any) => b.brushEnum === BrushEnum.All);
- return ModelHelpers.GetBrushIndex(histogramResult, brush);
- }
-
- public static RestBrushIndex(histogramResult: HistogramResult): number {
- var brush = ArrayUtil.First(histogramResult.brushes!, (b: Brush) => b.brushEnum === BrushEnum.Rest);
- return ModelHelpers.GetBrushIndex(histogramResult, brush);
- }
-
- public static GetBrushIndex(histogramResult: HistogramResult, brush: Brush): number {
- return ArrayUtil.IndexOfWithEqual(histogramResult.brushes!, brush);
- }
-
- public static GetAggregateResult(bin: Bin, aggregateKey: AggregateKey) {
- if (aggregateKey.aggregateParameterIndex === -1 || aggregateKey.brushIndex === -1) {
- return null;
- }
- return bin.aggregateResults![aggregateKey.aggregateParameterIndex! * bin.ySize! + aggregateKey.brushIndex!];
- }
-
- @action
- public static PossibleAggegationFunctions(atm: AttributeTransformationModel): Array<AggregateFunction> {
- var ret = new Array<AggregateFunction>();
- ret.push(AggregateFunction.None);
- ret.push(AggregateFunction.Count);
- if (atm.AttributeModel.DataType === DataType.Float ||
- atm.AttributeModel.DataType === DataType.Double ||
- atm.AttributeModel.DataType === DataType.Int) {
- ret.push(AggregateFunction.Avg);
- ret.push(AggregateFunction.Sum);
- }
- return ret;
- }
-
- public static GetBinFilterModel(
- bin: Bin, brushIndex: number, histogramResult: HistogramResult,
- xAom: AttributeTransformationModel, yAom: AttributeTransformationModel): FilterModel {
- var dimensions: Array<AttributeTransformationModel> = [xAom, yAom];
- var filterModel = new FilterModel();
-
- for (var i = 0; i < histogramResult.binRanges!.length; i++) {
- if (!(histogramResult.binRanges![i] instanceof AggregateBinRange)) {
- var binRange = VisualBinRangeHelper.GetNonAggregateVisualBinRange(histogramResult.binRanges![i]);
- var dataFrom = binRange.GetValueFromIndex(bin.binIndex!.indices![i]);
- var dataTo = binRange.AddStep(dataFrom);
-
- if (binRange instanceof NominalVisualBinRange) {
- var tt = binRange.GetLabel(dataFrom);
- filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.EQUALS, tt));
- }
- else if (binRange instanceof AlphabeticVisualBinRange) {
- filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.STARTS_WITH,
- binRange.GetLabel(dataFrom)));
- }
- else {
- filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.GREATER_THAN_EQUAL, dataFrom));
- filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.LESS_THAN, dataTo));
- }
- }
- }
-
- return filterModel;
- }
-
- public GetAllAttributes(schema: Schema) {
- if (!schema || !schema.rootAttributeGroup) {
- return [];
- }
- const recurs = (attrs: Attribute[], g: AttributeGroup) => {
- if (g.attributes) {
- attrs.push.apply(attrs, g.attributes);
- if (g.attributeGroups) {
- g.attributeGroups.forEach(ng => recurs(attrs, ng));
- }
- }
- };
- const allAttributes: Attribute[] = new Array<Attribute>();
- recurs(allAttributes, schema.rootAttributeGroup);
- return allAttributes;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
deleted file mode 100644
index 120b034f2..000000000
--- a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-
-export class AlphabeticVisualBinRange extends VisualBinRange {
- public DataBinRange: AlphabeticBinRange;
-
- constructor(dataBinRange: AlphabeticBinRange) {
- super();
- this.DataBinRange = dataBinRange;
- }
-
- public AddStep(value: number): number {
- return value + 1;
- }
-
- public GetValueFromIndex(index: number): number {
- return index;
- }
-
- public GetBins(): number[] {
- var bins = new Array<number>();
- var idx = 0;
- for (var key in this.DataBinRange.labelsValue) {
- if (this.DataBinRange.labelsValue.hasOwnProperty(key)) {
- bins.push(idx);
- idx++;
- }
- }
- return bins;
- }
-
- public GetLabel(value: number): string {
- return this.DataBinRange.prefix + this.DataBinRange.valuesLabel![value];
- }
-
- public GetLabels(): Array<BinLabel> {
- var labels = new Array<BinLabel>();
- var count = 0;
- for (var key in this.DataBinRange.valuesLabel) {
- if (this.DataBinRange.valuesLabel.hasOwnProperty(key)) {
- var value = this.DataBinRange.valuesLabel[key];
- labels.push(new BinLabel({
- value: parseFloat(key),
- minValue: count++,
- maxValue: count,
- label: this.DataBinRange.prefix + value
- }));
- }
- }
- return labels;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
deleted file mode 100644
index 776e643cd..000000000
--- a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-
-export class DateTimeVisualBinRange extends VisualBinRange {
- public DataBinRange: DateTimeBinRange;
-
- constructor(dataBinRange: DateTimeBinRange) {
- super();
- this.DataBinRange = dataBinRange;
- }
-
- public AddStep(value: number): number {
- return DateTimeVisualBinRange.AddToDateTimeTicks(value, this.DataBinRange.step!);
- }
-
- public GetValueFromIndex(index: number): number {
- var v = this.DataBinRange.minValue!;
- for (var i = 0; i < index; i++) {
- v = this.AddStep(v);
- }
- return v;
- }
-
- public GetBins(): number[] {
- var bins = new Array<number>();
- for (var v: number = this.DataBinRange.minValue!;
- v < this.DataBinRange.maxValue!;
- v = DateTimeVisualBinRange.AddToDateTimeTicks(v, this.DataBinRange.step!)) {
- bins.push(v);
- }
- return bins;
- }
-
- private pad(n: number, size: number) {
- var sign = n < 0 ? '-' : '';
- return sign + new Array(size).concat([Math.abs(n)]).join('0').slice(-size);
- }
-
-
- public GetLabel(value: number): string {
- var dt = DateTimeVisualBinRange.TicksToDate(value);
- if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Second ||
- this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Minute) {
- return ("" + this.pad(dt.getMinutes(), 2) + ":" + this.pad(dt.getSeconds(), 2));
- //return dt.ToString("mm:ss");
- }
- else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Hour) {
- return (this.pad(dt.getHours(), 2) + ":" + this.pad(dt.getMinutes(), 2));
- //return dt.ToString("HH:mm");
- }
- else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Day) {
- return ((dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear());
- //return dt.ToString("MM/dd/yyyy");
- }
- else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Month) {
- //return dt.ToString("MM/yyyy");
- return ((dt.getMonth() + 1) + "/" + dt.getFullYear());
- }
- else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Year) {
- return "" + dt.getFullYear();
- }
- return "n/a";
- }
-
- public static TicksToDate(ticks: number): Date {
- var dd = new Date((ticks - 621355968000000000) / 10000);
- dd.setMinutes(dd.getMinutes() + dd.getTimezoneOffset());
- return dd;
- }
-
-
- public static DateToTicks(date: Date): number {
- var copiedDate = new Date(date.getTime());
- copiedDate.setMinutes(copiedDate.getMinutes() - copiedDate.getTimezoneOffset());
- var t = copiedDate.getTime() * 10000 + 621355968000000000;
- /*var dd = new Date((ticks - 621355968000000000) / 10000);
- dd.setMinutes(dd.getMinutes() + dd.getTimezoneOffset());
- return dd;*/
- return t;
- }
-
- public static AddToDateTimeTicks(ticks: number, dateTimeStep: DateTimeStep): number {
- var copiedDate = DateTimeVisualBinRange.TicksToDate(ticks);
- var returnDate: Date = new Date(Date.now());
- if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Second) {
- returnDate = new Date(copiedDate.setSeconds(copiedDate.getSeconds() + dateTimeStep.dateTimeStepValue!));
- }
- else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Minute) {
- returnDate = new Date(copiedDate.setMinutes(copiedDate.getMinutes() + dateTimeStep.dateTimeStepValue!));
- }
- else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Hour) {
- returnDate = new Date(copiedDate.setHours(copiedDate.getHours() + dateTimeStep.dateTimeStepValue!));
- }
- else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Day) {
- returnDate = new Date(copiedDate.setDate(copiedDate.getDate() + dateTimeStep.dateTimeStepValue!));
- }
- else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Month) {
- returnDate = new Date(copiedDate.setMonth(copiedDate.getMonth() + dateTimeStep.dateTimeStepValue!));
- }
- else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Year) {
- returnDate = new Date(copiedDate.setFullYear(copiedDate.getFullYear() + dateTimeStep.dateTimeStepValue!));
- }
- return DateTimeVisualBinRange.DateToTicks(returnDate);
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts
deleted file mode 100644
index 42509d797..000000000
--- a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { NominalBinRange, BinLabel } from '../../model/idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-
-export class NominalVisualBinRange extends VisualBinRange {
- public DataBinRange: NominalBinRange;
-
- constructor(dataBinRange: NominalBinRange) {
- super();
- this.DataBinRange = dataBinRange;
- }
-
- public AddStep(value: number): number {
- return value + 1;
- }
-
- public GetValueFromIndex(index: number): number {
- return index;
- }
-
- public GetBins(): number[] {
- var bins = new Array<number>();
- var idx = 0;
- for (var key in this.DataBinRange.labelsValue) {
- if (this.DataBinRange.labelsValue.hasOwnProperty(key)) {
- bins.push(idx);
- idx++;
- }
- }
- return bins;
- }
-
- public GetLabel(value: number): string {
- return this.DataBinRange.valuesLabel![value];
- }
-
- public GetLabels(): Array<BinLabel> {
- var labels = new Array<BinLabel>();
- var count = 0;
- for (var key in this.DataBinRange.valuesLabel) {
- if (this.DataBinRange.valuesLabel.hasOwnProperty(key)) {
- var value = this.DataBinRange.valuesLabel[key];
- labels.push(new BinLabel({
- value: parseFloat(key),
- minValue: count++,
- maxValue: count,
- label: value
- }));
- }
- }
- return labels;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
deleted file mode 100644
index 7bc097e1d..000000000
--- a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { QuantitativeBinRange } from '../idea/idea';
-import { VisualBinRange } from './VisualBinRange';
-import { format } from "d3-format";
-
-export class QuantitativeVisualBinRange extends VisualBinRange {
-
- public DataBinRange: QuantitativeBinRange;
-
- constructor(dataBinRange: QuantitativeBinRange) {
- super();
- this.DataBinRange = dataBinRange;
- }
-
- public AddStep(value: number): number {
- return value + this.DataBinRange.step!;
- }
-
- public GetValueFromIndex(index: number): number {
- return this.DataBinRange.minValue! + (index * this.DataBinRange.step!);
- }
-
- public GetLabel(value: number): string {
- return QuantitativeVisualBinRange.NumberFormatter(value);
- }
-
- public static NumberFormatter(val: number): string {
- if (val === 0) {
- return "0";
- }
- if (val < 1) {
- /*if (val < Math.abs(0.001)) {
- return val.toExponential(2);
- }*/
- return format(".3")(val);
- }
- return format("~s")(val);
- }
-
- public GetBins(): number[] {
- const bins = new Array<number>();
-
- for (let v: number = this.DataBinRange.minValue!; v < this.DataBinRange.maxValue!; v += this.DataBinRange.step!) {
- bins.push(v);
- }
- return bins;
- }
-
- public static Initialize(dataMinValue: number, dataMaxValue: number, targetBinNumber: number, isIntegerRange: boolean): QuantitativeVisualBinRange {
- const extent = QuantitativeVisualBinRange.getExtent(dataMinValue, dataMaxValue, targetBinNumber, isIntegerRange);
- const dataBinRange = new QuantitativeBinRange();
- dataBinRange.minValue = extent[0];
- dataBinRange.maxValue = extent[1];
- dataBinRange.step = extent[2];
-
- return new QuantitativeVisualBinRange(dataBinRange);
- }
-
- private static getExtent(dataMin: number, dataMax: number, m: number, isIntegerRange: boolean): number[] {
- if (dataMin === dataMax) {
- // dataMin -= 0.1;
- dataMax += 0.1;
- }
- const span = dataMax - dataMin;
-
- let step = Math.pow(10, Math.floor(Math.log10(span / m)));
- const err = m / span * step;
-
- if (err <= .15) {
- step *= 10;
- }
- else if (err <= .35) {
- step *= 5;
- }
- else if (err <= .75) {
- step *= 2;
- }
-
- if (isIntegerRange) {
- step = Math.ceil(step);
- }
- const ret: number[] = new Array<number>(3);
- const minDivStep = Math.floor(dataMin / step);
- const maxDivStep = Math.floor(dataMax / step);
- ret[0] = minDivStep * step; // Math.floor(Math.Round(dataMin, 8)/step)*step;
- ret[1] = maxDivStep * step + step; // Math.floor(Math.Round(dataMax, 8)/step)*step + step;
- ret[2] = step;
-
- return ret;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/VisualBinRange.ts b/src/client/northstar/model/binRanges/VisualBinRange.ts
deleted file mode 100644
index 449a22e91..000000000
--- a/src/client/northstar/model/binRanges/VisualBinRange.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { BinLabel } from '../../model/idea/idea';
-
-export abstract class VisualBinRange {
-
- public abstract AddStep(value: number): number;
-
- public abstract GetValueFromIndex(index: number): number;
-
- public abstract GetBins(): Array<number>;
-
- public GetLabel(value: number): string {
- return value.toString();
- }
-
- public GetLabels(): Array<BinLabel> {
- var labels = new Array<BinLabel>();
- var bins = this.GetBins();
- bins.forEach(b => {
- labels.push(new BinLabel({
- value: b,
- minValue: b,
- maxValue: this.AddStep(b),
- label: this.GetLabel(b)
- }));
- });
- return labels;
- }
-}
-
-export enum ChartType {
- HorizontalBar = 0, VerticalBar = 1, HeatMap = 2, SinglePoint = 3
-} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
deleted file mode 100644
index a92412686..000000000
--- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import { BinRange, NominalBinRange, QuantitativeBinRange, Exception, AlphabeticBinRange, DateTimeBinRange, AggregateBinRange, DoubleValueAggregateResult, HistogramResult, AttributeParameters } from "../idea/idea";
-import { VisualBinRange, ChartType } from "./VisualBinRange";
-import { NominalVisualBinRange } from "./NominalVisualBinRange";
-import { QuantitativeVisualBinRange } from "./QuantitativeVisualBinRange";
-import { AlphabeticVisualBinRange } from "./AlphabeticVisualBinRange";
-import { DateTimeVisualBinRange } from "./DateTimeVisualBinRange";
-import { NorthstarSettings } from "../../manager/Gateway";
-import { ModelHelpers } from "../ModelHelpers";
-import { AttributeTransformationModel } from "../../core/attribute/AttributeTransformationModel";
-
-export const SETTINGS_X_BINS = 15;
-export const SETTINGS_Y_BINS = 15;
-export const SETTINGS_SAMPLE_SIZE = 100000;
-
-export class VisualBinRangeHelper {
-
- public static GetNonAggregateVisualBinRange(dataBinRange: BinRange): VisualBinRange {
- if (dataBinRange instanceof NominalBinRange) {
- return new NominalVisualBinRange(dataBinRange);
- }
- else if (dataBinRange instanceof QuantitativeBinRange) {
- return new QuantitativeVisualBinRange(dataBinRange);
- }
- else if (dataBinRange instanceof AlphabeticBinRange) {
- return new AlphabeticVisualBinRange(dataBinRange);
- }
- else if (dataBinRange instanceof DateTimeBinRange) {
- return new DateTimeVisualBinRange(dataBinRange);
- }
- throw new Exception();
- }
-
- public static GetVisualBinRange(distinctAttributeParameters: AttributeParameters | undefined, dataBinRange: BinRange, histoResult: HistogramResult, attr: AttributeTransformationModel, chartType: ChartType): VisualBinRange {
-
- if (!(dataBinRange instanceof AggregateBinRange)) {
- return VisualBinRangeHelper.GetNonAggregateVisualBinRange(dataBinRange);
- }
- else {
- var aggregateKey = ModelHelpers.CreateAggregateKey(distinctAttributeParameters, attr, histoResult, ModelHelpers.AllBrushIndex(histoResult));
- var minValue = Number.MAX_VALUE;
- var maxValue = Number.MIN_VALUE;
- for (const brush of histoResult.brushes!) {
- aggregateKey.brushIndex = brush.brushIndex;
- for (var key in histoResult.bins) {
- if (histoResult.bins.hasOwnProperty(key)) {
- var bin = histoResult.bins[key];
- var res = <DoubleValueAggregateResult>ModelHelpers.GetAggregateResult(bin, aggregateKey);
- if (res && res.hasResult && res.result) {
- minValue = Math.min(minValue, res.result);
- maxValue = Math.max(maxValue, res.result);
- }
- }
- }
- }
-
- let visualBinRange = QuantitativeVisualBinRange.Initialize(minValue, maxValue, 10, false);
-
- if (chartType === ChartType.HorizontalBar || chartType === ChartType.VerticalBar) {
- visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue),
- Math.max(0, (visualBinRange).DataBinRange.maxValue!),
- SETTINGS_X_BINS, false);
- }
- else if (chartType === ChartType.SinglePoint) {
- visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue), Math.max(0, maxValue),
- SETTINGS_X_BINS, false);
- }
- return visualBinRange;
- }
- }
-}
diff --git a/src/client/northstar/model/idea/MetricTypeMapping.ts b/src/client/northstar/model/idea/MetricTypeMapping.ts
deleted file mode 100644
index e9759cf16..000000000
--- a/src/client/northstar/model/idea/MetricTypeMapping.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { MetricType } from "./Idea";
-import { Dictionary } from 'typescript-collections';
-
-
-export class MetricTypeMapping {
-
- public static GetMetricInterpretation(metricType: MetricType): MetricInterpretation {
- if (metricType === MetricType.Accuracy ||
- metricType === MetricType.F1 ||
- metricType === MetricType.F1Macro ||
- metricType === MetricType.F1Micro ||
- metricType === MetricType.JaccardSimilarityScore ||
- metricType === MetricType.ObjectDetectionAveragePrecision ||
- metricType === MetricType.Precision ||
- metricType === MetricType.PrecisionAtTopK ||
- metricType === MetricType.NormalizedMutualInformation ||
- metricType === MetricType.Recall ||
- metricType === MetricType.RocAucMacro ||
- metricType === MetricType.RocAuc ||
- metricType === MetricType.RocAucMicro ||
- metricType === MetricType.RSquared) {
- return MetricInterpretation.HigherIsBetter;
- }
- return MetricInterpretation.LowerIsBetter;
- }
-}
-
-export enum MetricInterpretation {
- HigherIsBetter, LowerIsBetter
-} \ No newline at end of file
diff --git a/src/client/northstar/model/idea/idea.ts b/src/client/northstar/model/idea/idea.ts
deleted file mode 100644
index c73a822c7..000000000
--- a/src/client/northstar/model/idea/idea.ts
+++ /dev/null
@@ -1,8557 +0,0 @@
-/* tslint:disable */
-//----------------------
-// <auto-generated>
-// Generated using the NSwag toolchain v11.19.2.0 (NJsonSchema v9.10.73.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org)
-// </auto-generated>
-//----------------------
-// ReSharper disable InconsistentNaming
-
-
-
-export enum AggregateFunction {
- None = "None",
- Sum = "Sum",
- SumE = "SumE",
- Count = "Count",
- Min = "Min",
- Max = "Max",
- Avg = "Avg",
-}
-
-export abstract class AggregateParameters implements IAggregateParameters {
-
- protected _discriminator: string;
-
- public Equals(other: Object): boolean {
- return this == other;
- }
- constructor(data?: IAggregateParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "AggregateParameters";
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): AggregateParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "AverageAggregateParameters") {
- let result = new AverageAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SingleDimensionAggregateParameters") {
- throw new Error("The abstract class 'SingleDimensionAggregateParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "CountAggregateParameters") {
- let result = new CountAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "KDEAggregateParameters") {
- let result = new KDEAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "MarginAggregateParameters") {
- let result = new MarginAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "MaxAggregateParameters") {
- let result = new MaxAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "MinAggregateParameters") {
- let result = new MinAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SumAggregateParameters") {
- let result = new SumAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SumEstimationAggregateParameters") {
- let result = new SumEstimationAggregateParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'AggregateParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- return data;
- }
-}
-
-export interface IAggregateParameters {
-}
-
-export abstract class SingleDimensionAggregateParameters extends AggregateParameters implements ISingleDimensionAggregateParameters {
- attributeParameters?: AttributeParameters | undefined;
- distinctAttributeParameters?: AttributeParameters | undefined;
-
- constructor(data?: ISingleDimensionAggregateParameters) {
- super(data);
- this._discriminator = "SingleDimensionAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.attributeParameters = data["AttributeParameters"] ? AttributeParameters.fromJS(data["AttributeParameters"]) : <any>undefined;
- this.distinctAttributeParameters = data["DistinctAttributeParameters"] ? AttributeParameters.fromJS(data["DistinctAttributeParameters"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): SingleDimensionAggregateParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "AverageAggregateParameters") {
- let result = new AverageAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CountAggregateParameters") {
- let result = new CountAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "KDEAggregateParameters") {
- let result = new KDEAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "MarginAggregateParameters") {
- let result = new MarginAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "MaxAggregateParameters") {
- let result = new MaxAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "MinAggregateParameters") {
- let result = new MinAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SumAggregateParameters") {
- let result = new SumAggregateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SumEstimationAggregateParameters") {
- let result = new SumEstimationAggregateParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'SingleDimensionAggregateParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["AttributeParameters"] = this.attributeParameters ? this.attributeParameters.toJSON() : <any>undefined;
- data["DistinctAttributeParameters"] = this.distinctAttributeParameters ? this.distinctAttributeParameters.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISingleDimensionAggregateParameters extends IAggregateParameters {
- attributeParameters?: AttributeParameters | undefined;
- distinctAttributeParameters?: AttributeParameters | undefined;
-}
-
-export class AverageAggregateParameters extends SingleDimensionAggregateParameters implements IAverageAggregateParameters {
-
- constructor(data?: IAverageAggregateParameters) {
- super(data);
- this._discriminator = "AverageAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): AverageAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new AverageAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAverageAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export abstract class AttributeParameters implements IAttributeParameters {
- visualizationHints?: VisualizationHint[] | undefined;
- rawName?: string | undefined;
- public Equals(other: Object): boolean {
- return this == other;
- }
-
- protected _discriminator: string;
-
- constructor(data?: IAttributeParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "AttributeParameters";
- }
-
- init(data?: any) {
- if (data) {
- if (data["VisualizationHints"] && data["VisualizationHints"].constructor === Array) {
- this.visualizationHints = [];
- for (let item of data["VisualizationHints"])
- this.visualizationHints.push(item);
- }
- this.rawName = data["RawName"];
- }
- }
-
- static fromJS(data: any): AttributeParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "AttributeBackendParameters") {
- let result = new AttributeBackendParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AttributeCaclculatedParameters") {
- throw new Error("The abstract class 'AttributeCaclculatedParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "AttributeCodeParameters") {
- let result = new AttributeCodeParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AttributeColumnParameters") {
- let result = new AttributeColumnParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'AttributeParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- if (this.visualizationHints && this.visualizationHints.constructor === Array) {
- data["VisualizationHints"] = [];
- for (let item of this.visualizationHints)
- data["VisualizationHints"].push(item);
- }
- data["RawName"] = this.rawName;
- return data;
- }
-}
-
-export interface IAttributeParameters {
- visualizationHints?: VisualizationHint[] | undefined;
- rawName?: string | undefined;
-}
-
-export enum VisualizationHint {
- TreatAsEnumeration = "TreatAsEnumeration",
- DefaultFlipAxis = "DefaultFlipAxis",
- Image = "Image",
-}
-
-export abstract class AttributeCaclculatedParameters extends AttributeParameters implements IAttributeCaclculatedParameters {
-
- constructor(data?: IAttributeCaclculatedParameters) {
- super(data);
- this._discriminator = "AttributeCaclculatedParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): AttributeCaclculatedParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "AttributeBackendParameters") {
- let result = new AttributeBackendParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AttributeCodeParameters") {
- let result = new AttributeCodeParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'AttributeCaclculatedParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAttributeCaclculatedParameters extends IAttributeParameters {
-}
-
-export class AttributeBackendParameters extends AttributeCaclculatedParameters implements IAttributeBackendParameters {
- id?: string | undefined;
-
- constructor(data?: IAttributeBackendParameters) {
- super(data);
- this._discriminator = "AttributeBackendParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.id = data["Id"];
- }
- }
-
- static fromJS(data: any): AttributeBackendParameters {
- data = typeof data === 'object' ? data : {};
- let result = new AttributeBackendParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAttributeBackendParameters extends IAttributeCaclculatedParameters {
- id?: string | undefined;
-}
-
-export class AttributeCodeParameters extends AttributeCaclculatedParameters implements IAttributeCodeParameters {
- code?: string | undefined;
-
- constructor(data?: IAttributeCodeParameters) {
- super(data);
- this._discriminator = "AttributeCodeParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.code = data["Code"];
- }
- }
-
- static fromJS(data: any): AttributeCodeParameters {
- data = typeof data === 'object' ? data : {};
- let result = new AttributeCodeParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Code"] = this.code;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAttributeCodeParameters extends IAttributeCaclculatedParameters {
- code?: string | undefined;
-}
-
-export class AttributeColumnParameters extends AttributeParameters implements IAttributeColumnParameters {
-
- constructor(data?: IAttributeColumnParameters) {
- super(data);
- this._discriminator = "AttributeColumnParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): AttributeColumnParameters {
- data = typeof data === 'object' ? data : {};
- let result = new AttributeColumnParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAttributeColumnParameters extends IAttributeParameters {
-}
-
-export class CountAggregateParameters extends SingleDimensionAggregateParameters implements ICountAggregateParameters {
-
- constructor(data?: ICountAggregateParameters) {
- super(data);
- this._discriminator = "CountAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): CountAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new CountAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ICountAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class KDEAggregateParameters extends SingleDimensionAggregateParameters implements IKDEAggregateParameters {
- nrOfSamples?: number | undefined;
-
- constructor(data?: IKDEAggregateParameters) {
- super(data);
- this._discriminator = "KDEAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.nrOfSamples = data["NrOfSamples"];
- }
- }
-
- static fromJS(data: any): KDEAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new KDEAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["NrOfSamples"] = this.nrOfSamples;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IKDEAggregateParameters extends ISingleDimensionAggregateParameters {
- nrOfSamples?: number | undefined;
-}
-
-export class MarginAggregateParameters extends SingleDimensionAggregateParameters implements IMarginAggregateParameters {
- aggregateFunction?: AggregateFunction | undefined;
-
- constructor(data?: IMarginAggregateParameters) {
- super(data);
- this._discriminator = "MarginAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.aggregateFunction = data["AggregateFunction"];
- }
- }
-
- static fromJS(data: any): MarginAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new MarginAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["AggregateFunction"] = this.aggregateFunction;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IMarginAggregateParameters extends ISingleDimensionAggregateParameters {
- aggregateFunction?: AggregateFunction | undefined;
-}
-
-export class MaxAggregateParameters extends SingleDimensionAggregateParameters implements IMaxAggregateParameters {
-
- constructor(data?: IMaxAggregateParameters) {
- super(data);
- this._discriminator = "MaxAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): MaxAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new MaxAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IMaxAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class MinAggregateParameters extends SingleDimensionAggregateParameters implements IMinAggregateParameters {
-
- constructor(data?: IMinAggregateParameters) {
- super(data);
- this._discriminator = "MinAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): MinAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new MinAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IMinAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class SumAggregateParameters extends SingleDimensionAggregateParameters implements ISumAggregateParameters {
-
- constructor(data?: ISumAggregateParameters) {
- super(data);
- this._discriminator = "SumAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): SumAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new SumAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISumAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export class SumEstimationAggregateParameters extends SingleDimensionAggregateParameters implements ISumEstimationAggregateParameters {
-
- constructor(data?: ISumEstimationAggregateParameters) {
- super(data);
- this._discriminator = "SumEstimationAggregateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): SumEstimationAggregateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new SumEstimationAggregateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISumEstimationAggregateParameters extends ISingleDimensionAggregateParameters {
-}
-
-export enum OrderingFunction {
- None = 0,
- SortUp = 1,
- SortDown = 2,
-}
-
-export abstract class BinningParameters implements IBinningParameters {
- attributeParameters?: AttributeParameters | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IBinningParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "BinningParameters";
- }
-
- init(data?: any) {
- if (data) {
- this.attributeParameters = data["AttributeParameters"] ? AttributeParameters.fromJS(data["AttributeParameters"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): BinningParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "EquiWidthBinningParameters") {
- let result = new EquiWidthBinningParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SingleBinBinningParameters") {
- let result = new SingleBinBinningParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'BinningParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["AttributeParameters"] = this.attributeParameters ? this.attributeParameters.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface IBinningParameters {
- attributeParameters?: AttributeParameters | undefined;
-}
-
-export class EquiWidthBinningParameters extends BinningParameters implements IEquiWidthBinningParameters {
- minValue?: number | undefined;
- maxValue?: number | undefined;
- requestedNrOfBins?: number | undefined;
- referenceValue?: number | undefined;
- step?: number | undefined;
-
- constructor(data?: IEquiWidthBinningParameters) {
- super(data);
- this._discriminator = "EquiWidthBinningParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.minValue = data["MinValue"];
- this.maxValue = data["MaxValue"];
- this.requestedNrOfBins = data["RequestedNrOfBins"];
- this.referenceValue = data["ReferenceValue"];
- this.step = data["Step"];
- }
- }
-
- static fromJS(data: any): EquiWidthBinningParameters {
- data = typeof data === 'object' ? data : {};
- let result = new EquiWidthBinningParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["MinValue"] = this.minValue;
- data["MaxValue"] = this.maxValue;
- data["RequestedNrOfBins"] = this.requestedNrOfBins;
- data["ReferenceValue"] = this.referenceValue;
- data["Step"] = this.step;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IEquiWidthBinningParameters extends IBinningParameters {
- minValue?: number | undefined;
- maxValue?: number | undefined;
- requestedNrOfBins?: number | undefined;
- referenceValue?: number | undefined;
- step?: number | undefined;
-}
-
-export class SingleBinBinningParameters extends BinningParameters implements ISingleBinBinningParameters {
-
- constructor(data?: ISingleBinBinningParameters) {
- super(data);
- this._discriminator = "SingleBinBinningParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): SingleBinBinningParameters {
- data = typeof data === 'object' ? data : {};
- let result = new SingleBinBinningParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISingleBinBinningParameters extends IBinningParameters {
-}
-
-export class Attribute implements IAttribute {
- displayName?: string | undefined;
- rawName?: string | undefined;
- description?: string | undefined;
- dataType?: DataType | undefined;
- visualizationHints?: VisualizationHint[] | undefined;
- isTarget?: boolean | undefined;
-
- constructor(data?: IAttribute) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.displayName = data["DisplayName"];
- this.rawName = data["RawName"];
- this.description = data["Description"];
- this.dataType = data["DataType"];
- if (data["VisualizationHints"] && data["VisualizationHints"].constructor === Array) {
- this.visualizationHints = [];
- for (let item of data["VisualizationHints"])
- this.visualizationHints.push(item);
- }
- this.isTarget = data["IsTarget"];
- }
- }
-
- static fromJS(data: any): Attribute {
- data = typeof data === 'object' ? data : {};
- let result = new Attribute();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["DisplayName"] = this.displayName;
- data["RawName"] = this.rawName;
- data["Description"] = this.description;
- data["DataType"] = this.dataType;
- if (this.visualizationHints && this.visualizationHints.constructor === Array) {
- data["VisualizationHints"] = [];
- for (let item of this.visualizationHints)
- data["VisualizationHints"].push(item);
- }
- data["IsTarget"] = this.isTarget;
- return data;
- }
-}
-
-export interface IAttribute {
- displayName?: string | undefined;
- rawName?: string | undefined;
- description?: string | undefined;
- dataType?: DataType | undefined;
- visualizationHints?: VisualizationHint[] | undefined;
- isTarget?: boolean | undefined;
-}
-
-export enum DataType {
- Int = "Int",
- String = "String",
- Float = "Float",
- Double = "Double",
- DateTime = "DateTime",
- Object = "Object",
- Undefined = "Undefined",
-}
-
-export class AttributeGroup implements IAttributeGroup {
- name?: string | undefined;
- attributeGroups?: AttributeGroup[] | undefined;
- attributes?: Attribute[] | undefined;
-
- constructor(data?: IAttributeGroup) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.name = data["Name"];
- if (data["AttributeGroups"] && data["AttributeGroups"].constructor === Array) {
- this.attributeGroups = [];
- for (let item of data["AttributeGroups"])
- this.attributeGroups.push(AttributeGroup.fromJS(item));
- }
- if (data["Attributes"] && data["Attributes"].constructor === Array) {
- this.attributes = [];
- for (let item of data["Attributes"])
- this.attributes.push(Attribute.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): AttributeGroup {
- data = typeof data === 'object' ? data : {};
- let result = new AttributeGroup();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Name"] = this.name;
- if (this.attributeGroups && this.attributeGroups.constructor === Array) {
- data["AttributeGroups"] = [];
- for (let item of this.attributeGroups)
- data["AttributeGroups"].push(item.toJSON());
- }
- if (this.attributes && this.attributes.constructor === Array) {
- data["Attributes"] = [];
- for (let item of this.attributes)
- data["Attributes"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IAttributeGroup {
- name?: string | undefined;
- attributeGroups?: AttributeGroup[] | undefined;
- attributes?: Attribute[] | undefined;
-}
-
-export class Catalog implements ICatalog {
- supportedOperations?: string[] | undefined;
- schemas?: Schema[] | undefined;
-
- constructor(data?: ICatalog) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["SupportedOperations"] && data["SupportedOperations"].constructor === Array) {
- this.supportedOperations = [];
- for (let item of data["SupportedOperations"])
- this.supportedOperations.push(item);
- }
- if (data["Schemas"] && data["Schemas"].constructor === Array) {
- this.schemas = [];
- for (let item of data["Schemas"])
- this.schemas.push(Schema.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): Catalog {
- data = typeof data === 'object' ? data : {};
- let result = new Catalog();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.supportedOperations && this.supportedOperations.constructor === Array) {
- data["SupportedOperations"] = [];
- for (let item of this.supportedOperations)
- data["SupportedOperations"].push(item);
- }
- if (this.schemas && this.schemas.constructor === Array) {
- data["Schemas"] = [];
- for (let item of this.schemas)
- data["Schemas"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface ICatalog {
- supportedOperations?: string[] | undefined;
- schemas?: Schema[] | undefined;
-}
-
-export class Schema implements ISchema {
- rootAttributeGroup?: AttributeGroup | undefined;
- displayName?: string | undefined;
- augmentedFrom?: string | undefined;
- rawName?: string | undefined;
- problemDescription?: string | undefined;
- darpaProblemDoc?: DarpaProblemDoc | undefined;
- distinctAttributeParameters?: AttributeParameters | undefined;
- darpaDatasetDoc?: DarpaDatasetDoc | undefined;
- darpaDatasetLocation?: string | undefined;
- isMultiResourceData?: boolean | undefined;
- problemFinderRows?: ProblemFinderRows[] | undefined;
- correlationRows?: ProblemFinderRows[] | undefined;
-
- constructor(data?: ISchema) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.rootAttributeGroup = data["RootAttributeGroup"] ? AttributeGroup.fromJS(data["RootAttributeGroup"]) : <any>undefined;
- this.displayName = data["DisplayName"];
- this.augmentedFrom = data["AugmentedFrom"];
- this.rawName = data["RawName"];
- this.problemDescription = data["ProblemDescription"];
- this.darpaProblemDoc = data["DarpaProblemDoc"] ? DarpaProblemDoc.fromJS(data["DarpaProblemDoc"]) : <any>undefined;
- this.distinctAttributeParameters = data["DistinctAttributeParameters"] ? AttributeParameters.fromJS(data["DistinctAttributeParameters"]) : <any>undefined;
- this.darpaDatasetDoc = data["DarpaDatasetDoc"] ? DarpaDatasetDoc.fromJS(data["DarpaDatasetDoc"]) : <any>undefined;
- this.darpaDatasetLocation = data["DarpaDatasetLocation"];
- this.isMultiResourceData = data["IsMultiResourceData"];
- if (data["ProblemFinderRows"] && data["ProblemFinderRows"].constructor === Array) {
- this.problemFinderRows = [];
- for (let item of data["ProblemFinderRows"])
- this.problemFinderRows.push(ProblemFinderRows.fromJS(item));
- }
- if (data["CorrelationRows"] && data["CorrelationRows"].constructor === Array) {
- this.correlationRows = [];
- for (let item of data["CorrelationRows"])
- this.correlationRows.push(ProblemFinderRows.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): Schema {
- data = typeof data === 'object' ? data : {};
- let result = new Schema();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["RootAttributeGroup"] = this.rootAttributeGroup ? this.rootAttributeGroup.toJSON() : <any>undefined;
- data["DisplayName"] = this.displayName;
- data["AugmentedFrom"] = this.augmentedFrom;
- data["RawName"] = this.rawName;
- data["ProblemDescription"] = this.problemDescription;
- data["DarpaProblemDoc"] = this.darpaProblemDoc ? this.darpaProblemDoc.toJSON() : <any>undefined;
- data["DistinctAttributeParameters"] = this.distinctAttributeParameters ? this.distinctAttributeParameters.toJSON() : <any>undefined;
- data["DarpaDatasetDoc"] = this.darpaDatasetDoc ? this.darpaDatasetDoc.toJSON() : <any>undefined;
- data["DarpaDatasetLocation"] = this.darpaDatasetLocation;
- data["IsMultiResourceData"] = this.isMultiResourceData;
- if (this.problemFinderRows && this.problemFinderRows.constructor === Array) {
- data["ProblemFinderRows"] = [];
- for (let item of this.problemFinderRows)
- data["ProblemFinderRows"].push(item.toJSON());
- }
- if (this.correlationRows && this.correlationRows.constructor === Array) {
- data["CorrelationRows"] = [];
- for (let item of this.correlationRows)
- data["CorrelationRows"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface ISchema {
- rootAttributeGroup?: AttributeGroup | undefined;
- displayName?: string | undefined;
- augmentedFrom?: string | undefined;
- rawName?: string | undefined;
- problemDescription?: string | undefined;
- darpaProblemDoc?: DarpaProblemDoc | undefined;
- distinctAttributeParameters?: AttributeParameters | undefined;
- darpaDatasetDoc?: DarpaDatasetDoc | undefined;
- darpaDatasetLocation?: string | undefined;
- isMultiResourceData?: boolean | undefined;
- problemFinderRows?: ProblemFinderRows[] | undefined;
- correlationRows?: ProblemFinderRows[] | undefined;
-}
-
-export class DarpaProblemDoc implements IDarpaProblemDoc {
- about?: ProblemAbout | undefined;
- inputs?: ProblemInputs | undefined;
-
- constructor(data?: IDarpaProblemDoc) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.about = data["about"] ? ProblemAbout.fromJS(data["about"]) : <any>undefined;
- this.inputs = data["inputs"] ? ProblemInputs.fromJS(data["inputs"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): DarpaProblemDoc {
- data = typeof data === 'object' ? data : {};
- let result = new DarpaProblemDoc();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["about"] = this.about ? this.about.toJSON() : <any>undefined;
- data["inputs"] = this.inputs ? this.inputs.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface IDarpaProblemDoc {
- about?: ProblemAbout | undefined;
- inputs?: ProblemInputs | undefined;
-}
-
-export class ProblemAbout implements IProblemAbout {
- problemID?: string | undefined;
- problemName?: string | undefined;
- problemDescription?: string | undefined;
- taskType?: string | undefined;
- taskSubType?: string | undefined;
- problemSchemaVersion?: string | undefined;
- problemVersion?: string | undefined;
-
- constructor(data?: IProblemAbout) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.problemID = data["problemID"];
- this.problemName = data["problemName"];
- this.problemDescription = data["problemDescription"];
- this.taskType = data["taskType"];
- this.taskSubType = data["taskSubType"];
- this.problemSchemaVersion = data["problemSchemaVersion"];
- this.problemVersion = data["problemVersion"];
- }
- }
-
- static fromJS(data: any): ProblemAbout {
- data = typeof data === 'object' ? data : {};
- let result = new ProblemAbout();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["problemID"] = this.problemID;
- data["problemName"] = this.problemName;
- data["problemDescription"] = this.problemDescription;
- data["taskType"] = this.taskType;
- data["taskSubType"] = this.taskSubType;
- data["problemSchemaVersion"] = this.problemSchemaVersion;
- data["problemVersion"] = this.problemVersion;
- return data;
- }
-}
-
-export interface IProblemAbout {
- problemID?: string | undefined;
- problemName?: string | undefined;
- problemDescription?: string | undefined;
- taskType?: string | undefined;
- taskSubType?: string | undefined;
- problemSchemaVersion?: string | undefined;
- problemVersion?: string | undefined;
-}
-
-export class ProblemInputs implements IProblemInputs {
- data?: ProblemData[] | undefined;
- performanceMetrics?: ProblemPerformanceMetric[] | undefined;
-
- constructor(data?: IProblemInputs) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["data"] && data["data"].constructor === Array) {
- this.data = [];
- for (let item of data["data"])
- this.data.push(ProblemData.fromJS(item));
- }
- if (data["performanceMetrics"] && data["performanceMetrics"].constructor === Array) {
- this.performanceMetrics = [];
- for (let item of data["performanceMetrics"])
- this.performanceMetrics.push(ProblemPerformanceMetric.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): ProblemInputs {
- data = typeof data === 'object' ? data : {};
- let result = new ProblemInputs();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.data && this.data.constructor === Array) {
- data["data"] = [];
- for (let item of this.data)
- data["data"].push(item.toJSON());
- }
- if (this.performanceMetrics && this.performanceMetrics.constructor === Array) {
- data["performanceMetrics"] = [];
- for (let item of this.performanceMetrics)
- data["performanceMetrics"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IProblemInputs {
- data?: ProblemData[] | undefined;
- performanceMetrics?: ProblemPerformanceMetric[] | undefined;
-}
-
-export class ProblemData implements IProblemData {
- datasetID?: string | undefined;
- targets?: ProblemTarget[] | undefined;
-
- constructor(data?: IProblemData) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.datasetID = data["datasetID"];
- if (data["targets"] && data["targets"].constructor === Array) {
- this.targets = [];
- for (let item of data["targets"])
- this.targets.push(ProblemTarget.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): ProblemData {
- data = typeof data === 'object' ? data : {};
- let result = new ProblemData();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["datasetID"] = this.datasetID;
- if (this.targets && this.targets.constructor === Array) {
- data["targets"] = [];
- for (let item of this.targets)
- data["targets"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IProblemData {
- datasetID?: string | undefined;
- targets?: ProblemTarget[] | undefined;
-}
-
-export class ProblemTarget implements IProblemTarget {
- targetIndex?: number | undefined;
- resID?: string | undefined;
- colIndex?: number | undefined;
- colName?: string | undefined;
-
- constructor(data?: IProblemTarget) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.targetIndex = data["targetIndex"];
- this.resID = data["resID"];
- this.colIndex = data["colIndex"];
- this.colName = data["colName"];
- }
- }
-
- static fromJS(data: any): ProblemTarget {
- data = typeof data === 'object' ? data : {};
- let result = new ProblemTarget();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["targetIndex"] = this.targetIndex;
- data["resID"] = this.resID;
- data["colIndex"] = this.colIndex;
- data["colName"] = this.colName;
- return data;
- }
-}
-
-export interface IProblemTarget {
- targetIndex?: number | undefined;
- resID?: string | undefined;
- colIndex?: number | undefined;
- colName?: string | undefined;
-}
-
-export class ProblemPerformanceMetric implements IProblemPerformanceMetric {
- metric?: string | undefined;
-
- constructor(data?: IProblemPerformanceMetric) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.metric = data["metric"];
- }
- }
-
- static fromJS(data: any): ProblemPerformanceMetric {
- data = typeof data === 'object' ? data : {};
- let result = new ProblemPerformanceMetric();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["metric"] = this.metric;
- return data;
- }
-}
-
-export interface IProblemPerformanceMetric {
- metric?: string | undefined;
-}
-
-export class DarpaDatasetDoc implements IDarpaDatasetDoc {
- about?: DatasetAbout | undefined;
- dataResources?: Resource[] | undefined;
-
- constructor(data?: IDarpaDatasetDoc) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.about = data["about"] ? DatasetAbout.fromJS(data["about"]) : <any>undefined;
- if (data["dataResources"] && data["dataResources"].constructor === Array) {
- this.dataResources = [];
- for (let item of data["dataResources"])
- this.dataResources.push(Resource.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): DarpaDatasetDoc {
- data = typeof data === 'object' ? data : {};
- let result = new DarpaDatasetDoc();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["about"] = this.about ? this.about.toJSON() : <any>undefined;
- if (this.dataResources && this.dataResources.constructor === Array) {
- data["dataResources"] = [];
- for (let item of this.dataResources)
- data["dataResources"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IDarpaDatasetDoc {
- about?: DatasetAbout | undefined;
- dataResources?: Resource[] | undefined;
-}
-
-export class DatasetAbout implements IDatasetAbout {
- datasetID?: string | undefined;
- datasetName?: string | undefined;
- description?: string | undefined;
- citation?: string | undefined;
- license?: string | undefined;
- source?: string | undefined;
- sourceURI?: string | undefined;
- approximateSize?: string | undefined;
- datasetSchemaVersion?: string | undefined;
- redacted?: boolean | undefined;
- datasetVersion?: string | undefined;
-
- constructor(data?: IDatasetAbout) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.datasetID = data["datasetID"];
- this.datasetName = data["datasetName"];
- this.description = data["description"];
- this.citation = data["citation"];
- this.license = data["license"];
- this.source = data["source"];
- this.sourceURI = data["sourceURI"];
- this.approximateSize = data["approximateSize"];
- this.datasetSchemaVersion = data["datasetSchemaVersion"];
- this.redacted = data["redacted"];
- this.datasetVersion = data["datasetVersion"];
- }
- }
-
- static fromJS(data: any): DatasetAbout {
- data = typeof data === 'object' ? data : {};
- let result = new DatasetAbout();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["datasetID"] = this.datasetID;
- data["datasetName"] = this.datasetName;
- data["description"] = this.description;
- data["citation"] = this.citation;
- data["license"] = this.license;
- data["source"] = this.source;
- data["sourceURI"] = this.sourceURI;
- data["approximateSize"] = this.approximateSize;
- data["datasetSchemaVersion"] = this.datasetSchemaVersion;
- data["redacted"] = this.redacted;
- data["datasetVersion"] = this.datasetVersion;
- return data;
- }
-}
-
-export interface IDatasetAbout {
- datasetID?: string | undefined;
- datasetName?: string | undefined;
- description?: string | undefined;
- citation?: string | undefined;
- license?: string | undefined;
- source?: string | undefined;
- sourceURI?: string | undefined;
- approximateSize?: string | undefined;
- datasetSchemaVersion?: string | undefined;
- redacted?: boolean | undefined;
- datasetVersion?: string | undefined;
-}
-
-export class Resource implements IResource {
- resID?: string | undefined;
- resPath?: string | undefined;
- resType?: string | undefined;
- resFormat?: string[] | undefined;
- columns?: Column[] | undefined;
- isCollection?: boolean | undefined;
-
- constructor(data?: IResource) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.resID = data["resID"];
- this.resPath = data["resPath"];
- this.resType = data["resType"];
- if (data["resFormat"] && data["resFormat"].constructor === Array) {
- this.resFormat = [];
- for (let item of data["resFormat"])
- this.resFormat.push(item);
- }
- if (data["columns"] && data["columns"].constructor === Array) {
- this.columns = [];
- for (let item of data["columns"])
- this.columns.push(Column.fromJS(item));
- }
- this.isCollection = data["isCollection"];
- }
- }
-
- static fromJS(data: any): Resource {
- data = typeof data === 'object' ? data : {};
- let result = new Resource();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["resID"] = this.resID;
- data["resPath"] = this.resPath;
- data["resType"] = this.resType;
- if (this.resFormat && this.resFormat.constructor === Array) {
- data["resFormat"] = [];
- for (let item of this.resFormat)
- data["resFormat"].push(item);
- }
- if (this.columns && this.columns.constructor === Array) {
- data["columns"] = [];
- for (let item of this.columns)
- data["columns"].push(item.toJSON());
- }
- data["isCollection"] = this.isCollection;
- return data;
- }
-}
-
-export interface IResource {
- resID?: string | undefined;
- resPath?: string | undefined;
- resType?: string | undefined;
- resFormat?: string[] | undefined;
- columns?: Column[] | undefined;
- isCollection?: boolean | undefined;
-}
-
-export class Column implements IColumn {
- colIndex?: number | undefined;
- colDescription?: string | undefined;
- colName?: string | undefined;
- colType?: string | undefined;
- role?: string[] | undefined;
- refersTo?: Reference | undefined;
-
- constructor(data?: IColumn) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.colIndex = data["colIndex"];
- this.colDescription = data["colDescription"];
- this.colName = data["colName"];
- this.colType = data["colType"];
- if (data["role"] && data["role"].constructor === Array) {
- this.role = [];
- for (let item of data["role"])
- this.role.push(item);
- }
- this.refersTo = data["refersTo"] ? Reference.fromJS(data["refersTo"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): Column {
- data = typeof data === 'object' ? data : {};
- let result = new Column();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["colIndex"] = this.colIndex;
- data["colDescription"] = this.colDescription;
- data["colName"] = this.colName;
- data["colType"] = this.colType;
- if (this.role && this.role.constructor === Array) {
- data["role"] = [];
- for (let item of this.role)
- data["role"].push(item);
- }
- data["refersTo"] = this.refersTo ? this.refersTo.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface IColumn {
- colIndex?: number | undefined;
- colDescription?: string | undefined;
- colName?: string | undefined;
- colType?: string | undefined;
- role?: string[] | undefined;
- refersTo?: Reference | undefined;
-}
-
-export class Reference implements IReference {
- resID?: string | undefined;
-
- constructor(data?: IReference) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.resID = data["resID"];
- }
- }
-
- static fromJS(data: any): Reference {
- data = typeof data === 'object' ? data : {};
- let result = new Reference();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["resID"] = this.resID;
- return data;
- }
-}
-
-export interface IReference {
- resID?: string | undefined;
-}
-
-export class ProblemFinderRows implements IProblemFinderRows {
- label?: string | undefined;
- type?: string | undefined;
- features?: Feature[] | undefined;
-
- constructor(data?: IProblemFinderRows) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.label = data["label"];
- this.type = data["type"];
- if (data["features"] && data["features"].constructor === Array) {
- this.features = [];
- for (let item of data["features"])
- this.features.push(Feature.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): ProblemFinderRows {
- data = typeof data === 'object' ? data : {};
- let result = new ProblemFinderRows();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["label"] = this.label;
- data["type"] = this.type;
- if (this.features && this.features.constructor === Array) {
- data["features"] = [];
- for (let item of this.features)
- data["features"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IProblemFinderRows {
- label?: string | undefined;
- type?: string | undefined;
- features?: Feature[] | undefined;
-}
-
-export class Feature implements IFeature {
- name?: string | undefined;
- selected?: boolean | undefined;
- value?: number | undefined;
-
- constructor(data?: IFeature) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.name = data["name"];
- this.selected = data["selected"];
- this.value = data["value"];
- }
- }
-
- static fromJS(data: any): Feature {
- data = typeof data === 'object' ? data : {};
- let result = new Feature();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["name"] = this.name;
- data["selected"] = this.selected;
- data["value"] = this.value;
- return data;
- }
-}
-
-export interface IFeature {
- name?: string | undefined;
- selected?: boolean | undefined;
- value?: number | undefined;
-}
-
-export enum DataType2 {
- Int = 0,
- String = 1,
- Float = 2,
- Double = 3,
- DateTime = 4,
- Object = 5,
- Undefined = 6,
-}
-
-export abstract class DataTypeExtensions implements IDataTypeExtensions {
-
- constructor(data?: IDataTypeExtensions) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): DataTypeExtensions {
- data = typeof data === 'object' ? data : {};
- throw new Error("The abstract class 'DataTypeExtensions' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- return data;
- }
-}
-
-export interface IDataTypeExtensions {
-}
-
-export class ResObject implements IResObject {
- columnName?: string | undefined;
-
- constructor(data?: IResObject) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.columnName = data["columnName"];
- }
- }
-
- static fromJS(data: any): ResObject {
- data = typeof data === 'object' ? data : {};
- let result = new ResObject();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["columnName"] = this.columnName;
- return data;
- }
-}
-
-export interface IResObject {
- columnName?: string | undefined;
-}
-
-export class Exception implements IException {
- message?: string | undefined;
- innerException?: Exception | undefined;
- stackTrace?: string | undefined;
- source?: string | undefined;
-
- constructor(data?: IException) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.message = data["Message"];
- this.innerException = data["InnerException"] ? Exception.fromJS(data["InnerException"]) : <any>undefined;
- this.stackTrace = data["StackTrace"];
- this.source = data["Source"];
- }
- }
-
- static fromJS(data: any): Exception {
- data = typeof data === 'object' ? data : {};
- let result = new Exception();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Message"] = this.message;
- data["InnerException"] = this.innerException ? this.innerException.toJSON() : <any>undefined;
- data["StackTrace"] = this.stackTrace;
- data["Source"] = this.source;
- return data;
- }
-}
-
-export interface IException {
- message?: string | undefined;
- innerException?: Exception | undefined;
- stackTrace?: string | undefined;
- source?: string | undefined;
-}
-
-export class IDEAException extends Exception implements IIDEAException {
-
- constructor(data?: IIDEAException) {
- super(data);
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): IDEAException {
- data = typeof data === 'object' ? data : {};
- let result = new IDEAException();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IIDEAException extends IException {
-}
-
-export class CodeParameters implements ICodeParameters {
- attributeCodeParameters?: AttributeCodeParameters[] | undefined;
- adapterName?: string | undefined;
-
- constructor(data?: ICodeParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) {
- this.attributeCodeParameters = [];
- for (let item of data["AttributeCodeParameters"])
- this.attributeCodeParameters.push(AttributeCodeParameters.fromJS(item));
- }
- this.adapterName = data["AdapterName"];
- }
- }
-
- static fromJS(data: any): CodeParameters {
- data = typeof data === 'object' ? data : {};
- let result = new CodeParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) {
- data["AttributeCodeParameters"] = [];
- for (let item of this.attributeCodeParameters)
- data["AttributeCodeParameters"].push(item.toJSON());
- }
- data["AdapterName"] = this.adapterName;
- return data;
- }
-}
-
-export interface ICodeParameters {
- attributeCodeParameters?: AttributeCodeParameters[] | undefined;
- adapterName?: string | undefined;
-}
-
-export class CompileResult implements ICompileResult {
- compileSuccess?: boolean | undefined;
- compileMessage?: string | undefined;
- dataType?: DataType | undefined;
- replaceAttributeParameters?: AttributeParameters[] | undefined;
-
- constructor(data?: ICompileResult) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.compileSuccess = data["CompileSuccess"];
- this.compileMessage = data["CompileMessage"];
- this.dataType = data["DataType"];
- if (data["ReplaceAttributeParameters"] && data["ReplaceAttributeParameters"].constructor === Array) {
- this.replaceAttributeParameters = [];
- for (let item of data["ReplaceAttributeParameters"])
- this.replaceAttributeParameters.push(AttributeParameters.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): CompileResult {
- data = typeof data === 'object' ? data : {};
- let result = new CompileResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["CompileSuccess"] = this.compileSuccess;
- data["CompileMessage"] = this.compileMessage;
- data["DataType"] = this.dataType;
- if (this.replaceAttributeParameters && this.replaceAttributeParameters.constructor === Array) {
- data["ReplaceAttributeParameters"] = [];
- for (let item of this.replaceAttributeParameters)
- data["ReplaceAttributeParameters"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface ICompileResult {
- compileSuccess?: boolean | undefined;
- compileMessage?: string | undefined;
- dataType?: DataType | undefined;
- replaceAttributeParameters?: AttributeParameters[] | undefined;
-}
-
-export class CompileResults implements ICompileResults {
- rawNameToCompileResult?: { [key: string]: CompileResult; } | undefined;
-
- constructor(data?: ICompileResults) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["RawNameToCompileResult"]) {
- this.rawNameToCompileResult = {};
- for (let key in data["RawNameToCompileResult"]) {
- if (data["RawNameToCompileResult"].hasOwnProperty(key))
- this.rawNameToCompileResult[key] = data["RawNameToCompileResult"][key] ? CompileResult.fromJS(data["RawNameToCompileResult"][key]) : new CompileResult();
- }
- }
- }
- }
-
- static fromJS(data: any): CompileResults {
- data = typeof data === 'object' ? data : {};
- let result = new CompileResults();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.rawNameToCompileResult) {
- data["RawNameToCompileResult"] = {};
- for (let key in this.rawNameToCompileResult) {
- if (this.rawNameToCompileResult.hasOwnProperty(key))
- data["RawNameToCompileResult"][key] = this.rawNameToCompileResult[key];
- }
- }
- return data;
- }
-}
-
-export interface ICompileResults {
- rawNameToCompileResult?: { [key: string]: CompileResult; } | undefined;
-}
-
-export abstract class UniqueJson implements IUniqueJson {
-
- constructor(data?: IUniqueJson) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): UniqueJson {
- data = typeof data === 'object' ? data : {};
- throw new Error("The abstract class 'UniqueJson' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- return data;
- }
-}
-
-export interface IUniqueJson {
-}
-
-export abstract class OperationParameters extends UniqueJson implements IOperationParameters {
- isCachable?: boolean | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IOperationParameters) {
- super(data);
- this._discriminator = "OperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.isCachable = data["IsCachable"];
- }
- }
-
- static fromJS(data: any): OperationParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "DataOperationParameters") {
- throw new Error("The abstract class 'DataOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "ExampleOperationParameters") {
- let result = new ExampleOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "HistogramOperationParameters") {
- let result = new HistogramOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DistOperationParameters") {
- throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "OptimizerOperationParameters") {
- let result = new OptimizerOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RawDataOperationParameters") {
- let result = new RawDataOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RecommenderOperationParameters") {
- let result = new RecommenderOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CDFOperationParameters") {
- let result = new CDFOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TestDistOperationParameters") {
- throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "ChiSquaredTestOperationParameters") {
- let result = new ChiSquaredTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "HypothesisTestParameters") {
- throw new Error("The abstract class 'HypothesisTestParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "CorrelationTestOperationParameters") {
- let result = new CorrelationTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "EmpiricalDistOperationParameters") {
- let result = new EmpiricalDistOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "KSTestOperationParameters") {
- let result = new KSTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "NewModelOperationParameters") {
- let result = new NewModelOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "ModelOperationParameters") {
- throw new Error("The abstract class 'ModelOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "RootMeanSquareTestOperationParameters") {
- let result = new RootMeanSquareTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TTestOperationParameters") {
- let result = new TTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FeatureImportanceOperationParameters") {
- let result = new FeatureImportanceOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SampleOperationParameters") {
- let result = new SampleOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AddComparisonParameters") {
- let result = new AddComparisonParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "GetModelStateParameters") {
- let result = new GetModelStateParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FrequentItemsetOperationParameters") {
- let result = new FrequentItemsetOperationParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'OperationParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["IsCachable"] = this.isCachable;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IOperationParameters extends IUniqueJson {
- isCachable?: boolean | undefined;
-}
-
-export abstract class DataOperationParameters extends OperationParameters implements IDataOperationParameters {
- sampleStreamBlockSize?: number | undefined;
- adapterName?: string | undefined;
- isCachable?: boolean | undefined;
-
- constructor(data?: IDataOperationParameters) {
- super(data);
- this._discriminator = "DataOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.sampleStreamBlockSize = data["SampleStreamBlockSize"];
- this.adapterName = data["AdapterName"];
- this.isCachable = data["IsCachable"];
- }
- }
-
- static fromJS(data: any): DataOperationParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "ExampleOperationParameters") {
- let result = new ExampleOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "HistogramOperationParameters") {
- let result = new HistogramOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DistOperationParameters") {
- throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "OptimizerOperationParameters") {
- let result = new OptimizerOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RawDataOperationParameters") {
- let result = new RawDataOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RecommenderOperationParameters") {
- let result = new RecommenderOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CDFOperationParameters") {
- let result = new CDFOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TestDistOperationParameters") {
- throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "EmpiricalDistOperationParameters") {
- let result = new EmpiricalDistOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FeatureImportanceOperationParameters") {
- let result = new FeatureImportanceOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SampleOperationParameters") {
- let result = new SampleOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FrequentItemsetOperationParameters") {
- let result = new FrequentItemsetOperationParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'DataOperationParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SampleStreamBlockSize"] = this.sampleStreamBlockSize;
- data["AdapterName"] = this.adapterName;
- data["IsCachable"] = this.isCachable;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDataOperationParameters extends IOperationParameters {
- sampleStreamBlockSize?: number | undefined;
- adapterName?: string | undefined;
- isCachable?: boolean | undefined;
-}
-
-export class ExampleOperationParameters extends DataOperationParameters implements IExampleOperationParameters {
- filter?: string | undefined;
- attributeParameters?: AttributeParameters[] | undefined;
- attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
- dummyValue?: number | undefined;
- exampleType?: string | undefined;
-
- constructor(data?: IExampleOperationParameters) {
- super(data);
- this._discriminator = "ExampleOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.filter = data["Filter"];
- if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
- this.attributeParameters = [];
- for (let item of data["AttributeParameters"])
- this.attributeParameters.push(AttributeParameters.fromJS(item));
- }
- if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) {
- this.attributeCodeParameters = [];
- for (let item of data["AttributeCodeParameters"])
- this.attributeCodeParameters.push(AttributeCaclculatedParameters.fromJS(item));
- }
- this.dummyValue = data["DummyValue"];
- this.exampleType = data["ExampleType"];
- }
- }
-
- static fromJS(data: any): ExampleOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new ExampleOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Filter"] = this.filter;
- if (this.attributeParameters && this.attributeParameters.constructor === Array) {
- data["AttributeParameters"] = [];
- for (let item of this.attributeParameters)
- data["AttributeParameters"].push(item.toJSON());
- }
- if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) {
- data["AttributeCodeParameters"] = [];
- for (let item of this.attributeCodeParameters)
- data["AttributeCodeParameters"].push(item.toJSON());
- }
- data["DummyValue"] = this.dummyValue;
- data["ExampleType"] = this.exampleType;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IExampleOperationParameters extends IDataOperationParameters {
- filter?: string | undefined;
- attributeParameters?: AttributeParameters[] | undefined;
- attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
- dummyValue?: number | undefined;
- exampleType?: string | undefined;
-}
-
-export abstract class DistOperationParameters extends DataOperationParameters implements IDistOperationParameters {
- filter?: string | undefined;
- attributeCalculatedParameters?: AttributeCaclculatedParameters[] | undefined;
-
- constructor(data?: IDistOperationParameters) {
- super(data);
- this._discriminator = "DistOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.filter = data["Filter"];
- if (data["AttributeCalculatedParameters"] && data["AttributeCalculatedParameters"].constructor === Array) {
- this.attributeCalculatedParameters = [];
- for (let item of data["AttributeCalculatedParameters"])
- this.attributeCalculatedParameters.push(AttributeCaclculatedParameters.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): DistOperationParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "HistogramOperationParameters") {
- let result = new HistogramOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "OptimizerOperationParameters") {
- let result = new OptimizerOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RawDataOperationParameters") {
- let result = new RawDataOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CDFOperationParameters") {
- let result = new CDFOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TestDistOperationParameters") {
- throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
- }
- if (data["discriminator"] === "EmpiricalDistOperationParameters") {
- let result = new EmpiricalDistOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FeatureImportanceOperationParameters") {
- let result = new FeatureImportanceOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SampleOperationParameters") {
- let result = new SampleOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FrequentItemsetOperationParameters") {
- let result = new FrequentItemsetOperationParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Filter"] = this.filter;
- if (this.attributeCalculatedParameters && this.attributeCalculatedParameters.constructor === Array) {
- data["AttributeCalculatedParameters"] = [];
- for (let item of this.attributeCalculatedParameters)
- data["AttributeCalculatedParameters"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDistOperationParameters extends IDataOperationParameters {
- filter?: string | undefined;
- attributeCalculatedParameters?: AttributeCaclculatedParameters[] | undefined;
-}
-
-export class HistogramOperationParameters extends DistOperationParameters implements IHistogramOperationParameters {
- sortPerBinAggregateParameter?: AggregateParameters | undefined;
- binningParameters?: BinningParameters[] | undefined;
- perBinAggregateParameters?: AggregateParameters[] | undefined;
- globalAggregateParameters?: AggregateParameters[] | undefined;
- brushes?: string[] | undefined;
- enableBrushComputation?: boolean | undefined;
- degreeOfParallism?: number | undefined;
-
- constructor(data?: IHistogramOperationParameters) {
- super(data);
- this._discriminator = "HistogramOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.sortPerBinAggregateParameter = data["SortPerBinAggregateParameter"] ? AggregateParameters.fromJS(data["SortPerBinAggregateParameter"]) : <any>undefined;
- if (data["BinningParameters"] && data["BinningParameters"].constructor === Array) {
- this.binningParameters = [];
- for (let item of data["BinningParameters"])
- this.binningParameters.push(BinningParameters.fromJS(item));
- }
- if (data["PerBinAggregateParameters"] && data["PerBinAggregateParameters"].constructor === Array) {
- this.perBinAggregateParameters = [];
- for (let item of data["PerBinAggregateParameters"])
- this.perBinAggregateParameters.push(AggregateParameters.fromJS(item));
- }
- if (data["GlobalAggregateParameters"] && data["GlobalAggregateParameters"].constructor === Array) {
- this.globalAggregateParameters = [];
- for (let item of data["GlobalAggregateParameters"])
- this.globalAggregateParameters.push(AggregateParameters.fromJS(item));
- }
- if (data["Brushes"] && data["Brushes"].constructor === Array) {
- this.brushes = [];
- for (let item of data["Brushes"])
- this.brushes.push(item);
- }
- this.enableBrushComputation = data["EnableBrushComputation"];
- this.degreeOfParallism = data["DegreeOfParallism"];
- }
- }
-
- static fromJS(data: any): HistogramOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new HistogramOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SortPerBinAggregateParameter"] = this.sortPerBinAggregateParameter ? this.sortPerBinAggregateParameter.toJSON() : <any>undefined;
- if (this.binningParameters && this.binningParameters.constructor === Array) {
- data["BinningParameters"] = [];
- for (let item of this.binningParameters)
- data["BinningParameters"].push(item.toJSON());
- }
- if (this.perBinAggregateParameters && this.perBinAggregateParameters.constructor === Array) {
- data["PerBinAggregateParameters"] = [];
- for (let item of this.perBinAggregateParameters)
- data["PerBinAggregateParameters"].push(item.toJSON());
- }
- if (this.globalAggregateParameters && this.globalAggregateParameters.constructor === Array) {
- data["GlobalAggregateParameters"] = [];
- for (let item of this.globalAggregateParameters)
- data["GlobalAggregateParameters"].push(item.toJSON());
- }
- if (this.brushes && this.brushes.constructor === Array) {
- data["Brushes"] = [];
- for (let item of this.brushes)
- data["Brushes"].push(item);
- }
- data["EnableBrushComputation"] = this.enableBrushComputation;
- data["DegreeOfParallism"] = this.degreeOfParallism;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IHistogramOperationParameters extends IDistOperationParameters {
- sortPerBinAggregateParameter?: AggregateParameters | undefined;
- binningParameters?: BinningParameters[] | undefined;
- perBinAggregateParameters?: AggregateParameters[] | undefined;
- globalAggregateParameters?: AggregateParameters[] | undefined;
- brushes?: string[] | undefined;
- enableBrushComputation?: boolean | undefined;
- degreeOfParallism?: number | undefined;
-}
-
-export class OptimizerOperationParameters extends DistOperationParameters implements IOptimizerOperationParameters {
- taskType?: TaskType | undefined;
- taskSubType?: TaskSubType | undefined;
- metricType?: MetricType | undefined;
- labelAttribute?: AttributeParameters | undefined;
- featureAttributes?: AttributeParameters[] | undefined;
- requiredPrimitives?: string[] | undefined;
- pythonFilter?: string | undefined;
- trainFilter?: string | undefined;
- pythonTrainFilter?: string | undefined;
- testFilter?: string | undefined;
- pythonTestFilter?: string | undefined;
-
- constructor(data?: IOptimizerOperationParameters) {
- super(data);
- this._discriminator = "OptimizerOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.taskType = data["TaskType"];
- this.taskSubType = data["TaskSubType"];
- this.metricType = data["MetricType"];
- this.labelAttribute = data["LabelAttribute"] ? AttributeParameters.fromJS(data["LabelAttribute"]) : <any>undefined;
- if (data["FeatureAttributes"] && data["FeatureAttributes"].constructor === Array) {
- this.featureAttributes = [];
- for (let item of data["FeatureAttributes"])
- this.featureAttributes.push(AttributeParameters.fromJS(item));
- }
- if (data["RequiredPrimitives"] && data["RequiredPrimitives"].constructor === Array) {
- this.requiredPrimitives = [];
- for (let item of data["RequiredPrimitives"])
- this.requiredPrimitives.push(item);
- }
- this.pythonFilter = data["PythonFilter"];
- this.trainFilter = data["TrainFilter"];
- this.pythonTrainFilter = data["PythonTrainFilter"];
- this.testFilter = data["TestFilter"];
- this.pythonTestFilter = data["PythonTestFilter"];
- }
- }
-
- static fromJS(data: any): OptimizerOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new OptimizerOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["TaskType"] = this.taskType;
- data["TaskSubType"] = this.taskSubType;
- data["MetricType"] = this.metricType;
- data["LabelAttribute"] = this.labelAttribute ? this.labelAttribute.toJSON() : <any>undefined;
- if (this.featureAttributes && this.featureAttributes.constructor === Array) {
- data["FeatureAttributes"] = [];
- for (let item of this.featureAttributes)
- data["FeatureAttributes"].push(item.toJSON());
- }
- if (this.requiredPrimitives && this.requiredPrimitives.constructor === Array) {
- data["RequiredPrimitives"] = [];
- for (let item of this.requiredPrimitives)
- data["RequiredPrimitives"].push(item);
- }
- data["PythonFilter"] = this.pythonFilter;
- data["TrainFilter"] = this.trainFilter;
- data["PythonTrainFilter"] = this.pythonTrainFilter;
- data["TestFilter"] = this.testFilter;
- data["PythonTestFilter"] = this.pythonTestFilter;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IOptimizerOperationParameters extends IDistOperationParameters {
- taskType?: TaskType | undefined;
- taskSubType?: TaskSubType | undefined;
- metricType?: MetricType | undefined;
- labelAttribute?: AttributeParameters | undefined;
- featureAttributes?: AttributeParameters[] | undefined;
- requiredPrimitives?: string[] | undefined;
- pythonFilter?: string | undefined;
- trainFilter?: string | undefined;
- pythonTrainFilter?: string | undefined;
- testFilter?: string | undefined;
- pythonTestFilter?: string | undefined;
-}
-
-export enum TaskType {
- Undefined = 0,
- Classification = 1,
- Regression = 2,
- Clustering = 3,
- LinkPrediction = 4,
- VertexNomination = 5,
- CommunityDetection = 6,
- GraphClustering = 7,
- GraphMatching = 8,
- TimeSeriesForecasting = 9,
- CollaborativeFiltering = 10,
-}
-
-export enum TaskSubType {
- Undefined = 0,
- None = 1,
- Binary = 2,
- Multiclass = 3,
- Multilabel = 4,
- Univariate = 5,
- Multivariate = 6,
- Overlapping = 7,
- Nonoverlapping = 8,
-}
-
-export enum MetricType {
- MetricUndefined = 0,
- Accuracy = 1,
- Precision = 2,
- Recall = 3,
- F1 = 4,
- F1Micro = 5,
- F1Macro = 6,
- RocAuc = 7,
- RocAucMicro = 8,
- RocAucMacro = 9,
- MeanSquaredError = 10,
- RootMeanSquaredError = 11,
- RootMeanSquaredErrorAvg = 12,
- MeanAbsoluteError = 13,
- RSquared = 14,
- NormalizedMutualInformation = 15,
- JaccardSimilarityScore = 16,
- PrecisionAtTopK = 17,
- ObjectDetectionAveragePrecision = 18,
- Loss = 100,
-}
-
-export class RawDataOperationParameters extends DistOperationParameters implements IRawDataOperationParameters {
- sortUpRawName?: string | undefined;
- sortDownRawName?: string | undefined;
- numRecords?: number | undefined;
- binningParameters?: BinningParameters[] | undefined;
- brushes?: string[] | undefined;
- enableBrushComputation?: boolean | undefined;
-
- constructor(data?: IRawDataOperationParameters) {
- super(data);
- this._discriminator = "RawDataOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.sortUpRawName = data["SortUpRawName"];
- this.sortDownRawName = data["SortDownRawName"];
- this.numRecords = data["NumRecords"];
- if (data["BinningParameters"] && data["BinningParameters"].constructor === Array) {
- this.binningParameters = [];
- for (let item of data["BinningParameters"])
- this.binningParameters.push(BinningParameters.fromJS(item));
- }
- if (data["Brushes"] && data["Brushes"].constructor === Array) {
- this.brushes = [];
- for (let item of data["Brushes"])
- this.brushes.push(item);
- }
- this.enableBrushComputation = data["EnableBrushComputation"];
- }
- }
-
- static fromJS(data: any): RawDataOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new RawDataOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SortUpRawName"] = this.sortUpRawName;
- data["SortDownRawName"] = this.sortDownRawName;
- data["NumRecords"] = this.numRecords;
- if (this.binningParameters && this.binningParameters.constructor === Array) {
- data["BinningParameters"] = [];
- for (let item of this.binningParameters)
- data["BinningParameters"].push(item.toJSON());
- }
- if (this.brushes && this.brushes.constructor === Array) {
- data["Brushes"] = [];
- for (let item of this.brushes)
- data["Brushes"].push(item);
- }
- data["EnableBrushComputation"] = this.enableBrushComputation;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRawDataOperationParameters extends IDistOperationParameters {
- sortUpRawName?: string | undefined;
- sortDownRawName?: string | undefined;
- numRecords?: number | undefined;
- binningParameters?: BinningParameters[] | undefined;
- brushes?: string[] | undefined;
- enableBrushComputation?: boolean | undefined;
-}
-
-export class RecommenderOperationParameters extends DataOperationParameters implements IRecommenderOperationParameters {
- target?: HistogramOperationParameters | undefined;
- budget?: number | undefined;
- modelId?: ModelId | undefined;
- includeAttributeParameters?: AttributeParameters[] | undefined;
- excludeAttributeParameters?: AttributeParameters[] | undefined;
- riskControlType?: RiskControlType | undefined;
-
- constructor(data?: IRecommenderOperationParameters) {
- super(data);
- this._discriminator = "RecommenderOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.target = data["Target"] ? HistogramOperationParameters.fromJS(data["Target"]) : <any>undefined;
- this.budget = data["Budget"];
- this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
- if (data["IncludeAttributeParameters"] && data["IncludeAttributeParameters"].constructor === Array) {
- this.includeAttributeParameters = [];
- for (let item of data["IncludeAttributeParameters"])
- this.includeAttributeParameters.push(AttributeParameters.fromJS(item));
- }
- if (data["ExcludeAttributeParameters"] && data["ExcludeAttributeParameters"].constructor === Array) {
- this.excludeAttributeParameters = [];
- for (let item of data["ExcludeAttributeParameters"])
- this.excludeAttributeParameters.push(AttributeParameters.fromJS(item));
- }
- this.riskControlType = data["RiskControlType"];
- }
- }
-
- static fromJS(data: any): RecommenderOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new RecommenderOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Target"] = this.target ? this.target.toJSON() : <any>undefined;
- data["Budget"] = this.budget;
- data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
- if (this.includeAttributeParameters && this.includeAttributeParameters.constructor === Array) {
- data["IncludeAttributeParameters"] = [];
- for (let item of this.includeAttributeParameters)
- data["IncludeAttributeParameters"].push(item.toJSON());
- }
- if (this.excludeAttributeParameters && this.excludeAttributeParameters.constructor === Array) {
- data["ExcludeAttributeParameters"] = [];
- for (let item of this.excludeAttributeParameters)
- data["ExcludeAttributeParameters"].push(item.toJSON());
- }
- data["RiskControlType"] = this.riskControlType;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRecommenderOperationParameters extends IDataOperationParameters {
- target?: HistogramOperationParameters | undefined;
- budget?: number | undefined;
- modelId?: ModelId | undefined;
- includeAttributeParameters?: AttributeParameters[] | undefined;
- excludeAttributeParameters?: AttributeParameters[] | undefined;
- riskControlType?: RiskControlType | undefined;
-}
-
-export class ModelId implements IModelId {
- value?: string | undefined;
-
- constructor(data?: IModelId) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): ModelId {
- data = typeof data === 'object' ? data : {};
- let result = new ModelId();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- return data;
- }
-}
-
-export interface IModelId {
- value?: string | undefined;
-}
-
-export enum RiskControlType {
- PCER = 0,
- Bonferroni = 1,
- AdaBonferroni = 2,
- HolmBonferroni = 3,
- BHFDR = 4,
- SeqFDR = 5,
- AlphaFDR = 6,
- BestFootForward = 7,
- BetaFarsighted = 8,
- BetaFarsightedWithSupport = 9,
- GammaFixed = 10,
- DeltaHopeful = 11,
- EpsilonHybrid = 12,
- EpsilonHybridWithoutSupport = 13,
- PsiSupport = 14,
- ZetaDynamic = 15,
- Unknown = 16,
-}
-
-export abstract class TestDistOperationParameters extends DistOperationParameters implements ITestDistOperationParameters {
- attributeParameters?: AttributeParameters[] | undefined;
-
- constructor(data?: ITestDistOperationParameters) {
- super(data);
- this._discriminator = "TestDistOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
- this.attributeParameters = [];
- for (let item of data["AttributeParameters"])
- this.attributeParameters.push(AttributeParameters.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): TestDistOperationParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "CDFOperationParameters") {
- let result = new CDFOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "EmpiricalDistOperationParameters") {
- let result = new EmpiricalDistOperationParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.attributeParameters && this.attributeParameters.constructor === Array) {
- data["AttributeParameters"] = [];
- for (let item of this.attributeParameters)
- data["AttributeParameters"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ITestDistOperationParameters extends IDistOperationParameters {
- attributeParameters?: AttributeParameters[] | undefined;
-}
-
-export class CDFOperationParameters extends TestDistOperationParameters implements ICDFOperationParameters {
-
- constructor(data?: ICDFOperationParameters) {
- super(data);
- this._discriminator = "CDFOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): CDFOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new CDFOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ICDFOperationParameters extends ITestDistOperationParameters {
-}
-
-export abstract class HypothesisTestParameters extends OperationParameters implements IHypothesisTestParameters {
- childOperationParameters?: OperationParameters[] | undefined;
- isCachable?: boolean | undefined;
-
- constructor(data?: IHypothesisTestParameters) {
- super(data);
- this._discriminator = "HypothesisTestParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["ChildOperationParameters"] && data["ChildOperationParameters"].constructor === Array) {
- this.childOperationParameters = [];
- for (let item of data["ChildOperationParameters"])
- this.childOperationParameters.push(OperationParameters.fromJS(item));
- }
- this.isCachable = data["IsCachable"];
- }
- }
-
- static fromJS(data: any): HypothesisTestParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "ChiSquaredTestOperationParameters") {
- let result = new ChiSquaredTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CorrelationTestOperationParameters") {
- let result = new CorrelationTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "KSTestOperationParameters") {
- let result = new KSTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RootMeanSquareTestOperationParameters") {
- let result = new RootMeanSquareTestOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TTestOperationParameters") {
- let result = new TTestOperationParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'HypothesisTestParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.childOperationParameters && this.childOperationParameters.constructor === Array) {
- data["ChildOperationParameters"] = [];
- for (let item of this.childOperationParameters)
- data["ChildOperationParameters"].push(item.toJSON());
- }
- data["IsCachable"] = this.isCachable;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IHypothesisTestParameters extends IOperationParameters {
- childOperationParameters?: OperationParameters[] | undefined;
- isCachable?: boolean | undefined;
-}
-
-export class ChiSquaredTestOperationParameters extends HypothesisTestParameters implements IChiSquaredTestOperationParameters {
-
- constructor(data?: IChiSquaredTestOperationParameters) {
- super(data);
- this._discriminator = "ChiSquaredTestOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): ChiSquaredTestOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new ChiSquaredTestOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IChiSquaredTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export class CorrelationTestOperationParameters extends HypothesisTestParameters implements ICorrelationTestOperationParameters {
-
- constructor(data?: ICorrelationTestOperationParameters) {
- super(data);
- this._discriminator = "CorrelationTestOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): CorrelationTestOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new CorrelationTestOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ICorrelationTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export class SubmitProblemParameters implements ISubmitProblemParameters {
- id?: string | undefined;
-
- constructor(data?: ISubmitProblemParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.id = data["Id"];
- }
- }
-
- static fromJS(data: any): SubmitProblemParameters {
- data = typeof data === 'object' ? data : {};
- let result = new SubmitProblemParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- return data;
- }
-}
-
-export interface ISubmitProblemParameters {
- id?: string | undefined;
-}
-
-export class SpecifyProblemParameters implements ISpecifyProblemParameters {
- id?: string | undefined;
- userComment?: string | undefined;
- optimizerOperationParameters?: OptimizerOperationParameters | undefined;
-
- constructor(data?: ISpecifyProblemParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.id = data["Id"];
- this.userComment = data["UserComment"];
- this.optimizerOperationParameters = data["OptimizerOperationParameters"] ? OptimizerOperationParameters.fromJS(data["OptimizerOperationParameters"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): SpecifyProblemParameters {
- data = typeof data === 'object' ? data : {};
- let result = new SpecifyProblemParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- data["UserComment"] = this.userComment;
- data["OptimizerOperationParameters"] = this.optimizerOperationParameters ? this.optimizerOperationParameters.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface ISpecifyProblemParameters {
- id?: string | undefined;
- userComment?: string | undefined;
- optimizerOperationParameters?: OptimizerOperationParameters | undefined;
-}
-
-export class EmpiricalDistOperationParameters extends TestDistOperationParameters implements IEmpiricalDistOperationParameters {
- keepSamples?: boolean | undefined;
-
- constructor(data?: IEmpiricalDistOperationParameters) {
- super(data);
- this._discriminator = "EmpiricalDistOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.keepSamples = data["KeepSamples"];
- }
- }
-
- static fromJS(data: any): EmpiricalDistOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new EmpiricalDistOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["KeepSamples"] = this.keepSamples;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IEmpiricalDistOperationParameters extends ITestDistOperationParameters {
- keepSamples?: boolean | undefined;
-}
-
-export class KSTestOperationParameters extends HypothesisTestParameters implements IKSTestOperationParameters {
-
- constructor(data?: IKSTestOperationParameters) {
- super(data);
- this._discriminator = "KSTestOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): KSTestOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new KSTestOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IKSTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export abstract class ModelOperationParameters extends OperationParameters implements IModelOperationParameters {
-
- constructor(data?: IModelOperationParameters) {
- super(data);
- this._discriminator = "ModelOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): ModelOperationParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "NewModelOperationParameters") {
- let result = new NewModelOperationParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AddComparisonParameters") {
- let result = new AddComparisonParameters();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "GetModelStateParameters") {
- let result = new GetModelStateParameters();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'ModelOperationParameters' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IModelOperationParameters extends IOperationParameters {
-}
-
-export class NewModelOperationParameters extends ModelOperationParameters implements INewModelOperationParameters {
- riskControlTypes?: RiskControlType[] | undefined;
- alpha?: number | undefined;
- alphaInvestParameter?: AlphaInvestParameter | undefined;
-
- constructor(data?: INewModelOperationParameters) {
- super(data);
- this._discriminator = "NewModelOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["RiskControlTypes"] && data["RiskControlTypes"].constructor === Array) {
- this.riskControlTypes = [];
- for (let item of data["RiskControlTypes"])
- this.riskControlTypes.push(item);
- }
- this.alpha = data["Alpha"];
- this.alphaInvestParameter = data["AlphaInvestParameter"] ? AlphaInvestParameter.fromJS(data["AlphaInvestParameter"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): NewModelOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new NewModelOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.riskControlTypes && this.riskControlTypes.constructor === Array) {
- data["RiskControlTypes"] = [];
- for (let item of this.riskControlTypes)
- data["RiskControlTypes"].push(item);
- }
- data["Alpha"] = this.alpha;
- data["AlphaInvestParameter"] = this.alphaInvestParameter ? this.alphaInvestParameter.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface INewModelOperationParameters extends IModelOperationParameters {
- riskControlTypes?: RiskControlType[] | undefined;
- alpha?: number | undefined;
- alphaInvestParameter?: AlphaInvestParameter | undefined;
-}
-
-export class AlphaInvestParameter extends UniqueJson implements IAlphaInvestParameter {
- beta?: number | undefined;
- gamma?: number | undefined;
- delta?: number | undefined;
- epsilon?: number | undefined;
- windowSize?: number | undefined;
- psi?: number | undefined;
-
- constructor(data?: IAlphaInvestParameter) {
- super(data);
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.beta = data["Beta"];
- this.gamma = data["Gamma"];
- this.delta = data["Delta"];
- this.epsilon = data["Epsilon"];
- this.windowSize = data["WindowSize"];
- this.psi = data["Psi"];
- }
- }
-
- static fromJS(data: any): AlphaInvestParameter {
- data = typeof data === 'object' ? data : {};
- let result = new AlphaInvestParameter();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Beta"] = this.beta;
- data["Gamma"] = this.gamma;
- data["Delta"] = this.delta;
- data["Epsilon"] = this.epsilon;
- data["WindowSize"] = this.windowSize;
- data["Psi"] = this.psi;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAlphaInvestParameter extends IUniqueJson {
- beta?: number | undefined;
- gamma?: number | undefined;
- delta?: number | undefined;
- epsilon?: number | undefined;
- windowSize?: number | undefined;
- psi?: number | undefined;
-}
-
-export class RootMeanSquareTestOperationParameters extends HypothesisTestParameters implements IRootMeanSquareTestOperationParameters {
- seeded?: boolean | undefined;
- pValueConvergenceThreshold?: number | undefined;
- maxSimulationBatchCount?: number | undefined;
- perBatchSimulationCount?: number | undefined;
-
- constructor(data?: IRootMeanSquareTestOperationParameters) {
- super(data);
- this._discriminator = "RootMeanSquareTestOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.seeded = data["Seeded"];
- this.pValueConvergenceThreshold = data["PValueConvergenceThreshold"];
- this.maxSimulationBatchCount = data["MaxSimulationBatchCount"];
- this.perBatchSimulationCount = data["PerBatchSimulationCount"];
- }
- }
-
- static fromJS(data: any): RootMeanSquareTestOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new RootMeanSquareTestOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Seeded"] = this.seeded;
- data["PValueConvergenceThreshold"] = this.pValueConvergenceThreshold;
- data["MaxSimulationBatchCount"] = this.maxSimulationBatchCount;
- data["PerBatchSimulationCount"] = this.perBatchSimulationCount;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRootMeanSquareTestOperationParameters extends IHypothesisTestParameters {
- seeded?: boolean | undefined;
- pValueConvergenceThreshold?: number | undefined;
- maxSimulationBatchCount?: number | undefined;
- perBatchSimulationCount?: number | undefined;
-}
-
-export class TTestOperationParameters extends HypothesisTestParameters implements ITTestOperationParameters {
-
- constructor(data?: ITTestOperationParameters) {
- super(data);
- this._discriminator = "TTestOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): TTestOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new TTestOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ITTestOperationParameters extends IHypothesisTestParameters {
-}
-
-export enum EffectSize {
- Small = 1,
- Meduim = 2,
- Large = 4,
-}
-
-export abstract class Result extends UniqueJson implements IResult {
- progress?: number | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IResult) {
- super(data);
- this._discriminator = "Result";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.progress = data["Progress"];
- }
- }
-
- static fromJS(data: any): Result {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "ErrorResult") {
- let result = new ErrorResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "HistogramResult") {
- let result = new HistogramResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DistResult") {
- throw new Error("The abstract class 'DistResult' cannot be instantiated.");
- }
- if (data["discriminator"] === "ModelWealthResult") {
- let result = new ModelWealthResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "HypothesisTestResult") {
- throw new Error("The abstract class 'HypothesisTestResult' cannot be instantiated.");
- }
- if (data["discriminator"] === "ModelOperationResult") {
- throw new Error("The abstract class 'ModelOperationResult' cannot be instantiated.");
- }
- if (data["discriminator"] === "RecommenderResult") {
- let result = new RecommenderResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "Decision") {
- let result = new Decision();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "OptimizerResult") {
- let result = new OptimizerResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "ExampleResult") {
- let result = new ExampleResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "NewModelOperationResult") {
- let result = new NewModelOperationResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AddComparisonResult") {
- let result = new AddComparisonResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "GetModelStateResult") {
- let result = new GetModelStateResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FeatureImportanceResult") {
- let result = new FeatureImportanceResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RawDataResult") {
- let result = new RawDataResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SampleResult") {
- let result = new SampleResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CDFResult") {
- let result = new CDFResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "ChiSquaredTestResult") {
- let result = new ChiSquaredTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CorrelationTestResult") {
- let result = new CorrelationTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "EmpiricalDistResult") {
- let result = new EmpiricalDistResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "KSTestResult") {
- let result = new KSTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RootMeanSquareTestResult") {
- let result = new RootMeanSquareTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TTestResult") {
- let result = new TTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "FrequentItemsetResult") {
- let result = new FrequentItemsetResult();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'Result' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["Progress"] = this.progress;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IResult extends IUniqueJson {
- progress?: number | undefined;
-}
-
-export class ErrorResult extends Result implements IErrorResult {
- message?: string | undefined;
-
- constructor(data?: IErrorResult) {
- super(data);
- this._discriminator = "ErrorResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.message = data["Message"];
- }
- }
-
- static fromJS(data: any): ErrorResult {
- data = typeof data === 'object' ? data : {};
- let result = new ErrorResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Message"] = this.message;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IErrorResult extends IResult {
- message?: string | undefined;
-}
-
-export abstract class DistResult extends Result implements IDistResult {
- sampleSize?: number | undefined;
- populationSize?: number | undefined;
-
- constructor(data?: IDistResult) {
- super(data);
- this._discriminator = "DistResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.sampleSize = data["SampleSize"];
- this.populationSize = data["PopulationSize"];
- }
- }
-
- static fromJS(data: any): DistResult {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "HistogramResult") {
- let result = new HistogramResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RawDataResult") {
- let result = new RawDataResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SampleResult") {
- let result = new SampleResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CDFResult") {
- let result = new CDFResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "EmpiricalDistResult") {
- let result = new EmpiricalDistResult();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'DistResult' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SampleSize"] = this.sampleSize;
- data["PopulationSize"] = this.populationSize;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDistResult extends IResult {
- sampleSize?: number | undefined;
- populationSize?: number | undefined;
-}
-
-export class HistogramResult extends DistResult implements IHistogramResult {
- aggregateResults?: AggregateResult[][] | undefined;
- isEmpty?: boolean | undefined;
- brushes?: Brush[] | undefined;
- binRanges?: BinRange[] | undefined;
- aggregateParameters?: AggregateParameters[] | undefined;
- nullValueCount?: number | undefined;
- bins?: { [key: string]: Bin; } | undefined;
-
- constructor(data?: IHistogramResult) {
- super(data);
- this._discriminator = "HistogramResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["AggregateResults"] && data["AggregateResults"].constructor === Array) {
- this.aggregateResults = [];
- for (let item of data["AggregateResults"])
- this.aggregateResults.push(item);
- }
- this.isEmpty = data["IsEmpty"];
- if (data["Brushes"] && data["Brushes"].constructor === Array) {
- this.brushes = [];
- for (let item of data["Brushes"])
- this.brushes.push(Brush.fromJS(item));
- }
- if (data["BinRanges"] && data["BinRanges"].constructor === Array) {
- this.binRanges = [];
- for (let item of data["BinRanges"])
- this.binRanges.push(BinRange.fromJS(item));
- }
- if (data["AggregateParameters"] && data["AggregateParameters"].constructor === Array) {
- this.aggregateParameters = [];
- for (let item of data["AggregateParameters"])
- this.aggregateParameters.push(AggregateParameters.fromJS(item));
- }
- this.nullValueCount = data["NullValueCount"];
- if (data["Bins"]) {
- this.bins = {};
- for (let key in data["Bins"]) {
- if (data["Bins"].hasOwnProperty(key))
- this.bins[key] = data["Bins"][key] ? Bin.fromJS(data["Bins"][key]) : new Bin();
- }
- }
- }
- }
-
- static fromJS(data: any): HistogramResult {
- data = typeof data === 'object' ? data : {};
- let result = new HistogramResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.aggregateResults && this.aggregateResults.constructor === Array) {
- data["AggregateResults"] = [];
- for (let item of this.aggregateResults)
- data["AggregateResults"].push(item);
- }
- data["IsEmpty"] = this.isEmpty;
- if (this.brushes && this.brushes.constructor === Array) {
- data["Brushes"] = [];
- for (let item of this.brushes)
- data["Brushes"].push(item.toJSON());
- }
- if (this.binRanges && this.binRanges.constructor === Array) {
- data["BinRanges"] = [];
- for (let item of this.binRanges)
- data["BinRanges"].push(item.toJSON());
- }
- if (this.aggregateParameters && this.aggregateParameters.constructor === Array) {
- data["AggregateParameters"] = [];
- for (let item of this.aggregateParameters)
- data["AggregateParameters"].push(item.toJSON());
- }
- data["NullValueCount"] = this.nullValueCount;
- if (this.bins) {
- data["Bins"] = {};
- for (let key in this.bins) {
- if (this.bins.hasOwnProperty(key))
- data["Bins"][key] = this.bins[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IHistogramResult extends IDistResult {
- aggregateResults?: AggregateResult[][] | undefined;
- isEmpty?: boolean | undefined;
- brushes?: Brush[] | undefined;
- binRanges?: BinRange[] | undefined;
- aggregateParameters?: AggregateParameters[] | undefined;
- nullValueCount?: number | undefined;
- bins?: { [key: string]: Bin; } | undefined;
-}
-
-export abstract class AggregateResult implements IAggregateResult {
- hasResult?: boolean | undefined;
- n?: number | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IAggregateResult) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "AggregateResult";
- }
-
- init(data?: any) {
- if (data) {
- this.hasResult = data["HasResult"];
- this.n = data["N"];
- }
- }
-
- static fromJS(data: any): AggregateResult | undefined {
- if (data === null || data === undefined) {
- return undefined;
- }
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "MarginAggregateResult") {
- let result = new MarginAggregateResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DoubleValueAggregateResult") {
- let result = new DoubleValueAggregateResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PointsAggregateResult") {
- let result = new PointsAggregateResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SumEstimationAggregateResult") {
- let result = new SumEstimationAggregateResult();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'AggregateResult' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["HasResult"] = this.hasResult;
- data["N"] = this.n;
- return data;
- }
-}
-
-export interface IAggregateResult {
- hasResult?: boolean | undefined;
- n?: number | undefined;
-}
-
-export class MarginAggregateResult extends AggregateResult implements IMarginAggregateResult {
- margin?: number | undefined;
- absolutMargin?: number | undefined;
- sumOfSquare?: number | undefined;
- sampleStandardDeviation?: number | undefined;
- mean?: number | undefined;
- ex?: number | undefined;
- ex2?: number | undefined;
- variance?: number | undefined;
-
- constructor(data?: IMarginAggregateResult) {
- super(data);
- this._discriminator = "MarginAggregateResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.margin = data["Margin"];
- this.absolutMargin = data["AbsolutMargin"];
- this.sumOfSquare = data["SumOfSquare"];
- this.sampleStandardDeviation = data["SampleStandardDeviation"];
- this.mean = data["Mean"];
- this.ex = data["Ex"];
- this.ex2 = data["Ex2"];
- this.variance = data["Variance"];
- }
- }
-
- static fromJS(data: any): MarginAggregateResult {
- data = typeof data === 'object' ? data : {};
- let result = new MarginAggregateResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Margin"] = this.margin;
- data["AbsolutMargin"] = this.absolutMargin;
- data["SumOfSquare"] = this.sumOfSquare;
- data["SampleStandardDeviation"] = this.sampleStandardDeviation;
- data["Mean"] = this.mean;
- data["Ex"] = this.ex;
- data["Ex2"] = this.ex2;
- data["Variance"] = this.variance;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IMarginAggregateResult extends IAggregateResult {
- margin?: number | undefined;
- absolutMargin?: number | undefined;
- sumOfSquare?: number | undefined;
- sampleStandardDeviation?: number | undefined;
- mean?: number | undefined;
- ex?: number | undefined;
- ex2?: number | undefined;
- variance?: number | undefined;
-}
-
-export class DoubleValueAggregateResult extends AggregateResult implements IDoubleValueAggregateResult {
- result?: number | undefined;
- temporaryResult?: number | undefined;
-
- constructor(data?: IDoubleValueAggregateResult) {
- super(data);
- this._discriminator = "DoubleValueAggregateResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.result = data["Result"];
- this.temporaryResult = data["TemporaryResult"];
- }
- }
-
- static fromJS(data: any): DoubleValueAggregateResult {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "SumEstimationAggregateResult") {
- let result = new SumEstimationAggregateResult();
- result.init(data);
- return result;
- }
- let result = new DoubleValueAggregateResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Result"] = this.result;
- data["TemporaryResult"] = this.temporaryResult;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDoubleValueAggregateResult extends IAggregateResult {
- result?: number | undefined;
- temporaryResult?: number | undefined;
-}
-
-export class PointsAggregateResult extends AggregateResult implements IPointsAggregateResult {
- points?: Point[] | undefined;
-
- constructor(data?: IPointsAggregateResult) {
- super(data);
- this._discriminator = "PointsAggregateResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Points"] && data["Points"].constructor === Array) {
- this.points = [];
- for (let item of data["Points"])
- this.points.push(Point.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): PointsAggregateResult {
- data = typeof data === 'object' ? data : {};
- let result = new PointsAggregateResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.points && this.points.constructor === Array) {
- data["Points"] = [];
- for (let item of this.points)
- data["Points"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPointsAggregateResult extends IAggregateResult {
- points?: Point[] | undefined;
-}
-
-export class Point implements IPoint {
- x?: number | undefined;
- y?: number | undefined;
-
- constructor(data?: IPoint) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.x = data["X"];
- this.y = data["Y"];
- }
- }
-
- static fromJS(data: any): Point {
- data = typeof data === 'object' ? data : {};
- let result = new Point();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["X"] = this.x;
- data["Y"] = this.y;
- return data;
- }
-}
-
-export interface IPoint {
- x?: number | undefined;
- y?: number | undefined;
-}
-
-export class SumEstimationAggregateResult extends DoubleValueAggregateResult implements ISumEstimationAggregateResult {
- sum?: number | undefined;
- sumEstimation?: number | undefined;
-
- constructor(data?: ISumEstimationAggregateResult) {
- super(data);
- this._discriminator = "SumEstimationAggregateResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.sum = data["Sum"];
- this.sumEstimation = data["SumEstimation"];
- }
- }
-
- static fromJS(data: any): SumEstimationAggregateResult {
- data = typeof data === 'object' ? data : {};
- let result = new SumEstimationAggregateResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Sum"] = this.sum;
- data["SumEstimation"] = this.sumEstimation;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISumEstimationAggregateResult extends IDoubleValueAggregateResult {
- sum?: number | undefined;
- sumEstimation?: number | undefined;
-}
-
-export class Brush implements IBrush {
- brushIndex?: number | undefined;
- brushEnum?: BrushEnum | undefined;
-
- constructor(data?: IBrush) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.brushIndex = data["BrushIndex"];
- this.brushEnum = data["BrushEnum"];
- }
- }
-
- static fromJS(data: any): Brush {
- data = typeof data === 'object' ? data : {};
- let result = new Brush();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["BrushIndex"] = this.brushIndex;
- data["BrushEnum"] = this.brushEnum;
- return data;
- }
-}
-
-export interface IBrush {
- brushIndex?: number | undefined;
- brushEnum?: BrushEnum | undefined;
-}
-
-export enum BrushEnum {
- Overlap = 0,
- Rest = 1,
- All = 2,
- UserSpecified = 3,
-}
-
-export abstract class BinRange implements IBinRange {
- minValue?: number | undefined;
- maxValue?: number | undefined;
- targetBinNumber?: number | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IBinRange) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "BinRange";
- }
-
- init(data?: any) {
- if (data) {
- this.minValue = data["MinValue"];
- this.maxValue = data["MaxValue"];
- this.targetBinNumber = data["TargetBinNumber"];
- }
- }
-
- static fromJS(data: any): BinRange {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "NominalBinRange") {
- let result = new NominalBinRange();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "QuantitativeBinRange") {
- let result = new QuantitativeBinRange();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AggregateBinRange") {
- let result = new AggregateBinRange();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AlphabeticBinRange") {
- let result = new AlphabeticBinRange();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DateTimeBinRange") {
- let result = new DateTimeBinRange();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'BinRange' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["MinValue"] = this.minValue;
- data["MaxValue"] = this.maxValue;
- data["TargetBinNumber"] = this.targetBinNumber;
- return data;
- }
-}
-
-export interface IBinRange {
- minValue?: number | undefined;
- maxValue?: number | undefined;
- targetBinNumber?: number | undefined;
-}
-
-export class NominalBinRange extends BinRange implements INominalBinRange {
- labelsValue?: { [key: string]: number; } | undefined;
- valuesLabel?: { [key: string]: string; } | undefined;
-
- constructor(data?: INominalBinRange) {
- super(data);
- this._discriminator = "NominalBinRange";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["LabelsValue"]) {
- this.labelsValue = {};
- for (let key in data["LabelsValue"]) {
- if (data["LabelsValue"].hasOwnProperty(key))
- this.labelsValue[key] = data["LabelsValue"][key];
- }
- }
- if (data["ValuesLabel"]) {
- this.valuesLabel = {};
- for (let key in data["ValuesLabel"]) {
- if (data["ValuesLabel"].hasOwnProperty(key))
- this.valuesLabel[key] = data["ValuesLabel"][key];
- }
- }
- }
- }
-
- static fromJS(data: any): NominalBinRange {
- data = typeof data === 'object' ? data : {};
- let result = new NominalBinRange();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.labelsValue) {
- data["LabelsValue"] = {};
- for (let key in this.labelsValue) {
- if (this.labelsValue.hasOwnProperty(key))
- data["LabelsValue"][key] = this.labelsValue[key];
- }
- }
- if (this.valuesLabel) {
- data["ValuesLabel"] = {};
- for (let key in this.valuesLabel) {
- if (this.valuesLabel.hasOwnProperty(key))
- data["ValuesLabel"][key] = this.valuesLabel[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface INominalBinRange extends IBinRange {
- labelsValue?: { [key: string]: number; } | undefined;
- valuesLabel?: { [key: string]: string; } | undefined;
-}
-
-export class QuantitativeBinRange extends BinRange implements IQuantitativeBinRange {
- isIntegerRange?: boolean | undefined;
- step?: number | undefined;
-
- constructor(data?: IQuantitativeBinRange) {
- super(data);
- this._discriminator = "QuantitativeBinRange";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.isIntegerRange = data["IsIntegerRange"];
- this.step = data["Step"];
- }
- }
-
- static fromJS(data: any): QuantitativeBinRange {
- data = typeof data === 'object' ? data : {};
- let result = new QuantitativeBinRange();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["IsIntegerRange"] = this.isIntegerRange;
- data["Step"] = this.step;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IQuantitativeBinRange extends IBinRange {
- isIntegerRange?: boolean | undefined;
- step?: number | undefined;
-}
-
-export class AggregateBinRange extends BinRange implements IAggregateBinRange {
-
- constructor(data?: IAggregateBinRange) {
- super(data);
- this._discriminator = "AggregateBinRange";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): AggregateBinRange {
- data = typeof data === 'object' ? data : {};
- let result = new AggregateBinRange();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAggregateBinRange extends IBinRange {
-}
-
-export class AlphabeticBinRange extends BinRange implements IAlphabeticBinRange {
- prefix?: string | undefined;
- labelsValue?: { [key: string]: number; } | undefined;
- valuesLabel?: { [key: string]: string; } | undefined;
-
- constructor(data?: IAlphabeticBinRange) {
- super(data);
- this._discriminator = "AlphabeticBinRange";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.prefix = data["Prefix"];
- if (data["LabelsValue"]) {
- this.labelsValue = {};
- for (let key in data["LabelsValue"]) {
- if (data["LabelsValue"].hasOwnProperty(key))
- this.labelsValue[key] = data["LabelsValue"][key];
- }
- }
- if (data["ValuesLabel"]) {
- this.valuesLabel = {};
- for (let key in data["ValuesLabel"]) {
- if (data["ValuesLabel"].hasOwnProperty(key))
- this.valuesLabel[key] = data["ValuesLabel"][key];
- }
- }
- }
- }
-
- static fromJS(data: any): AlphabeticBinRange {
- data = typeof data === 'object' ? data : {};
- let result = new AlphabeticBinRange();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Prefix"] = this.prefix;
- if (this.labelsValue) {
- data["LabelsValue"] = {};
- for (let key in this.labelsValue) {
- if (this.labelsValue.hasOwnProperty(key))
- data["LabelsValue"][key] = this.labelsValue[key];
- }
- }
- if (this.valuesLabel) {
- data["ValuesLabel"] = {};
- for (let key in this.valuesLabel) {
- if (this.valuesLabel.hasOwnProperty(key))
- data["ValuesLabel"][key] = this.valuesLabel[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAlphabeticBinRange extends IBinRange {
- prefix?: string | undefined;
- labelsValue?: { [key: string]: number; } | undefined;
- valuesLabel?: { [key: string]: string; } | undefined;
-}
-
-export class DateTimeBinRange extends BinRange implements IDateTimeBinRange {
- step?: DateTimeStep | undefined;
-
- constructor(data?: IDateTimeBinRange) {
- super(data);
- this._discriminator = "DateTimeBinRange";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.step = data["Step"] ? DateTimeStep.fromJS(data["Step"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): DateTimeBinRange {
- data = typeof data === 'object' ? data : {};
- let result = new DateTimeBinRange();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Step"] = this.step ? this.step.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDateTimeBinRange extends IBinRange {
- step?: DateTimeStep | undefined;
-}
-
-export class DateTimeStep implements IDateTimeStep {
- dateTimeStepGranularity?: DateTimeStepGranularity | undefined;
- dateTimeStepValue?: number | undefined;
- dateTimeStepMaxValue?: number | undefined;
-
- constructor(data?: IDateTimeStep) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.dateTimeStepGranularity = data["DateTimeStepGranularity"];
- this.dateTimeStepValue = data["DateTimeStepValue"];
- this.dateTimeStepMaxValue = data["DateTimeStepMaxValue"];
- }
- }
-
- static fromJS(data: any): DateTimeStep {
- data = typeof data === 'object' ? data : {};
- let result = new DateTimeStep();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["DateTimeStepGranularity"] = this.dateTimeStepGranularity;
- data["DateTimeStepValue"] = this.dateTimeStepValue;
- data["DateTimeStepMaxValue"] = this.dateTimeStepMaxValue;
- return data;
- }
-}
-
-export interface IDateTimeStep {
- dateTimeStepGranularity?: DateTimeStepGranularity | undefined;
- dateTimeStepValue?: number | undefined;
- dateTimeStepMaxValue?: number | undefined;
-}
-
-export enum DateTimeStepGranularity {
- Second = 0,
- Minute = 1,
- Hour = 2,
- Day = 3,
- Month = 4,
- Year = 5,
-}
-
-export class Bin implements IBin {
- aggregateResults?: AggregateResult[] | undefined;
- count?: number | undefined;
- binIndex?: BinIndex | undefined;
- spans?: Span[] | undefined;
- xSize?: number | undefined;
- ySize?: number | undefined;
-
- constructor(data?: IBin) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["AggregateResults"] && data["AggregateResults"].constructor === Array) {
- this.aggregateResults = [];
- for (let item of data["AggregateResults"]) {
- let fromJs = AggregateResult.fromJS(item);
- if (fromJs)
- this.aggregateResults.push(fromJs);
- }
- }
- this.count = data["Count"];
- this.binIndex = data["BinIndex"] ? BinIndex.fromJS(data["BinIndex"]) : <any>undefined;
- if (data["Spans"] && data["Spans"].constructor === Array) {
- this.spans = [];
- for (let item of data["Spans"])
- this.spans.push(Span.fromJS(item));
- }
- this.xSize = data["XSize"];
- this.ySize = data["YSize"];
- }
- }
-
- static fromJS(data: any): Bin {
- data = typeof data === 'object' ? data : {};
- let result = new Bin();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.aggregateResults && this.aggregateResults.constructor === Array) {
- data["AggregateResults"] = [];
- for (let item of this.aggregateResults)
- data["AggregateResults"].push(item.toJSON());
- }
- data["Count"] = this.count;
- data["BinIndex"] = this.binIndex ? this.binIndex.toJSON() : <any>undefined;
- if (this.spans && this.spans.constructor === Array) {
- data["Spans"] = [];
- for (let item of this.spans)
- data["Spans"].push(item.toJSON());
- }
- data["XSize"] = this.xSize;
- data["YSize"] = this.ySize;
- return data;
- }
-}
-
-export interface IBin {
- aggregateResults?: AggregateResult[] | undefined;
- count?: number | undefined;
- binIndex?: BinIndex | undefined;
- spans?: Span[] | undefined;
- xSize?: number | undefined;
- ySize?: number | undefined;
-}
-
-export class BinIndex implements IBinIndex {
- indices?: number[] | undefined;
- flatIndex?: number | undefined;
-
- constructor(data?: IBinIndex) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["Indices"] && data["Indices"].constructor === Array) {
- this.indices = [];
- for (let item of data["Indices"])
- this.indices.push(item);
- }
- this.flatIndex = data["FlatIndex"];
- }
- }
-
- static fromJS(data: any): BinIndex {
- data = typeof data === 'object' ? data : {};
- let result = new BinIndex();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.indices && this.indices.constructor === Array) {
- data["Indices"] = [];
- for (let item of this.indices)
- data["Indices"].push(item);
- }
- data["FlatIndex"] = this.flatIndex;
- return data;
- }
-}
-
-export interface IBinIndex {
- indices?: number[] | undefined;
- flatIndex?: number | undefined;
-}
-
-export class Span implements ISpan {
- min?: number | undefined;
- max?: number | undefined;
- index?: number | undefined;
-
- constructor(data?: ISpan) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.min = data["Min"];
- this.max = data["Max"];
- this.index = data["Index"];
- }
- }
-
- static fromJS(data: any): Span {
- data = typeof data === 'object' ? data : {};
- let result = new Span();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Min"] = this.min;
- data["Max"] = this.max;
- data["Index"] = this.index;
- return data;
- }
-}
-
-export interface ISpan {
- min?: number | undefined;
- max?: number | undefined;
- index?: number | undefined;
-}
-
-export class ModelWealthResult extends Result implements IModelWealthResult {
- wealth?: number | undefined;
- startWealth?: number | undefined;
-
- constructor(data?: IModelWealthResult) {
- super(data);
- this._discriminator = "ModelWealthResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.wealth = data["Wealth"];
- this.startWealth = data["StartWealth"];
- }
- }
-
- static fromJS(data: any): ModelWealthResult {
- data = typeof data === 'object' ? data : {};
- let result = new ModelWealthResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Wealth"] = this.wealth;
- data["StartWealth"] = this.startWealth;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IModelWealthResult extends IResult {
- wealth?: number | undefined;
- startWealth?: number | undefined;
-}
-
-export abstract class HypothesisTestResult extends Result implements IHypothesisTestResult {
- pValue?: number | undefined;
- statistic?: number | undefined;
- support?: number | undefined;
- sampleSizes?: number[] | undefined;
- errorMessage?: string | undefined;
-
- constructor(data?: IHypothesisTestResult) {
- super(data);
- this._discriminator = "HypothesisTestResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.pValue = data["PValue"];
- this.statistic = data["Statistic"];
- this.support = data["Support"];
- if (data["SampleSizes"] && data["SampleSizes"].constructor === Array) {
- this.sampleSizes = [];
- for (let item of data["SampleSizes"])
- this.sampleSizes.push(item);
- }
- this.errorMessage = data["ErrorMessage"];
- }
- }
-
- static fromJS(data: any): HypothesisTestResult {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "ChiSquaredTestResult") {
- let result = new ChiSquaredTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CorrelationTestResult") {
- let result = new CorrelationTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "KSTestResult") {
- let result = new KSTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "RootMeanSquareTestResult") {
- let result = new RootMeanSquareTestResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "TTestResult") {
- let result = new TTestResult();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'HypothesisTestResult' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["PValue"] = this.pValue;
- data["Statistic"] = this.statistic;
- data["Support"] = this.support;
- if (this.sampleSizes && this.sampleSizes.constructor === Array) {
- data["SampleSizes"] = [];
- for (let item of this.sampleSizes)
- data["SampleSizes"].push(item);
- }
- data["ErrorMessage"] = this.errorMessage;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IHypothesisTestResult extends IResult {
- pValue?: number | undefined;
- statistic?: number | undefined;
- support?: number | undefined;
- sampleSizes?: number[] | undefined;
- errorMessage?: string | undefined;
-}
-
-export abstract class ModelOperationResult extends Result implements IModelOperationResult {
- modelId?: ModelId | undefined;
-
- constructor(data?: IModelOperationResult) {
- super(data);
- this._discriminator = "ModelOperationResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): ModelOperationResult {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "NewModelOperationResult") {
- let result = new NewModelOperationResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "AddComparisonResult") {
- let result = new AddComparisonResult();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "GetModelStateResult") {
- let result = new GetModelStateResult();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'ModelOperationResult' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IModelOperationResult extends IResult {
- modelId?: ModelId | undefined;
-}
-
-export class RecommenderResult extends Result implements IRecommenderResult {
- recommendedHistograms?: RecommendedHistogram[] | undefined;
- totalCount?: number | undefined;
-
- constructor(data?: IRecommenderResult) {
- super(data);
- this._discriminator = "RecommenderResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["RecommendedHistograms"] && data["RecommendedHistograms"].constructor === Array) {
- this.recommendedHistograms = [];
- for (let item of data["RecommendedHistograms"])
- this.recommendedHistograms.push(RecommendedHistogram.fromJS(item));
- }
- this.totalCount = data["TotalCount"];
- }
- }
-
- static fromJS(data: any): RecommenderResult {
- data = typeof data === 'object' ? data : {};
- let result = new RecommenderResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.recommendedHistograms && this.recommendedHistograms.constructor === Array) {
- data["RecommendedHistograms"] = [];
- for (let item of this.recommendedHistograms)
- data["RecommendedHistograms"].push(item.toJSON());
- }
- data["TotalCount"] = this.totalCount;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRecommenderResult extends IResult {
- recommendedHistograms?: RecommendedHistogram[] | undefined;
- totalCount?: number | undefined;
-}
-
-export class RecommendedHistogram implements IRecommendedHistogram {
- histogramResult?: HistogramResult | undefined;
- selectedBinIndices?: BinIndex[] | undefined;
- selections?: Selection[] | undefined;
- pValue?: number | undefined;
- significance?: boolean | undefined;
- decision?: Decision | undefined;
- effectSize?: number | undefined;
- hypothesisTestResult?: HypothesisTestResult | undefined;
- id?: string | undefined;
- xAttribute?: Attribute | undefined;
- yAttribute?: Attribute | undefined;
-
- constructor(data?: IRecommendedHistogram) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.histogramResult = data["HistogramResult"] ? HistogramResult.fromJS(data["HistogramResult"]) : <any>undefined;
- if (data["SelectedBinIndices"] && data["SelectedBinIndices"].constructor === Array) {
- this.selectedBinIndices = [];
- for (let item of data["SelectedBinIndices"])
- this.selectedBinIndices.push(BinIndex.fromJS(item));
- }
- if (data["Selections"] && data["Selections"].constructor === Array) {
- this.selections = [];
- for (let item of data["Selections"])
- this.selections.push(Selection.fromJS(item));
- }
- this.pValue = data["PValue"];
- this.significance = data["Significance"];
- this.decision = data["Decision"] ? Decision.fromJS(data["Decision"]) : <any>undefined;
- this.effectSize = data["EffectSize"];
- this.hypothesisTestResult = data["HypothesisTestResult"] ? HypothesisTestResult.fromJS(data["HypothesisTestResult"]) : <any>undefined;
- this.id = data["Id"];
- this.xAttribute = data["XAttribute"] ? Attribute.fromJS(data["XAttribute"]) : <any>undefined;
- this.yAttribute = data["YAttribute"] ? Attribute.fromJS(data["YAttribute"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): RecommendedHistogram {
- data = typeof data === 'object' ? data : {};
- let result = new RecommendedHistogram();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["HistogramResult"] = this.histogramResult ? this.histogramResult.toJSON() : <any>undefined;
- if (this.selectedBinIndices && this.selectedBinIndices.constructor === Array) {
- data["SelectedBinIndices"] = [];
- for (let item of this.selectedBinIndices)
- data["SelectedBinIndices"].push(item.toJSON());
- }
- if (this.selections && this.selections.constructor === Array) {
- data["Selections"] = [];
- for (let item of this.selections)
- data["Selections"].push(item.toJSON());
- }
- data["PValue"] = this.pValue;
- data["Significance"] = this.significance;
- data["Decision"] = this.decision ? this.decision.toJSON() : <any>undefined;
- data["EffectSize"] = this.effectSize;
- data["HypothesisTestResult"] = this.hypothesisTestResult ? this.hypothesisTestResult.toJSON() : <any>undefined;
- data["Id"] = this.id;
- data["XAttribute"] = this.xAttribute ? this.xAttribute.toJSON() : <any>undefined;
- data["YAttribute"] = this.yAttribute ? this.yAttribute.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface IRecommendedHistogram {
- histogramResult?: HistogramResult | undefined;
- selectedBinIndices?: BinIndex[] | undefined;
- selections?: Selection[] | undefined;
- pValue?: number | undefined;
- significance?: boolean | undefined;
- decision?: Decision | undefined;
- effectSize?: number | undefined;
- hypothesisTestResult?: HypothesisTestResult | undefined;
- id?: string | undefined;
- xAttribute?: Attribute | undefined;
- yAttribute?: Attribute | undefined;
-}
-
-export class Selection implements ISelection {
- statements?: Statement[] | undefined;
- filterHistogramOperationReference?: IOperationReference | undefined;
-
- constructor(data?: ISelection) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- if (data["Statements"] && data["Statements"].constructor === Array) {
- this.statements = [];
- for (let item of data["Statements"])
- this.statements.push(Statement.fromJS(item));
- }
- this.filterHistogramOperationReference = data["FilterHistogramOperationReference"] ? IOperationReference.fromJS(data["FilterHistogramOperationReference"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): Selection {
- data = typeof data === 'object' ? data : {};
- let result = new Selection();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.statements && this.statements.constructor === Array) {
- data["Statements"] = [];
- for (let item of this.statements)
- data["Statements"].push(item.toJSON());
- }
- data["FilterHistogramOperationReference"] = this.filterHistogramOperationReference ? this.filterHistogramOperationReference.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface ISelection {
- statements?: Statement[] | undefined;
- filterHistogramOperationReference?: IOperationReference | undefined;
-}
-
-export class Statement implements IStatement {
- attribute?: Attribute | undefined;
- predicate?: Predicate | undefined;
- value?: any | undefined;
-
- constructor(data?: IStatement) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.attribute = data["Attribute"] ? Attribute.fromJS(data["Attribute"]) : <any>undefined;
- this.predicate = data["Predicate"];
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): Statement {
- data = typeof data === 'object' ? data : {};
- let result = new Statement();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Attribute"] = this.attribute ? this.attribute.toJSON() : <any>undefined;
- data["Predicate"] = this.predicate;
- data["Value"] = this.value;
- return data;
- }
-}
-
-export interface IStatement {
- attribute?: Attribute | undefined;
- predicate?: Predicate | undefined;
- value?: any | undefined;
-}
-
-export enum Predicate {
- EQUALS = 0,
- LIKE = 1,
- GREATER_THAN = 2,
- LESS_THAN = 3,
- GREATER_THAN_EQUAL = 4,
- LESS_THAN_EQUAL = 5,
- STARTS_WITH = 6,
- ENDS_WITH = 7,
- CONTAINS = 8,
-}
-
-export abstract class IOperationReference implements IIOperationReference {
- id?: string | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IIOperationReference) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "IOperationReference";
- }
-
- init(data?: any) {
- if (data) {
- this.id = data["Id"];
- }
- }
-
- static fromJS(data: any): IOperationReference {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "OperationReference") {
- let result = new OperationReference();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'IOperationReference' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["Id"] = this.id;
- return data;
- }
-}
-
-export interface IIOperationReference {
- id?: string | undefined;
-}
-
-export class OperationReference extends IOperationReference implements IOperationReference {
- id?: string | undefined;
-
- constructor(data?: IOperationReference) {
- super(data);
- this._discriminator = "OperationReference";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.id = data["Id"];
- }
- }
-
- static fromJS(data: any): OperationReference {
- data = typeof data === 'object' ? data : {};
- let result = new OperationReference();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IOperationReference extends IIOperationReference {
- id?: string | undefined;
-}
-
-export class Decision extends Result implements IDecision {
- comparisonId?: ComparisonId | undefined;
- riskControlType?: RiskControlType | undefined;
- significance?: boolean | undefined;
- pValue?: number | undefined;
- lhs?: number | undefined;
- significanceLevel?: number | undefined;
- sampleSizeEstimate?: number | undefined;
-
- constructor(data?: IDecision) {
- super(data);
- this._discriminator = "Decision";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.comparisonId = data["ComparisonId"] ? ComparisonId.fromJS(data["ComparisonId"]) : <any>undefined;
- this.riskControlType = data["RiskControlType"];
- this.significance = data["Significance"];
- this.pValue = data["PValue"];
- this.lhs = data["Lhs"];
- this.significanceLevel = data["SignificanceLevel"];
- this.sampleSizeEstimate = data["SampleSizeEstimate"];
- }
- }
-
- static fromJS(data: any): Decision {
- data = typeof data === 'object' ? data : {};
- let result = new Decision();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["ComparisonId"] = this.comparisonId ? this.comparisonId.toJSON() : <any>undefined;
- data["RiskControlType"] = this.riskControlType;
- data["Significance"] = this.significance;
- data["PValue"] = this.pValue;
- data["Lhs"] = this.lhs;
- data["SignificanceLevel"] = this.significanceLevel;
- data["SampleSizeEstimate"] = this.sampleSizeEstimate;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDecision extends IResult {
- comparisonId?: ComparisonId | undefined;
- riskControlType?: RiskControlType | undefined;
- significance?: boolean | undefined;
- pValue?: number | undefined;
- lhs?: number | undefined;
- significanceLevel?: number | undefined;
- sampleSizeEstimate?: number | undefined;
-}
-
-export class ComparisonId implements IComparisonId {
- value?: string | undefined;
-
- constructor(data?: IComparisonId) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): ComparisonId {
- data = typeof data === 'object' ? data : {};
- let result = new ComparisonId();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- return data;
- }
-}
-
-export interface IComparisonId {
- value?: string | undefined;
-}
-
-export class OptimizerResult extends Result implements IOptimizerResult {
- topKSolutions?: Solution[] | undefined;
-
- constructor(data?: IOptimizerResult) {
- super(data);
- this._discriminator = "OptimizerResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["TopKSolutions"] && data["TopKSolutions"].constructor === Array) {
- this.topKSolutions = [];
- for (let item of data["TopKSolutions"])
- this.topKSolutions.push(Solution.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): OptimizerResult {
- data = typeof data === 'object' ? data : {};
- let result = new OptimizerResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.topKSolutions && this.topKSolutions.constructor === Array) {
- data["TopKSolutions"] = [];
- for (let item of this.topKSolutions)
- data["TopKSolutions"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IOptimizerResult extends IResult {
- topKSolutions?: Solution[] | undefined;
-}
-
-export class Solution implements ISolution {
- solutionId?: string | undefined;
- stepDescriptions?: StepDescription[] | undefined;
- pipelineDescription?: PipelineDescription | undefined;
- score?: Score | undefined;
- naiveScore?: Score | undefined;
-
- constructor(data?: ISolution) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.solutionId = data["SolutionId"];
- if (data["StepDescriptions"] && data["StepDescriptions"].constructor === Array) {
- this.stepDescriptions = [];
- for (let item of data["StepDescriptions"])
- this.stepDescriptions.push(StepDescription.fromJS(item));
- }
- this.pipelineDescription = data["PipelineDescription"] ? PipelineDescription.fromJS(data["PipelineDescription"]) : <any>undefined;
- this.score = data["Score"] ? Score.fromJS(data["Score"]) : <any>undefined;
- this.naiveScore = data["NaiveScore"] ? Score.fromJS(data["NaiveScore"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): Solution {
- data = typeof data === 'object' ? data : {};
- let result = new Solution();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SolutionId"] = this.solutionId;
- if (this.stepDescriptions && this.stepDescriptions.constructor === Array) {
- data["StepDescriptions"] = [];
- for (let item of this.stepDescriptions)
- data["StepDescriptions"].push(item.toJSON());
- }
- data["PipelineDescription"] = this.pipelineDescription ? this.pipelineDescription.toJSON() : <any>undefined;
- data["Score"] = this.score ? this.score.toJSON() : <any>undefined;
- data["NaiveScore"] = this.naiveScore ? this.naiveScore.toJSON() : <any>undefined;
- return data;
- }
-}
-
-export interface ISolution {
- solutionId?: string | undefined;
- stepDescriptions?: StepDescription[] | undefined;
- pipelineDescription?: PipelineDescription | undefined;
- score?: Score | undefined;
- naiveScore?: Score | undefined;
-}
-
-export class StepDescription implements IStepDescription {
-
- protected _discriminator: string;
-
- constructor(data?: IStepDescription) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "StepDescription";
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): StepDescription {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "SubpipelineStepDescription") {
- let result = new SubpipelineStepDescription();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PrimitiveStepDescription") {
- let result = new PrimitiveStepDescription();
- result.init(data);
- return result;
- }
- let result = new StepDescription();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- return data;
- }
-}
-
-export interface IStepDescription {
-}
-
-export class SubpipelineStepDescription extends StepDescription implements ISubpipelineStepDescription {
- steps?: StepDescription[] | undefined;
-
- constructor(data?: ISubpipelineStepDescription) {
- super(data);
- this._discriminator = "SubpipelineStepDescription";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Steps"] && data["Steps"].constructor === Array) {
- this.steps = [];
- for (let item of data["Steps"])
- this.steps.push(StepDescription.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): SubpipelineStepDescription {
- data = typeof data === 'object' ? data : {};
- let result = new SubpipelineStepDescription();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.steps && this.steps.constructor === Array) {
- data["Steps"] = [];
- for (let item of this.steps)
- data["Steps"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISubpipelineStepDescription extends IStepDescription {
- steps?: StepDescription[] | undefined;
-}
-
-export class PipelineDescription implements IPipelineDescription {
- id?: string | undefined;
- name?: string | undefined;
- description?: string | undefined;
- inputs?: PipelineDescriptionInput[] | undefined;
- outputs?: PipelineDescriptionOutput[] | undefined;
- steps?: PipelineDescriptionStep[] | undefined;
-
- constructor(data?: IPipelineDescription) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.id = data["Id"];
- this.name = data["Name"];
- this.description = data["Description"];
- if (data["Inputs"] && data["Inputs"].constructor === Array) {
- this.inputs = [];
- for (let item of data["Inputs"])
- this.inputs.push(PipelineDescriptionInput.fromJS(item));
- }
- if (data["Outputs"] && data["Outputs"].constructor === Array) {
- this.outputs = [];
- for (let item of data["Outputs"])
- this.outputs.push(PipelineDescriptionOutput.fromJS(item));
- }
- if (data["Steps"] && data["Steps"].constructor === Array) {
- this.steps = [];
- for (let item of data["Steps"])
- this.steps.push(PipelineDescriptionStep.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): PipelineDescription {
- data = typeof data === 'object' ? data : {};
- let result = new PipelineDescription();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- data["Name"] = this.name;
- data["Description"] = this.description;
- if (this.inputs && this.inputs.constructor === Array) {
- data["Inputs"] = [];
- for (let item of this.inputs)
- data["Inputs"].push(item.toJSON());
- }
- if (this.outputs && this.outputs.constructor === Array) {
- data["Outputs"] = [];
- for (let item of this.outputs)
- data["Outputs"].push(item.toJSON());
- }
- if (this.steps && this.steps.constructor === Array) {
- data["Steps"] = [];
- for (let item of this.steps)
- data["Steps"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IPipelineDescription {
- id?: string | undefined;
- name?: string | undefined;
- description?: string | undefined;
- inputs?: PipelineDescriptionInput[] | undefined;
- outputs?: PipelineDescriptionOutput[] | undefined;
- steps?: PipelineDescriptionStep[] | undefined;
-}
-
-export class PipelineDescriptionInput implements IPipelineDescriptionInput {
- name?: string | undefined;
-
- constructor(data?: IPipelineDescriptionInput) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.name = data["Name"];
- }
- }
-
- static fromJS(data: any): PipelineDescriptionInput {
- data = typeof data === 'object' ? data : {};
- let result = new PipelineDescriptionInput();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Name"] = this.name;
- return data;
- }
-}
-
-export interface IPipelineDescriptionInput {
- name?: string | undefined;
-}
-
-export class PipelineDescriptionOutput implements IPipelineDescriptionOutput {
- name?: string | undefined;
- data?: string | undefined;
-
- constructor(data?: IPipelineDescriptionOutput) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.name = data["Name"];
- this.data = data["Data"];
- }
- }
-
- static fromJS(data: any): PipelineDescriptionOutput {
- data = typeof data === 'object' ? data : {};
- let result = new PipelineDescriptionOutput();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Name"] = this.name;
- data["Data"] = this.data;
- return data;
- }
-}
-
-export interface IPipelineDescriptionOutput {
- name?: string | undefined;
- data?: string | undefined;
-}
-
-export class PipelineDescriptionStep implements IPipelineDescriptionStep {
- outputs?: StepOutput[] | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IPipelineDescriptionStep) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "PipelineDescriptionStep";
- }
-
- init(data?: any) {
- if (data) {
- if (data["Outputs"] && data["Outputs"].constructor === Array) {
- this.outputs = [];
- for (let item of data["Outputs"])
- this.outputs.push(StepOutput.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): PipelineDescriptionStep {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "PlaceholderPipelineDescriptionStep") {
- let result = new PlaceholderPipelineDescriptionStep();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "SubpipelinePipelineDescriptionStep") {
- let result = new SubpipelinePipelineDescriptionStep();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PrimitivePipelineDescriptionStep") {
- let result = new PrimitivePipelineDescriptionStep();
- result.init(data);
- return result;
- }
- let result = new PipelineDescriptionStep();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- if (this.outputs && this.outputs.constructor === Array) {
- data["Outputs"] = [];
- for (let item of this.outputs)
- data["Outputs"].push(item.toJSON());
- }
- return data;
- }
-}
-
-export interface IPipelineDescriptionStep {
- outputs?: StepOutput[] | undefined;
-}
-
-export class StepOutput implements IStepOutput {
- id?: string | undefined;
-
- constructor(data?: IStepOutput) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.id = data["Id"];
- }
- }
-
- static fromJS(data: any): StepOutput {
- data = typeof data === 'object' ? data : {};
- let result = new StepOutput();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- return data;
- }
-}
-
-export interface IStepOutput {
- id?: string | undefined;
-}
-
-export class PlaceholderPipelineDescriptionStep extends PipelineDescriptionStep implements IPlaceholderPipelineDescriptionStep {
- inputs?: StepInput[] | undefined;
-
- constructor(data?: IPlaceholderPipelineDescriptionStep) {
- super(data);
- this._discriminator = "PlaceholderPipelineDescriptionStep";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Inputs"] && data["Inputs"].constructor === Array) {
- this.inputs = [];
- for (let item of data["Inputs"])
- this.inputs.push(StepInput.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): PlaceholderPipelineDescriptionStep {
- data = typeof data === 'object' ? data : {};
- let result = new PlaceholderPipelineDescriptionStep();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.inputs && this.inputs.constructor === Array) {
- data["Inputs"] = [];
- for (let item of this.inputs)
- data["Inputs"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPlaceholderPipelineDescriptionStep extends IPipelineDescriptionStep {
- inputs?: StepInput[] | undefined;
-}
-
-export class StepInput implements IStepInput {
- data?: string | undefined;
-
- constructor(data?: IStepInput) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.data = data["Data"];
- }
- }
-
- static fromJS(data: any): StepInput {
- data = typeof data === 'object' ? data : {};
- let result = new StepInput();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Data"] = this.data;
- return data;
- }
-}
-
-export interface IStepInput {
- data?: string | undefined;
-}
-
-export class SubpipelinePipelineDescriptionStep extends PipelineDescriptionStep implements ISubpipelinePipelineDescriptionStep {
- pipelineDescription?: PipelineDescription | undefined;
- inputs?: StepInput[] | undefined;
-
- constructor(data?: ISubpipelinePipelineDescriptionStep) {
- super(data);
- this._discriminator = "SubpipelinePipelineDescriptionStep";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.pipelineDescription = data["PipelineDescription"] ? PipelineDescription.fromJS(data["PipelineDescription"]) : <any>undefined;
- if (data["Inputs"] && data["Inputs"].constructor === Array) {
- this.inputs = [];
- for (let item of data["Inputs"])
- this.inputs.push(StepInput.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): SubpipelinePipelineDescriptionStep {
- data = typeof data === 'object' ? data : {};
- let result = new SubpipelinePipelineDescriptionStep();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["PipelineDescription"] = this.pipelineDescription ? this.pipelineDescription.toJSON() : <any>undefined;
- if (this.inputs && this.inputs.constructor === Array) {
- data["Inputs"] = [];
- for (let item of this.inputs)
- data["Inputs"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISubpipelinePipelineDescriptionStep extends IPipelineDescriptionStep {
- pipelineDescription?: PipelineDescription | undefined;
- inputs?: StepInput[] | undefined;
-}
-
-export class PrimitivePipelineDescriptionStep extends PipelineDescriptionStep implements IPrimitivePipelineDescriptionStep {
- primitive?: Primitive | undefined;
- arguments?: { [key: string]: PrimitiveStepArgument; } | undefined;
- hyperparams?: { [key: string]: PrimitiveStepHyperparameter; } | undefined;
-
- constructor(data?: IPrimitivePipelineDescriptionStep) {
- super(data);
- this._discriminator = "PrimitivePipelineDescriptionStep";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.primitive = data["Primitive"] ? Primitive.fromJS(data["Primitive"]) : <any>undefined;
- if (data["Arguments"]) {
- this.arguments = {};
- for (let key in data["Arguments"]) {
- if (data["Arguments"].hasOwnProperty(key))
- this.arguments[key] = data["Arguments"][key] ? PrimitiveStepArgument.fromJS(data["Arguments"][key]) : new PrimitiveStepArgument();
- }
- }
- if (data["Hyperparams"]) {
- this.hyperparams = {};
- for (let key in data["Hyperparams"]) {
- if (data["Hyperparams"].hasOwnProperty(key))
- this.hyperparams[key] = data["Hyperparams"][key] ? PrimitiveStepHyperparameter.fromJS(data["Hyperparams"][key]) : new PrimitiveStepHyperparameter();
- }
- }
- }
- }
-
- static fromJS(data: any): PrimitivePipelineDescriptionStep {
- data = typeof data === 'object' ? data : {};
- let result = new PrimitivePipelineDescriptionStep();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Primitive"] = this.primitive ? this.primitive.toJSON() : <any>undefined;
- if (this.arguments) {
- data["Arguments"] = {};
- for (let key in this.arguments) {
- if (this.arguments.hasOwnProperty(key))
- data["Arguments"][key] = this.arguments[key];
- }
- }
- if (this.hyperparams) {
- data["Hyperparams"] = {};
- for (let key in this.hyperparams) {
- if (this.hyperparams.hasOwnProperty(key))
- data["Hyperparams"][key] = this.hyperparams[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPrimitivePipelineDescriptionStep extends IPipelineDescriptionStep {
- primitive?: Primitive | undefined;
- arguments?: { [key: string]: PrimitiveStepArgument; } | undefined;
- hyperparams?: { [key: string]: PrimitiveStepHyperparameter; } | undefined;
-}
-
-export class Primitive implements IPrimitive {
- id?: string | undefined;
- version?: string | undefined;
- pythonPath?: string | undefined;
- name?: string | undefined;
- digest?: string | undefined;
-
- constructor(data?: IPrimitive) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.id = data["Id"];
- this.version = data["Version"];
- this.pythonPath = data["PythonPath"];
- this.name = data["Name"];
- this.digest = data["Digest"];
- }
- }
-
- static fromJS(data: any): Primitive {
- data = typeof data === 'object' ? data : {};
- let result = new Primitive();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Id"] = this.id;
- data["Version"] = this.version;
- data["PythonPath"] = this.pythonPath;
- data["Name"] = this.name;
- data["Digest"] = this.digest;
- return data;
- }
-}
-
-export interface IPrimitive {
- id?: string | undefined;
- version?: string | undefined;
- pythonPath?: string | undefined;
- name?: string | undefined;
- digest?: string | undefined;
-}
-
-export class PrimitiveStepHyperparameter implements IPrimitiveStepHyperparameter {
-
- protected _discriminator: string;
-
- constructor(data?: IPrimitiveStepHyperparameter) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "PrimitiveStepHyperparameter";
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): PrimitiveStepHyperparameter {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "PrimitiveStepArgument") {
- let result = new PrimitiveStepArgument();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DataArguments") {
- let result = new DataArguments();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PrimitiveArgument") {
- let result = new PrimitiveArgument();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PrimitiveArguments") {
- let result = new PrimitiveArguments();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "ValueArgument") {
- let result = new ValueArgument();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "ContainerArgument") {
- let result = new ContainerArgument();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DataArgument") {
- let result = new DataArgument();
- result.init(data);
- return result;
- }
- let result = new PrimitiveStepHyperparameter();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- return data;
- }
-}
-
-export interface IPrimitiveStepHyperparameter {
-}
-
-export class PrimitiveStepArgument extends PrimitiveStepHyperparameter implements IPrimitiveStepArgument {
-
- protected _discriminator: string;
-
- constructor(data?: IPrimitiveStepArgument) {
- super(data);
- this._discriminator = "PrimitiveStepArgument";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): PrimitiveStepArgument {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "ContainerArgument") {
- let result = new ContainerArgument();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DataArgument") {
- let result = new DataArgument();
- result.init(data);
- return result;
- }
- let result = new PrimitiveStepArgument();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPrimitiveStepArgument extends IPrimitiveStepHyperparameter {
-}
-
-export class DataArguments extends PrimitiveStepHyperparameter implements IDataArguments {
- data?: string[] | undefined;
-
- constructor(data?: IDataArguments) {
- super(data);
- this._discriminator = "DataArguments";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Data"] && data["Data"].constructor === Array) {
- this.data = [];
- for (let item of data["Data"])
- this.data.push(item);
- }
- }
- }
-
- static fromJS(data: any): DataArguments {
- data = typeof data === 'object' ? data : {};
- let result = new DataArguments();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.data && this.data.constructor === Array) {
- data["Data"] = [];
- for (let item of this.data)
- data["Data"].push(item);
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDataArguments extends IPrimitiveStepHyperparameter {
- data?: string[] | undefined;
-}
-
-export class PrimitiveArgument extends PrimitiveStepHyperparameter implements IPrimitiveArgument {
- data?: number | undefined;
-
- constructor(data?: IPrimitiveArgument) {
- super(data);
- this._discriminator = "PrimitiveArgument";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.data = data["Data"];
- }
- }
-
- static fromJS(data: any): PrimitiveArgument {
- data = typeof data === 'object' ? data : {};
- let result = new PrimitiveArgument();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Data"] = this.data;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPrimitiveArgument extends IPrimitiveStepHyperparameter {
- data?: number | undefined;
-}
-
-export class PrimitiveArguments extends PrimitiveStepHyperparameter implements IPrimitiveArguments {
- data?: number[] | undefined;
-
- constructor(data?: IPrimitiveArguments) {
- super(data);
- this._discriminator = "PrimitiveArguments";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Data"] && data["Data"].constructor === Array) {
- this.data = [];
- for (let item of data["Data"])
- this.data.push(item);
- }
- }
- }
-
- static fromJS(data: any): PrimitiveArguments {
- data = typeof data === 'object' ? data : {};
- let result = new PrimitiveArguments();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.data && this.data.constructor === Array) {
- data["Data"] = [];
- for (let item of this.data)
- data["Data"].push(item);
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPrimitiveArguments extends IPrimitiveStepHyperparameter {
- data?: number[] | undefined;
-}
-
-export class ValueArgument extends PrimitiveStepHyperparameter implements IValueArgument {
- data?: Value | undefined;
-
- constructor(data?: IValueArgument) {
- super(data);
- this._discriminator = "ValueArgument";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.data = data["Data"] ? Value.fromJS(data["Data"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): ValueArgument {
- data = typeof data === 'object' ? data : {};
- let result = new ValueArgument();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Data"] = this.data ? this.data.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IValueArgument extends IPrimitiveStepHyperparameter {
- data?: Value | undefined;
-}
-
-export abstract class Value implements IValue {
-
- protected _discriminator: string;
-
- constructor(data?: IValue) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- this._discriminator = "Value";
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): Value {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "ErrorValue") {
- let result = new ErrorValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DoubleValue") {
- let result = new DoubleValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "LongValue") {
- let result = new LongValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "BoolValue") {
- let result = new BoolValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "StringValue") {
- let result = new StringValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "DatasetUriValue") {
- let result = new DatasetUriValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "CsvUriValue") {
- let result = new CsvUriValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PickleUriValue") {
- let result = new PickleUriValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PickleBlobValue") {
- let result = new PickleBlobValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "PlasmaIdValue") {
- let result = new PlasmaIdValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "BytesValue") {
- let result = new BytesValue();
- result.init(data);
- return result;
- }
- if (data["discriminator"] === "ListValue") {
- let result = new ListValue();
- result.init(data);
- return result;
- }
- throw new Error("The abstract class 'Value' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- return data;
- }
-}
-
-export interface IValue {
-}
-
-export class ErrorValue extends Value implements IErrorValue {
- message?: string | undefined;
-
- constructor(data?: IErrorValue) {
- super(data);
- this._discriminator = "ErrorValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.message = data["Message"];
- }
- }
-
- static fromJS(data: any): ErrorValue {
- data = typeof data === 'object' ? data : {};
- let result = new ErrorValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Message"] = this.message;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IErrorValue extends IValue {
- message?: string | undefined;
-}
-
-export class DoubleValue extends Value implements IDoubleValue {
- value?: number | undefined;
-
- constructor(data?: IDoubleValue) {
- super(data);
- this._discriminator = "DoubleValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): DoubleValue {
- data = typeof data === 'object' ? data : {};
- let result = new DoubleValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDoubleValue extends IValue {
- value?: number | undefined;
-}
-
-export class LongValue extends Value implements ILongValue {
- value?: number | undefined;
-
- constructor(data?: ILongValue) {
- super(data);
- this._discriminator = "LongValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): LongValue {
- data = typeof data === 'object' ? data : {};
- let result = new LongValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ILongValue extends IValue {
- value?: number | undefined;
-}
-
-export class BoolValue extends Value implements IBoolValue {
- value?: boolean | undefined;
-
- constructor(data?: IBoolValue) {
- super(data);
- this._discriminator = "BoolValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): BoolValue {
- data = typeof data === 'object' ? data : {};
- let result = new BoolValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IBoolValue extends IValue {
- value?: boolean | undefined;
-}
-
-export class StringValue extends Value implements IStringValue {
- value?: string | undefined;
-
- constructor(data?: IStringValue) {
- super(data);
- this._discriminator = "StringValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): StringValue {
- data = typeof data === 'object' ? data : {};
- let result = new StringValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IStringValue extends IValue {
- value?: string | undefined;
-}
-
-export class DatasetUriValue extends Value implements IDatasetUriValue {
- value?: string | undefined;
-
- constructor(data?: IDatasetUriValue) {
- super(data);
- this._discriminator = "DatasetUriValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): DatasetUriValue {
- data = typeof data === 'object' ? data : {};
- let result = new DatasetUriValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDatasetUriValue extends IValue {
- value?: string | undefined;
-}
-
-export class CsvUriValue extends Value implements ICsvUriValue {
- value?: string | undefined;
-
- constructor(data?: ICsvUriValue) {
- super(data);
- this._discriminator = "CsvUriValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): CsvUriValue {
- data = typeof data === 'object' ? data : {};
- let result = new CsvUriValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ICsvUriValue extends IValue {
- value?: string | undefined;
-}
-
-export class PickleUriValue extends Value implements IPickleUriValue {
- value?: string | undefined;
-
- constructor(data?: IPickleUriValue) {
- super(data);
- this._discriminator = "PickleUriValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): PickleUriValue {
- data = typeof data === 'object' ? data : {};
- let result = new PickleUriValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPickleUriValue extends IValue {
- value?: string | undefined;
-}
-
-export class PickleBlobValue extends Value implements IPickleBlobValue {
- value?: string | undefined;
-
- constructor(data?: IPickleBlobValue) {
- super(data);
- this._discriminator = "PickleBlobValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): PickleBlobValue {
- data = typeof data === 'object' ? data : {};
- let result = new PickleBlobValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPickleBlobValue extends IValue {
- value?: string | undefined;
-}
-
-export class PlasmaIdValue extends Value implements IPlasmaIdValue {
- value?: string | undefined;
-
- constructor(data?: IPlasmaIdValue) {
- super(data);
- this._discriminator = "PlasmaIdValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): PlasmaIdValue {
- data = typeof data === 'object' ? data : {};
- let result = new PlasmaIdValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPlasmaIdValue extends IValue {
- value?: string | undefined;
-}
-
-export class BytesValue extends Value implements IBytesValue {
- value?: string | undefined;
-
- constructor(data?: IBytesValue) {
- super(data);
- this._discriminator = "BytesValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): BytesValue {
- data = typeof data === 'object' ? data : {};
- let result = new BytesValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IBytesValue extends IValue {
- value?: string | undefined;
-}
-
-export class ContainerArgument extends PrimitiveStepArgument implements IContainerArgument {
- data?: string | undefined;
-
- constructor(data?: IContainerArgument) {
- super(data);
- this._discriminator = "ContainerArgument";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.data = data["Data"];
- }
- }
-
- static fromJS(data: any): ContainerArgument {
- data = typeof data === 'object' ? data : {};
- let result = new ContainerArgument();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Data"] = this.data;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IContainerArgument extends IPrimitiveStepArgument {
- data?: string | undefined;
-}
-
-export class Score implements IScore {
- metricType?: MetricType | undefined;
- value?: number | undefined;
-
- constructor(data?: IScore) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.metricType = data["MetricType"];
- this.value = data["Value"];
- }
- }
-
- static fromJS(data: any): Score {
- data = typeof data === 'object' ? data : {};
- let result = new Score();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["MetricType"] = this.metricType;
- data["Value"] = this.value;
- return data;
- }
-}
-
-export interface IScore {
- metricType?: MetricType | undefined;
- value?: number | undefined;
-}
-
-export class ExampleResult extends Result implements IExampleResult {
- resultValues?: { [key: string]: string; } | undefined;
- message?: string | undefined;
-
- constructor(data?: IExampleResult) {
- super(data);
- this._discriminator = "ExampleResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["ResultValues"]) {
- this.resultValues = {};
- for (let key in data["ResultValues"]) {
- if (data["ResultValues"].hasOwnProperty(key))
- this.resultValues[key] = data["ResultValues"][key];
- }
- }
- this.message = data["Message"];
- }
- }
-
- static fromJS(data: any): ExampleResult {
- data = typeof data === 'object' ? data : {};
- let result = new ExampleResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.resultValues) {
- data["ResultValues"] = {};
- for (let key in this.resultValues) {
- if (this.resultValues.hasOwnProperty(key))
- data["ResultValues"][key] = this.resultValues[key];
- }
- }
- data["Message"] = this.message;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IExampleResult extends IResult {
- resultValues?: { [key: string]: string; } | undefined;
- message?: string | undefined;
-}
-
-export class NewModelOperationResult extends ModelOperationResult implements INewModelOperationResult {
-
- constructor(data?: INewModelOperationResult) {
- super(data);
- this._discriminator = "NewModelOperationResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): NewModelOperationResult {
- data = typeof data === 'object' ? data : {};
- let result = new NewModelOperationResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface INewModelOperationResult extends IModelOperationResult {
-}
-
-export class AddComparisonResult extends ModelOperationResult implements IAddComparisonResult {
- comparisonId?: ComparisonId | undefined;
-
- constructor(data?: IAddComparisonResult) {
- super(data);
- this._discriminator = "AddComparisonResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.comparisonId = data["ComparisonId"] ? ComparisonId.fromJS(data["ComparisonId"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): AddComparisonResult {
- data = typeof data === 'object' ? data : {};
- let result = new AddComparisonResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["ComparisonId"] = this.comparisonId ? this.comparisonId.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAddComparisonResult extends IModelOperationResult {
- comparisonId?: ComparisonId | undefined;
-}
-
-export class GetModelStateResult extends ModelOperationResult implements IGetModelStateResult {
- decisions?: Decision[] | undefined;
- startingWealth?: number | undefined;
- currentWealth?: number | undefined;
-
- constructor(data?: IGetModelStateResult) {
- super(data);
- this._discriminator = "GetModelStateResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Decisions"] && data["Decisions"].constructor === Array) {
- this.decisions = [];
- for (let item of data["Decisions"])
- this.decisions.push(Decision.fromJS(item));
- }
- this.startingWealth = data["StartingWealth"];
- this.currentWealth = data["CurrentWealth"];
- }
- }
-
- static fromJS(data: any): GetModelStateResult {
- data = typeof data === 'object' ? data : {};
- let result = new GetModelStateResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.decisions && this.decisions.constructor === Array) {
- data["Decisions"] = [];
- for (let item of this.decisions)
- data["Decisions"].push(item.toJSON());
- }
- data["StartingWealth"] = this.startingWealth;
- data["CurrentWealth"] = this.currentWealth;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IGetModelStateResult extends IModelOperationResult {
- decisions?: Decision[] | undefined;
- startingWealth?: number | undefined;
- currentWealth?: number | undefined;
-}
-
-export class AggregateKey implements IAggregateKey {
- aggregateParameterIndex?: number | undefined;
- brushIndex?: number | undefined;
-
- constructor(data?: IAggregateKey) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.aggregateParameterIndex = data["AggregateParameterIndex"];
- this.brushIndex = data["BrushIndex"];
- }
- }
-
- static fromJS(data: any): AggregateKey {
- data = typeof data === 'object' ? data : {};
- let result = new AggregateKey();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["AggregateParameterIndex"] = this.aggregateParameterIndex;
- data["BrushIndex"] = this.brushIndex;
- return data;
- }
-}
-
-export interface IAggregateKey {
- aggregateParameterIndex?: number | undefined;
- brushIndex?: number | undefined;
-}
-
-export abstract class IResult implements IIResult {
-
- constructor(data?: IIResult) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): IResult {
- data = typeof data === 'object' ? data : {};
- throw new Error("The abstract class 'IResult' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- return data;
- }
-}
-
-export interface IIResult {
-}
-
-export class DataArgument extends PrimitiveStepArgument implements IDataArgument {
- data?: string | undefined;
-
- constructor(data?: IDataArgument) {
- super(data);
- this._discriminator = "DataArgument";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.data = data["Data"];
- }
- }
-
- static fromJS(data: any): DataArgument {
- data = typeof data === 'object' ? data : {};
- let result = new DataArgument();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Data"] = this.data;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IDataArgument extends IPrimitiveStepArgument {
- data?: string | undefined;
-}
-
-export class ListValue extends Value implements IListValue {
- items?: Value[] | undefined;
-
- constructor(data?: IListValue) {
- super(data);
- this._discriminator = "ListValue";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Items"] && data["Items"].constructor === Array) {
- this.items = [];
- for (let item of data["Items"])
- this.items.push(Value.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): ListValue {
- data = typeof data === 'object' ? data : {};
- let result = new ListValue();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.items && this.items.constructor === Array) {
- data["Items"] = [];
- for (let item of this.items)
- data["Items"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IListValue extends IValue {
- items?: Value[] | undefined;
-}
-
-export class Metrics implements IMetrics {
- averageAccuracy?: number | undefined;
- averageRSquared?: number | undefined;
- f1Macro?: number | undefined;
-
- constructor(data?: IMetrics) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.averageAccuracy = data["AverageAccuracy"];
- this.averageRSquared = data["AverageRSquared"];
- this.f1Macro = data["F1Macro"];
- }
- }
-
- static fromJS(data: any): Metrics {
- data = typeof data === 'object' ? data : {};
- let result = new Metrics();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["AverageAccuracy"] = this.averageAccuracy;
- data["AverageRSquared"] = this.averageRSquared;
- data["F1Macro"] = this.f1Macro;
- return data;
- }
-}
-
-export interface IMetrics {
- averageAccuracy?: number | undefined;
- averageRSquared?: number | undefined;
- f1Macro?: number | undefined;
-}
-
-export class FeatureImportanceOperationParameters extends DistOperationParameters implements IFeatureImportanceOperationParameters {
- solutionId?: string | undefined;
-
- constructor(data?: IFeatureImportanceOperationParameters) {
- super(data);
- this._discriminator = "FeatureImportanceOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.solutionId = data["SolutionId"];
- }
- }
-
- static fromJS(data: any): FeatureImportanceOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new FeatureImportanceOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SolutionId"] = this.solutionId;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IFeatureImportanceOperationParameters extends IDistOperationParameters {
- solutionId?: string | undefined;
-}
-
-export class FeatureImportanceResult extends Result implements IFeatureImportanceResult {
- featureImportances?: { [key: string]: TupleOfDoubleAndDouble; } | undefined;
-
- constructor(data?: IFeatureImportanceResult) {
- super(data);
- this._discriminator = "FeatureImportanceResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["FeatureImportances"]) {
- this.featureImportances = {};
- for (let key in data["FeatureImportances"]) {
- if (data["FeatureImportances"].hasOwnProperty(key))
- this.featureImportances[key] = data["FeatureImportances"][key] ? TupleOfDoubleAndDouble.fromJS(data["FeatureImportances"][key]) : new TupleOfDoubleAndDouble();
- }
- }
- }
- }
-
- static fromJS(data: any): FeatureImportanceResult {
- data = typeof data === 'object' ? data : {};
- let result = new FeatureImportanceResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.featureImportances) {
- data["FeatureImportances"] = {};
- for (let key in this.featureImportances) {
- if (this.featureImportances.hasOwnProperty(key))
- data["FeatureImportances"][key] = this.featureImportances[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IFeatureImportanceResult extends IResult {
- featureImportances?: { [key: string]: TupleOfDoubleAndDouble; } | undefined;
-}
-
-export class TupleOfDoubleAndDouble implements ITupleOfDoubleAndDouble {
- item1?: number | undefined;
- item2?: number | undefined;
-
- constructor(data?: ITupleOfDoubleAndDouble) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.item1 = data["Item1"];
- this.item2 = data["Item2"];
- }
- }
-
- static fromJS(data: any): TupleOfDoubleAndDouble {
- data = typeof data === 'object' ? data : {};
- let result = new TupleOfDoubleAndDouble();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Item1"] = this.item1;
- data["Item2"] = this.item2;
- return data;
- }
-}
-
-export interface ITupleOfDoubleAndDouble {
- item1?: number | undefined;
- item2?: number | undefined;
-}
-
-export class PrimitiveStepDescription extends StepDescription implements IPrimitiveStepDescription {
- hyperparams?: { [key: string]: Value; } | undefined;
-
- constructor(data?: IPrimitiveStepDescription) {
- super(data);
- this._discriminator = "PrimitiveStepDescription";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Hyperparams"]) {
- this.hyperparams = {};
- for (let key in data["Hyperparams"]) {
- if (data["Hyperparams"].hasOwnProperty(key))
- this.hyperparams[key] = data["Hyperparams"][key] ? Value.fromJS(data["Hyperparams"][key]) : <any>undefined;
- }
- }
- }
- }
-
- static fromJS(data: any): PrimitiveStepDescription {
- data = typeof data === 'object' ? data : {};
- let result = new PrimitiveStepDescription();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.hyperparams) {
- data["Hyperparams"] = {};
- for (let key in this.hyperparams) {
- if (this.hyperparams.hasOwnProperty(key))
- data["Hyperparams"][key] = this.hyperparams[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IPrimitiveStepDescription extends IStepDescription {
- hyperparams?: { [key: string]: Value; } | undefined;
-}
-
-export enum ValueType {
- VALUE_TYPE_UNDEFINED = 0,
- RAW = 1,
- DATASET_URI = 2,
- CSV_URI = 3,
- PICKLE_URI = 4,
- PICKLE_BLOB = 5,
- PLASMA_ID = 6,
-}
-
-export class DatamartSearchParameters implements IDatamartSearchParameters {
- adapterName?: string | undefined;
- queryJson?: string | undefined;
-
- constructor(data?: IDatamartSearchParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.adapterName = data["AdapterName"];
- this.queryJson = data["QueryJson"];
- }
- }
-
- static fromJS(data: any): DatamartSearchParameters {
- data = typeof data === 'object' ? data : {};
- let result = new DatamartSearchParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["AdapterName"] = this.adapterName;
- data["QueryJson"] = this.queryJson;
- return data;
- }
-}
-
-export interface IDatamartSearchParameters {
- adapterName?: string | undefined;
- queryJson?: string | undefined;
-}
-
-export class DatamartAugmentParameters implements IDatamartAugmentParameters {
- adapterName?: string | undefined;
- augmentationJson?: string | undefined;
- numberOfSamples?: number | undefined;
- augmentedAdapterName?: string | undefined;
-
- constructor(data?: IDatamartAugmentParameters) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.adapterName = data["AdapterName"];
- this.augmentationJson = data["AugmentationJson"];
- this.numberOfSamples = data["NumberOfSamples"];
- this.augmentedAdapterName = data["AugmentedAdapterName"];
- }
- }
-
- static fromJS(data: any): DatamartAugmentParameters {
- data = typeof data === 'object' ? data : {};
- let result = new DatamartAugmentParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["AdapterName"] = this.adapterName;
- data["AugmentationJson"] = this.augmentationJson;
- data["NumberOfSamples"] = this.numberOfSamples;
- data["AugmentedAdapterName"] = this.augmentedAdapterName;
- return data;
- }
-}
-
-export interface IDatamartAugmentParameters {
- adapterName?: string | undefined;
- augmentationJson?: string | undefined;
- numberOfSamples?: number | undefined;
- augmentedAdapterName?: string | undefined;
-}
-
-export class RawDataResult extends DistResult implements IRawDataResult {
- samples?: { [key: string]: any[]; } | undefined;
- weightedWords?: { [key: string]: Word[]; } | undefined;
-
- constructor(data?: IRawDataResult) {
- super(data);
- this._discriminator = "RawDataResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Samples"]) {
- this.samples = {};
- for (let key in data["Samples"]) {
- if (data["Samples"].hasOwnProperty(key))
- this.samples[key] = data["Samples"][key] !== undefined ? data["Samples"][key] : [];
- }
- }
- if (data["WeightedWords"]) {
- this.weightedWords = {};
- for (let key in data["WeightedWords"]) {
- if (data["WeightedWords"].hasOwnProperty(key))
- this.weightedWords[key] = data["WeightedWords"][key] ? data["WeightedWords"][key].map((i: any) => Word.fromJS(i)) : [];
- }
- }
- }
- }
-
- static fromJS(data: any): RawDataResult {
- data = typeof data === 'object' ? data : {};
- let result = new RawDataResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.samples) {
- data["Samples"] = {};
- for (let key in this.samples) {
- if (this.samples.hasOwnProperty(key))
- data["Samples"][key] = this.samples[key];
- }
- }
- if (this.weightedWords) {
- data["WeightedWords"] = {};
- for (let key in this.weightedWords) {
- if (this.weightedWords.hasOwnProperty(key))
- data["WeightedWords"][key] = this.weightedWords[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRawDataResult extends IDistResult {
- samples?: { [key: string]: any[]; } | undefined;
- weightedWords?: { [key: string]: Word[]; } | undefined;
-}
-
-export class Word implements IWord {
- text?: string | undefined;
- occurrences?: number | undefined;
- stem?: string | undefined;
- isWordGroup?: boolean | undefined;
-
- constructor(data?: IWord) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.text = data["Text"];
- this.occurrences = data["Occurrences"];
- this.stem = data["Stem"];
- this.isWordGroup = data["IsWordGroup"];
- }
- }
-
- static fromJS(data: any): Word {
- data = typeof data === 'object' ? data : {};
- let result = new Word();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Text"] = this.text;
- data["Occurrences"] = this.occurrences;
- data["Stem"] = this.stem;
- data["IsWordGroup"] = this.isWordGroup;
- return data;
- }
-}
-
-export interface IWord {
- text?: string | undefined;
- occurrences?: number | undefined;
- stem?: string | undefined;
- isWordGroup?: boolean | undefined;
-}
-
-export class SampleOperationParameters extends DistOperationParameters implements ISampleOperationParameters {
- numSamples?: number | undefined;
- attributeParameters?: AttributeParameters[] | undefined;
- brushes?: string[] | undefined;
-
- constructor(data?: ISampleOperationParameters) {
- super(data);
- this._discriminator = "SampleOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.numSamples = data["NumSamples"];
- if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
- this.attributeParameters = [];
- for (let item of data["AttributeParameters"])
- this.attributeParameters.push(AttributeParameters.fromJS(item));
- }
- if (data["Brushes"] && data["Brushes"].constructor === Array) {
- this.brushes = [];
- for (let item of data["Brushes"])
- this.brushes.push(item);
- }
- }
- }
-
- static fromJS(data: any): SampleOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new SampleOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["NumSamples"] = this.numSamples;
- if (this.attributeParameters && this.attributeParameters.constructor === Array) {
- data["AttributeParameters"] = [];
- for (let item of this.attributeParameters)
- data["AttributeParameters"].push(item.toJSON());
- }
- if (this.brushes && this.brushes.constructor === Array) {
- data["Brushes"] = [];
- for (let item of this.brushes)
- data["Brushes"].push(item);
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISampleOperationParameters extends IDistOperationParameters {
- numSamples?: number | undefined;
- attributeParameters?: AttributeParameters[] | undefined;
- brushes?: string[] | undefined;
-}
-
-export class SampleResult extends DistResult implements ISampleResult {
- samples?: { [key: string]: { [key: string]: number; }; } | undefined;
- isTruncated?: boolean | undefined;
-
- constructor(data?: ISampleResult) {
- super(data);
- this._discriminator = "SampleResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Samples"]) {
- this.samples = {};
- for (let key in data["Samples"]) {
- if (data["Samples"].hasOwnProperty(key))
- this.samples[key] = data["Samples"][key] !== undefined ? data["Samples"][key] : {};
- }
- }
- this.isTruncated = data["IsTruncated"];
- }
- }
-
- static fromJS(data: any): SampleResult {
- data = typeof data === 'object' ? data : {};
- let result = new SampleResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.samples) {
- data["Samples"] = {};
- for (let key in this.samples) {
- if (this.samples.hasOwnProperty(key))
- data["Samples"][key] = this.samples[key];
- }
- }
- data["IsTruncated"] = this.isTruncated;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ISampleResult extends IDistResult {
- samples?: { [key: string]: { [key: string]: number; }; } | undefined;
- isTruncated?: boolean | undefined;
-}
-
-export class ResultParameters extends UniqueJson implements IResultParameters {
- operationReference?: IOperationReference | undefined;
- stopOperation?: boolean | undefined;
-
- protected _discriminator: string;
-
- constructor(data?: IResultParameters) {
- super(data);
- this._discriminator = "ResultParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.operationReference = data["OperationReference"] ? IOperationReference.fromJS(data["OperationReference"]) : <any>undefined;
- this.stopOperation = data["StopOperation"];
- }
- }
-
- static fromJS(data: any): ResultParameters {
- data = typeof data === 'object' ? data : {};
- if (data["discriminator"] === "RecommenderResultParameters") {
- let result = new RecommenderResultParameters();
- result.init(data);
- return result;
- }
- let result = new ResultParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["discriminator"] = this._discriminator;
- data["OperationReference"] = this.operationReference ? this.operationReference.toJSON() : <any>undefined;
- data["StopOperation"] = this.stopOperation;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IResultParameters extends IUniqueJson {
- operationReference?: IOperationReference | undefined;
- stopOperation?: boolean | undefined;
-}
-
-export class RecommenderResultParameters extends ResultParameters implements IRecommenderResultParameters {
- from?: number | undefined;
- to?: number | undefined;
- pValueSorting?: Sorting | undefined;
- effectSizeFilter?: EffectSize | undefined;
-
- constructor(data?: IRecommenderResultParameters) {
- super(data);
- this._discriminator = "RecommenderResultParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.from = data["From"];
- this.to = data["To"];
- this.pValueSorting = data["PValueSorting"];
- this.effectSizeFilter = data["EffectSizeFilter"];
- }
- }
-
- static fromJS(data: any): RecommenderResultParameters {
- data = typeof data === 'object' ? data : {};
- let result = new RecommenderResultParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["From"] = this.from;
- data["To"] = this.to;
- data["PValueSorting"] = this.pValueSorting;
- data["EffectSizeFilter"] = this.effectSizeFilter;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRecommenderResultParameters extends IResultParameters {
- from?: number | undefined;
- to?: number | undefined;
- pValueSorting?: Sorting | undefined;
- effectSizeFilter?: EffectSize | undefined;
-}
-
-export enum Sorting {
- Ascending = "Ascending",
- Descending = "Descending",
-}
-
-export class AddComparisonParameters extends ModelOperationParameters implements IAddComparisonParameters {
- modelId?: ModelId | undefined;
- comparisonOrder?: number | undefined;
- childOperationParameters?: OperationParameters[] | undefined;
- isCachable?: boolean | undefined;
-
- constructor(data?: IAddComparisonParameters) {
- super(data);
- this._discriminator = "AddComparisonParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
- this.comparisonOrder = data["ComparisonOrder"];
- if (data["ChildOperationParameters"] && data["ChildOperationParameters"].constructor === Array) {
- this.childOperationParameters = [];
- for (let item of data["ChildOperationParameters"])
- this.childOperationParameters.push(OperationParameters.fromJS(item));
- }
- this.isCachable = data["IsCachable"];
- }
- }
-
- static fromJS(data: any): AddComparisonParameters {
- data = typeof data === 'object' ? data : {};
- let result = new AddComparisonParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
- data["ComparisonOrder"] = this.comparisonOrder;
- if (this.childOperationParameters && this.childOperationParameters.constructor === Array) {
- data["ChildOperationParameters"] = [];
- for (let item of this.childOperationParameters)
- data["ChildOperationParameters"].push(item.toJSON());
- }
- data["IsCachable"] = this.isCachable;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IAddComparisonParameters extends IModelOperationParameters {
- modelId?: ModelId | undefined;
- comparisonOrder?: number | undefined;
- childOperationParameters?: OperationParameters[] | undefined;
- isCachable?: boolean | undefined;
-}
-
-export class CDFResult extends DistResult implements ICDFResult {
- cDF?: { [key: string]: number; } | undefined;
-
- constructor(data?: ICDFResult) {
- super(data);
- this._discriminator = "CDFResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["CDF"]) {
- this.cDF = {};
- for (let key in data["CDF"]) {
- if (data["CDF"].hasOwnProperty(key))
- this.cDF[key] = data["CDF"][key];
- }
- }
- }
- }
-
- static fromJS(data: any): CDFResult {
- data = typeof data === 'object' ? data : {};
- let result = new CDFResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.cDF) {
- data["CDF"] = {};
- for (let key in this.cDF) {
- if (this.cDF.hasOwnProperty(key))
- data["CDF"][key] = this.cDF[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ICDFResult extends IDistResult {
- cDF?: { [key: string]: number; } | undefined;
-}
-
-export class ChiSquaredTestResult extends HypothesisTestResult implements IChiSquaredTestResult {
- hs_aligned?: TupleOfDoubleAndDouble[] | undefined;
-
- constructor(data?: IChiSquaredTestResult) {
- super(data);
- this._discriminator = "ChiSquaredTestResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["hs_aligned"] && data["hs_aligned"].constructor === Array) {
- this.hs_aligned = [];
- for (let item of data["hs_aligned"])
- this.hs_aligned.push(TupleOfDoubleAndDouble.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): ChiSquaredTestResult {
- data = typeof data === 'object' ? data : {};
- let result = new ChiSquaredTestResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.hs_aligned && this.hs_aligned.constructor === Array) {
- data["hs_aligned"] = [];
- for (let item of this.hs_aligned)
- data["hs_aligned"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IChiSquaredTestResult extends IHypothesisTestResult {
- hs_aligned?: TupleOfDoubleAndDouble[] | undefined;
-}
-
-export class CorrelationTestResult extends HypothesisTestResult implements ICorrelationTestResult {
- degreeOfFreedom?: number | undefined;
- sampleCorrelationCoefficient?: number | undefined;
- distResult?: EmpiricalDistResult | undefined;
-
- constructor(data?: ICorrelationTestResult) {
- super(data);
- this._discriminator = "CorrelationTestResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.degreeOfFreedom = data["DegreeOfFreedom"];
- this.sampleCorrelationCoefficient = data["SampleCorrelationCoefficient"];
- this.distResult = data["DistResult"] ? EmpiricalDistResult.fromJS(data["DistResult"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): CorrelationTestResult {
- data = typeof data === 'object' ? data : {};
- let result = new CorrelationTestResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["DegreeOfFreedom"] = this.degreeOfFreedom;
- data["SampleCorrelationCoefficient"] = this.sampleCorrelationCoefficient;
- data["DistResult"] = this.distResult ? this.distResult.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ICorrelationTestResult extends IHypothesisTestResult {
- degreeOfFreedom?: number | undefined;
- sampleCorrelationCoefficient?: number | undefined;
- distResult?: EmpiricalDistResult | undefined;
-}
-
-export class EmpiricalDistResult extends DistResult implements IEmpiricalDistResult {
- marginals?: AttributeParameters[] | undefined;
- marginalDistParameters?: { [key: string]: DistParameter; } | undefined;
- jointDistParameter?: JointDistParameter | undefined;
-
- constructor(data?: IEmpiricalDistResult) {
- super(data);
- this._discriminator = "EmpiricalDistResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["Marginals"] && data["Marginals"].constructor === Array) {
- this.marginals = [];
- for (let item of data["Marginals"])
- this.marginals.push(AttributeParameters.fromJS(item));
- }
- if (data["MarginalDistParameters"]) {
- this.marginalDistParameters = {};
- for (let key in data["MarginalDistParameters"]) {
- if (data["MarginalDistParameters"].hasOwnProperty(key))
- this.marginalDistParameters[key] = data["MarginalDistParameters"][key] ? DistParameter.fromJS(data["MarginalDistParameters"][key]) : new DistParameter();
- }
- }
- this.jointDistParameter = data["JointDistParameter"] ? JointDistParameter.fromJS(data["JointDistParameter"]) : <any>undefined;
- }
- }
-
- static fromJS(data: any): EmpiricalDistResult {
- data = typeof data === 'object' ? data : {};
- let result = new EmpiricalDistResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.marginals && this.marginals.constructor === Array) {
- data["Marginals"] = [];
- for (let item of this.marginals)
- data["Marginals"].push(item.toJSON());
- }
- if (this.marginalDistParameters) {
- data["MarginalDistParameters"] = {};
- for (let key in this.marginalDistParameters) {
- if (this.marginalDistParameters.hasOwnProperty(key))
- data["MarginalDistParameters"][key] = this.marginalDistParameters[key];
- }
- }
- data["JointDistParameter"] = this.jointDistParameter ? this.jointDistParameter.toJSON() : <any>undefined;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IEmpiricalDistResult extends IDistResult {
- marginals?: AttributeParameters[] | undefined;
- marginalDistParameters?: { [key: string]: DistParameter; } | undefined;
- jointDistParameter?: JointDistParameter | undefined;
-}
-
-export class DistParameter implements IDistParameter {
- mean?: number | undefined;
- moment2?: number | undefined;
- variance?: number | undefined;
- varianceEstimate?: number | undefined;
- min?: number | undefined;
- max?: number | undefined;
-
- constructor(data?: IDistParameter) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.mean = data["Mean"];
- this.moment2 = data["Moment2"];
- this.variance = data["Variance"];
- this.varianceEstimate = data["VarianceEstimate"];
- this.min = data["Min"];
- this.max = data["Max"];
- }
- }
-
- static fromJS(data: any): DistParameter {
- data = typeof data === 'object' ? data : {};
- let result = new DistParameter();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Mean"] = this.mean;
- data["Moment2"] = this.moment2;
- data["Variance"] = this.variance;
- data["VarianceEstimate"] = this.varianceEstimate;
- data["Min"] = this.min;
- data["Max"] = this.max;
- return data;
- }
-}
-
-export interface IDistParameter {
- mean?: number | undefined;
- moment2?: number | undefined;
- variance?: number | undefined;
- varianceEstimate?: number | undefined;
- min?: number | undefined;
- max?: number | undefined;
-}
-
-export class JointDistParameter implements IJointDistParameter {
- jointDist?: DistParameter | undefined;
- covariance?: number | undefined;
-
- constructor(data?: IJointDistParameter) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.jointDist = data["JointDist"] ? DistParameter.fromJS(data["JointDist"]) : <any>undefined;
- this.covariance = data["Covariance"];
- }
- }
-
- static fromJS(data: any): JointDistParameter {
- data = typeof data === 'object' ? data : {};
- let result = new JointDistParameter();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["JointDist"] = this.jointDist ? this.jointDist.toJSON() : <any>undefined;
- data["Covariance"] = this.covariance;
- return data;
- }
-}
-
-export interface IJointDistParameter {
- jointDist?: DistParameter | undefined;
- covariance?: number | undefined;
-}
-
-export enum DistributionType {
- Continuous = 0,
- Discrete = 1,
-}
-
-export abstract class DistributionTypeExtension implements IDistributionTypeExtension {
-
- constructor(data?: IDistributionTypeExtension) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): DistributionTypeExtension {
- data = typeof data === 'object' ? data : {};
- throw new Error("The abstract class 'DistributionTypeExtension' cannot be instantiated.");
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- return data;
- }
-}
-
-export interface IDistributionTypeExtension {
-}
-
-export class GetModelStateParameters extends ModelOperationParameters implements IGetModelStateParameters {
- modelId?: ModelId | undefined;
- comparisonIds?: ComparisonId[] | undefined;
- riskControlType?: RiskControlType | undefined;
-
- constructor(data?: IGetModelStateParameters) {
- super(data);
- this._discriminator = "GetModelStateParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
- if (data["ComparisonIds"] && data["ComparisonIds"].constructor === Array) {
- this.comparisonIds = [];
- for (let item of data["ComparisonIds"])
- this.comparisonIds.push(ComparisonId.fromJS(item));
- }
- this.riskControlType = data["RiskControlType"];
- }
- }
-
- static fromJS(data: any): GetModelStateParameters {
- data = typeof data === 'object' ? data : {};
- let result = new GetModelStateParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
- if (this.comparisonIds && this.comparisonIds.constructor === Array) {
- data["ComparisonIds"] = [];
- for (let item of this.comparisonIds)
- data["ComparisonIds"].push(item.toJSON());
- }
- data["RiskControlType"] = this.riskControlType;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IGetModelStateParameters extends IModelOperationParameters {
- modelId?: ModelId | undefined;
- comparisonIds?: ComparisonId[] | undefined;
- riskControlType?: RiskControlType | undefined;
-}
-
-export class KSTestResult extends HypothesisTestResult implements IKSTestResult {
-
- constructor(data?: IKSTestResult) {
- super(data);
- this._discriminator = "KSTestResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- }
- }
-
- static fromJS(data: any): KSTestResult {
- data = typeof data === 'object' ? data : {};
- let result = new KSTestResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IKSTestResult extends IHypothesisTestResult {
-}
-
-export class ModelWealthParameters extends UniqueJson implements IModelWealthParameters {
- modelId?: ModelId | undefined;
- riskControlType?: RiskControlType | undefined;
-
- constructor(data?: IModelWealthParameters) {
- super(data);
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : <any>undefined;
- this.riskControlType = data["RiskControlType"];
- }
- }
-
- static fromJS(data: any): ModelWealthParameters {
- data = typeof data === 'object' ? data : {};
- let result = new ModelWealthParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["ModelId"] = this.modelId ? this.modelId.toJSON() : <any>undefined;
- data["RiskControlType"] = this.riskControlType;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IModelWealthParameters extends IUniqueJson {
- modelId?: ModelId | undefined;
- riskControlType?: RiskControlType | undefined;
-}
-
-export class RootMeanSquareTestResult extends HypothesisTestResult implements IRootMeanSquareTestResult {
- simulationCount?: number | undefined;
- extremeSimulationCount?: number | undefined;
-
- constructor(data?: IRootMeanSquareTestResult) {
- super(data);
- this._discriminator = "RootMeanSquareTestResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.simulationCount = data["SimulationCount"];
- this.extremeSimulationCount = data["ExtremeSimulationCount"];
- }
- }
-
- static fromJS(data: any): RootMeanSquareTestResult {
- data = typeof data === 'object' ? data : {};
- let result = new RootMeanSquareTestResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["SimulationCount"] = this.simulationCount;
- data["ExtremeSimulationCount"] = this.extremeSimulationCount;
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IRootMeanSquareTestResult extends IHypothesisTestResult {
- simulationCount?: number | undefined;
- extremeSimulationCount?: number | undefined;
-}
-
-export class TTestResult extends HypothesisTestResult implements ITTestResult {
- degreeOfFreedom?: number | undefined;
- distResults?: EmpiricalDistResult[] | undefined;
-
- constructor(data?: ITTestResult) {
- super(data);
- this._discriminator = "TTestResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.degreeOfFreedom = data["DegreeOfFreedom"];
- if (data["DistResults"] && data["DistResults"].constructor === Array) {
- this.distResults = [];
- for (let item of data["DistResults"])
- this.distResults.push(EmpiricalDistResult.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): TTestResult {
- data = typeof data === 'object' ? data : {};
- let result = new TTestResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["DegreeOfFreedom"] = this.degreeOfFreedom;
- if (this.distResults && this.distResults.constructor === Array) {
- data["DistResults"] = [];
- for (let item of this.distResults)
- data["DistResults"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface ITTestResult extends IHypothesisTestResult {
- degreeOfFreedom?: number | undefined;
- distResults?: EmpiricalDistResult[] | undefined;
-}
-
-export enum Sorting2 {
- Ascending = 0,
- Descending = 1,
-}
-
-export class BinLabel implements IBinLabel {
- value?: number | undefined;
- minValue?: number | undefined;
- maxValue?: number | undefined;
- label?: string | undefined;
-
- constructor(data?: IBinLabel) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.value = data["Value"];
- this.minValue = data["MinValue"];
- this.maxValue = data["MaxValue"];
- this.label = data["Label"];
- }
- }
-
- static fromJS(data: any): BinLabel {
- data = typeof data === 'object' ? data : {};
- let result = new BinLabel();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- data["MinValue"] = this.minValue;
- data["MaxValue"] = this.maxValue;
- data["Label"] = this.label;
- return data;
- }
-}
-
-export interface IBinLabel {
- value?: number | undefined;
- minValue?: number | undefined;
- maxValue?: number | undefined;
- label?: string | undefined;
-}
-
-export class PreProcessedString implements IPreProcessedString {
- value?: string | undefined;
- id?: number | undefined;
- stringLookup?: { [key: string]: number; } | undefined;
- indexLookup?: { [key: string]: string; } | undefined;
-
- constructor(data?: IPreProcessedString) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.value = data["Value"];
- this.id = data["Id"];
- if (data["StringLookup"]) {
- this.stringLookup = {};
- for (let key in data["StringLookup"]) {
- if (data["StringLookup"].hasOwnProperty(key))
- this.stringLookup[key] = data["StringLookup"][key];
- }
- }
- if (data["IndexLookup"]) {
- this.indexLookup = {};
- for (let key in data["IndexLookup"]) {
- if (data["IndexLookup"].hasOwnProperty(key))
- this.indexLookup[key] = data["IndexLookup"][key];
- }
- }
- }
- }
-
- static fromJS(data: any): PreProcessedString {
- data = typeof data === 'object' ? data : {};
- let result = new PreProcessedString();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Value"] = this.value;
- data["Id"] = this.id;
- if (this.stringLookup) {
- data["StringLookup"] = {};
- for (let key in this.stringLookup) {
- if (this.stringLookup.hasOwnProperty(key))
- data["StringLookup"][key] = this.stringLookup[key];
- }
- }
- if (this.indexLookup) {
- data["IndexLookup"] = {};
- for (let key in this.indexLookup) {
- if (this.indexLookup.hasOwnProperty(key))
- data["IndexLookup"][key] = this.indexLookup[key];
- }
- }
- return data;
- }
-}
-
-export interface IPreProcessedString {
- value?: string | undefined;
- id?: number | undefined;
- stringLookup?: { [key: string]: number; } | undefined;
- indexLookup?: { [key: string]: string; } | undefined;
-}
-
-export class BitSet implements IBitSet {
- length?: number | undefined;
- size?: number | undefined;
-
- constructor(data?: IBitSet) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- this.length = data["Length"];
- this.size = data["Size"];
- }
- }
-
- static fromJS(data: any): BitSet {
- data = typeof data === 'object' ? data : {};
- let result = new BitSet();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Length"] = this.length;
- data["Size"] = this.size;
- return data;
- }
-}
-
-export interface IBitSet {
- length?: number | undefined;
- size?: number | undefined;
-}
-
-export class DateTimeUtil implements IDateTimeUtil {
-
- constructor(data?: IDateTimeUtil) {
- if (data) {
- for (var property in data) {
- if (data.hasOwnProperty(property))
- (<any>this)[property] = (<any>data)[property];
- }
- }
- }
-
- init(data?: any) {
- if (data) {
- }
- }
-
- static fromJS(data: any): DateTimeUtil {
- data = typeof data === 'object' ? data : {};
- let result = new DateTimeUtil();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- return data;
- }
-}
-
-export interface IDateTimeUtil {
-}
-
-export class FrequentItemsetOperationParameters extends DistOperationParameters implements IFrequentItemsetOperationParameters {
- filter?: string | undefined;
- attributeParameters?: AttributeParameters[] | undefined;
- attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
-
- constructor(data?: IFrequentItemsetOperationParameters) {
- super(data);
- this._discriminator = "FrequentItemsetOperationParameters";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- this.filter = data["Filter"];
- if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) {
- this.attributeParameters = [];
- for (let item of data["AttributeParameters"])
- this.attributeParameters.push(AttributeParameters.fromJS(item));
- }
- if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) {
- this.attributeCodeParameters = [];
- for (let item of data["AttributeCodeParameters"])
- this.attributeCodeParameters.push(AttributeCaclculatedParameters.fromJS(item));
- }
- }
- }
-
- static fromJS(data: any): FrequentItemsetOperationParameters {
- data = typeof data === 'object' ? data : {};
- let result = new FrequentItemsetOperationParameters();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- data["Filter"] = this.filter;
- if (this.attributeParameters && this.attributeParameters.constructor === Array) {
- data["AttributeParameters"] = [];
- for (let item of this.attributeParameters)
- data["AttributeParameters"].push(item.toJSON());
- }
- if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) {
- data["AttributeCodeParameters"] = [];
- for (let item of this.attributeCodeParameters)
- data["AttributeCodeParameters"].push(item.toJSON());
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IFrequentItemsetOperationParameters extends IDistOperationParameters {
- filter?: string | undefined;
- attributeParameters?: AttributeParameters[] | undefined;
- attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined;
-}
-
-export class FrequentItemsetResult extends Result implements IFrequentItemsetResult {
- frequentItems?: { [key: string]: number; } | undefined;
-
- constructor(data?: IFrequentItemsetResult) {
- super(data);
- this._discriminator = "FrequentItemsetResult";
- }
-
- init(data?: any) {
- super.init(data);
- if (data) {
- if (data["FrequentItems"]) {
- this.frequentItems = {};
- for (let key in data["FrequentItems"]) {
- if (data["FrequentItems"].hasOwnProperty(key))
- this.frequentItems[key] = data["FrequentItems"][key];
- }
- }
- }
- }
-
- static fromJS(data: any): FrequentItemsetResult {
- data = typeof data === 'object' ? data : {};
- let result = new FrequentItemsetResult();
- result.init(data);
- return result;
- }
-
- toJSON(data?: any) {
- data = typeof data === 'object' ? data : {};
- if (this.frequentItems) {
- data["FrequentItems"] = {};
- for (let key in this.frequentItems) {
- if (this.frequentItems.hasOwnProperty(key))
- data["FrequentItems"][key] = this.frequentItems[key];
- }
- }
- super.toJSON(data);
- return data;
- }
-}
-
-export interface IFrequentItemsetResult extends IResult {
- frequentItems?: { [key: string]: number; } | undefined;
-}
-
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
deleted file mode 100644
index 013f2244e..000000000
--- a/src/client/northstar/operations/BaseOperation.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-import { FilterModel } from '../core/filter/FilterModel';
-import { ErrorResult, Exception, OperationParameters, OperationReference, Result, ResultParameters } from '../model/idea/idea';
-import { action, computed, observable } from "mobx";
-import { Gateway } from '../manager/Gateway';
-
-export abstract class BaseOperation {
- private _interactionTimeoutId: number = 0;
- private static _currentOperations: Map<number, PollPromise> = new Map<number, PollPromise>();
- //public InteractionTimeout: EventDelegate<InteractionTimeoutEventArgs> = new EventDelegate<InteractionTimeoutEventArgs>();
-
- @observable public Error: string = "";
- @observable public OverridingFilters: FilterModel[] = [];
- //@observable
- @observable public Result?: Result = undefined;
- @observable public ComputationStarted: boolean = false;
- public OperationReference?: OperationReference = undefined;
-
- private static _nextId = 0;
- public RequestSalt: string = "";
- public Id: number;
-
- constructor() {
- this.Id = BaseOperation._nextId++;
- }
-
- @computed
- public get FilterString(): string {
- return "";
- }
-
-
- @action
- public SetResult(result: Result): void {
- this.Result = result;
- }
-
- public async Update(): Promise<void> {
-
- try {
- if (BaseOperation._currentOperations.has(this.Id)) {
- BaseOperation._currentOperations.get(this.Id)!.Cancel();
- if (this.OperationReference) {
- Gateway.Instance.PauseOperation(this.OperationReference.toJSON());
- }
- }
-
- const operationParameters = this.CreateOperationParameters();
- if (this.Result) {
- this.Result.progress = 0;
- } // bcz: used to set Result to undefined, but that causes the display to blink
- this.Error = "";
- const salt = Math.random().toString();
- this.RequestSalt = salt;
-
- if (!operationParameters) {
- this.ComputationStarted = false;
- return;
- }
-
- this.ComputationStarted = true;
- //let start = performance.now();
- const promise = Gateway.Instance.StartOperation(operationParameters.toJSON());
- promise.catch(err => {
- action(() => {
- this.Error = err;
- console.error(err);
- });
- });
- const operationReference = await promise;
-
-
- if (operationReference) {
- this.OperationReference = operationReference;
-
- const resultParameters = new ResultParameters();
- resultParameters.operationReference = operationReference;
-
- const pollPromise = new PollPromise(salt, operationReference);
- BaseOperation._currentOperations.set(this.Id, pollPromise);
-
- pollPromise.Start(async () => {
- const result = await Gateway.Instance.GetResult(resultParameters.toJSON());
- if (result instanceof ErrorResult) {
- throw new Error((result).message);
- }
- if (this.RequestSalt === pollPromise.RequestSalt) {
- if (result && (!this.Result || this.Result.progress !== result.progress)) {
- /*if (operationViewModel.Result !== null && operationViewModel.Result !== undefined) {
- let t1 = performance.now();
- console.log((t1 - start) + " milliseconds.");
- start = performance.now();
- }*/
- this.SetResult(result);
- }
-
- if (!result || result.progress! < 1) {
- return true;
- }
- }
- return false;
- }, 100).catch((err: Error) => action(() => {
- this.Error = err.message;
- console.error(err.message);
- })()
- );
- }
- }
- catch (err) {
- console.error(err as Exception);
- // ErrorDialog.Instance.HandleError(err, operationViewModel);
- }
- }
-
- public CreateOperationParameters(): OperationParameters | undefined { return undefined; }
-
- private interactionTimeout() {
- // clearTimeout(this._interactionTimeoutId);
- // this.InteractionTimeout.Fire(new InteractionTimeoutEventArgs(this.TypedViewModel, InteractionTimeoutType.Timeout));
- }
-}
-
-export class PollPromise {
- public RequestSalt: string;
- public OperationReference: OperationReference;
-
- private _notCanceled: boolean = true;
- private _poll: undefined | (() => Promise<boolean>);
- private _delay: number = 0;
-
- public constructor(requestKey: string, operationReference: OperationReference) {
- this.RequestSalt = requestKey;
- this.OperationReference = operationReference;
- }
-
- public Cancel(): void {
- this._notCanceled = false;
- }
-
- public Start(poll: () => Promise<boolean>, delay: number): Promise<void> {
- this._poll = poll;
- this._delay = delay;
- return this.pollRecursive();
- }
-
- private pollRecursive = (): Promise<void> => {
- return Promise.resolve().then(this._poll).then((flag) => {
- this._notCanceled && flag && new Promise((res) => (setTimeout(res, this._delay)))
- .then(this.pollRecursive);
- });
- }
-}
-
-
-export class InteractionTimeoutEventArgs {
- constructor(public Sender: object, public Type: InteractionTimeoutType) {
- }
-}
-
-export enum InteractionTimeoutType {
- Reset = 0,
- Timeout = 1
-}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
deleted file mode 100644
index 74e23ea48..000000000
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import { action, computed, observable, trace } from "mobx";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel";
-import { FilterModel } from "../core/filter/FilterModel";
-import { FilterOperand } from "../core/filter/FilterOperand";
-import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
-import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
-import { HistogramField } from "../dash-fields/HistogramField";
-import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
-import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, Bin, DataType, DoubleValueAggregateResult, HistogramOperationParameters, HistogramResult, QuantitativeBinRange } from "../model/idea/idea";
-import { ModelHelpers } from "../model/ModelHelpers";
-import { ArrayUtil } from "../utils/ArrayUtil";
-import { BaseOperation } from "./BaseOperation";
-import { Doc } from "../../../new_fields/Doc";
-import { Cast, NumCast } from "../../../new_fields/Types";
-
-export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
- public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
- @observable public FilterOperand: FilterOperand = FilterOperand.AND;
- @observable public Links: Doc[] = [];
- @observable public BrushLinks: { l: Doc, b: Doc }[] = [];
- @observable public BrushColors: number[] = [];
- @observable public BarFilterModels: FilterModel[] = [];
-
- @observable public Normalization: number = -1;
- @observable public X: AttributeTransformationModel;
- @observable public Y: AttributeTransformationModel;
- @observable public V: AttributeTransformationModel;
- @observable public SchemaName: string;
- @observable public QRange: QuantitativeBinRange | undefined;
- public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
-
- constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
- super();
- this.X = x;
- this.Y = y;
- this.V = v;
- this.Normalization = normalized ? normalized : -1;
- this.SchemaName = schemaName;
- }
-
- public static Duplicate(op: HistogramOperation) {
-
- return new HistogramOperation(op.SchemaName, op.X, op.Y, op.V, op.Normalization);
- }
- public Copy(): HistogramOperation {
- return new HistogramOperation(this.SchemaName, this.X, this.Y, this.V, this.Normalization);
- }
-
- Equals(other: Object): boolean {
- throw new Error("Method not implemented.");
- }
-
-
- public get FilterModels() {
- return this.BarFilterModels;
- }
- @action
- public AddFilterModels(filterModels: FilterModel[]): void {
- filterModels.filter(f => f !== null).forEach(fm => this.BarFilterModels.push(fm));
- }
- @action
- public RemoveFilterModels(filterModels: FilterModel[]): void {
- ArrayUtil.RemoveMany(this.BarFilterModels, filterModels);
- }
-
- @computed
- public get FilterString(): string {
- if (this.OverridingFilters.length > 0) {
- return "(" + this.OverridingFilters.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")";
- }
- let filterModels: FilterModel[] = [];
- return FilterModel.GetFilterModelsRecursive(this, new Set<IBaseFilterProvider>(), filterModels, true);
- }
-
- public get BrushString(): string[] {
- let brushes: string[] = [];
- this.BrushLinks.map(brushLink => {
- let brushHistogram = Cast(brushLink.b.data, HistogramField);
- if (brushHistogram) {
- let filterModels: FilterModel[] = [];
- brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.HistoOp, new Set<IBaseFilterProvider>(), filterModels, false));
- }
- });
- return brushes;
- }
-
- _stackedFilters: (FilterModel[])[] = [];
- @action
- public DrillDown(up: boolean) {
- if (!up) {
- if (!this.BarFilterModels.length) {
- return;
- }
- this._stackedFilters.push(this.BarFilterModels.map(f => f));
- this.OverridingFilters.length = 0;
- this.OverridingFilters.push(...this._stackedFilters[this._stackedFilters.length - 1]);
- this.BarFilterModels.map(fm => fm).map(fm => this.RemoveFilterModels([fm]));
- //this.updateHistogram();
- } else {
- this.OverridingFilters.length = 0;
- if (this._stackedFilters.length) {
- this.OverridingFilters.push(...this._stackedFilters.pop()!);
- }
- // else
- // this.updateHistogram();
- }
- }
-
- private getAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
- let allAttributes = new Array<AttributeTransformationModel>(histoX, histoY, histoValue);
- allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
-
- let numericDataTypes = [DataType.Int, DataType.Double, DataType.Float];
- let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(this.Schema!.distinctAttributeParameters, allAttributes);
- let globalAggregateParameters: AggregateParameters[] = [];
- [histoX, histoY]
- .filter(a => a.AggregateFunction === AggregateFunction.None && ArrayUtil.Contains(numericDataTypes, a.AttributeModel.DataType))
- .forEach(a => {
- let avg = new AverageAggregateParameters();
- avg.attributeParameters = ModelHelpers.GetAttributeParameters(a.AttributeModel);
- globalAggregateParameters.push(avg);
- });
- return [perBinAggregateParameters, globalAggregateParameters];
- }
-
- public CreateOperationParameters(): HistogramOperationParameters | undefined {
- if (this.X && this.Y && this.V) {
- let [perBinAggregateParameters, globalAggregateParameters] = this.getAggregateParameters(this.X, this.Y, this.V);
- return new HistogramOperationParameters({
- enableBrushComputation: true,
- adapterName: this.SchemaName,
- filter: this.FilterString,
- brushes: this.BrushString,
- binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined),
- ModelHelpers.GetBinningParameters(this.Y, SETTINGS_Y_BINS)],
- sampleStreamBlockSize: SETTINGS_SAMPLE_SIZE,
- perBinAggregateParameters: perBinAggregateParameters,
- globalAggregateParameters: globalAggregateParameters,
- sortPerBinAggregateParameter: undefined,
- attributeCalculatedParameters: CalculatedAttributeManager
- .AllCalculatedAttributes.map(a => ModelHelpers.GetAttributeParametersFromAttributeModel(a)),
- degreeOfParallism: 1, // Settings.Instance.DegreeOfParallelism,
- isCachable: false
- });
- }
- }
-
- @action
- public async Update(): Promise<void> {
- this.BrushColors = this.BrushLinks.map(e => NumCast(e.l.backgroundColor));
- return super.Update();
- }
-}
-
-
diff --git a/src/client/northstar/utils/ArrayUtil.ts b/src/client/northstar/utils/ArrayUtil.ts
deleted file mode 100644
index 12b8d8e77..000000000
--- a/src/client/northstar/utils/ArrayUtil.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { Exception } from "../model/idea/idea";
-
-export class ArrayUtil {
-
- public static Contains(arr1: any[], arr2: any): boolean {
- if (arr1.length === 0) {
- return false;
- }
- let isComplex = typeof arr1[0] === "object";
- for (const ele of arr1) {
- if (isComplex && "Equals" in ele) {
- if (ele.Equals(arr2)) {
- return true;
- }
- }
- else {
- if (ele === arr2) {
- return true;
- }
- }
- }
- return false;
- }
-
-
- public static RemoveMany(arr: any[], elements: Object[]) {
- elements.forEach(e => ArrayUtil.Remove(arr, e));
- }
-
- public static AddMany(arr: any[], others: Object[]) {
- arr.push(...others);
- }
-
- public static Clear(arr: any[]) {
- arr.splice(0, arr.length);
- }
-
-
- public static Remove(arr: any[], other: Object) {
- const index = ArrayUtil.IndexOfWithEqual(arr, other);
- if (index === -1) {
- return;
- }
- arr.splice(index, 1);
- }
-
-
- public static First<T>(arr: T[], predicate: (x: any) => boolean): T {
- let filtered = arr.filter(predicate);
- if (filtered.length > 0) {
- return filtered[0];
- }
- throw new Exception();
- }
-
- public static FirstOrDefault<T>(arr: T[], predicate: (x: any) => boolean): T | undefined {
- let filtered = arr.filter(predicate);
- if (filtered.length > 0) {
- return filtered[0];
- }
- return undefined;
- }
-
- public static Distinct(arr: any[]): any[] {
- let ret = [];
- for (const ele of arr) {
- if (!ArrayUtil.Contains(ret, ele)) {
- ret.push(ele);
- }
- }
- return ret;
- }
-
- public static IndexOfWithEqual(arr: any[], other: any): number {
- for (let i = 0; i < arr.length; i++) {
- let isComplex = typeof arr[0] === "object";
- if (isComplex && "Equals" in arr[i]) {
- if (arr[i].Equals(other)) {
- return i;
- }
- }
- else {
- if (arr[i] === other) {
- return i;
- }
- }
- }
- return -1;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/Extensions.ts b/src/client/northstar/utils/Extensions.ts
deleted file mode 100644
index df14d4da0..000000000
--- a/src/client/northstar/utils/Extensions.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-interface String {
- ReplaceAll(toReplace: string, replacement: string): string;
- Truncate(length: number, replacement: string): String;
-}
-
-String.prototype.ReplaceAll = function (toReplace: string, replacement: string): string {
- var target = this;
- return target.split(toReplace).join(replacement);
-};
-
-String.prototype.Truncate = function (length: number, replacement: string): String {
- var target = this;
- if (target.length >= length) {
- target = target.slice(0, Math.max(0, length - replacement.length)) + replacement;
- }
- return target;
-};
-
-interface Math {
- log10(val: number): number;
-}
-
-Math.log10 = function (val: number): number {
- return Math.log(val) / Math.LN10;
-};
-
-declare interface ObjectConstructor {
- assign(...objects: Object[]): Object;
-}
diff --git a/src/client/northstar/utils/GeometryUtil.ts b/src/client/northstar/utils/GeometryUtil.ts
deleted file mode 100644
index d5220c479..000000000
--- a/src/client/northstar/utils/GeometryUtil.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import { MathUtil, PIXIRectangle, PIXIPoint } from "./MathUtil";
-
-
-export class GeometryUtil {
-
- public static ComputeBoundingBox(points: { x: number, y: number }[], scale = 1, padding: number = 0): PIXIRectangle {
- let minX: number = Number.MAX_VALUE;
- let minY: number = Number.MAX_VALUE;
- let maxX: number = Number.MIN_VALUE;
- let maxY: number = Number.MIN_VALUE;
- for (const point of points) {
- if (point.x < minX) {
- minX = point.x;
- }
- if (point.y < minY) {
- minY = point.y;
- }
- if (point.x > maxX) {
- maxX = point.x;
- }
- if (point.y > maxY) {
- maxY = point.y;
- }
- }
- return new PIXIRectangle(minX * scale - padding, minY * scale - padding, (maxX - minX) * scale + padding * 2, (maxY - minY) * scale + padding * 2);
- }
-
- public static RectangleOverlap(rect1: PIXIRectangle, rect2: PIXIRectangle) {
- let x_overlap = Math.max(0, Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left));
- let y_overlap = Math.max(0, Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top));
- return x_overlap * y_overlap;
- }
-
- public static RotatePoints(center: { x: number, y: number }, points: { x: number, y: number }[], angle: number): PIXIPoint[] {
- const rotate = (cx: number, cy: number, x: number, y: number, angle: number) => {
- const radians = angle,
- cos = Math.cos(radians),
- sin = Math.sin(radians),
- nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
- ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
- return new PIXIPoint(nx, ny);
- };
- return points.map(p => rotate(center.x, center.y, p.x, p.y, angle));
- }
-
- public static LineByLeastSquares(points: { x: number, y: number }[]): PIXIPoint[] {
- let sum_x: number = 0;
- let sum_y: number = 0;
- let sum_xy: number = 0;
- let sum_xx: number = 0;
- let count: number = 0;
-
- let x: number = 0;
- let y: number = 0;
-
-
- if (points.length === 0) {
- return [];
- }
-
- for (const point of points) {
- x = point.x;
- y = point.y;
- sum_x += x;
- sum_y += y;
- sum_xx += x * x;
- sum_xy += x * y;
- count++;
- }
-
- let m = (count * sum_xy - sum_x * sum_y) / (count * sum_xx - sum_x * sum_x);
- let b = (sum_y / count) - (m * sum_x) / count;
- let result: PIXIPoint[] = new Array<PIXIPoint>();
-
- for (const point of points) {
- x = point.x;
- y = x * m + b;
- result.push(new PIXIPoint(x, y));
- }
- return result;
- }
-
- // public static PointInsidePolygon(vs:Point[], x:number, y:number):boolean {
- // // ray-casting algorithm based on
- // // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
-
- // var inside = false;
- // for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
- // var xi = vs[i].x, yi = vs[i].y;
- // var xj = vs[j].x, yj = vs[j].y;
-
- // var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
- // if (intersect)
- // inside = !inside;
- // }
-
- // return inside;
- // };
-
- public static IntersectLines(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): boolean {
- let a1: number, a2: number, b1: number, b2: number, c1: number, c2: number;
- let r1: number, r2: number, r3: number, r4: number;
- let denom: number, offset: number, num: number;
-
- a1 = y2 - y1;
- b1 = x1 - x2;
- c1 = (x2 * y1) - (x1 * y2);
- r3 = ((a1 * x3) + (b1 * y3) + c1);
- r4 = ((a1 * x4) + (b1 * y4) + c1);
-
- if ((r3 !== 0) && (r4 !== 0) && (MathUtil.Sign(r3) === MathUtil.Sign(r4))) {
- return false;
- }
-
- a2 = y4 - y3;
- b2 = x3 - x4;
- c2 = (x4 * y3) - (x3 * y4);
-
- r1 = (a2 * x1) + (b2 * y1) + c2;
- r2 = (a2 * x2) + (b2 * y2) + c2;
-
- if ((r1 !== 0) && (r2 !== 0) && (MathUtil.Sign(r1) === MathUtil.Sign(r2))) {
- return false;
- }
-
- denom = (a1 * b2) - (a2 * b1);
-
- if (denom === 0) {
- return false;
- }
- return true;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/IDisposable.ts b/src/client/northstar/utils/IDisposable.ts
deleted file mode 100644
index 5e9843326..000000000
--- a/src/client/northstar/utils/IDisposable.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface IDisposable {
- Dispose(): void;
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/IEquatable.ts b/src/client/northstar/utils/IEquatable.ts
deleted file mode 100644
index 2f81c2478..000000000
--- a/src/client/northstar/utils/IEquatable.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface IEquatable {
- Equals(other: Object): boolean;
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/KeyCodes.ts b/src/client/northstar/utils/KeyCodes.ts
deleted file mode 100644
index 044569ffe..000000000
--- a/src/client/northstar/utils/KeyCodes.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Class contains the keycodes for keys on your keyboard.
- *
- * Useful for auto completion:
- *
- * ```
- * switch (event.key)
- * {
- * case KeyCode.UP:
- * {
- * // Up key pressed
- * break;
- * }
- * case KeyCode.DOWN:
- * {
- * // Down key pressed
- * break;
- * }
- * case KeyCode.LEFT:
- * {
- * // Left key pressed
- * break;
- * }
- * case KeyCode.RIGHT:
- * {
- * // Right key pressed
- * break;
- * }
- * default:
- * {
- * // ignore
- * break;
- * }
- * }
- * ```
- */
-export class KeyCodes
-{
- public static TAB:number = 9;
- public static CAPS_LOCK:number = 20;
- public static SHIFT:number = 16;
- public static CONTROL:number = 17;
- public static SPACE:number = 32;
- public static DOWN:number = 40;
- public static UP:number = 38;
- public static LEFT:number = 37;
- public static RIGHT:number = 39;
- public static ESCAPE:number = 27;
- public static F1:number = 112;
- public static F2:number = 113;
- public static F3:number = 114;
- public static F4:number = 115;
- public static F5:number = 116;
- public static F6:number = 117;
- public static F7:number = 118;
- public static F8:number = 119;
- public static F9:number = 120;
- public static F10:number = 121;
- public static F11:number = 122;
- public static F12:number = 123;
- public static INSERT:number = 45;
- public static HOME:number = 36;
- public static PAGE_UP:number = 33;
- public static PAGE_DOWN:number = 34;
- public static DELETE:number = 46;
- public static END:number = 35;
- public static ENTER:number = 13;
- public static BACKSPACE:number = 8;
- public static NUMPAD_0:number = 96;
- public static NUMPAD_1:number = 97;
- public static NUMPAD_2:number = 98;
- public static NUMPAD_3:number = 99;
- public static NUMPAD_4:number = 100;
- public static NUMPAD_5:number = 101;
- public static NUMPAD_6:number = 102;
- public static NUMPAD_7:number = 103;
- public static NUMPAD_8:number = 104;
- public static NUMPAD_9:number = 105;
- public static NUMPAD_DIVIDE:number = 111;
- public static NUMPAD_ADD:number = 107;
- public static NUMPAD_ENTER:number = 13;
- public static NUMPAD_DECIMAL:number = 110;
- public static NUMPAD_SUBTRACT:number = 109;
- public static NUMPAD_MULTIPLY:number = 106;
- public static SEMICOLON:number = 186;
- public static EQUAL:number = 187;
- public static COMMA:number = 188;
- public static MINUS:number = 189;
- public static PERIOD:number = 190;
- public static SLASH:number = 191;
- public static BACKQUOTE:number = 192;
- public static LEFTBRACKET:number = 219;
- public static BACKSLASH:number = 220;
- public static RIGHTBRACKET:number = 221;
- public static QUOTE:number = 222;
- public static ALT:number = 18;
- public static COMMAND:number = 15;
- public static NUMPAD:number = 21;
- public static A:number = 65;
- public static B:number = 66;
- public static C:number = 67;
- public static D:number = 68;
- public static E:number = 69;
- public static F:number = 70;
- public static G:number = 71;
- public static H:number = 72;
- public static I:number = 73;
- public static J:number = 74;
- public static K:number = 75;
- public static L:number = 76;
- public static M:number = 77;
- public static N:number = 78;
- public static O:number = 79;
- public static P:number = 80;
- public static Q:number = 81;
- public static R:number = 82;
- public static S:number = 83;
- public static T:number = 84;
- public static U:number = 85;
- public static V:number = 86;
- public static W:number = 87;
- public static X:number = 88;
- public static Y:number = 89;
- public static Z:number = 90;
- public static NUM_0:number = 48;
- public static NUM_1:number = 49;
- public static NUM_2:number = 50;
- public static NUM_3:number = 51;
- public static NUM_4:number = 52;
- public static NUM_5:number = 53;
- public static NUM_6:number = 54;
- public static NUM_7:number = 55;
- public static NUM_8:number = 56;
- public static NUM_9:number = 57;
- public static SUBSTRACT:number = 189;
- public static ADD:number = 187;
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/LABColor.ts b/src/client/northstar/utils/LABColor.ts
deleted file mode 100644
index 72e46fb7f..000000000
--- a/src/client/northstar/utils/LABColor.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-
-export class LABColor {
- public L: number;
- public A: number;
- public B: number;
-
- // constructor - takes three floats for lightness and color-opponent dimensions
- constructor(l: number, a: number, b: number) {
- this.L = l;
- this.A = a;
- this.B = b;
- }
-
- // static function for linear interpolation between two LABColors
- public static Lerp(a: LABColor, b: LABColor, t: number): LABColor {
- return new LABColor(LABColor.LerpNumber(a.L, b.L, t), LABColor.LerpNumber(a.A, b.A, t), LABColor.LerpNumber(a.B, b.B, t));
- }
-
- public static LerpNumber(a: number, b: number, percent: number): number {
- return a + percent * (b - a);
- }
-
- static hexToRGB(hex: number, alpha: number): number[] {
- var r = (hex & (0xff << 16)) >> 16;
- var g = (hex & (0xff << 8)) >> 8;
- var b = (hex & (0xff << 0)) >> 0;
- return [r, g, b];
- }
- static RGBtoHex(red: number, green: number, blue: number): number {
- return blue | (green << 8) | (red << 16);
- }
-
- public static RGBtoHexString(rgb: number): string {
- let str = "#" + this.hex((rgb & (0xff << 16)) >> 16) + this.hex((rgb & (0xff << 8)) >> 8) + this.hex((rgb & (0xff << 0)) >> 0);
- return str;
- }
-
- static hex(x: number): string {
- var hexDigits = new Array
- ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
- return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
- }
-
- public static FromColor(c: number): LABColor {
- var rgb = LABColor.hexToRGB(c, 0);
- var r = LABColor.d3_rgb_xyz(rgb[0] * 255);
- var g = LABColor.d3_rgb_xyz(rgb[1] * 255);
- var b = LABColor.d3_rgb_xyz(rgb[2] * 255);
-
- var x = LABColor.d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / LABColor.d3_lab_X);
- var y = LABColor.d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / LABColor.d3_lab_Y);
- var z = LABColor.d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / LABColor.d3_lab_Z);
- var lab = new LABColor(116 * y - 16, 500 * (x - y), 200 * (y - z));
- return lab;
- }
-
- private static d3_lab_X: number = 0.950470;
- private static d3_lab_Y: number = 1;
- private static d3_lab_Z: number = 1.088830;
-
- public static d3_lab_xyz(x: number): number {
- return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
- }
-
- public static d3_xyz_rgb(r: number): number {
- return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
- }
-
- public static d3_rgb_xyz(r: number): number {
- return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
- }
-
- public static d3_xyz_lab(x: number): number {
- return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
- }
-
- public static ToColor(lab: LABColor): number {
- var y = (lab.L + 16) / 116;
- var x = y + lab.A / 500;
- var z = y - lab.B / 200;
- x = LABColor.d3_lab_xyz(x) * LABColor.d3_lab_X;
- y = LABColor.d3_lab_xyz(y) * LABColor.d3_lab_Y;
- z = LABColor.d3_lab_xyz(z) * LABColor.d3_lab_Z;
-
- return LABColor.RGBtoHex(
- LABColor.d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z) / 255,
- LABColor.d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z) / 255,
- LABColor.d3_xyz_rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z) / 255);
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts
deleted file mode 100644
index 5def5e704..000000000
--- a/src/client/northstar/utils/MathUtil.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-
-
-export class PIXIPoint {
- public get x() { return this.coords[0]; }
- public get y() { return this.coords[1]; }
- public set x(value: number) { this.coords[0] = value; }
- public set y(value: number) { this.coords[1] = value; }
- public coords: number[] = [0, 0];
- constructor(x: number, y: number) {
- this.coords[0] = x;
- this.coords[1] = y;
- }
-}
-
-export class PIXIRectangle {
- public x: number;
- public y: number;
- public width: number;
- public height: number;
- public get left() { return this.x; }
- public get right() { return this.x + this.width; }
- public get top() { return this.y; }
- public get bottom() { return this.top + this.height; }
- public static get EMPTY() { return new PIXIRectangle(0, 0, -1, -1); }
- constructor(x: number, y: number, width: number, height: number) {
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
- }
-}
-
-export class MathUtil {
-
- public static EPSILON: number = 0.001;
-
- public static Sign(value: number): number {
- return value >= 0 ? 1 : -1;
- }
-
- public static AddPoint(p1: PIXIPoint, p2: PIXIPoint, inline: boolean = false): PIXIPoint {
- if (inline) {
- p1.x += p2.x;
- p1.y += p2.y;
- return p1;
- }
- else {
- return new PIXIPoint(p1.x + p2.x, p1.y + p2.y);
- }
- }
-
- public static Perp(p1: PIXIPoint): PIXIPoint {
- return new PIXIPoint(-p1.y, p1.x);
- }
-
- public static DividePoint(p1: PIXIPoint, by: number, inline: boolean = false): PIXIPoint {
- if (inline) {
- p1.x /= by;
- p1.y /= by;
- return p1;
- }
- else {
- return new PIXIPoint(p1.x / by, p1.y / by);
- }
- }
-
- public static MultiplyConstant(p1: PIXIPoint, by: number, inline: boolean = false) {
- if (inline) {
- p1.x *= by;
- p1.y *= by;
- return p1;
- }
- else {
- return new PIXIPoint(p1.x * by, p1.y * by);
- }
- }
-
- public static SubtractPoint(p1: PIXIPoint, p2: PIXIPoint, inline: boolean = false): PIXIPoint {
- if (inline) {
- p1.x -= p2.x;
- p1.y -= p2.y;
- return p1;
- }
- else {
- return new PIXIPoint(p1.x - p2.x, p1.y - p2.y);
- }
- }
-
- public static Area(rect: PIXIRectangle): number {
- return rect.width * rect.height;
- }
-
- public static DistToLineSegment(v: PIXIPoint, w: PIXIPoint, p: PIXIPoint) {
- // Return minimum distance between line segment vw and point p
- const l2 = MathUtil.DistSquared(v, w); // i.e. |w-v|^2 - avoid a sqrt
- if (l2 === 0.0) return MathUtil.Dist(p, v); // v === w case
- // Consider the line extending the segment, parameterized as v + t (w - v).
- // We find projection of point p onto the line.
- // It falls where t = [(p-v) . (w-v)] / |w-v|^2
- // We clamp t from [0,1] to handle points outside the segment vw.
- const dot = MathUtil.Dot(
- MathUtil.SubtractPoint(p, v),
- MathUtil.SubtractPoint(w, v)) / l2;
- const t = Math.max(0, Math.min(1, dot));
- // Projection falls on the segment
- const projection = MathUtil.AddPoint(v,
- MathUtil.MultiplyConstant(
- MathUtil.SubtractPoint(w, v), t));
- return MathUtil.Dist(p, projection);
- }
-
- public static LineSegmentIntersection(ps1: PIXIPoint, pe1: PIXIPoint, ps2: PIXIPoint, pe2: PIXIPoint): PIXIPoint | undefined {
- const a1 = pe1.y - ps1.y;
- const b1 = ps1.x - pe1.x;
-
- const a2 = pe2.y - ps2.y;
- const b2 = ps2.x - pe2.x;
-
- const delta = a1 * b2 - a2 * b1;
- if (delta === 0) {
- return undefined;
- }
- const c2 = a2 * ps2.x + b2 * ps2.y;
- const c1 = a1 * ps1.x + b1 * ps1.y;
- const invdelta = 1 / delta;
- return new PIXIPoint((b2 * c1 - b1 * c2) * invdelta, (a1 * c2 - a2 * c1) * invdelta);
- }
-
- public static PointInPIXIRectangle(p: PIXIPoint, rect: PIXIRectangle): boolean {
- if (p.x < rect.left - this.EPSILON) {
- return false;
- }
- if (p.x > rect.right + this.EPSILON) {
- return false;
- }
- if (p.y < rect.top - this.EPSILON) {
- return false;
- }
- if (p.y > rect.bottom + this.EPSILON) {
- return false;
- }
-
- return true;
- }
-
- public static LinePIXIRectangleIntersection(lineFrom: PIXIPoint, lineTo: PIXIPoint, rect: PIXIRectangle): Array<PIXIPoint> {
- const r1 = new PIXIPoint(rect.left, rect.top);
- const r2 = new PIXIPoint(rect.right, rect.top);
- const r3 = new PIXIPoint(rect.right, rect.bottom);
- const r4 = new PIXIPoint(rect.left, rect.bottom);
- const ret = new Array<PIXIPoint>();
- const dist = this.Dist(lineFrom, lineTo);
- let inter = this.LineSegmentIntersection(lineFrom, lineTo, r1, r2);
- if (inter && this.PointInPIXIRectangle(inter, rect) &&
- this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
- ret.push(inter);
- }
- inter = this.LineSegmentIntersection(lineFrom, lineTo, r2, r3);
- if (inter && this.PointInPIXIRectangle(inter, rect) &&
- this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
- ret.push(inter);
- }
- inter = this.LineSegmentIntersection(lineFrom, lineTo, r3, r4);
- if (inter && this.PointInPIXIRectangle(inter, rect) &&
- this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
- ret.push(inter);
- }
- inter = this.LineSegmentIntersection(lineFrom, lineTo, r4, r1);
- if (inter && this.PointInPIXIRectangle(inter, rect) &&
- this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) {
- ret.push(inter);
- }
- return ret;
- }
-
- public static Intersection(rect1: PIXIRectangle, rect2: PIXIRectangle): PIXIRectangle {
- const left = Math.max(rect1.x, rect2.x);
- const right = Math.min(rect1.x + rect1.width, rect2.x + rect2.width);
- const top = Math.max(rect1.y, rect2.y);
- const bottom = Math.min(rect1.y + rect1.height, rect2.y + rect2.height);
- return new PIXIRectangle(left, top, right - left, bottom - top);
- }
-
- public static Dist(p1: PIXIPoint, p2: PIXIPoint): number {
- return Math.sqrt(MathUtil.DistSquared(p1, p2));
- }
-
- public static Dot(p1: PIXIPoint, p2: PIXIPoint): number {
- return p1.x * p2.x + p1.y * p2.y;
- }
-
- public static Normalize(p1: PIXIPoint) {
- const d = this.Length(p1);
- return new PIXIPoint(p1.x / d, p1.y / d);
- }
-
- public static Length(p1: PIXIPoint): number {
- return Math.sqrt(p1.x * p1.x + p1.y * p1.y);
- }
-
- public static DistSquared(p1: PIXIPoint, p2: PIXIPoint): number {
- const a = p1.x - p2.x;
- const b = p1.y - p2.y;
- return (a * a + b * b);
- }
-
- public static RectIntersectsRect(r1: PIXIRectangle, r2: PIXIRectangle): boolean {
- return !(r2.x > r1.x + r1.width ||
- r2.x + r2.width < r1.x ||
- r2.y > r1.y + r1.height ||
- r2.y + r2.height < r1.y);
- }
-
- public static ArgMin(temp: number[]): number {
- let index = 0;
- let value = temp[0];
- for (let i = 1; i < temp.length; i++) {
- if (temp[i] < value) {
- value = temp[i];
- index = i;
- }
- }
- return index;
- }
-
- public static ArgMax(temp: number[]): number {
- let index = 0;
- let value = temp[0];
- for (let i = 1; i < temp.length; i++) {
- if (temp[i] > value) {
- value = temp[i];
- index = i;
- }
- }
- return index;
- }
-
- public static Combinations<T>(chars: T[]) {
- const result = new Array<T>();
- const f = (prefix: any, chars: any) => {
- for (let i = 0; i < chars.length; i++) {
- result.push(prefix.concat(chars[i]));
- f(prefix.concat(chars[i]), chars.slice(i + 1));
- }
- };
- f([], chars);
- return result;
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/PartialClass.ts b/src/client/northstar/utils/PartialClass.ts
deleted file mode 100644
index 2f20de96f..000000000
--- a/src/client/northstar/utils/PartialClass.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-
-export class PartialClass<T> {
-
- constructor(data?: Partial<T>) {
- Object.assign(this, data);
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts
deleted file mode 100644
index a52890ed9..000000000
--- a/src/client/northstar/utils/SizeConverter.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import { PIXIPoint } from "./MathUtil";
-import { VisualBinRange } from "../model/binRanges/VisualBinRange";
-import { Bin, DoubleValueAggregateResult, AggregateKey } from "../model/idea/idea";
-import { ModelHelpers } from "../model/ModelHelpers";
-import { observable, action, computed } from "mobx";
-
-export class SizeConverter {
- public DataMins: Array<number> = new Array<number>(2);
- public DataMaxs: Array<number> = new Array<number>(2);
- public DataRanges: Array<number> = new Array<number>(2);
- public MaxLabelSizes: Array<PIXIPoint> = new Array<PIXIPoint>(2);
- public RenderDimension: number = 300;
-
- @observable _leftOffset: number = 40;
- @observable _rightOffset: number = 20;
- @observable _topOffset: number = 20;
- @observable _bottomOffset: number = 45;
- @observable _labelAngle: number = 0;
- @observable _isSmall: boolean = false;
- @observable public Initialized = 0;
-
- @action public SetIsSmall(isSmall: boolean) { this._isSmall = isSmall; }
- @action public SetLabelAngle(angle: number) { this._labelAngle = angle; }
- @computed public get IsSmall() { return this._isSmall; }
- @computed public get LabelAngle() { return this._labelAngle; }
- @computed public get LeftOffset() { return this.IsSmall ? 5 : this._leftOffset; }
- @computed public get RightOffset() { return this.IsSmall ? 5 : !this._labelAngle ? this._bottomOffset : Math.max(this._rightOffset, Math.cos(this._labelAngle) * (this.MaxLabelSizes[0].x + 18)); }
- @computed public get TopOffset() { return this.IsSmall ? 5 : this._topOffset; }
- @computed public get BottomOffset() { return this.IsSmall ? 25 : !this._labelAngle ? this._bottomOffset : Math.max(this._bottomOffset, Math.sin(this._labelAngle) * (this.MaxLabelSizes[0].x + 18)) + 18; }
-
- public SetVisualBinRanges(visualBinRanges: Array<VisualBinRange>) {
- this.Initialized++;
- var xLabels = visualBinRanges[0].GetLabels();
- var yLabels = visualBinRanges[1].GetLabels();
- var xLabelStrings = xLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length; });
- var yLabelStrings = yLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length; });
-
- var metricsX = { width: 75 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number,
- //xLabelStrings[0]!.slice(0, 20)) // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS));
- var metricsY = { width: 22 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number,
- // yLabelStrings[0]!.slice(0, 20)); // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS));
- this.MaxLabelSizes[0] = new PIXIPoint(metricsX.width, 12);// FontStyles.AxisLabel.fontSize as number);
- this.MaxLabelSizes[1] = new PIXIPoint(metricsY.width, 12); // FontStyles.AxisLabel.fontSize as number);
-
- this._leftOffset = Math.max(10, metricsY.width + 10 + 20);
-
- this.DataMins[0] = xLabels.map(l => l.minValue!).reduce((m, c) => Math.min(m, c), Number.MAX_VALUE);
- this.DataMins[1] = yLabels.map(l => l.minValue!).reduce((m, c) => Math.min(m, c), Number.MAX_VALUE);
- this.DataMaxs[0] = xLabels.map(l => l.maxValue!).reduce((m, c) => Math.max(m, c), Number.MIN_VALUE);
- this.DataMaxs[1] = yLabels.map(l => l.maxValue!).reduce((m, c) => Math.max(m, c), Number.MIN_VALUE);
-
- this.DataRanges[0] = this.DataMaxs[0] - this.DataMins[0];
- this.DataRanges[1] = this.DataMaxs[1] - this.DataMins[1];
- }
-
- public DataToScreenNormalizedRange(dataValue: number, normalization: number, axis: number, binBrushMaxAxis: number) {
- var value = normalization !== 1 - axis || binBrushMaxAxis === 0 ? dataValue : (dataValue - 0) / (binBrushMaxAxis - 0) * this.DataRanges[axis];
- var from = this.DataToScreenCoord(Math.min(0, value), axis);
- var to = this.DataToScreenCoord(Math.max(0, value), axis);
- return [from, value, to];
- }
-
- public DataToScreenPointRange(axis: number, bin: Bin, aggregateKey: AggregateKey) {
- var value = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
- if (value && value.hasResult) {
- return [this.DataToScreenCoord(value.result!, axis) - 5,
- this.DataToScreenCoord(value.result!, axis) + 5];
- }
- return [undefined, undefined];
- }
-
- public DataToScreenXAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
- var value = visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![index]);
- return [this.DataToScreenX(value), this.DataToScreenX(visualBinRanges[index].AddStep(value))];
- }
- public DataToScreenYAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
- var value = visualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![index]);
- return [this.DataToScreenY(value), this.DataToScreenY(visualBinRanges[index].AddStep(value))];
- }
-
- public DataToScreenX(x: number): number {
- return ((x - this.DataMins[0]) / this.DataRanges[0]) * this.RenderDimension;
- }
- public DataToScreenY(y: number, flip: boolean = true) {
- var retY = ((y - this.DataMins[1]) / this.DataRanges[1]) * this.RenderDimension;
- return flip ? (this.RenderDimension) - retY : retY;
- }
- public DataToScreenCoord(v: number, axis: number) {
- if (axis === 0) {
- return this.DataToScreenX(v);
- }
- return this.DataToScreenY(v);
- }
- public DataToScreenRange(minVal: number, maxVal: number, axis: number) {
- let xFrom = this.DataToScreenX(axis === 0 ? minVal : this.DataMins[0]);
- let xTo = this.DataToScreenX(axis === 0 ? maxVal : this.DataMaxs[0]);
- let yFrom = this.DataToScreenY(axis === 1 ? minVal : this.DataMins[1]);
- let yTo = this.DataToScreenY(axis === 1 ? maxVal : this.DataMaxs[1]);
- return { xFrom, yFrom, xTo, yTo };
- }
-} \ No newline at end of file
diff --git a/src/client/northstar/utils/StyleContants.ts b/src/client/northstar/utils/StyleContants.ts
deleted file mode 100644
index e9b6e0297..000000000
--- a/src/client/northstar/utils/StyleContants.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { PIXIPoint } from "./MathUtil";
-
-export class StyleConstants {
-
- static DEFAULT_FONT: string = "Roboto Condensed";
-
- static MENU_SUBMENU_WIDTH: number = 85;
- static MENU_SUBMENU_HEIGHT: number = 400;
- static MENU_BOX_SIZE: PIXIPoint = new PIXIPoint(80, 35);
- static MENU_BOX_PADDING: number = 10;
-
- static OPERATOR_MENU_LARGE: number = 35;
- static OPERATOR_MENU_SMALL: number = 25;
- static BRUSH_PALETTE: number[] = [0x42b43c, 0xfa217f, 0x6a9c75, 0xfb5de7, 0x25b8ea, 0x9b5bc4, 0xda9f63, 0xe23209, 0xfb899b, 0x94a6fd];
- static GAP: number = 3;
-
- static BACKGROUND_COLOR: number = 0xF3F3F3;
- static TOOL_TIP_BACKGROUND_COLOR: number = 0xffffff;
- static LIGHT_TEXT_COLOR: number = 0xffffff;
- static LIGHT_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.LIGHT_TEXT_COLOR);
- static DARK_TEXT_COLOR: number = 0x282828;
- static HIGHLIGHT_TEXT_COLOR: number = 0xffcc00;
- static FPS_TEXT_COLOR: number = StyleConstants.DARK_TEXT_COLOR;
- static CORRELATION_LABEL_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.DARK_TEXT_COLOR);
- static LOADING_SCREEN_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.DARK_TEXT_COLOR);
- static ERROR_COLOR: number = 0x540E25;
- static WARNING_COLOR: number = 0xE58F24;
- static LOWER_THAN_NAIVE_COLOR: number = 0xee0000;
- static HIGHLIGHT_COLOR: number = 0x82A8D9;
- static HIGHLIGHT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.HIGHLIGHT_COLOR);
- static OPERATOR_BACKGROUND_COLOR: number = 0x282828;
- static LOADING_ANIMATION_COLOR: number = StyleConstants.OPERATOR_BACKGROUND_COLOR;
- static MENU_COLOR: number = 0x282828;
- static MENU_FONT_COLOR: number = StyleConstants.LIGHT_TEXT_COLOR;
- static MENU_SELECTED_COLOR: number = StyleConstants.HIGHLIGHT_COLOR;
- static MENU_SELECTED_FONT_COLOR: number = StyleConstants.LIGHT_TEXT_COLOR;
- static BRUSH_COLOR: number = 0xff0000;
- static DROP_ACCEPT_COLOR: number = StyleConstants.HIGHLIGHT_COLOR;
- static SELECTED_COLOR: number = 0xffffff;
- static SELECTED_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.SELECTED_COLOR);
- static PROGRESS_BACKGROUND_COLOR: number = 0x595959;
- static GRID_LINES_COLOR: number = 0x3D3D3D;
- static GRID_LINES_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.GRID_LINES_COLOR);
-
- static MAX_CHAR_FOR_HISTOGRAM_LABELS: number = 20;
-
- static OVERLAP_COLOR: number = 0x0000ff;//0x540E25;
- static BRUSH_COLORS: Array<number> = new Array<number>(
- 0xFFDA7E, 0xFE8F65, 0xDA5655, 0x8F2240
- );
-
- static MIN_VALUE_COLOR: number = 0x373d43; //32343d, 373d43, 3b4648
- static MARGIN_BARS_COLOR: number = 0xffffff;
- static MARGIN_BARS_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.MARGIN_BARS_COLOR);
-
- static HISTOGRAM_WIDTH: number = 200;
- static HISTOGRAM_HEIGHT: number = 150;
- static PREDICTOR_WIDTH: number = 150;
- static PREDICTOR_HEIGHT: number = 100;
- static RAWDATA_WIDTH: number = 150;
- static RAWDATA_HEIGHT: number = 100;
- static FREQUENT_ITEM_WIDTH: number = 180;
- static FREQUENT_ITEM_HEIGHT: number = 100;
- static CORRELATION_WIDTH: number = 555;
- static CORRELATION_HEIGHT: number = 390;
- static PROBLEM_FINDER_WIDTH: number = 450;
- static PROBLEM_FINDER_HEIGHT: number = 150;
- static PIPELINE_OPERATOR_WIDTH: number = 300;
- static PIPELINE_OPERATOR_HEIGHT: number = 120;
- static SLICE_WIDTH: number = 150;
- static SLICE_HEIGHT: number = 45;
- static BORDER_MENU_ITEM_WIDTH: number = 50;
- static BORDER_MENU_ITEM_HEIGHT: number = 30;
-
-
- static SLICE_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.OPERATOR_BACKGROUND_COLOR);
- static SLICE_EMPTY_COLOR: number = StyleConstants.OPERATOR_BACKGROUND_COLOR;
- static SLICE_OCCUPIED_COLOR: number = 0xffffff;
- static SLICE_OCCUPIED_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.OPERATOR_BACKGROUND_COLOR);
- static SLICE_HOVER_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.HIGHLIGHT_COLOR);
- static SLICE_HOVER_COLOR: number = 0xffffff;
-
- static HexToHexString(hex: number): string {
- if (hex === undefined) {
- return "#000000";
- }
- var s = hex.toString(16);
- while (s.length < 6) {
- s = "0" + s;
- }
- return "#" + s;
- }
-
-
-}
diff --git a/src/client/northstar/utils/Utils.ts b/src/client/northstar/utils/Utils.ts
deleted file mode 100644
index d071dec62..000000000
--- a/src/client/northstar/utils/Utils.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { IBaseBrushable } from '../core/brusher/IBaseBrushable';
-import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer';
-import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider';
-import { AggregateFunction } from '../model/idea/idea';
-
-export class Utils {
-
- public static EqualityHelper(a: Object, b: Object): boolean {
- if (a === b) return true;
- if (a === undefined && b !== undefined) return false;
- if (a === null && b !== null) return false;
- if (b === undefined && a !== undefined) return false;
- if (b === null && a !== null) return false;
- if ((<any>a).constructor.name !== (<any>b).constructor.name) return false;
- return true;
- }
-
- public static LowercaseFirstLetter(str: string) {
- return str.charAt(0).toUpperCase() + str.slice(1);
- }
-
- //
- // this Type Guard tests if dropTarget is an IDropTarget. If it is, it coerces the compiler
- // to treat the dropTarget parameter as an IDropTarget *ouside* this function scope (ie, in
- // the scope of where this function is called from).
- //
-
- public static isBaseBrushable<T>(obj: Object): obj is IBaseBrushable<T> {
- let typed = <IBaseBrushable<T>>obj;
- return typed !== null && typed.BrusherModels !== undefined;
- }
-
- public static isBaseFilterProvider(obj: Object): obj is IBaseFilterProvider {
- let typed = <IBaseFilterProvider>obj;
- return typed !== null && typed.FilterModels !== undefined;
- }
-
- public static isBaseFilterConsumer(obj: Object): obj is IBaseFilterConsumer {
- let typed = <IBaseFilterConsumer>obj;
- return typed !== null && typed.FilterOperand !== undefined;
- }
-
- public static EncodeQueryData(data: any): string {
- const ret = [];
- for (let d in data) {
- ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
- }
- return ret.join("&");
- }
-
- public static ToVegaAggregationString(agg: AggregateFunction): string {
- if (agg === AggregateFunction.Avg) {
- return "average";
- }
- else if (agg === AggregateFunction.Count) {
- return "count";
- }
- else {
- return "";
- }
- }
-
- public static GetQueryVariable(variable: string) {
- let query = window.location.search.substring(1);
- let vars = query.split("&");
- for (const variable of vars) {
- let pair = variable.split("=");
- if (decodeURIComponent(pair[0]) === variable) {
- return decodeURIComponent(pair[1]);
- }
- }
- return undefined;
- }
-}
-
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 569c1ef6d..b3295ece0 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -10,7 +10,6 @@ import { CollectionViewType } from "../views/collections/CollectionView";
import { Cast, CastCtor } from "../../new_fields/Types";
import { listSpec } from "../../new_fields/Schema";
import { AudioField, ImageField } from "../../new_fields/URLField";
-import { HistogramField } from "../northstar/dash-fields/HistogramField";
import { Utils } from "../../Utils";
import { RichTextField } from "../../new_fields/RichTextField";
import { DictationOverlay } from "../views/DictationOverlay";
@@ -282,9 +281,8 @@ export namespace DictationManager {
[DocumentType.COL, listSpec(Doc)],
[DocumentType.AUDIO, AudioField],
[DocumentType.IMG, ImageField],
- [DocumentType.HIST, HistogramField],
[DocumentType.IMPORT, listSpec(Doc)],
- [DocumentType.TEXT, "string"]
+ [DocumentType.RTF, "string"]
]);
const tryCast = (view: DocumentView, type: DocumentType) => {
@@ -377,7 +375,7 @@ export namespace DictationManager {
{
expression: /view as (freeform|stacking|masonry|schema|tree)/g,
action: (target: DocumentView, matches: RegExpExecArray) => {
- const mode = CollectionViewType.valueOf(matches[1]);
+ const mode = matches[1];
mode && (target.props.Document._viewType = mode);
},
restrictTo: [DocumentType.COL]
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 3d5306841..4683e77a8 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -148,7 +148,7 @@ export class DocumentManager {
const highlight = () => {
const finalDocView = getFirstDocView(targetDoc);
if (finalDocView) {
- finalDocView.Document.scrollToLinkID = linkId;
+ finalDocView.layoutDoc.scrollToLinkID = linkId;
Doc.linkFollowHighlight(finalDocView.props.Document);
}
};
@@ -156,7 +156,12 @@ export class DocumentManager {
let annotatedDoc = await Cast(targetDoc.annotationOn, Doc);
if (annotatedDoc) {
const first = getFirstDocView(annotatedDoc);
- if (first) annotatedDoc = first.props.Document;
+ if (first) {
+ annotatedDoc = first.props.Document;
+ if (docView) {
+ docView.props.focus(annotatedDoc, false);
+ }
+ }
}
if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight?
docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish);
@@ -219,9 +224,12 @@ export class DocumentManager {
if (linkDoc) {
const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 :
(Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc;
+ const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") :
+ doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
+ (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
if (target) {
const containerDoc = (await Cast(target.annotationOn, Doc)) || target;
- containerDoc.currentTimecode !== undefined && (containerDoc.currentTimecode = NumCast(target?.timecode));
+ containerDoc.currentTimecode = targetTimecode;
const targetContext = await target?.context as Doc;
const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc[Id], undefined, doc, finished);
@@ -233,4 +241,4 @@ export class DocumentManager {
}
}
}
-Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file
+Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 53c0a2963..35694a6bd 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,5 +1,5 @@
import { Doc, Field, DocListCast } from "../../new_fields/Doc";
-import { Cast, ScriptCast } from "../../new_fields/Types";
+import { Cast, ScriptCast, StrCast } from "../../new_fields/Types";
import { emptyFunction } from "../../Utils";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import * as globalCssVariables from "../views/globalCssVariables.scss";
@@ -19,7 +19,7 @@ import { DateField } from "../../new_fields/DateField";
import { DocumentView } from "../views/nodes/DocumentView";
import { UndoManager } from "./UndoManager";
-export type dropActionType = "place" | "alias" | "copy" | undefined;
+export type dropActionType = "alias" | "copy" | "move" | undefined; // undefined = move
export function SetupDrag(
_reference: React.RefObject<HTMLElement>,
docFunc: () => Doc | Promise<Doc> | undefined,
@@ -83,6 +83,7 @@ export namespace DragManager {
}
export let AbortDrag: () => void = emptyFunction;
export type MoveFunction = (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+ export type RemoveFunction = (document: Doc) => boolean;
export interface DragDropDisposer { (): void; }
export interface DragOptions {
@@ -138,6 +139,7 @@ export namespace DragManager {
userDropAction: dropActionType;
embedDoc?: boolean;
moveDocument?: MoveFunction;
+ removeDocument?: RemoveFunction;
isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts
}
export class LinkDragData {
@@ -177,7 +179,8 @@ export namespace DragManager {
export function MakeDropTarget(
element: HTMLElement,
- dropFunc: (e: Event, de: DropEvent) => void
+ dropFunc: (e: Event, de: DropEvent) => void,
+ doc?: Doc
): DragDropDisposer {
if ("canDrop" in element.dataset) {
throw new Error(
@@ -185,10 +188,18 @@ export namespace DragManager {
);
}
element.dataset.canDrop = "true";
- const handler = (e: Event) => { dropFunc(e, (e as CustomEvent<DropEvent>).detail); };
+ const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
+ const preDropHandler = (e: Event) => {
+ const de = (e as CustomEvent<DropEvent>).detail;
+ if (de.complete.docDragData && doc?.targetDropAction) {
+ de.complete.docDragData.dropAction = StrCast(doc.targetDropAction) as dropActionType;
+ }
+ };
element.addEventListener("dashOnDrop", handler);
+ doc && element.addEventListener("dashPreDrop", preDropHandler);
return () => {
element.removeEventListener("dashOnDrop", handler);
+ doc && element.removeEventListener("dashPreDrop", preDropHandler);
delete element.dataset.canDrop;
};
}
@@ -205,7 +216,7 @@ export namespace DragManager {
e.docDragData && (e.docDragData.droppedDocuments =
dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? Doc.MakeAlias(d) :
- dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeCopy(d, true) : d)
+ dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeClone(d) : d)
);
e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) =>
(dragData?.removeDropProperties || []).concat(Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), [])).map(prop => drop[prop] = undefined)
@@ -219,10 +230,10 @@ export namespace DragManager {
// drag a button template and drop a new button
export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) {
const finishDrag = (e: DragCompleteEvent) => {
- const bd = Docs.Create.ButtonDocument({ _width: 150, _height: 50, title, isButton: true, onClick: ScriptField.MakeScript(script) });
- params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc)));
+ const bd = Docs.Create.ButtonDocument({ _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) });
+ params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields
initialize?.(bd);
- bd.buttonParams = new List<string>(params);
+ Doc.GetProto(bd)["onClick-paramFieldKeys"] = new List<string>(params);
e.docDragData && (e.docDragData.droppedDocuments = [bd]);
};
StartDrag(eles, new DragManager.DocumentDragData([]), downX, downY, options, finishDrag);
@@ -351,12 +362,17 @@ export namespace DragManager {
let lastX = downX;
let lastY = downY;
+ let alias = "alias";
const moveHandler = (e: PointerEvent) => {
e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
if (dragData instanceof DocumentDragData) {
dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined;
}
if (e.shiftKey && CollectionDockingView.Instance && dragData.droppedDocuments.length === 1) {
+ !dragData.dropAction && (dragData.dropAction = alias);
+ if (dragData.dropAction === "move") {
+ dragData.removeDocument?.(dragData.draggedDocuments[0]);
+ }
AbortDrag();
finishDrag?.(new DragCompleteEvent(true, dragData));
CollectionDockingView.Instance.StartOtherDrag({
@@ -366,7 +382,7 @@ export namespace DragManager {
button: 0
}, dragData.droppedDocuments);
}
- //TODO: Why can't we use e.movementX and e.movementY?
+ alias = "move";
const moveX = e.pageX - lastX;
const moveY = e.pageY - lastY;
lastX = e.pageX;
@@ -418,8 +434,21 @@ export namespace DragManager {
});
if (target) {
const complete = new DragCompleteEvent(false, dragData);
+ target.dispatchEvent(
+ new CustomEvent<DropEvent>("dashPreDrop", {
+ bubbles: true,
+ detail: {
+ x: e.x,
+ y: e.y,
+ complete: complete,
+ shiftKey: e.shiftKey,
+ altKey: e.altKey,
+ metaKey: e.metaKey,
+ ctrlKey: e.ctrlKey
+ }
+ })
+ );
finishDrag?.(complete);
- console.log(complete.aborted);
target.dispatchEvent(
new CustomEvent<DropEvent>("dashOnDrop", {
bubbles: true,
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index d96257ca1..60a6bbb3c 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -35,8 +35,14 @@ export function makeTemplate(doc: Doc, first: boolean = true, rename: Opt<string
any = makeTemplate(d, false) || any;
}
});
- if (!docs.length && first) {
- any = Doc.MakeMetadataFieldTemplate(doc, Doc.GetProto(layoutDoc)) || any;
+ if (first) {
+ if (docs.length) { // bcz: feels hacky : if the root level document has items, it's not a field template, but we still want its caption to be a textTemplate
+ if (doc.caption instanceof RichTextField && !doc.caption.Empty()) {
+ doc["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`);
+ }
+ } else {
+ any = Doc.MakeMetadataFieldTemplate(doc, Doc.GetProto(layoutDoc)) || any;
+ }
}
if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) {
if (!StrCast(layoutDoc.title).startsWith("-")) {
@@ -52,14 +58,12 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
// bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
if (!doc.onDragStart && !doc.isButtonBar) {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
- if (layoutDoc.type === DocumentType.COL || layoutDoc.type === DocumentType.TEXT || layoutDoc.type === DocumentType.IMG) {
+ if (layoutDoc.type !== DocumentType.FONTICON) {
!layoutDoc.isTemplateDoc && makeTemplate(layoutDoc);
- } else {
- (layoutDoc.layout instanceof Doc) && !data.userDropAction;
}
layoutDoc.isTemplateDoc = true;
dbox = Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, isButton: true,
+ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
backgroundColor: StrCast(doc.backgroundColor), title: StrCast(layoutDoc.title), icon: layoutDoc.isTemplateDoc ? "font" : "bolt"
});
dbox.dragFactory = layoutDoc;
diff --git a/src/client/util/History.ts b/src/client/util/History.ts
index 545e8acb4..2c53d7e52 100644
--- a/src/client/util/History.ts
+++ b/src/client/util/History.ts
@@ -40,8 +40,12 @@ export namespace HistoryUtil {
// }
}
+ let _lastStatePush = 0;
export function pushState(state: ParsedUrl) {
- history.pushState(state, "", createUrl(state));
+ if (Date.now() - _lastStatePush > 1000) {
+ history.pushState(state, "", createUrl(state));
+ }
+ _lastStatePush = Date.now();
}
export function replaceState(state: ParsedUrl) {
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 3d8bcbab7..438904688 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx
@@ -126,7 +126,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
const document = await Docs.Get.DocumentFromType(type, path, { _width: 300, title: name });
const { data, error } = exifData;
if (document) {
- Doc.GetProto(document).exif = error || Docs.Get.DocumentHierarchyFromJson(data);
+ Doc.GetProto(document).exif = error || Docs.Get.FromJson({ data });
docs.push(document);
}
}));
diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts
index ab8c73d15..c8d1530b3 100644
--- a/src/client/util/Import & Export/ImageUtils.ts
+++ b/src/client/util/Import & Export/ImageUtils.ts
@@ -20,10 +20,11 @@ export namespace ImageUtils {
nativeHeight,
exifData: { error, data }
} = await Networking.PostToServer("/inspectImage", { source });
- document.exif = error || Docs.Get.DocumentHierarchyFromJson(data);
+ document.exif = error || Docs.Get.FromJson({ data });
const proto = Doc.GetProto(document);
proto["data-nativeWidth"] = nativeWidth;
proto["data-nativeHeight"] = nativeHeight;
+ proto["data-path"] = source;
proto.contentSize = contentSize ? contentSize : undefined;
return data !== undefined;
};
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index f2d569cf3..b1f136430 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -13,7 +13,6 @@ export namespace InteractionUtils {
export class MultiTouchEvent<T extends React.TouchEvent | TouchEvent> {
constructor(
readonly fingers: number,
- // readonly points: T extends React.TouchEvent ? React.TouchList : TouchList,
readonly targetTouches: T extends React.TouchEvent ? React.Touch[] : Touch[],
readonly touches: T extends React.TouchEvent ? React.Touch[] : Touch[],
readonly changedTouches: T extends React.TouchEvent ? React.Touch[] : Touch[],
@@ -23,6 +22,11 @@ export namespace InteractionUtils {
export interface MultiTouchEventDisposer { (): void; }
+ /**
+ *
+ * @param element - element to turn into a touch target
+ * @param startFunc - event handler, typically Touchable.onTouchStart (classes that inherit touchable can pass in this.onTouchStart)
+ */
export function MakeMultiTouchTarget(
element: HTMLElement,
startFunc: (e: Event, me: MultiTouchEvent<React.TouchEvent>) => void
@@ -48,6 +52,11 @@ export namespace InteractionUtils {
};
}
+ /**
+ * Turns an element onto a target for touch hold handling.
+ * @param element - element to add events to
+ * @param func - function to add to the event
+ */
export function MakeHoldTouchTarget(
element: HTMLElement,
func: (e: Event, me: MultiTouchEvent<React.TouchEvent>) => void
@@ -78,7 +87,6 @@ export namespace InteractionUtils {
return myTouches;
}
- // TODO: find a way to reference this function from InkingStroke instead of copy pastign here. copied bc of weird error when on mobile view
export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: number) {
const pts = points.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${pt.X - left},${pt.Y - top} `, "");
return (
@@ -93,6 +101,11 @@ export namespace InteractionUtils {
);
}
+ /**
+ * Returns whether or not the pointer event passed in is of the type passed in
+ * @param e - pointer event. this event could be from a mouse, a pen, or a finger
+ * @param type - InteractionUtils.(PENTYPE | ERASERTYPE | MOUSETYPE | TOUCHTYPE)
+ */
export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean {
switch (type) {
// pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2
@@ -105,6 +118,11 @@ export namespace InteractionUtils {
}
}
+ /**
+ * Returns euclidean distance between two points
+ * @param pt1
+ * @param pt2
+ */
export function TwoPointEuclidist(pt1: React.Touch, pt2: React.Touch): number {
return Math.sqrt(Math.pow(pt1.clientX - pt2.clientX, 2) + Math.pow(pt1.clientY - pt2.clientY, 2));
}
diff --git a/src/client/util/KeyCodes.ts b/src/client/util/KeyCodes.ts
new file mode 100644
index 000000000..cacb72a57
--- /dev/null
+++ b/src/client/util/KeyCodes.ts
@@ -0,0 +1,136 @@
+/**
+ * Class contains the keycodes for keys on your keyboard.
+ *
+ * Useful for auto completion:
+ *
+ * ```
+ * switch (event.key)
+ * {
+ * case KeyCode.UP:
+ * {
+ * // Up key pressed
+ * break;
+ * }
+ * case KeyCode.DOWN:
+ * {
+ * // Down key pressed
+ * break;
+ * }
+ * case KeyCode.LEFT:
+ * {
+ * // Left key pressed
+ * break;
+ * }
+ * case KeyCode.RIGHT:
+ * {
+ * // Right key pressed
+ * break;
+ * }
+ * default:
+ * {
+ * // ignore
+ * break;
+ * }
+ * }
+ * ```
+ */
+export class KeyCodes {
+ public static TAB: number = 9;
+ public static CAPS_LOCK: number = 20;
+ public static SHIFT: number = 16;
+ public static CONTROL: number = 17;
+ public static SPACE: number = 32;
+ public static DOWN: number = 40;
+ public static UP: number = 38;
+ public static LEFT: number = 37;
+ public static RIGHT: number = 39;
+ public static ESCAPE: number = 27;
+ public static F1: number = 112;
+ public static F2: number = 113;
+ public static F3: number = 114;
+ public static F4: number = 115;
+ public static F5: number = 116;
+ public static F6: number = 117;
+ public static F7: number = 118;
+ public static F8: number = 119;
+ public static F9: number = 120;
+ public static F10: number = 121;
+ public static F11: number = 122;
+ public static F12: number = 123;
+ public static INSERT: number = 45;
+ public static HOME: number = 36;
+ public static PAGE_UP: number = 33;
+ public static PAGE_DOWN: number = 34;
+ public static DELETE: number = 46;
+ public static END: number = 35;
+ public static ENTER: number = 13;
+ public static BACKSPACE: number = 8;
+ public static NUMPAD_0: number = 96;
+ public static NUMPAD_1: number = 97;
+ public static NUMPAD_2: number = 98;
+ public static NUMPAD_3: number = 99;
+ public static NUMPAD_4: number = 100;
+ public static NUMPAD_5: number = 101;
+ public static NUMPAD_6: number = 102;
+ public static NUMPAD_7: number = 103;
+ public static NUMPAD_8: number = 104;
+ public static NUMPAD_9: number = 105;
+ public static NUMPAD_DIVIDE: number = 111;
+ public static NUMPAD_ADD: number = 107;
+ public static NUMPAD_ENTER: number = 13;
+ public static NUMPAD_DECIMAL: number = 110;
+ public static NUMPAD_SUBTRACT: number = 109;
+ public static NUMPAD_MULTIPLY: number = 106;
+ public static SEMICOLON: number = 186;
+ public static EQUAL: number = 187;
+ public static COMMA: number = 188;
+ public static MINUS: number = 189;
+ public static PERIOD: number = 190;
+ public static SLASH: number = 191;
+ public static BACKQUOTE: number = 192;
+ public static LEFTBRACKET: number = 219;
+ public static BACKSLASH: number = 220;
+ public static RIGHTBRACKET: number = 221;
+ public static QUOTE: number = 222;
+ public static ALT: number = 18;
+ public static COMMAND: number = 15;
+ public static NUMPAD: number = 21;
+ public static A: number = 65;
+ public static B: number = 66;
+ public static C: number = 67;
+ public static D: number = 68;
+ public static E: number = 69;
+ public static F: number = 70;
+ public static G: number = 71;
+ public static H: number = 72;
+ public static I: number = 73;
+ public static J: number = 74;
+ public static K: number = 75;
+ public static L: number = 76;
+ public static M: number = 77;
+ public static N: number = 78;
+ public static O: number = 79;
+ public static P: number = 80;
+ public static Q: number = 81;
+ public static R: number = 82;
+ public static S: number = 83;
+ public static T: number = 84;
+ public static U: number = 85;
+ public static V: number = 86;
+ public static W: number = 87;
+ public static X: number = 88;
+ public static Y: number = 89;
+ public static Z: number = 90;
+ public static NUM_0: number = 48;
+ public static NUM_1: number = 49;
+ public static NUM_2: number = 50;
+ public static NUM_3: number = 51;
+ public static NUM_4: number = 52;
+ public static NUM_5: number = 53;
+ public static NUM_6: number = 54;
+ public static NUM_7: number = 55;
+ public static NUM_8: number = 56;
+ public static NUM_9: number = 57;
+ public static SUBSTRACT: number = 189;
+ public static ADD: number = 187;
+} \ No newline at end of file
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 4457f41e2..e236c7f47 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -136,12 +136,12 @@ export class LinkManager {
}
}
public addGroupToAnchor(linkDoc: Doc, anchor: Doc, groupDoc: Doc, replace: boolean = false) {
- linkDoc.linkRelationship = groupDoc.linkRelationship;
+ Doc.GetProto(linkDoc).linkRelationship = groupDoc.linkRelationship;
}
// removes group doc of given group type only from given anchor on given link
public removeGroupFromAnchor(linkDoc: Doc, anchor: Doc, groupType: string) {
- linkDoc.linkRelationship = "-ungrouped-";
+ Doc.GetProto(linkDoc).linkRelationship = "-ungrouped-";
}
// returns map of group type to anchor's links in that group type
diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 42247f177..356f20ce6 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -7,7 +7,7 @@ import { splitListItem, wrapInList, } from "prosemirror-schema-list";
import { EditorState, Transaction, TextSelection } from "prosemirror-state";
import { SelectionManager } from "./SelectionManager";
import { Docs } from "../documents/Documents";
-import { NumCast, BoolCast, Cast } from "../../new_fields/Types";
+import { NumCast, BoolCast, Cast, StrCast } from "../../new_fields/Types";
import { Doc } from "../../new_fields/Doc";
import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
import { Id } from "../../new_fields/FieldSymbols";
@@ -153,10 +153,16 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
const layoutDoc = props.Document;
const originalDoc = layoutDoc.rootDocument || layoutDoc;
if (originalDoc instanceof Doc) {
+ const layoutKey = StrCast(originalDoc.layoutKey);
const newDoc = Docs.Create.TextDocument("", {
- title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine),
+ layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout,
+ layoutKey,
+ _singleLine: BoolCast(originalDoc._singleLine),
x: NumCast(originalDoc.x), y: NumCast(originalDoc.y) + NumCast(originalDoc._height) + 10, _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height)
});
+ if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) {
+ newDoc[layoutKey] = originalDoc[layoutKey];
+ }
FormattedTextBox.SelectOnLoad = newDoc[Id];
props.addDocument(newDoc);
}
@@ -171,10 +177,16 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
const layoutDoc = props.Document;
const originalDoc = layoutDoc.rootDocument || layoutDoc;
if (force || props.Document._singleLine) {
+ const layoutKey = StrCast(originalDoc.layoutKey);
const newDoc = Docs.Create.TextDocument("", {
- title: "", layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout, _singleLine: BoolCast(originalDoc._singleLine),
+ layout: Cast(originalDoc.layout, Doc, null) || FormattedTextBox.DefaultLayout,
+ layoutKey,
+ _singleLine: BoolCast(originalDoc._singleLine),
x: NumCast(originalDoc.x) + NumCast(originalDoc._width) + 10, y: NumCast(originalDoc.y), _width: NumCast(layoutDoc._width), _height: NumCast(layoutDoc._height)
});
+ if (layoutKey !== "layout" && originalDoc[layoutKey] instanceof Doc) {
+ newDoc[layoutKey] = originalDoc[layoutKey];
+ }
FormattedTextBox.SelectOnLoad = newDoc[Id];
props.addDocument(newDoc);
return true;
diff --git a/src/client/util/RichTextMenu.tsx b/src/client/util/RichTextMenu.tsx
index 34bdf246a..140635a1d 100644
--- a/src/client/util/RichTextMenu.tsx
+++ b/src/client/util/RichTextMenu.tsx
@@ -445,8 +445,8 @@ export default class RichTextMenu extends AntimodeMenu {
}
const button =
- <button className="antimodeMenu-button" title="" onPointerDown={onBrushClick} style={this.brushMarks && this.brushMarks.size > 0 ? { backgroundColor: "121212" } : {}}>
- <FontAwesomeIcon icon="paint-roller" size="lg" style={{ transition: "transform 0.1s", transform: this.brushMarks && this.brushMarks.size > 0 ? "rotate(45deg)" : "" }} />
+ <button className="antimodeMenu-button" title="" onPointerDown={onBrushClick} style={this.brushMarks?.size > 0 ? { backgroundColor: "121212" } : {}}>
+ <FontAwesomeIcon icon="paint-roller" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.brushMarks?.size > 0 ? 45 : 0}deg)` }} />
</button>;
const dropdownContent =
@@ -790,11 +790,11 @@ export default class RichTextMenu extends AntimodeMenu {
<div key="button">
<div key="collapser">
<button className="antimodeMenu-button" key="collapse menu" title="Collapse menu" onClick={this.toggleCollapse} style={{ backgroundColor: this.collapsed ? "#121212" : "", width: 25 }}>
- <FontAwesomeIcon icon="chevron-left" size="lg" style={{ transition: "transform 0.3s", transform: this.collapsed ? "rotate(180deg)" : "" }} />
+ <FontAwesomeIcon icon="chevron-left" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.3s", transform: `rotate(${this.collapsed ? 180 : 0}deg)` }} />
</button>
</div>
<button className="antimodeMenu-button" key="pin menu" title="Pin menu" onClick={this.toggleMenuPin} style={{ backgroundColor: this.Pinned ? "#121212" : "", display: this.collapsed ? "none" : undefined }}>
- <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this.Pinned ? "rotate(45deg)" : "" }} />
+ <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
</button>
{this.getDragger()}
</div>
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index d18907ad3..63a3815ea 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -62,6 +62,17 @@ export class RichTextRules {
// ``` code block
textblockTypeInputRule(/^```$/, schema.nodes.code_block),
+ // create an inline view of a tag stored under the '#' field
+ new InputRule(
+ new RegExp(/#([a-zA-Z_\-]+[a-zA-Z_\-0-9]*)\s$/),
+ (state, match, start, end) => {
+ const tag = match[1];
+ if (!tag) return state.tr;
+ this.Document[DataSym]["#"] = tag;
+ const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" });
+ return state.tr.deleteRange(start, end).insert(start, fieldView);
+ }),
+
// # heading
textblockTypeInputRule(
new RegExp(/^(#{1,6})\s$/),
@@ -81,7 +92,7 @@ export class RichTextRules {
// create a text display of a metadata field on this or another document, or create a hyperlink portal to another document [[ <fieldKey> : <Doc>]] // [[:Doc]] => hyperlink [[fieldKey]] => show field [[fieldKey:Doc]] => show field of doc
new InputRule(
- new RegExp(/\[\[([a-zA-Z_#@\? \-0-9]*)(=[a-zA-Z_#@\? \-0-9]*)?(:[a-zA-Z_#@\? \-0-9]+)?\]\]$/),
+ new RegExp(/\[\[([a-zA-Z_@\? \-0-9]*)(=[a-zA-Z_@\? \-0-9]*)?(:[a-zA-Z_@\? \-0-9]+)?\]\]$/),
(state, match, start, end) => {
const fieldKey = match[1];
const docid = match[3]?.substring(1);
@@ -99,21 +110,12 @@ export class RichTextRules {
return state.tr;
}
if (value !== "" && value !== undefined) {
- this.Document[DataSym][fieldKey] = value === "true" ? true : value === "false" ? false : value;
+ const num = value.match(/^[0-9.]/);
+ this.Document[DataSym][fieldKey] = value === "true" ? true : value === "false" ? false : (num ? Number(value) : value);
}
const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid });
return state.tr.deleteRange(start, end).insert(start, fieldView);
}),
- // create an inline view of a tag stored under the '#' field
- new InputRule(
- new RegExp(/#([a-zA-Z_\-0-9]+)\s$/),
- (state, match, start, end) => {
- const tag = match[1];
- if (!tag) return state.tr;
- this.Document[DataSym]["#"] = tag;
- const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" });
- return state.tr.deleteRange(start, end).insert(start, fieldView);
- }),
// create an inline view of a document {{ <layoutKey> : <Doc> }} // {{:Doc}} => show default view of document {{<layout>}} => show layout for this doc {{<layout> : Doc}} => show layout for another doc
new InputRule(
new RegExp(/\{\{([a-zA-Z_ \-0-9]*)(\([a-zA-Z0-9…._\-]*\))?(:[a-zA-Z_ \-0-9]+)?\}\}$/),
@@ -129,24 +131,24 @@ export class RichTextRules {
}
});
const node = (state.doc.resolve(start) as any).nodeAfter;
- const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid, fieldKey: fieldKey + fieldParam, float: "right", alias: Utils.GenerateGuid() });
+ const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 75, title: "dashDoc", docid, fieldKey: fieldKey + fieldParam, float: "unset", alias: Utils.GenerateGuid() });
const sm = state.storedMarks || undefined;
return node ? state.tr.replaceRangeWith(start, end, dashDoc).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr;
}),
new InputRule(
- new RegExp(/##$/),
+ new RegExp(/>>$/),
(state, match, start, end) => {
const textDoc = this.Document[DataSym];
const numInlines = NumCast(textDoc.inlineTextCount);
textDoc.inlineTextCount = numInlines + 1;
const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to
const inlineLayoutKey = "layout_" + inlineFieldKey; // the field holding the layout string that will render the inline annotation
- const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, fontSize: 9, title: "inline comment" });
+ const textDocInline = Docs.Create.TextDocument("", { layoutKey: inlineLayoutKey, _width: 75, _height: 35, annotationOn: textDoc, _autoHeight: true, _fontSize: 9, title: "inline comment" });
textDocInline.title = inlineFieldKey; // give the annotation its own title
textDocInline.customTitle = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
- textDocInline._textContext = ComputedField.MakeFunction(`copyField(this.${inlineFieldKey})`, { this: Doc.name });
+ textDocInline._textContext = ComputedField.MakeFunction(`copyField(self.${inlineFieldKey})`);
textDoc[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
textDoc[inlineFieldKey] = ""; // set a default value for the annotation
const node = (state.doc.resolve(start) as any).nodeAfter;
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index c860bbe28..3e45d5de5 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -15,7 +15,7 @@ import { ObjectField } from "../../new_fields/ObjectField";
import { listSpec } from "../../new_fields/Schema";
import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
import { ComputedField } from "../../new_fields/ScriptField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../new_fields/Types";
import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils, returnZero } from "../../Utils";
import { DocServer } from "../DocServer";
import { Docs } from "../documents/Documents";
@@ -206,7 +206,7 @@ export class DashDocView {
this._outer = document.createElement("span");
this._outer.style.position = "relative";
this._outer.style.textIndent = "0";
- this._outer.style.border = "1px solid " + StrCast(tbox.Document.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray"));
+ this._outer.style.border = "1px solid " + StrCast(tbox.layoutDoc.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray"));
this._outer.style.width = node.attrs.width;
this._outer.style.height = node.attrs.height;
this._outer.style.display = node.attrs.hidden ? "none" : "inline-block";
@@ -244,7 +244,7 @@ export class DashDocView {
if (dashDocBase instanceof Doc) {
const aliasedDoc = Doc.MakeAlias(dashDocBase, docid + alias);
aliasedDoc.layoutKey = "layout";
- node.attrs.fieldKey && DocumentView.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined);
+ node.attrs.fieldKey && Doc.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, node.attrs.fieldKey, undefined);
self.doRender(aliasedDoc, removeDoc, node, view, getPos);
}
});
@@ -319,9 +319,9 @@ export class DashDocView {
};
this._renderDisposer?.();
this._renderDisposer = reaction(() => {
- if (!Doc.AreProtosEqual(finalLayout, dashDoc)) {
- finalLayout.rootDocument = dashDoc.aliasOf;
- }
+ // if (!Doc.AreProtosEqual(finalLayout, dashDoc)) {
+ // finalLayout.rootDocument = dashDoc.aliasOf; // bcz: check on this ... why is it here?
+ // }
const layoutKey = StrCast(finalLayout.layoutKey);
const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1];
if (finalLayout !== dashDoc && finalKey) {
@@ -345,7 +345,7 @@ export class DashDocView {
export class DashFieldView {
_fieldWrapper: HTMLDivElement; // container for label and value
_labelSpan: HTMLSpanElement; // field label
- _fieldSpan: HTMLDivElement; // field value
+ _fieldSpan: HTMLSpanElement; // field value
_fieldCheck: HTMLInputElement;
_enumerables: HTMLDivElement; // field value
_reactionDisposer: IReactionDisposer | undefined;
@@ -357,12 +357,12 @@ export class DashFieldView {
constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) {
this._fieldKey = node.attrs.fieldKey;
this._textBoxDoc = tbox.props.Document;
-
- this._fieldWrapper = document.createElement("div");
+ this._fieldWrapper = document.createElement("p");
this._fieldWrapper.style.width = node.attrs.width;
this._fieldWrapper.style.height = node.attrs.height;
+ this._fieldWrapper.style.fontWeight = "bold";
this._fieldWrapper.style.position = "relative";
- this._fieldWrapper.style.display = "inline-flex";
+ this._fieldWrapper.style.display = "inline-block";
const self = this;
@@ -371,7 +371,6 @@ export class DashFieldView {
this._enumerables.style.height = "10px";
this._enumerables.style.position = "relative";
this._enumerables.style.display = "none";
- this._enumerables.style.background = "dimGray";
//Moved
this._enumerables.onpointerdown = async (e) => {
@@ -416,14 +415,13 @@ export class DashFieldView {
self._dashDoc![self._fieldKey] = e.target.checked;
};
- //Moved
- this._fieldSpan = document.createElement("div");
+ this._fieldSpan = document.createElement("span");
this._fieldSpan.id = Utils.GenerateGuid();
this._fieldSpan.contentEditable = "true";
this._fieldSpan.style.position = "relative";
this._fieldSpan.style.display = "none";
this._fieldSpan.style.minWidth = "12px";
- this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
+ this._fieldSpan.style.fontSize = "large";
this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); };
this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); };
this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); self._enumerables.style.display = "inline-block"; };
@@ -435,12 +433,10 @@ export class DashFieldView {
if (self._options?.length && !self._dashDoc[self._fieldKey]) {
self._dashDoc[self._fieldKey] = StrCast(self._options[0].title);
}
- // NOTE: if the field key starts with "@", then the actual field key is stored in the field 'fieldKey' (removing the @).
- self._fieldKey = self._fieldKey.startsWith("@") ? StrCast(tbox.props.Document[StrCast(self._fieldKey).substring(1)]) : self._fieldKey;
this._labelSpan.innerHTML = `${self._fieldKey}: `;
const fieldVal = Cast(this._dashDoc?.[self._fieldKey], "boolean", null);
this._fieldCheck.style.display = (fieldVal === true || fieldVal === false) ? "inline-block" : "none";
- this._fieldSpan.style.display = !(fieldVal === true || fieldVal === false) ? "inline-block" : "none";
+ this._fieldSpan.style.display = !(fieldVal === true || fieldVal === false) ? StrCast(this._dashDoc?.[self._fieldKey]) ? "" : "inline-block" : "none";
};
//Moved
@@ -463,11 +459,10 @@ export class DashFieldView {
};
this._labelSpan = document.createElement("span");
- this._labelSpan.style.backgroundColor = "rgba(155, 155, 155, 0.44)";
this._labelSpan.style.position = "relative";
- this._labelSpan.style.display = "inline-block";
this._labelSpan.style.fontSize = "small";
this._labelSpan.title = "click to see related tags";
+ this._labelSpan.style.fontSize = "x-small";
this._labelSpan.onpointerdown = function (e: any) {
e.stopPropagation();
let container = tbox.props.ContainingCollectionView;
@@ -509,7 +504,7 @@ export class DashFieldView {
this._fieldSpan.innerHTML = Field.toString(fval as Field) || "";
}
this._fieldCheck.style.display = (boolVal === true || boolVal === false) ? "inline-block" : "none";
- this._fieldSpan.style.display = !(boolVal === true || boolVal === false) ? "inline-block" : "none";
+ this._fieldSpan.style.display = !(fval === true || fval === false) ? (StrCast(fval) ? "" : "inline-block") : "none";
}, { fireImmediately: true });
//MOVED IN ORDER
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index cf04c44ca..12628273b 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -24,6 +24,8 @@ export interface ScriptError {
export type ScriptResult = ScriptSucccess | ScriptError;
+export type ScriptParam = { [name: string]: string };
+
export interface CompiledScript {
readonly compiled: true;
readonly originalScript: string;
@@ -37,6 +39,12 @@ export interface CompileError {
}
export type CompileResult = CompiledScript | CompileError;
+export function isCompileError(toBeDetermined: CompileResult): toBeDetermined is CompileError {
+ if ((toBeDetermined as CompileError).errors) {
+ return true;
+ }
+ return false;
+}
export namespace Scripting {
export function addGlobal(global: { name: string }): void;
@@ -89,9 +97,9 @@ const _scriptingGlobals: { [name: string]: any } = {};
let scriptingGlobals: { [name: string]: any } = _scriptingGlobals;
function Run(script: string | undefined, customParams: string[], diagnostics: any[], originalScript: string, options: ScriptOptions): CompileResult {
- const errors = diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error);
- if ((options.typecheck !== false && errors) || !script) {
- return { compiled: false, errors: diagnostics };
+ const errors = diagnostics.filter(diag => diag.category === ts.DiagnosticCategory.Error);
+ if ((options.typecheck !== false && errors.length) || !script) {
+ return { compiled: false, errors };
}
const paramNames = Object.keys(scriptingGlobals);
@@ -201,7 +209,7 @@ export interface ScriptOptions {
capturedVariables?: { [name: string]: Field }; // list of captured variables
typecheck?: boolean; // should the compiler perform typechecking
editable?: boolean; // can the script edit Docs
- traverser?: TraverserParam;
+ traverser?: TraverserParam;
transformer?: Transformer; // does the editor display a text label by each document that can be used as a captured document reference
globals?: { [name: string]: any };
}
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 2026bf940..6501da34a 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -44,7 +44,7 @@ export namespace SearchUtil {
const { ids, highlighting } = result;
const txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), {
- qs: { ...options, q: query },
+ qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, "") }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures
}));
const fileids = txtresult ? txtresult.ids : [];
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 6c386d684..a49977c42 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -28,21 +28,21 @@ export namespace SelectionManager {
manager.SelectedDocuments.clear();
manager.SelectedDocuments.set(docView, true);
}
- Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
+ Doc.UserDoc().activeSelection = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
}
@action
DeselectDoc(docView: DocumentView): void {
if (manager.SelectedDocuments.get(docView)) {
manager.SelectedDocuments.delete(docView);
docView.props.whenActiveChanged(false);
- Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
+ Doc.UserDoc().activeSelection = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
}
}
@action
DeselectAll(): void {
Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
manager.SelectedDocuments.clear();
- Doc.UserDoc().SelectedDocs = new List<Doc>([]);
+ Doc.UserDoc().activeSelection = new List<Doc>([]);
}
}
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 7496ac73c..3ce6de80d 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -109,7 +109,7 @@ export default class SharingManager extends React.Component<{}> {
if (isCandidate) {
const userDocument = await DocServer.GetRefField(user.userDocumentId);
if (userDocument instanceof Doc) {
- const notificationDoc = await Cast(userDocument.optionalRightCollection, Doc);
+ const notificationDoc = await Cast(userDocument.rightSidebarCollection, Doc);
runInAction(() => {
if (notificationDoc instanceof Doc) {
this.users.push({ user, notificationDoc });
diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d
index 97f6b79fb..08aec3724 100644
--- a/src/client/util/type_decls.d
+++ b/src/client/util/type_decls.d
@@ -195,7 +195,6 @@ interface DocumentOptions { }
declare const Docs: {
ImageDocument(url: string, options?: DocumentOptions): Doc;
VideoDocument(url: string, options?: DocumentOptions): Doc;
- // HistogramDocument(url:string, options?:DocumentOptions);
TextDocument(options?: DocumentOptions): Doc;
PdfDocument(url: string, options?: DocumentOptions): Doc;
WebDocument(url: string, options?: DocumentOptions): Doc;
diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx
index fba2fb5c6..f810361c6 100644
--- a/src/client/views/AntimodeMenu.tsx
+++ b/src/client/views/AntimodeMenu.tsx
@@ -16,7 +16,8 @@ export default abstract class AntimodeMenu extends React.Component {
@observable protected _top: number = -300;
@observable protected _left: number = -300;
@observable protected _opacity: number = 1;
- @observable protected _transition: string = "opacity 0.5s";
+ @observable protected _transitionProperty: string = "opacity";
+ @observable protected _transitionDuration: string = "0.5s";
@observable protected _transitionDelay: string = "";
@observable protected _canFade: boolean = true;
@@ -34,7 +35,7 @@ export default abstract class AntimodeMenu extends React.Component {
*/
public jumpTo = (x: number, y: number, forceJump: boolean = false) => {
if (!this.Pinned || forceJump) {
- this._transition = this._transitionDelay = "";
+ this._transitionProperty = this._transitionDuration = this._transitionDelay = "";
this._opacity = 1;
this._left = x;
this._top = y;
@@ -49,14 +50,16 @@ export default abstract class AntimodeMenu extends React.Component {
public fadeOut = (forceOut: boolean) => {
if (!this.Pinned) {
if (this._opacity === 0.2) {
- this._transition = "opacity 0.1s";
+ this._transitionProperty = "opacity";
+ this._transitionDuration = "0.1s";
this._transitionDelay = "";
this._opacity = 0;
this._left = this._top = -300;
}
if (forceOut) {
- this._transition = "";
+ this._transitionProperty = "";
+ this._transitionDuration = "";
this._transitionDelay = "";
this._opacity = 0;
this._left = this._top = -300;
@@ -67,7 +70,8 @@ export default abstract class AntimodeMenu extends React.Component {
@action
protected pointerLeave = (e: React.PointerEvent) => {
if (!this.Pinned && this._canFade) {
- this._transition = "opacity 0.5s";
+ this._transitionProperty = "opacity";
+ this._transitionDuration = "0.5s";
this._transitionDelay = "1s";
this._opacity = 0.2;
setTimeout(() => this.fadeOut(false), 3000);
@@ -76,7 +80,8 @@ export default abstract class AntimodeMenu extends React.Component {
@action
protected pointerEntered = (e: React.PointerEvent) => {
- this._transition = "opacity 0.1s";
+ this._transitionProperty = "opacity";
+ this._transitionDuration = "0.1s";
this._transitionDelay = "";
this._opacity = 1;
}
@@ -133,7 +138,7 @@ export default abstract class AntimodeMenu extends React.Component {
protected getElement(buttons: JSX.Element[]) {
return (
<div className="antimodeMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
- style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}>
+ style={{ left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay }}>
{buttons}
<div className="antimodeMenu-dragger" onPointerDown={this.dragStart} style={{ width: this.Pinned ? "20px" : "0px" }} />
</div>
@@ -143,7 +148,7 @@ export default abstract class AntimodeMenu extends React.Component {
protected getElementWithRows(rows: JSX.Element[], numRows: number, hasDragger: boolean = true) {
return (
<div className="antimodeMenu-cont with-rows" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
- style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay, height: "auto" }}>
+ style={{ left: this._left, top: this._top, opacity: this._opacity, transitionProperty: this._transitionProperty, transitionDuration: this._transitionDuration, transitionDelay: this._transitionDelay, height: "auto" }}>
{rows}
{hasDragger ? <div className="antimodeMenu-dragger" onPointerDown={this.dragStart} style={{ width: this.Pinned ? "20px" : "0px" }} /> : <></>}
</div>
diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 8f112de0c..30938688d 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -61,6 +61,42 @@
letter-spacing: 2px;
text-transform: uppercase;
padding-right: 30px;
+
+ .icon-background {
+ pointer-events: all;
+ background-color: transparent;
+ width: 35px;
+ text-align: center;
+ font-size: 20px;
+ margin-left: 5px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ height: 20px;
+ }
+}
+.contextMenu-description {
+ // width: 11vw; //10vw
+ background: whitesmoke;
+ display: flex; //comment out to allow search icon to be inline with search text
+ justify-content: left;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ transition: all .1s;
+ border-style: none;
+ // padding: 10px 0px 10px 0px;
+ white-space: nowrap;
+ font-size: 13px;
+ color: grey;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ padding-right: 30px;
+ margin-top: 5px;
+ height: 20px;
+ margin-bottom: 5px;
}
.contextMenu-item:hover {
@@ -121,15 +157,4 @@
padding-left: 10px;
border: solid black 1px;
border-radius: 5px;
-}
-
-.icon-background {
- pointer-events: all;
- height:100%;
- margin-top: 15px;
- background-color: transparent;
- width: 35px;
- text-align: center;
- font-size: 20px;
- margin-left: 5px;
} \ No newline at end of file
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 4d04d4e89..5b66b63ed 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -99,6 +99,15 @@ export class ContextMenu extends React.Component {
}
}
@action
+ moveAfter(item: ContextMenuProps, after: ContextMenuProps) {
+ if (this.findByDescription(after.description)) {
+ const curInd = this._items.findIndex((i) => i.description === item.description);
+ this._items.splice(curInd, 1);
+ const afterInd = this._items.findIndex((i) => i.description === after.description);
+ this._items.splice(afterInd + 1, 0, item);
+ }
+ }
+ @action
setDefaultItem(prefix: string, item: (name: string) => void) {
this._defaultPrefix = prefix;
this._defaultItem = item;
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index fef9e5f60..99840047f 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -51,7 +51,8 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
currentTimeout?: any;
static readonly timeout = 300;
- onPointerEnter = () => {
+ _overPosY = 0;
+ onPointerEnter = (e: React.MouseEvent) => {
if (this.currentTimeout) {
clearTimeout(this.currentTimeout);
this.currentTimeout = undefined;
@@ -59,6 +60,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
if (this.overItem) {
return;
}
+ this._overPosY = e.clientY;
this.currentTimeout = setTimeout(action(() => this.overItem = true), ContextMenuItem.timeout);
}
@@ -88,18 +90,22 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
</div>
);
} else if ("subitems" in this.props) {
+ const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center";
+ const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : "";
const submenu = !this.overItem ? (null) :
- <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px" }}>
+ <div className="contextMenu-subMenu-cont" style={{ marginLeft: "25%", left: "0px", marginTop }}>
{this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
</div>;
return (
- <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} onMouseLeave={this.onPointerLeave} onMouseEnter={this.onPointerEnter}>
+ <div className={"contextMenu-item" + (this.props.selected ? " contextMenu-itemSelected" : "")} style={{ alignItems: where }}
+ onMouseLeave={this.onPointerLeave} onMouseEnter={this.onPointerEnter}>
{this.props.icon ? (
- <span className="icon-background" onMouseEnter={this.onPointerLeave}>
+ <span className="icon-background" onMouseEnter={this.onPointerLeave} style={{ alignItems: "center" }}>
<FontAwesomeIcon icon={this.props.icon} size="sm" />
</span>
) : null}
- <div className="contextMenu-description" onMouseEnter={this.onPointerEnter} >
+ <div className="contextMenu-description" onMouseEnter={this.onPointerEnter}
+ style={{ alignItems: "center" }} >
{this.props.description}
<FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "10px" }} />
</div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 21eec66be..0a8f0c9a7 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,15 +1,14 @@
import { Doc, Opt, DataSym } from '../../new_fields/Doc';
import { Touchable } from './Touchable';
import { computed, action, observable } from 'mobx';
-import { Cast } from '../../new_fields/Types';
+import { Cast, BoolCast } from '../../new_fields/Types';
import { listSpec } from '../../new_fields/Schema';
import { InkingControl } from './InkingControl';
import { InkTool } from '../../new_fields/InkField';
-import { PositionDocument } from '../../new_fields/documentSchemas';
import { InteractionUtils } from '../util/InteractionUtils';
-/// DocComponent returns a generic React base class used by views that don't have any data extensions (e.g.,CollectionFreeFormDocumentView, DocumentView, ButtonBox)
+/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
interface DocComponentProps {
Document: Doc;
LayoutDoc?: () => Opt<Doc>;
@@ -18,14 +17,20 @@ export function DocComponent<P extends DocComponentProps, T>(schemaCtor: (doc: D
class Component extends Touchable<P> {
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
@computed get Document(): T { return schemaCtor(this.props.Document); }
- @computed get layoutDoc() { return PositionDocument(Doc.Layout(this.props.Document, this.props.LayoutDoc?.())); }
+ // This is the "The Document" -- it encapsulates, data, layout, and any templates
+ @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
+ @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
+ // This is the data part of a document -- ie, the data that is constant across all views of the document
+ @computed get dataDoc() { return this.props.Document[DataSym] as Doc; }
+
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
}
return Component;
}
-/// DocStaticProps return a base class for React document views that have data extensions but aren't annotatable (e.g. AudioBox, FormattedTextBox)
-interface DocExtendableProps {
+/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. AudioBox, FormattedTextBox)
+interface ViewBoxBaseProps {
Document: Doc;
DataDoc?: Doc;
fieldKey: string;
@@ -33,21 +38,30 @@ interface DocExtendableProps {
renderDepth: number;
rootSelected: (outsideReaction?: boolean) => boolean;
}
-export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCtor: (doc: Doc) => T) {
+export function ViewBoxBaseComponent<P extends ViewBoxBaseProps, T>(schemaCtor: (doc: Doc) => T) {
class Component extends Touchable<P> {
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
- @computed get Document(): T { return schemaCtor(this.props.Document); }
+ //@computed get Document(): T { return schemaCtor(this.props.Document); }
+
+ // This is the "The Document" -- it encapsulates, data, layout, and any templates
+ @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
@computed get layoutDoc() { return Doc.Layout(this.props.Document); }
- @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
- active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools
+ // This is the data part of a document -- ie, the data that is constant across all views of the document
+ @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
+
+ // key where data is stored
+ @computed get fieldKey() { return this.props.fieldKey; }
+
+ active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0 || this.layoutDoc.forceActive);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
}
return Component;
}
-/// DocAnnotatbleComponent return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image)
-export interface DocAnnotatableProps {
+/// DocAnnotatbleComponent -return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image)
+export interface ViewBoxAnnotatableProps {
Document: Doc;
DataDoc?: Doc;
fieldKey: string;
@@ -57,14 +71,22 @@ export interface DocAnnotatableProps {
rootSelected: (outsideReaction?: boolean) => boolean;
renderDepth: number;
}
-export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
+export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
class Component extends Touchable<P> {
@observable _isChildActive = false;
//TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
@computed get Document(): T { return schemaCtor(this.props.Document); }
- @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
+
+ // This is the "The Document" -- it encapsulates, data, layout, and any templates
+ @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
+ @computed get layoutDoc() { return schemaCtor(Doc.Layout(this.props.Document)); }
+ // This is the data part of a document -- ie, the data that is constant across all views of the document
@computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
+ // key where data is stored
+ @computed get fieldKey() { return this.props.fieldKey; }
+
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
_annotationKey: string = "annotations";
@@ -86,14 +108,14 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
}
@action.bound
addDocument(doc: Doc): boolean {
- Doc.GetProto(doc).annotationOn = this.props.Document;
+ doc.context = Doc.GetProto(doc).annotationOn = this.props.Document;
return Doc.AddDocToList(this.dataDoc, this.props.fieldKey + "-" + this._annotationKey, doc) ? true : false;
}
whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
- ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
- annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None ||
+ (this.props.rootSelected(outsideReaction) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0 || BoolCast((this.layoutDoc as any).forceActive)) ? true : false)
+ annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None || (this.props.Document.isBackground && this.props.active()) ||
(this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
}
return Component;
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index b95cc6627..c02f79187 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -6,7 +6,7 @@ import { observer } from "mobx-react";
import { Doc, DocListCast } from "../../new_fields/Doc";
import { RichTextField } from '../../new_fields/RichTextField';
import { NumCast, StrCast } from "../../new_fields/Types";
-import { emptyFunction } from "../../Utils";
+import { emptyFunction, setupMoveUpEvents } from "../../Utils";
import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
import { UndoManager } from "../util/UndoManager";
import { CollectionDockingView, DockedFrameRenderer } from './collections/CollectionDockingView';
@@ -21,7 +21,6 @@ import { Template, Templates } from "./Templates";
import React = require("react");
import { DragManager } from '../util/DragManager';
import { MetadataEntryMenu } from './MetadataEntryMenu';
-import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
@@ -109,16 +108,19 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
get view0() { return this.props.views?.[0]; }
@action
- onLinkButtonMoved = (e: PointerEvent): void => {
- if (this._linkButton.current !== null && (Math.abs(e.clientX - this._downX) > 3 || Math.abs(e.clientY - this._downY) > 3)) {
- document.removeEventListener("pointermove", this.onLinkButtonMoved);
- document.removeEventListener("pointerup", this.onLinkButtonUp);
+ onLinkButtonMoved = (e: PointerEvent) => {
+ if (this._linkButton.current !== null) {
const linkDrag = UndoManager.StartBatch("Drag Link");
this.view0 && DragManager.StartLinkDrag(this._linkButton.current, this.view0.props.Document, e.pageX, e.pageY, {
dragComplete: dropEv => {
const linkDoc = dropEv.linkDragData?.linkDocument as Doc; // equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop
if (this.view0 && linkDoc) {
Doc.GetProto(linkDoc).linkRelationship = "hyperlink";
+
+ // we want to allow specific views to handle the link creation in their own way (e.g., rich text makes text hyperlinks)
+ // the dragged view can regiser a linkDropCallback to be notified that the link was made and to update their data structures
+ // however, the dropped document isn't so accessible. What we do is set the newly created link document on the documentView
+ // The documentView passes a function prop returning this link doc to its descendants who can react to changes to it.
dropEv.linkDragData?.linkDropCallback?.(dropEv.linkDragData);
runInAction(() => this.view0!._link = linkDoc);
setTimeout(action(() => this.view0!._link = undefined), 0);
@@ -127,26 +129,16 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
},
hideSource: false
});
+ return true;
}
- e.stopPropagation();
+ return false;
}
onLinkButtonDown = (e: React.PointerEvent): void => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- document.removeEventListener("pointermove", this.onLinkButtonMoved);
- document.addEventListener("pointermove", this.onLinkButtonMoved);
- document.removeEventListener("pointerup", this.onLinkButtonUp);
- document.addEventListener("pointerup", this.onLinkButtonUp);
- e.stopPropagation();
+ setupMoveUpEvents(this, e, this.onLinkButtonMoved, emptyFunction, emptyFunction);
}
- onLinkButtonUp = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.onLinkButtonMoved);
- document.removeEventListener("pointerup", this.onLinkButtonUp);
- e.stopPropagation();
- }
@computed
get considerGoogleDocsPush() {
@@ -197,9 +189,9 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
@computed
get pinButton() {
const targetDoc = this.view0?.props.Document;
- const isPinned = targetDoc && CurrentUserUtils.IsDocPinned(targetDoc);
+ const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
return !targetDoc ? (null) : <div className="documentButtonBar-linker"
- title={CurrentUserUtils.IsDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}
+ title={Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}
style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }}
onClick={e => {
@@ -253,29 +245,12 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
}} />;
}
- private _downx = 0;
- private _downy = 0;
- onAliasButtonUp = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.onAliasButtonMoved);
- document.removeEventListener("pointerup", this.onAliasButtonUp);
- e.stopPropagation();
- }
-
+ @observable _aliasDown = false;
onAliasButtonDown = (e: React.PointerEvent): void => {
- this._downx = e.clientX;
- this._downy = e.clientY;
- e.stopPropagation();
- e.preventDefault();
- document.removeEventListener("pointermove", this.onAliasButtonMoved);
- document.addEventListener("pointermove", this.onAliasButtonMoved);
- document.removeEventListener("pointerup", this.onAliasButtonUp);
- document.addEventListener("pointerup", this.onAliasButtonUp);
+ setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
}
- onAliasButtonMoved = (e: PointerEvent): void => {
- if (this._dragRef.current !== null && (Math.abs(e.clientX - this._downx) > 4 || Math.abs(e.clientY - this._downy) > 4)) {
- document.removeEventListener("pointermove", this.onAliasButtonMoved);
- document.removeEventListener("pointerup", this.onAliasButtonUp);
-
+ onAliasButtonMoved = () => {
+ if (this._dragRef.current) {
const dragDocView = this.props.views[0]!;
const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]);
const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
@@ -286,8 +261,9 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
offsetY: dragData.offset[1],
hideSource: false
});
+ return true;
}
- e.stopPropagation();
+ return false;
}
@computed
@@ -297,9 +273,9 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
Array.from(Object.values(Templates.TemplateList)).map(template =>
templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
return !view0 ? (null) : <div title="Tap: Customize layout. Drag: Create alias" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
- <Flyout anchorPoint={anchorPoints.LEFT_TOP}
- content={<TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
- <div className={"documentButtonBar-linkButton-" + "empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} >
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} onOpen={action(() => this._aliasDown = true)} onClose={action(() => this._aliasDown = false)}
+ content={!this._aliasDown ? (null) : <TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
+ <div className={"documentButtonBar-linkButton-empty"} ref={this._dragRef} onPointerDown={this.onAliasButtonDown} >
{<FontAwesomeIcon className="documentdecorations-icon" icon="edit" size="sm" />}
</div>
</Flyout>
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 353520026..28cf9fd47 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -143,7 +143,6 @@ $linkGap : 3px;
pointer-events: all;
text-align: center;
cursor: pointer;
- padding-right: 10px;
}
.documentDecorations-minimizeButton {
@@ -157,7 +156,6 @@ $linkGap : 3px;
position: absolute;
left: 0px;
top: 0px;
- padding-top: 5px;
width: $MINIMIZED_ICON_SIZE;
height: $MINIMIZED_ICON_SIZE;
max-height: 20px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e313b117f..312acd5b2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -3,12 +3,11 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faT
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DataSym } from "../../new_fields/Doc";
+import { Doc, DataSym, Field } from "../../new_fields/Doc";
import { PositionDocument } from '../../new_fields/documentSchemas';
import { ScriptField } from '../../new_fields/ScriptField';
import { Cast, StrCast, NumCast } from "../../new_fields/Types";
-import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
-import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
+import { Utils, setupMoveUpEvents, emptyFunction, returnFalse, simulateMouseClick } from "../../Utils";
import { DocUtils } from "../documents/Documents";
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from "../util/DragManager";
@@ -20,6 +19,7 @@ import { DocumentView } from "./nodes/DocumentView";
import React = require("react");
import { Id } from '../../new_fields/FieldSymbols';
import e = require('express');
+import { CollectionDockingView } from './collections/CollectionDockingView';
library.add(faCaretUp);
library.add(faObjectGroup);
@@ -37,8 +37,6 @@ library.add(faCloudUploadAlt);
library.add(faSyncAlt);
library.add(faShare);
-export type CloseCall = (toBeDeleted: DocumentView[]) => void;
-
@observer
export class DocumentDecorations extends React.Component<{}, { value: string }> {
static Instance: DocumentDecorations;
@@ -52,7 +50,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@observable private _titleControlString: string = "#title";
@observable private _edtingTitle = false;
@observable private _hidden = false;
- @observable private _addedCloseCalls: CloseCall[] = [];
@observable public Interacting = false;
@observable public pushIcon: IconProp = "arrow-alt-circle-up";
@@ -69,14 +66,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
get Bounds(): { x: number, y: number, b: number, r: number } {
return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
if (documentView.props.renderDepth === 0 ||
- Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
+ Doc.AreProtosEqual(documentView.props.Document, Doc.UserDoc())) {
return bounds;
}
const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
var [sptX, sptY] = transform.transformPoint(0, 0);
let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
if (documentView.props.Document.type === DocumentType.LINK) {
- const docuBox = documentView.ContentDiv!.getElementsByClassName("docuLinkBox-cont");
+ const docuBox = documentView.ContentDiv!.getElementsByClassName("linkAnchorBox-cont");
if (docuBox.length) {
const rect = docuBox[0].getBoundingClientRect();
sptX = rect.left;
@@ -92,14 +89,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
}
- addCloseCall = (handler: CloseCall) => {
- const currentOffset = this._addedCloseCalls.length - 1;
- this._addedCloseCalls.push((toBeDeleted: DocumentView[]) => {
- this._addedCloseCalls.splice(currentOffset, 1);
- handler(toBeDeleted);
- });
- }
-
titleBlur = action((commit: boolean) => {
this._edtingTitle = false;
if (commit) {
@@ -142,40 +131,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@action onSettingsDown = (e: React.PointerEvent): void => {
setupMoveUpEvents(this, e, () => false, (e) => { }, this.onSettingsClick);
}
-
- simulateMouseClick(element: Element, x: number, y: number, sx: number, sy: number) {
- ["pointerdown", "pointerup"].map(event => element.dispatchEvent(
- new PointerEvent(event, {
- view: window,
- bubbles: true,
- cancelable: true,
- button: 2,
- pointerType: "mouse",
- clientX: x,
- clientY: y,
- screenX: sx,
- screenY: sy,
- })));
-
- element.dispatchEvent(
- new MouseEvent("contextmenu", {
- view: window,
- bubbles: true,
- cancelable: true,
- button: 2,
- clientX: x,
- clientY: y,
- movementX: 0,
- movementY: 0,
- screenX: sx,
- screenY: sy,
- }));
- }
@action onSettingsClick = (e: PointerEvent): void => {
if (e.button === 0 && !e.altKey && !e.ctrlKey) {
let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0];
- while (child.children.length && child.className !== "jsx-parser") child = child.children[0];
- this.simulateMouseClick(child.children[0], e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ while (child.children.length) {
+ const next = Array.from(child.children).find(c => !c.className.includes("collectionViewChrome"));
+ if (next?.className.includes("documentView-node")) break;
+ if (next) child = next;
+ else break;
+ }
+ simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
}
}
@@ -193,52 +158,51 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
dragData.isSelectionMove = true;
this.Interacting = true;
this._hidden = true;
- DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(documentView => documentView.ContentDiv!), dragData, e.x, e.y, {
+ DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(dv => dv.ContentDiv!), dragData, e.x, e.y, {
dragComplete: action(e => this._hidden = this.Interacting = false),
hideSource: true
});
return true;
}
- onCloseDown = (e: React.PointerEvent): void => {
- setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onCloseClick);
+ onIconifyDown = (e: React.PointerEvent): void => {
+ setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onIconifyClick);
}
@undoBatch
@action
onCloseClick = async (e: PointerEvent) => {
if (e.button === 0) {
- const recent = Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc) as Doc;
+ const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
SelectionManager.DeselectAll();
- this._addedCloseCalls.forEach(handler => handler(selected));
selected.map(dv => {
recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
- dv.props.removeDocument && dv.props.removeDocument(dv.props.Document);
+ dv.props.removeDocument?.(dv.props.Document);
});
}
}
@action
- onMinimizeDown = (e: React.PointerEvent): void => {
- setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMinimizeClick);
+ onMaximizeDown = (e: React.PointerEvent): void => {
+ setupMoveUpEvents(this, e, (e, d) => false, (e) => { }, this.onMaximizeClick);
}
@undoBatch
@action
- onMinimizeClick = (e: PointerEvent): void => {
+ onMaximizeClick = (e: PointerEvent): void => {
if (e.button === 0) {
- const selectedDocs = SelectionManager.SelectedDocuments().map(sd => sd);
- selectedDocs.map(dv => {
- const layoutKey = Cast(dv.props.Document.layoutKey, "string", null);
- const collapse = layoutKey !== "layout_icon";
- if (collapse) {
- dv.switchViews(collapse, "icon");
- if (layoutKey && layoutKey !== "layout") dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", "");
- } else {
- const deiconifyLayout = Cast(dv.props.Document.deiconifyLayout, "string", null);
- dv.switchViews(deiconifyLayout ? true : false, deiconifyLayout);
- dv.props.Document.deiconifyLayout = undefined;
- }
- });
+ const selectedDocs = SelectionManager.SelectedDocuments();
+ if (selectedDocs.length) {
+ //CollectionDockingView.Instance?.OpenFullScreen(selectedDocs[0], selectedDocs[0].props.LibraryPath);
+ CollectionDockingView.AddRightSplit(Doc.MakeAlias(selectedDocs[0].props.Document), selectedDocs[0].props.LibraryPath);
+ }
+ }
+ SelectionManager.DeselectAll();
+ }
+ @undoBatch
+ @action
+ onIconifyClick = (e: PointerEvent): void => {
+ if (e.button === 0) {
+ SelectionManager.SelectedDocuments().forEach(dv => dv?.iconify());
}
SelectionManager.DeselectAll();
}
@@ -393,10 +357,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (SelectionManager.SelectedDocuments().length === 1) {
const selected = SelectionManager.SelectedDocuments()[0];
if (this._titleControlString.startsWith("=")) {
- return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ this: selected.props.Document }, console.log).result?.toString() || "";
+ return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || "";
}
if (this._titleControlString.startsWith("#")) {
- return selected.props.Document[this._titleControlString.substring(1)]?.toString() || "-unset-";
+ return Field.toString(selected.props.Document[this._titleControlString.substring(1)] as Field) || "-unset-";
}
return this._accumulatedTitle;
} else if (SelectionManager.SelectedDocuments().length > 1) {
@@ -428,13 +392,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
return (null);
}
const minimal = bounds.r - bounds.x < 100 ? true : false;
- const minimizeIcon = minimal ? (
+ const maximizeIcon = minimal ? (
<div className="documentDecorations-contextMenu" title="Show context menu" onPointerDown={this.onSettingsDown}>
<FontAwesomeIcon size="lg" icon="cog" />
</div>) : (
- <div className="documentDecorations-minimizeButton" title="Iconify" onPointerDown={this.onMinimizeDown}>
+ <div className="documentDecorations-minimizeButton" title="Iconify" onPointerDown={this.onIconifyDown}>
{/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
- {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
+ <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
</div>);
const titleArea = this._edtingTitle ?
@@ -487,10 +451,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
}}>
- {minimizeIcon}
+ {maximizeIcon}
{titleArea}
- <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>
- <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
+ <div className="documentDecorations-closeButton" title="Open Document in Tab" onPointerDown={this.onMaximizeDown}>
+ {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
</div>
<div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer"
onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 2219966e5..c51173ad3 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -46,7 +46,6 @@ export interface EditableProps {
menuCallback?: (x: number, y: number) => void;
showMenuOnLoad?: boolean;
HeadingObject?: SchemaHeaderField | undefined;
- HeadingsHack?: number;
toggle?: () => void;
color?: string | undefined;
}
@@ -60,7 +59,6 @@ export interface EditableProps {
export class EditableView extends React.Component<EditableProps> {
public static loadId = "";
@observable _editing: boolean = false;
- @observable _headingsHack: number = 1;
constructor(props: EditableProps) {
super(props);
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 69aa8dbaa..1977f2406 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -82,6 +82,9 @@ export default class GestureOverlay extends Touchable {
this._inkToTextDoc = FieldValue(Cast(this._thumbDoc?.inkToTextDoc, Doc));
}
+ /**
+ * Ignores all touch events that belong to a hand being held down.
+ */
getNewTouches(e: React.TouchEvent | TouchEvent) {
const ntt: (React.Touch | Touch)[] = Array.from(e.targetTouches);
const nct: (React.Touch | Touch)[] = Array.from(e.changedTouches);
@@ -121,6 +124,8 @@ export default class GestureOverlay extends Touchable {
return;
}
+ // this chunk adds new touch targets to a map of pointer events; this helps us keep track of individual fingers
+ // so that we can know, for example, if two fingers are pinching out or in.
const actualPts: React.Touch[] = [];
for (let i = 0; i < te.touches.length; i++) {
const pt: any = te.touches.item(i);
@@ -128,9 +133,6 @@ export default class GestureOverlay extends Touchable {
// pen is also a touch, but with a radius of 0.5 (at least with the surface pens)
// and this seems to be the only way of differentiating pen and touch on touch events
if (pt.radiusX > 1 && pt.radiusY > 1) {
- // if (typeof pt.identifier !== "string") {
- // pt.identifier = Utils.GenerateGuid();
- // }
this.prevPoints.set(pt.identifier, pt);
}
}
@@ -144,6 +146,7 @@ export default class GestureOverlay extends Touchable {
ptsToDelete.forEach(pt => this.prevPoints.delete(pt));
const nts = this.getNewTouches(te);
+ // if there are fewer than five touch events, handle as a touch event
if (nts.nt.length < 5) {
const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
target?.dispatchEvent(
@@ -161,7 +164,7 @@ export default class GestureOverlay extends Touchable {
)
);
if (nts.nt.length === 1) {
- console.log("started");
+ // -- radial menu code --
this._holdTimer = setTimeout(() => {
console.log("hold");
const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
@@ -200,6 +203,7 @@ export default class GestureOverlay extends Touchable {
document.addEventListener("touchmove", this.onReactTouchMove);
document.addEventListener("touchend", this.onReactTouchEnd);
}
+ // otherwise, handle as a hand event
else {
this.handleHandDown(te);
document.removeEventListener("touchmove", this.onReactTouchMove);
@@ -207,67 +211,6 @@ export default class GestureOverlay extends Touchable {
}
}
- onReactHoldTouchMove = (e: TouchEvent) => {
- document.removeEventListener("touchmove", this.onReactTouchMove);
- document.removeEventListener("touchend", this.onReactTouchEnd);
- document.removeEventListener("touchmove", this.onReactHoldTouchMove);
- document.removeEventListener("touchend", this.onReactHoldTouchEnd);
- document.addEventListener("touchmove", this.onReactHoldTouchMove);
- document.addEventListener("touchend", this.onReactHoldTouchEnd);
- const nts: any = this.getNewTouches(e);
- if (this.prevPoints.size === 1 && this._holdTimer) {
- clearTimeout(this._holdTimer);
- }
- document.dispatchEvent(
- new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchHoldMove",
- {
- bubbles: true,
- detail: {
- fingers: this.prevPoints.size,
- targetTouches: nts.ntt,
- touches: nts.nt,
- changedTouches: nts.nct,
- touchEvent: e
- }
- })
- );
- }
-
- onReactHoldTouchEnd = (e: TouchEvent) => {
- const nts: any = this.getNewTouches(e);
- if (this.prevPoints.size === 1 && this._holdTimer) {
- clearTimeout(this._holdTimer);
- this._holdTimer = undefined;
- }
- document.dispatchEvent(
- new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchHoldEnd",
- {
- bubbles: true,
- detail: {
- fingers: this.prevPoints.size,
- targetTouches: nts.ntt,
- touches: nts.nt,
- changedTouches: nts.nct,
- touchEvent: e
- }
- })
- );
- for (let i = 0; i < e.changedTouches.length; i++) {
- const pt = e.changedTouches.item(i);
- if (pt) {
- if (this.prevPoints.has(pt.identifier)) {
- this.prevPoints.delete(pt.identifier);
- }
- }
- }
-
- document.removeEventListener("touchmove", this.onReactHoldTouchMove);
- document.removeEventListener("touchend", this.onReactHoldTouchEnd);
-
- e.stopPropagation();
- }
-
-
onReactTouchMove = (e: TouchEvent) => {
const nts: any = this.getNewTouches(e);
this._holdTimer && clearTimeout(this._holdTimer);
@@ -306,6 +249,8 @@ export default class GestureOverlay extends Touchable {
}
})
);
+
+ // cleanup any lingering pointers
for (let i = 0; i < e.changedTouches.length; i++) {
const pt = e.changedTouches.item(i);
if (pt) {
@@ -324,6 +269,10 @@ export default class GestureOverlay extends Touchable {
handleHandDown = async (e: React.TouchEvent) => {
this._holdTimer && clearTimeout(this._holdTimer);
+
+ // this chunk of code helps us keep track of which touch events are associated with a hand event
+ // so that if a hand is held down, but a second hand is interacting with dash, the second hand's events
+ // won't interfere with the first hand's events.
const fingers = new Array<React.Touch>();
for (let i = 0; i < e.touches.length; i++) {
const pt: any = e.touches.item(i);
@@ -338,6 +287,8 @@ export default class GestureOverlay extends Touchable {
}
}
}
+
+ // this chunk of code determines whether this is a left hand or a right hand, as well as which pointer is the thumb and pointer
const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
const rightMost = Math.max(...fingers.map(f => f.clientX));
const leftMost = Math.min(...fingers.map(f => f.clientX));
@@ -354,6 +305,7 @@ export default class GestureOverlay extends Touchable {
console.log("not hand");
}
this.pointerIdentifier = pointer?.identifier;
+
runInAction(() => {
this._pointerY = pointer?.clientY;
if (thumb.identifier === this.thumbIdentifier) {
@@ -370,6 +322,7 @@ export default class GestureOverlay extends Touchable {
const minX = Math.min(...others.map(f => f.clientX));
const minY = Math.min(...others.map(f => f.clientY));
+ // load up the palette collection around the thumb
const thumbDoc = await Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc);
if (thumbDoc) {
runInAction(() => {
@@ -393,6 +346,7 @@ export default class GestureOverlay extends Touchable {
@action
handleHandMove = (e: TouchEvent) => {
+ // update pointer trackers
const fingers = new Array<React.Touch>();
for (let i = 0; i < e.touches.length; i++) {
const pt: any = e.touches.item(i);
@@ -411,15 +365,19 @@ export default class GestureOverlay extends Touchable {
}
}
}
+ // update hand trackers
const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
if (thumb?.identifier && thumb?.identifier === this.thumbIdentifier) {
this._hands.set(thumb.identifier, fingers);
}
+ // loop through every changed pointer
for (let i = 0; i < e.changedTouches.length; i++) {
const pt = e.changedTouches.item(i);
+ // if the thumb was moved
if (pt && pt.identifier === this.thumbIdentifier && this._thumbY) {
if (this._thumbX && this._thumbY) {
+ // moving a thumb horiz. changes the palette collection selection, moving vert. changes the selection of any menus on the current palette item
const yOverX = Math.abs(pt.clientX - this._thumbX) < Math.abs(pt.clientY - this._thumbY);
if ((yOverX && this._inkToTextDoc) || this._selectedIndex > -1) {
if (Math.abs(pt.clientY - this._thumbY) > (10 * window.devicePixelRatio)) {
@@ -433,19 +391,8 @@ export default class GestureOverlay extends Touchable {
}
}
}
-
- // if (this._thumbX && this._thumbDoc) {
- // if (Math.abs(pt.clientX - this._thumbX) > 30) {
- // this._thumbDoc.selectedIndex = Math.max(0, NumCast(this._thumbDoc.selectedIndex) - Math.sign(pt.clientX - this._thumbX));
- // this._thumbX = pt.clientX;
- // }
- // }
- // if (this._thumbY && this._inkToTextDoc) {
- // if (Math.abs(pt.clientY - this._thumbY) > 20) {
- // this._selectedIndex = Math.min(Math.max(0, -Math.ceil((pt.clientY - this._thumbY) / 20)), this._possibilities.length - 1);
- // }
- // }
}
+ // if the pointer finger was moved
if (pt && pt.identifier === this.pointerIdentifier) {
this._pointerY = pt.clientY;
}
@@ -454,27 +401,31 @@ export default class GestureOverlay extends Touchable {
@action
handleHandUp = (e: TouchEvent) => {
+ // sometimes, users may lift up their thumb or index finger if they can't stretch far enough to scroll an entire menu,
+ // so we don't want to just remove the palette when that happens
if (e.touches.length < 3) {
- // this.onTouchEnd(e);
if (this.thumbIdentifier) this._hands.delete(this.thumbIdentifier);
this._palette = undefined;
this.thumbIdentifier = undefined;
this._thumbDoc = undefined;
+ // this chunk of code is for handling the ink to text toolglass
let scriptWorked = false;
if (NumCast(this._inkToTextDoc?.selectedIndex) > -1) {
+ // if there is a text option selected, activate it
const selectedButton = this._possibilities[this._selectedIndex];
if (selectedButton) {
selectedButton.props.onClick();
scriptWorked = true;
}
}
-
+ // if there isn't a text option selected, dry the ink strokes into ink documents
if (!scriptWorked) {
this._strokes.forEach(s => {
this.dispatchGesture(GestureUtils.Gestures.Stroke, s);
});
}
+
this._strokes = [];
this._points = [];
this._possibilities = [];
@@ -482,6 +433,72 @@ export default class GestureOverlay extends Touchable {
}
}
+ /**
+ * Code for radial menu
+ */
+ onReactHoldTouchMove = (e: TouchEvent) => {
+ document.removeEventListener("touchmove", this.onReactTouchMove);
+ document.removeEventListener("touchend", this.onReactTouchEnd);
+ document.removeEventListener("touchmove", this.onReactHoldTouchMove);
+ document.removeEventListener("touchend", this.onReactHoldTouchEnd);
+ document.addEventListener("touchmove", this.onReactHoldTouchMove);
+ document.addEventListener("touchend", this.onReactHoldTouchEnd);
+ const nts: any = this.getNewTouches(e);
+ if (this.prevPoints.size === 1 && this._holdTimer) {
+ clearTimeout(this._holdTimer);
+ }
+ document.dispatchEvent(
+ new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchHoldMove",
+ {
+ bubbles: true,
+ detail: {
+ fingers: this.prevPoints.size,
+ targetTouches: nts.ntt,
+ touches: nts.nt,
+ changedTouches: nts.nct,
+ touchEvent: e
+ }
+ })
+ );
+ }
+
+ /**
+ * Code for radial menu
+ */
+ onReactHoldTouchEnd = (e: TouchEvent) => {
+ const nts: any = this.getNewTouches(e);
+ if (this.prevPoints.size === 1 && this._holdTimer) {
+ clearTimeout(this._holdTimer);
+ this._holdTimer = undefined;
+ }
+ document.dispatchEvent(
+ new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchHoldEnd",
+ {
+ bubbles: true,
+ detail: {
+ fingers: this.prevPoints.size,
+ targetTouches: nts.ntt,
+ touches: nts.nt,
+ changedTouches: nts.nct,
+ touchEvent: e
+ }
+ })
+ );
+ for (let i = 0; i < e.changedTouches.length; i++) {
+ const pt = e.changedTouches.item(i);
+ if (pt) {
+ if (this.prevPoints.has(pt.identifier)) {
+ this.prevPoints.delete(pt.identifier);
+ }
+ }
+ }
+
+ document.removeEventListener("touchmove", this.onReactHoldTouchMove);
+ document.removeEventListener("touchend", this.onReactHoldTouchEnd);
+
+ e.stopPropagation();
+ }
+
@action
onPointerDown = (e: React.PointerEvent) => {
if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) {
@@ -524,22 +541,28 @@ export default class GestureOverlay extends Touchable {
handleLineGesture = (): boolean => {
let actionPerformed = false;
const B = this.svgBounds;
+
+ // get the two targets at the ends of the line
const ep1 = this._points[0];
const ep2 = this._points[this._points.length - 1];
-
const target1 = document.elementFromPoint(ep1.X, ep1.Y);
const target2 = document.elementFromPoint(ep2.X, ep2.Y);
+
+ // callback function to be called by each target
const callback = (doc: Doc) => {
if (!this._d1) {
this._d1 = doc;
}
+ // we don't want to create a link of both endpoints are the same document (doing so makes drawing an l very hard)
else if (this._d1 !== doc && !LinkManager.Instance.doesLinkExist(this._d1, doc)) {
+ // we don't want to create a link between ink strokes (doing so makes drawing a t very hard)
if (this._d1.type !== "ink" && doc.type !== "ink") {
DocUtils.MakeLink({ doc: this._d1 }, { doc: doc }, "gestural link");
actionPerformed = true;
}
}
};
+
const ge = new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
{
bubbles: true,
@@ -575,6 +598,7 @@ export default class GestureOverlay extends Touchable {
const xInGlass = initialPoint.X > (this._thumbX ?? Number.MAX_SAFE_INTEGER) && initialPoint.X < (this._thumbX ?? Number.MAX_SAFE_INTEGER) + (this.height);
const yInGlass = initialPoint.Y > (this._thumbY ?? Number.MAX_SAFE_INTEGER) - (this.height) && initialPoint.Y < (this._thumbY ?? Number.MAX_SAFE_INTEGER);
+ // if a toolglass is selected and the stroke starts within the toolglass boundaries
if (this.Tool !== ToolglassTools.None && xInGlass && yInGlass) {
switch (this.Tool) {
case ToolglassTools.InkToText:
@@ -583,20 +607,19 @@ export default class GestureOverlay extends Touchable {
this._strokes.push(new Array(...this._points));
this._points = [];
CognitiveServices.Inking.Appliers.InterpretStrokes(this._strokes).then((results) => {
- console.log(results);
const wordResults = results.filter((r: any) => r.category === "line");
const possibilities: string[] = [];
for (const wR of wordResults) {
- console.log(wR);
if (wR?.recognizedText) {
possibilities.push(wR?.recognizedText);
}
possibilities.push(...wR?.alternates?.map((a: any) => a.recognizedString));
}
- console.log(possibilities);
const r = Math.max(this.svgBounds.right, ...this._strokes.map(s => this.getBounds(s).right));
const l = Math.min(this.svgBounds.left, ...this._strokes.map(s => this.getBounds(s).left));
const t = Math.min(this.svgBounds.top, ...this._strokes.map(s => this.getBounds(s).top));
+
+ // if we receive any word results from cognitive services, display them
runInAction(() => {
this._possibilities = possibilities.map(p =>
<TouchScrollableMenuItem text={p} onClick={() => GestureOverlay.Instance.dispatchGesture(GestureUtils.Gestures.Text, [{ X: l, Y: t }], p)} />);
@@ -609,6 +632,7 @@ export default class GestureOverlay extends Touchable {
break;
}
}
+ // if we're not drawing in a toolglass try to recognize as gesture
else {
const result = GestureUtils.GestureRecognizer.Recognize(new Array(points));
let actionPerformed = false;
@@ -638,6 +662,7 @@ export default class GestureOverlay extends Touchable {
}
}
+ // if no gesture (or if the gesture was unsuccessful), "dry" the stroke into an ink document
if (!actionPerformed) {
this.dispatchGesture(GestureUtils.Gestures.Stroke);
this._points = [];
@@ -762,9 +787,6 @@ export default class GestureOverlay extends Touchable {
}}>
</div>
<TouchScrollableMenu options={this._possibilities} bounds={this.svgBounds} selectedIndex={this._selectedIndex} x={this._menuX} y={this._menuY} />
- {/* <div className="pointerBubbles">
- {this._pointers.map(p => <div className="bubble" style={{ translate: `transform(${p.clientX}px, ${p.clientY}px)` }}></div>)}
- </div> */}
</div>);
}
}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 52801b570..185222541 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -7,8 +7,7 @@ import { action, runInAction } from "mobx";
import { Doc } from "../../new_fields/Doc";
import { DictationManager } from "../util/DictationManager";
import SharingManager from "../util/SharingManager";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
-import { Cast, PromiseValue } from "../../new_fields/Types";
+import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
import { ScriptField } from "../../new_fields/ScriptField";
import { InkingControl } from "./InkingControl";
import { InkTool } from "../../new_fields/InkField";
@@ -89,13 +88,20 @@ export default class KeyManager {
return { stopPropagation: false, preventDefault: false };
}
}
- UndoManager.RunInBatch(() => {
- SelectionManager.SelectedDocuments().map(docView => {
- const doc = docView.props.Document;
- const remove = docView.props.removeDocument;
- remove && remove(doc);
- });
- }, "delete");
+ UndoManager.RunInBatch(() =>
+ SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument?.(dv.props.Document)), "delete");
+ break;
+ case "arrowleft":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(-1, 0)), "nudge left");
+ break;
+ case "arrowright":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(1, 0)), "nudge right");
+ break;
+ case "arrowup":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(0, -1)), "nudge up");
+ break;
+ case "arrowdown":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(0, 1)), "nudge down");
break;
}
@@ -114,6 +120,18 @@ export default class KeyManager {
// DictationManager.Controls.listen({ useOverlay: true, tryExecute: true });
// stopPropagation = true;
// preventDefault = true;
+ case "arrowleft":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(-10, 0)), "nudge left");
+ break;
+ case "arrowright":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(10, 0)), "nudge right");
+ break;
+ case "arrowup":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(0, -10)), "nudge up");
+ break;
+ case "arrowdown":
+ UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(0, 10)), "nudge down");
+ break;
}
return {
@@ -175,7 +193,7 @@ export default class KeyManager {
}
break;
case "t":
- PromiseValue(Cast(CurrentUserUtils.UserDocument.Create, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
+ PromiseValue(Cast(Doc.UserDoc()["tabs-button-tools"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
if (MainView.Instance.flyoutWidth === 240) {
MainView.Instance.flyoutWidth = 0;
} else {
@@ -183,7 +201,7 @@ export default class KeyManager {
}
break;
case "l":
- PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
+ PromiseValue(Cast(Doc.UserDoc()["tabs-button-library"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
if (MainView.Instance.flyoutWidth === 250) {
MainView.Instance.flyoutWidth = 0;
} else {
@@ -191,7 +209,7 @@ export default class KeyManager {
}
break;
case "f":
- PromiseValue(Cast(CurrentUserUtils.UserDocument.Search, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
+ PromiseValue(Cast(Doc.UserDoc()["tabs-button-search"], Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv }));
if (MainView.Instance.flyoutWidth === 400) {
MainView.Instance.flyoutWidth = 0;
} else {
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 645c7fa54..172c1864a 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -12,9 +12,9 @@ import { FormattedTextBox } from "./nodes/FormattedTextBox";
export class InkingControl {
@observable static Instance: InkingControl;
- @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(CurrentUserUtils.UserDocument.inkTool)) ?? InkTool.None; }
- @computed private get _selectedColor(): string { return GestureOverlay.Instance.Color ?? FieldValue(StrCast(CurrentUserUtils.UserDocument.inkColor)) ?? "rgb(244, 67, 54)"; }
- @computed private get _selectedWidth(): string { return GestureOverlay.Instance.Width?.toString() ?? FieldValue(StrCast(CurrentUserUtils.UserDocument.inkWidth)) ?? "5"; }
+ @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(Doc.UserDoc().inkTool)) ?? InkTool.None; }
+ @computed private get _selectedColor(): string { return GestureOverlay.Instance.Color ?? FieldValue(StrCast(Doc.UserDoc().inkColor)) ?? "rgb(244, 67, 54)"; }
+ @computed private get _selectedWidth(): string { return GestureOverlay.Instance.Width?.toString() ?? FieldValue(StrCast(Doc.UserDoc().inkWidth)) ?? "5"; }
@observable public _open: boolean = false;
constructor() {
@@ -23,7 +23,7 @@ export class InkingControl {
switchTool = action((tool: InkTool): void => {
// this._selectedTool = tool;
- CurrentUserUtils.UserDocument.inkTool = tool;
+ Doc.UserDoc().inkTool = tool;
});
decimalToHexString(number: number) {
if (number < 0) {
@@ -34,7 +34,7 @@ export class InkingControl {
@undoBatch
switchColor = action((color: ColorState): void => {
- CurrentUserUtils.UserDocument.inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
+ Doc.UserDoc().inkColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
if (InkingControl.Instance.selectedTool === InkTool.None) {
const selected = SelectionManager.SelectedDocuments();
@@ -44,9 +44,9 @@ export class InkingControl {
view.props.Document.isTemplateForField ? view.props.Document : Doc.GetProto(view.props.Document);
if (targetDoc) {
if (StrCast(Doc.Layout(view.props.Document).layout).indexOf("FormattedTextBox") !== -1 && FormattedTextBox.HadSelection) {
- Doc.Layout(view.props.Document).color = CurrentUserUtils.UserDocument.inkColor;
+ Doc.Layout(view.props.Document).color = Doc.UserDoc().inkColor;
} else {
- Doc.Layout(view.props.Document)._backgroundColor = CurrentUserUtils.UserDocument.inkColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment
+ Doc.Layout(view.props.Document)._backgroundColor = Doc.UserDoc().inkColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment
}
}
});
@@ -57,7 +57,7 @@ export class InkingControl {
@action
switchWidth = (width: string): void => {
// this._selectedWidth = width;
- CurrentUserUtils.UserDocument.inkWidth = width;
+ Doc.UserDoc().inkWidth = width;
}
@computed
@@ -73,7 +73,7 @@ export class InkingControl {
@action
updateSelectedColor(value: string) {
// this._selectedColor = value;
- CurrentUserUtils.UserDocument.inkColor = value;
+ Doc.UserDoc().inkColor = value;
}
@computed
diff --git a/src/client/views/InkingStroke.scss b/src/client/views/InkingStroke.scss
index cdbfdcff3..433433a42 100644
--- a/src/client/views/InkingStroke.scss
+++ b/src/client/views/InkingStroke.scss
@@ -1,3 +1,7 @@
-.inkingStroke-marker {
- mix-blend-mode: multiply
+.inkingStroke {
+ mix-blend-mode: multiply;
+ stroke-linejoin: round;
+ stroke-linecap: round;
+ overflow: visible !important;
+ transform-origin: top left;
} \ No newline at end of file
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index a791eed40..7a318d5c2 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -1,10 +1,9 @@
-import { computed } from "mobx";
import { observer } from "mobx-react";
import { documentSchema } from "../../new_fields/documentSchemas";
import { InkData, InkField, InkTool } from "../../new_fields/InkField";
import { makeInterface } from "../../new_fields/Schema";
-import { Cast } from "../../new_fields/Types";
-import { DocExtendableComponent } from "./DocComponent";
+import { Cast, StrCast, NumCast } from "../../new_fields/Types";
+import { ViewBoxBaseComponent } from "./DocComponent";
import { InkingControl } from "./InkingControl";
import "./InkingStroke.scss";
import { FieldView, FieldViewProps } from "./nodes/FieldView";
@@ -22,40 +21,37 @@ type InkDocument = makeInterface<[typeof documentSchema]>;
const InkDocument = makeInterface(documentSchema);
@observer
-export class InkingStroke extends DocExtendableComponent<FieldViewProps, InkDocument>(InkDocument) {
+export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocument>(InkDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); }
- @computed get PanelWidth() { return this.props.PanelWidth(); }
- @computed get PanelHeight() { return this.props.PanelHeight(); }
-
private analyzeStrokes = () => {
- const data: InkData = Cast(this.Document.data, InkField) ?.inkData ?? [];
- CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.Document, ["inkAnalysis", "handwriting"], [data]);
+ const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
+ CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.dataDoc, ["inkAnalysis", "handwriting"], [data]);
}
render() {
TraceMobx();
- const data: InkData = Cast(this.Document.data, InkField) ?.inkData ?? [];
+ const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
const xs = data.map(p => p.X);
const ys = data.map(p => p.Y);
const left = Math.min(...xs);
const top = Math.min(...ys);
const right = Math.max(...xs);
const bottom = Math.max(...ys);
- const points = InteractionUtils.CreatePolyline(data, left, top, this.Document.color ?? InkingControl.Instance.selectedColor, this.Document.strokeWidth ?? parseInt(InkingControl.Instance.selectedWidth));
+ const points = InteractionUtils.CreatePolyline(data, left, top,
+ StrCast(this.layoutDoc.color, InkingControl.Instance.selectedColor),
+ NumCast(this.layoutDoc.strokeWidth, parseInt(InkingControl.Instance.selectedWidth)));
const width = right - left;
const height = bottom - top;
- const scaleX = this.PanelWidth / width;
- const scaleY = this.PanelHeight / height;
+ const scaleX = this.props.PanelWidth() / width;
+ const scaleY = this.props.PanelHeight() / height;
return (
- <svg
+ <svg className="inkingStroke"
width={width}
height={height}
style={{
- transformOrigin: "top left",
transform: `scale(${scaleX}, ${scaleY})`,
- mixBlendMode: this.Document.tool === InkTool.Highlighter ? "multiply" : "unset",
- pointerEvents: "all"
+ mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset",
}}
onContextMenu={() => {
ContextMenu.Instance.addItem({
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 4709e7ef2..a2a9ceca5 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -24,7 +24,6 @@ body {
.jsx-parser {
width: 100%;
height: 100%;
- pointer-events: none;
border-radius: inherit;
position: inherit;
// background: inherit;
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6d705aa44..b21eb9c8f 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -5,7 +5,6 @@ import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { DocServer } from "../DocServer";
import { AssignAllExtensions } from "../../extensions/General/Extensions";
-process.env.HANDWRITING = "61088486d76c4b12ba578775a5f55422";
AssignAllExtensions();
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index e95802e54..81d427f64 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -5,6 +5,7 @@
.mainView-tabButtons {
position: relative;
width: 100%;
+ margin-top: 10px;
}
.mainContent-div {
@@ -28,6 +29,7 @@
width: 100%;
height: 100%;
position: absolute;
+ pointer-events: all;
top: 0;
left: 0;
z-index: 1;
@@ -71,6 +73,7 @@
flex-direction: column;
position: relative;
height: 100%;
+ background: dimgray;
.documentView-node-topmost {
background: lightgrey;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bef92f0fd..8fb67c435 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
+import { faTerminal, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -41,11 +41,12 @@ import { RadialMenu } from './nodes/RadialMenu';
import { OverlayView } from './OverlayView';
import PDFMenu from './pdf/PDFMenu';
import { PreviewCursor } from './PreviewCursor';
+import { ScriptField } from '../../new_fields/ScriptField';
@observer
export class MainView extends React.Component {
public static Instance: MainView;
- private _buttonBarHeight = 35;
+ private _buttonBarHeight = 26;
private _flyoutSizeOnDown = 0;
private _urlState: HistoryUtil.DocUrl;
private _docBtnRef = React.createRef<HTMLDivElement>();
@@ -60,7 +61,7 @@ export class MainView extends React.Component {
@computed private get userDoc() { return Doc.UserDoc(); }
@computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
@computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
- @computed public get sidebarButtonsDoc() { return Cast(CurrentUserUtils.UserDocument.sidebarButtons, Doc) as Doc; }
+ @computed public get sidebarButtonsDoc() { return Cast(this.userDoc["tabs-buttons"], Doc) as Doc; }
public isPointerDown = false;
@@ -101,7 +102,12 @@ export class MainView extends React.Component {
}
}
+ library.add(faTerminal);
+ library.add(faCalculator);
+ library.add(faWindowMaximize);
library.add(faFileAlt);
+ library.add(faAddressCard);
+ library.add(faQuestionCircle);
library.add(faStickyNote);
library.add(faFont);
library.add(faExclamation);
@@ -199,7 +205,7 @@ export class MainView extends React.Component {
@action
createNewWorkspace = async (id?: string) => {
- const workspaces = Cast(this.userDoc.workspaces, Doc) as Doc;
+ const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc;
const workspaceCount = DocListCast(workspaces.data).length + 1;
const freeformOptions: DocumentOptions = {
x: 0,
@@ -209,8 +215,13 @@ export class MainView extends React.Component {
title: "Collection " + workspaceCount,
};
const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
- Doc.AddDocToList(Doc.GetProto(CurrentUserUtils.UserDocument.documents as Doc), "data", freeformDoc);
- const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().documents as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
+ Doc.AddDocToList(Doc.GetProto(Doc.UserDoc().myDocuments as Doc), "data", freeformDoc);
+ const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myDocuments as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
+
+ const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`);
+ mainDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!]);
+ mainDoc.contextMenuLabels = new List<string>(["Toggle Theme Colors"]);
+
Doc.AddDocToList(workspaces, "data", mainDoc);
// bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
setTimeout(() => this.openWorkspace(mainDoc), 0);
@@ -251,7 +262,7 @@ export class MainView extends React.Component {
}
// if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized)
setTimeout(async () => {
- const col = this.userDoc && await Cast(this.userDoc.optionalRightCollection, Doc);
+ const col = this.userDoc && await Cast(this.userDoc.rightSidebarCollection, Doc);
col && Cast(col.data, listSpec(Doc)) && runInAction(() => MainViewNotifs.NotifsCol = col);
}, 100);
return true;
@@ -275,7 +286,7 @@ export class MainView extends React.Component {
defaultBackgroundColors = (doc: Doc) => {
if (this.darkScheme) {
switch (doc.type) {
- case DocumentType.TEXT || DocumentType.BUTTON: return "#2d2d2d";
+ case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d";
case DocumentType.LINK:
case DocumentType.COL: {
if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
@@ -284,8 +295,9 @@ export class MainView extends React.Component {
}
} else {
switch (doc.type) {
- case DocumentType.TEXT: return "#f1efeb";
- case DocumentType.BUTTON: return "lightgray";
+ case DocumentType.RTF: return "#f1efeb";
+ case DocumentType.BUTTON:
+ case DocumentType.LABEL: return "lightgray";
case DocumentType.LINK:
case DocumentType.COL: {
if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "lightgray";
@@ -388,15 +400,14 @@ export class MainView extends React.Component {
mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1);
@computed get flyout() {
- const sidebarContent = this.userDoc?.sidebarContainer;
+ const sidebarContent = this.userDoc?.["tabs-panelContainer"];
if (!(sidebarContent instanceof Doc)) {
return (null);
}
- const sidebarButtonsDoc = Cast(CurrentUserUtils.UserDocument.sidebarButtons, Doc) as Doc;
return <div className="mainView-flyoutContainer" >
- <div className="mainView-tabButtons" style={{ height: `${this._buttonBarHeight}px`, backgroundColor: StrCast(sidebarButtonsDoc.backgroundColor) }}>
+ <div className="mainView-tabButtons" style={{ height: `${this._buttonBarHeight}px`, backgroundColor: StrCast(this.sidebarButtonsDoc.backgroundColor) }}>
<DocumentView
- Document={sidebarButtonsDoc}
+ Document={this.sidebarButtonsDoc}
DataDoc={undefined}
LibraryPath={emptyPath}
addDocument={undefined}
@@ -457,7 +468,7 @@ export class MainView extends React.Component {
}
@computed get mainContent() {
- const sidebar = this.userDoc && this.userDoc.sidebarContainer;
+ const sidebar = this.userDoc?.["tabs-panelContainer"];
return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
<div className="mainView-mainContent" style={{ color: this.darkScheme ? "rgb(205,205,205)" : "black" }} >
<div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}>
@@ -494,8 +505,8 @@ export class MainView extends React.Component {
return !this._flyoutTranslate ? (<div className="mainView-expandFlyoutButton" title="Re-attach sidebar" onPointerDown={MainView.expandFlyout}><FontAwesomeIcon icon="chevron-right" color="grey" size="lg" /></div>) : (null);
}
- addButtonDoc = (doc: Doc) => Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc);
- remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc);
+ addButtonDoc = (doc: Doc) => Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc);
+ remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc);
moveButtonDoc = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => this.remButtonDoc(doc) && addDocument(doc);
buttonBarXf = () => {
@@ -504,13 +515,13 @@ export class MainView extends React.Component {
return new Transform(-translateX, -translateY, 1 / scale);
}
@computed get docButtons() {
- const expandingBtns = Doc.UserDoc()?.expandingButtons;
- if (expandingBtns instanceof Doc) {
+ const dockedBtns = Doc.UserDoc()?.dockedBtns;
+ if (dockedBtns instanceof Doc) {
return <div className="mainView-docButtons" ref={this._docBtnRef}
- style={{ height: !expandingBtns.linearViewIsExpanded ? "42px" : undefined }} >
+ style={{ height: !dockedBtns.linearViewIsExpanded ? "42px" : undefined }} >
<MainViewNotifs />
<CollectionLinearView
- Document={expandingBtns}
+ Document={dockedBtns}
DataDoc={undefined}
LibraryPath={emptyPath}
fieldKey={"data"}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 4000cade5..20aa14f84 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -1,16 +1,16 @@
-import * as React from "react";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { observable, action, trace, computed } from "mobx";
-import { Utils, emptyFunction, returnOne, returnTrue, returnEmptyString, returnZero, returnFalse, emptyPath } from "../../Utils";
-
-import './OverlayView.scss';
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
-import { DocListCast, Doc } from "../../new_fields/Doc";
+import * as React from "react";
+import { Doc, DocListCast } from "../../new_fields/Doc";
import { Id } from "../../new_fields/FieldSymbols";
-import { DocumentView } from "./nodes/DocumentView";
-import { Transform } from "../util/Transform";
import { NumCast } from "../../new_fields/Types";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils } from "../../Utils";
+import { Transform } from "../util/Transform";
import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView";
+import { DocumentView } from "./nodes/DocumentView";
+import './OverlayView.scss';
+import { Scripting } from "../util/Scripting";
+import { ScriptingRepl } from './ScriptingRepl';
export type OverlayDisposer = () => void;
@@ -140,10 +140,11 @@ export class OverlayView extends React.Component {
}
@computed get overlayDocs() {
- if (!CurrentUserUtils.UserDocument) {
+ const userDocOverlays = Doc.UserDoc().myOverlayDocuments;
+ if (!userDocOverlays) {
return (null);
}
- return CurrentUserUtils.UserDocument.overlays instanceof Doc && DocListCast(CurrentUserUtils.UserDocument.overlays.data).map(d => {
+ return userDocOverlays instanceof Doc && DocListCast(userDocOverlays.data).map(d => {
setTimeout(() => d.inOverlay = true, 0);
let offsetx = 0, offsety = 0;
const onPointerMove = action((e: PointerEvent) => {
@@ -195,7 +196,7 @@ export class OverlayView extends React.Component {
addDocTab={returnFalse}
pinToPres={emptyFunction}
ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}/>
+ ContainingCollectionDoc={undefined} />
</div>;
});
}
@@ -211,4 +212,6 @@ export class OverlayView extends React.Component {
</div>
);
}
-} \ No newline at end of file
+}
+// bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error
+Scripting.addGlobal(function addOverlayWindow(Tag: string, options: OverlayElementOptions) { const x = <ScriptingRepl />; OverlayView.Instance.addWindow(x, options); }); \ No newline at end of file
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index c011adb20..df30c1215 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -13,6 +13,7 @@ export class PreviewCursor extends React.Component<{}> {
static _getTransform: () => Transform;
static _addLiveTextDoc: (doc: Doc) => void;
static _addDocument: (doc: Doc) => boolean;
+ static _nudge: (x: number, y: number) => boolean;
@observable static _clickPoint = [0, 0];
@observable public static Visible = false;
constructor(props: any) {
@@ -85,9 +86,19 @@ export class PreviewCursor extends React.Component<{}> {
!e.key.startsWith("Arrow") &&
!e.defaultPrevented) {
if ((!e.ctrlKey || (e.keyCode >= 48 && e.keyCode <= 57)) && !e.metaKey) {// /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) {
- PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e);
+ PreviewCursor.Visible && PreviewCursor._onKeyPress?.(e);
PreviewCursor.Visible = false;
}
+ } else if (PreviewCursor.Visible) {
+ if (e.key === "ArrowRight") {
+ PreviewCursor._nudge?.(1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation();
+ } else if (e.key === "ArrowLeft") {
+ PreviewCursor._nudge?.(-1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation();
+ } else if (e.key === "ArrowUp") {
+ PreviewCursor._nudge?.(0, 1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation();
+ } else if (e.key === "ArrowDown") {
+ PreviewCursor._nudge?.(0, -1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation();
+ }
}
}
@@ -101,12 +112,14 @@ export class PreviewCursor extends React.Component<{}> {
onKeyPress: (e: KeyboardEvent) => void,
addLiveText: (doc: Doc) => void,
getTransform: () => Transform,
- addDocument: (doc: Doc) => boolean) {
+ addDocument: (doc: Doc) => boolean,
+ nudge: (nudgeX: number, nudgeY: number) => boolean) {
this._clickPoint = [x, y];
this._onKeyPress = onKeyPress;
this._addLiveTextDoc = addLiveText;
this._getTransform = getTransform;
this._addDocument = addDocument;
+ this._nudge = nudge;
this.Visible = true;
}
render() {
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index 1e81bb80b..153b81876 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -12,6 +12,7 @@ import { CompileScript } from "../util/Scripting";
import { ScriptField } from "../../new_fields/ScriptField";
import { DragManager } from "../util/DragManager";
import { EditableView } from "./EditableView";
+import { getEffectiveTypeRoots } from "typescript";
export interface ScriptBoxProps {
onSave: (text: string, onError: (error: string) => void) => void;
@@ -43,14 +44,12 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
overlayDisposer?: () => void;
onFocus = () => {
- if (this.overlayDisposer) {
- this.overlayDisposer();
- }
+ this.overlayDisposer?.();
this.overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
}
onBlur = () => {
- this.overlayDisposer && this.overlayDisposer();
+ this.overlayDisposer?.();
}
render() {
@@ -94,7 +93,7 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
const setParams = (p: string[]) => params.splice(0, params.length, ...p);
const scriptingBox = <ScriptBox initialText={originalText} setParams={setParams} onCancel={overlayDisposer} onSave={(text, onError) => {
if (!text) {
- doc[fieldKey] = undefined;
+ Doc.GetProto(doc)[fieldKey] = undefined;
} else {
const script = CompileScript(text, {
params: { this: Doc.name, ...contextParams },
@@ -117,7 +116,7 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
div.innerHTML = "button";
params.length && DragManager.StartButtonDrag([div], text, doc.title + "-instance", {}, params, (button: Doc) => { }, clientX, clientY);
- doc[fieldKey] = new ScriptField(script);
+ Doc.GetProto(doc)[fieldKey] = new ScriptField(script);
overlayDisposer();
}
}} showDocumentIcons />;
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index 4790a2ad7..799fa9d85 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -394,7 +394,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
render() {
const isEditing = this.editingMetadata;
- return (
+ return !this.content ? (null) : (
<div style={{ pointerEvents: "all" }}>
<ContentFittingDocumentView {...this.props}
Document={this.content}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 8fb8e7516..665ab4e41 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -14,6 +14,7 @@ import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZer
import { Transform } from "../util/Transform";
import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
import { Scripting } from "../util/Scripting";
+import { List } from "../../new_fields/List";
@observer
class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent<HTMLInputElement>, template: Template) => void }> {
@@ -76,7 +77,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
@undoBatch
@action
toggleTemplate = (event: React.ChangeEvent<HTMLInputElement>, template: Template): void => {
- this.props.docViews.forEach(d => Doc.Layout(d.Document)["_show" + template.Name] = event.target.checked ? template.Name.toLowerCase() : "");
+ this.props.docViews.forEach(d => Doc.Layout(d.layoutDoc)["_show" + template.Name] = event.target.checked ? template.Name.toLowerCase() : "");
}
@action
@@ -87,7 +88,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
@undoBatch
@action
toggleChrome = (): void => {
- this.props.docViews.map(dv => Doc.Layout(dv.Document)).forEach(layout =>
+ this.props.docViews.map(dv => Doc.Layout(dv.layoutDoc)).forEach(layout =>
layout._chromeStatus = (layout._chromeStatus !== "disabled" ? "disabled" : StrCast(layout._replacedChrome, "enabled")));
}
@@ -106,14 +107,13 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
return100 = () => 100;
@computed get scriptField() {
- return ScriptField.MakeScript("switchView(firstDoc, this)", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name },
- { firstDoc: this.props.docViews[0].props.Document });
+ return ScriptField.MakeScript("docs.map(d => switchView(d, this))", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name },
+ { docs: new List<Doc>(this.props.docViews.map(dv => dv.props.Document)) });
}
render() {
const firstDoc = this.props.docViews[0].props.Document;
const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", "");
- const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null);
- const noteTypes = DocListCast(noteTypesDoc?.data);
+ const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null));
const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data);
const layout = Doc.Layout(firstDoc);
const templateMenu: Array<JSX.Element> = [];
@@ -123,11 +123,9 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={firstDoc.z ? true : false} toggle={this.toggleFloat} />);
templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout._chromeStatus !== "disabled"} toggle={this.toggleChrome} />);
templateMenu.push(<OtherToggle key={"default"} name={"Default"} checked={templateName === "layout"} toggle={this.toggleDefault} />);
- if (noteTypesDoc) {
- addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(this)`));
- this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push(
- <OtherToggle key={template} name={template} checked={templateName === template} toggle={e => this.toggleLayout(e, template)} />));
- }
+ addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(self,firstDoc)`, {}, { firstDoc }));
+ this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push(
+ <OtherToggle key={template} name={template} checked={templateName === template} toggle={e => this.toggleLayout(e, template)} />));
return <ul className="template-list" style={{ display: "block" }}>
<input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress} />
{templateMenu}
@@ -167,19 +165,18 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
}
}
-Scripting.addGlobal(function switchView(doc: Doc, template: Doc) {
- if (template.dragFactory) {
+Scripting.addGlobal(function switchView(doc: Doc, template: Doc | undefined) {
+ if (template?.dragFactory) {
template = Cast(template.dragFactory, Doc, null);
}
const templateTitle = StrCast(template?.title);
- return templateTitle && DocumentView.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template);
+ return templateTitle && Doc.makeCustomViewClicked(doc, Docs.Create.FreeformDocument, templateTitle, template);
});
-Scripting.addGlobal(function templateIsUsed(templateDoc: Doc) {
- const firstDoc = SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0].props.Document : undefined;
- if (firstDoc) {
+Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, selDoc: Doc) {
+ if (selDoc) {
const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
- return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
+ return StrCast(selDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
}
return false;
}); \ No newline at end of file
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx
index 8c60f1c36..a6dbaa650 100644
--- a/src/client/views/Templates.tsx
+++ b/src/client/views/Templates.tsx
@@ -1,45 +1,23 @@
-import React = require("react");
-
-export enum TemplatePosition {
- InnerTop,
- InnerBottom,
- InnerRight,
- InnerLeft,
- TopRight,
- OutterTop,
- OutterBottom,
- OutterRight,
- OutterLeft,
-}
-
export class Template {
- constructor(name: string, position: TemplatePosition, layout: string) {
+ constructor(name: string, layout: string) {
this._name = name;
- this._position = position;
this._layout = layout;
}
private _name: string;
- private _position: TemplatePosition;
private _layout: string;
get Name(): string {
return this._name;
}
- get Position(): TemplatePosition {
- return this._position;
- }
-
get Layout(): string {
return this._layout;
}
}
export namespace Templates {
- // export const BasicLayout = new Template("Basic layout", "{layout}");
-
- export const Caption = new Template("Caption", TemplatePosition.OutterBottom,
+ export const Caption = new Template("Caption",
`<div>
<div style="height:100%; width:100%;">{layout}</div>
<div style="bottom: 0; font-size:14px; width:100%; position:absolute">
@@ -47,16 +25,7 @@ export namespace Templates {
</div>
</div>` );
- export const Title = new Template("Title", TemplatePosition.InnerTop,
- `<div>
- <div style="height:25px; width:100%; background-color: rgba(0, 0, 0, .4); color: white; z-index: 100">
- <span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.Document.title}</span>
- </div>
- <div style="height:calc(100% - 25px);">
- <div style="width:100%;overflow:auto">{layout}</div>
- </div>
- </div>` );
- export const TitleHover = new Template("TitleHover", TemplatePosition.InnerTop,
+ export const Title = new Template("Title",
`<div>
<div style="height:25px; width:100%; background-color: rgba(0, 0, 0, .4); color: white; z-index: 100">
<span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.Document.title}</span>
@@ -65,14 +34,8 @@ export namespace Templates {
<div style="width:100%;overflow:auto">{layout}</div>
</div>
</div>` );
+ export const TitleHover = new Template("TitleHover", Title.Layout);
export const TemplateList: Template[] = [Title, TitleHover, Caption];
-
- export function sortTemplates(a: Template, b: Template) {
- if (a.Position < b.Position) { return -1; }
- if (a.Position > b.Position) { return 1; }
- return 0;
- }
-
}
diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx
index 08310786b..10d023d83 100644
--- a/src/client/views/Touchable.tsx
+++ b/src/client/views/Touchable.tsx
@@ -64,20 +64,15 @@ export abstract class Touchable<T = {}> extends React.Component<T> {
case 1:
this.handle1PointerDown(te, me);
te.persist();
+ // -- code for radial menu --
// if (this.holdTimer) {
// clearTimeout(this.holdTimer)
// this.holdTimer = undefined;
// }
- // console.log(this.holdTimer);
- // console.log(this.holdTimer);
break;
case 2:
this.handle2PointersDown(te, me);
- // e.stopPropagation();
break;
- // case 5:
- // this.handleHandDown(te);
- // break;
}
}
}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 9e7248db2..f4250e96d 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -27,7 +27,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
this._dropDisposer?.();
if (ele) {
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+ this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
}
}
@@ -47,13 +47,22 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
<>
<div className="collectionCarouselView-image" key="image">
<ContentFittingDocumentView {...this.props}
+ renderDepth={this.props.renderDepth + 1}
Document={this.childLayoutPairs[index].layout}
DataDocument={this.childLayoutPairs[index].data}
PanelHeight={this.panelHeight}
getTransform={this.props.ScreenToLocalTransform} />
</div>
- <div className="collectionCarouselView-caption" key="caption" style={{ background: this.props.backgroundColor?.(this.props.Document) }}>
- <FormattedTextBox key={index} {...this.props} Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"}></FormattedTextBox>
+ <div className="collectionCarouselView-caption" key="caption"
+ style={{
+ background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.backgroundColor?.(this.props.Document)),
+ color: StrCast(this.layoutDoc._captionColor, StrCast(this.layoutDoc.color)),
+ borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
+ }}>
+ <FormattedTextBox key={index} {...this.props}
+ xMargin={NumCast(this.layoutDoc["caption-xMargin"])}
+ yMargin={NumCast(this.layoutDoc["caption-yMargin"])}
+ Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"}></FormattedTextBox>
</div>
</>;
}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 28aaf0c57..0d859c3f1 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -14,11 +14,9 @@ import { List } from '../../../new_fields/List';
import { FieldId } from "../../../new_fields/RefField";
import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { TraceMobx } from '../../../new_fields/util';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { Docs } from '../../documents/Documents';
-import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from "../../util/DragManager";
import { Scripting } from '../../util/Scripting';
@@ -31,6 +29,7 @@ import "./CollectionDockingView.scss";
import { SubCollectionViewProps } from "./CollectionSubView";
import { DockingViewButtonSelector } from './ParentDocumentSelector';
import React = require("react");
+import { CollectionViewType } from './CollectionView';
library.add(faFile);
const _global = (window /* browser */ || global /* node */) as any;
@@ -95,6 +94,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
@undoBatch
@action
public OpenFullScreen(docView: DocumentView, libraryPath?: Doc[]) {
+ if (docView.props.Document._viewType === CollectionViewType.Docking && docView.props.Document.layoutKey === "layout") {
+ return MainView.Instance.openWorkspace(docView.props.Document);
+ }
const document = Doc.MakeAlias(docView.props.Document);
const newItemStackConfig = {
type: 'stack',
@@ -376,8 +378,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
// Because this is in a set timeout, if this component unmounts right after mounting,
// we will leak a GoldenLayout, because we try to destroy it before we ever create it
setTimeout(() => this.setupGoldenLayout(), 1);
- const userDoc = CurrentUserUtils.UserDocument;
- userDoc && DocListCast((userDoc.workspaces as Doc).data).map(d => d.workspaceBrush = false);
+ DocListCast((Doc.UserDoc().myWorkspaces as Doc).data).map(d => d.workspaceBrush = false);
this.props.Document.workspaceBrush = true;
}
this._ignoreStateChange = "";
@@ -544,9 +545,8 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
const theDoc = doc;
CollectionDockingView.Instance._removedDocs.push(theDoc);
- const userDoc = CurrentUserUtils.UserDocument;
- let recent: Doc | undefined;
- if (userDoc && (recent = await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc))) {
+ const recent = await Cast(Doc.UserDoc().myRecentlyClosed, Doc);
+ if (recent) {
Doc.AddDocToList(recent, "data", doc, undefined, true, true);
}
SelectionManager.DeselectAll();
@@ -606,7 +606,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
const doc = await DocServer.GetRefField(contentItem.config.props.documentId);
if (doc instanceof Doc) {
let recent: Doc | undefined;
- if (CurrentUserUtils.UserDocument && (recent = await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc))) {
+ if (recent = await Cast(Doc.UserDoc().myRecentlyClosed, Doc)) {
Doc.AddDocToList(recent, "data", doc, undefined, true, true);
}
const theDoc = doc;
@@ -681,7 +681,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
@action
public static PinDoc(doc: Doc) {
//add this new doc to props.Document
- const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc;
+ const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
if (curPres) {
const pinDoc = Doc.MakeAlias(doc);
pinDoc.presentationTargetDoc = doc;
@@ -698,7 +698,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
@action
public static UnpinDoc(doc: Doc) {
//add this new doc to props.Document
- const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc;
+ const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
if (curPres) {
const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc));
ind !== -1 && Doc.RemoveDocFromList(curPres, "data", DocListCast(curPres.data)[ind]);
@@ -739,19 +739,27 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
nativeHeight = () => !this.layoutDoc!._fitWidth ? NumCast(this.layoutDoc!._nativeHeight) || this._panelHeight : 0;
contentScaling = () => {
- if (this.layoutDoc!.type === DocumentType.PDF) {
- if ((this.layoutDoc && this.layoutDoc._fitWidth) ||
- this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) {
- return this._panelWidth / NumCast(this.layoutDoc!._nativeWidth);
- } else {
- return this._panelHeight / NumCast(this.layoutDoc!._nativeHeight);
- }
- }
const nativeH = this.nativeHeight();
const nativeW = this.nativeWidth();
- if (!nativeW || !nativeH) return 1;
- const wscale = this.panelWidth() / nativeW;
- return wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale;
+ let scaling = 1;
+ if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) {
+ scaling = 1;
+ } else if ((this.layoutDoc?._fitWidth) ||
+ this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) {
+ scaling = this._panelWidth / NumCast(this.layoutDoc!._nativeWidth);
+ } else {
+ // if (this.layoutDoc!.type === DocumentType.PDF || this.layoutDoc!.type === DocumentType.WEB) {
+ // if ((this.layoutDoc?._fitWidth) ||
+ // this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) {
+ // return this._panelWidth / NumCast(this.layoutDoc!._nativeWidth);
+ // } else {
+ // return this._panelHeight / NumCast(this.layoutDoc!._nativeHeight);
+ // }
+ // }
+ const wscale = this.panelWidth() / nativeW;
+ scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale;
+ }
+ return scaling;
}
ScreenToLocalTransform = () => {
@@ -767,13 +775,13 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
SelectionManager.DeselectAll();
- if (doc.dockingConfig) {
+ if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") {
return MainView.Instance.openWorkspace(doc);
} else if (location === "onRight") {
return CollectionDockingView.AddRightSplit(doc, libraryPath);
} else if (location === "close") {
return CollectionDockingView.CloseRightSplit(doc);
- } else {
+ } else {// if (location === "inPlace") {
return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath);
}
}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index cb0206260..344dca23a 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -64,7 +64,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
this._dropDisposer && this._dropDisposer();
if (ele) {
- this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+ this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
}
}
diff --git a/src/client/views/collections/CollectionMapView.scss b/src/client/views/collections/CollectionMapView.scss
new file mode 100644
index 000000000..870b7fda8
--- /dev/null
+++ b/src/client/views/collections/CollectionMapView.scss
@@ -0,0 +1,30 @@
+.collectionMapView {
+ width: 100%;
+ height: 100%;
+
+ .collectionMapView-contents {
+ width: 100%;
+ height: 100%;
+ > div {
+ position: unset !important; // when the sidebar filter flys out, this prevents the map from extending outside the document box
+ }
+ }
+}
+
+.loadingWrapper {
+ width: 100%;
+ height: 100%;
+ background-color: pink;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+
+ .loadingGif {
+ align-self: center;
+ justify-self: center;
+ width: 50px;
+ height: 50px;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx
new file mode 100644
index 000000000..7b7828d7d
--- /dev/null
+++ b/src/client/views/collections/CollectionMapView.tsx
@@ -0,0 +1,263 @@
+import { GoogleApiWrapper, Map as GeoMap, MapProps, Marker } from "google-maps-react";
+import { observer } from "mobx-react";
+import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { makeInterface } from "../../../new_fields/Schema";
+import { Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
+import "./CollectionMapView.scss";
+import { CollectionSubView } from "./CollectionSubView";
+import React = require("react");
+import { DocumentManager } from "../../util/DocumentManager";
+import { UndoManager, undoBatch } from "../../util/UndoManager";
+import { computed, runInAction, Lambda, action } from "mobx";
+import requestPromise = require("request-promise");
+
+type MapSchema = makeInterface<[typeof documentSchema]>;
+const MapSchema = makeInterface(documentSchema);
+
+export type LocationData = google.maps.LatLngLiteral & {
+ address?: string
+ resolvedAddress?: string;
+ zoom?: number;
+};
+
+interface DocLatLng {
+ lat: FieldResult<Field>;
+ lng: FieldResult<Field>;
+}
+
+// Nowhere, Oklahoma
+const defaultLocation = { lat: 35.1592238, lng: -98.444512, zoom: 15 };
+const noResults = "ZERO_RESULTS";
+
+const query = async (data: string | google.maps.LatLngLiteral) => {
+ const contents = typeof data === "string" ? `address=${data.replace(/\s+/g, "+")}` : `latlng=${data.lat},${data.lng}`;
+ const target = `https://maps.googleapis.com/maps/api/geocode/json?${contents}&key=${process.env.GOOGLE_MAPS_GEO}`;
+ try {
+ return JSON.parse(await requestPromise.get(target));
+ } catch {
+ return undefined;
+ }
+};
+
+@observer
+class CollectionMapView extends CollectionSubView<MapSchema, Partial<MapProps> & { google: any }>(MapSchema) {
+
+ private _cancelAddrReq = new Map<string, boolean>();
+ private _cancelLocReq = new Map<string, boolean>();
+ private _initialLookupPending = new Map<string, boolean>();
+ private responders: { location: Lambda, address: Lambda }[] = [];
+
+ /**
+ * Note that all the uses of runInAction below are not included
+ * as a way to update observables (documents handle this already
+ * in their property setters), but rather to create a single bulk
+ * update and thus prevent uneeded invocations of the location-
+ * and address–updating reactions.
+ */
+
+ private getLocation = (doc: Opt<Doc>, fieldKey: string, returnDefault: boolean = true): Opt<LocationData> => {
+ if (doc) {
+ const titleLoc = StrCast(doc.title).startsWith("@") ? StrCast(doc.title).substring(1) : undefined;
+ const lat = Cast(doc[`${fieldKey}-lat`], "number", null) || (Cast(doc[`${fieldKey}-lat`], "string", null) && Number(Cast(doc[`${fieldKey}-lat`], "string", null))) || undefined;
+ const lng = Cast(doc[`${fieldKey}-lng`], "number", null) || (Cast(doc[`${fieldKey}-lng`], "string", null) && Number(Cast(doc[`${fieldKey}-lng`], "string", null))) || undefined;
+ const zoom = Cast(doc[`${fieldKey}-zoom`], "number", null) || (Cast(doc[`${fieldKey}-zoom`], "string", null) && Number(Cast(doc[`${fieldKey}-zoom`], "string", null))) || undefined;
+ const address = titleLoc || StrCast(doc[`${fieldKey}-address`], StrCast(doc.title).replace(/^-/, ""));
+ if (titleLoc || (address && (lat === undefined || lng === undefined))) {
+ const id = doc[Id];
+ if (!this._initialLookupPending.get(id)) {
+ this._initialLookupPending.set(id, true);
+ setTimeout(() => {
+ titleLoc && Doc.SetInPlace(doc, "title", titleLoc, true);
+ this.respondToAddressChange(doc, fieldKey, address).then(() => this._initialLookupPending.delete(id));
+ });
+ }
+ }
+ return (lat === undefined || lng === undefined) ? (returnDefault ? defaultLocation : undefined) : { lat, lng, zoom };
+ }
+ return undefined;
+ }
+
+ private markerClick = async (layout: Doc, { lat, lng, zoom }: LocationData) => {
+ const batch = UndoManager.StartBatch("marker click");
+ const { fieldKey } = this.props;
+ runInAction(() => {
+ this.layoutDoc[`${fieldKey}-mapCenter-lat`] = lat;
+ this.layoutDoc[`${fieldKey}-mapCenter-lng`] = lng;
+ zoom && (this.layoutDoc[`${fieldKey}-mapCenter-zoom`] = zoom);
+ });
+ if (layout.isLinkButton && DocListCast(layout.links).length) {
+ await DocumentManager.Instance.FollowLink(undefined, layout, (doc: Doc, where: string, finished?: () => void) => {
+ this.props.addDocTab(doc, where);
+ finished?.();
+ }, false, this.props.ContainingCollectionDoc, batch.end, undefined);
+ } else {
+ ScriptCast(layout.onClick)?.script.run({ this: layout, self: Cast(layout.rootDocument, Doc, null) || layout });
+ batch.end();
+ }
+ }
+
+ private renderMarkerIcon = (layout: Doc) => {
+ const { Document } = this.props;
+ const fieldKey = Doc.LayoutFieldKey(layout);
+ const iconUrl = StrCast(layout.mapIconUrl, StrCast(Document.mapIconUrl));
+ if (iconUrl) {
+ const iconWidth = NumCast(layout[`${fieldKey}-iconWidth`], 45);
+ const iconHeight = NumCast(layout[`${fieldKey}-iconHeight`], 45);
+ const iconSize = new google.maps.Size(iconWidth, iconHeight);
+ return {
+ size: iconSize,
+ scaledSize: iconSize,
+ url: iconUrl
+ };
+ }
+ }
+
+ private renderMarker = (layout: Doc) => {
+ const location = this.getLocation(layout, Doc.LayoutFieldKey(layout));
+ return !location ? (null) :
+ <Marker
+ key={layout[Id]}
+ label={StrCast(layout.title)}
+ position={location}
+ onClick={() => this.markerClick(layout, location)}
+ icon={this.renderMarkerIcon(layout)}
+ />;
+ }
+
+ private respondToAddressChange = async (doc: Doc, fieldKey: string, newAddress: string, oldAddress?: string) => {
+ if (newAddress === oldAddress) {
+ return false;
+ }
+ const response = await query(newAddress);
+ const id = doc[Id];
+ if (!response || response.status === noResults) {
+ this._cancelAddrReq.set(id, true);
+ doc[`${fieldKey}-address`] = oldAddress;
+ return false;
+ }
+ const { geometry, formatted_address } = response.results[0];
+ const { lat, lng } = geometry.location;
+ runInAction(() => {
+ if (doc[`${fieldKey}-lat`] !== lat || doc[`${fieldKey}-lng`] !== lng) {
+ this._cancelLocReq.set(id, true);
+ Doc.SetInPlace(doc, `${fieldKey}-lat`, lat, true);
+ Doc.SetInPlace(doc, `${fieldKey}-lng`, lng, true);
+ }
+ if (formatted_address !== newAddress) {
+ this._cancelAddrReq.set(id, true);
+ Doc.SetInPlace(doc, `${fieldKey}-address`, formatted_address, true);
+ }
+ });
+ return true;
+ }
+
+ private respondToLocationChange = async (doc: Doc, fieldKey: string, newLatLng: DocLatLng, oldLatLng: Opt<DocLatLng>) => {
+ if (newLatLng === oldLatLng) {
+ return false;
+ }
+ const response = await query({ lat: NumCast(newLatLng.lat), lng: NumCast(newLatLng.lng) });
+ const id = doc[Id];
+ if (!response || response.status === noResults) {
+ this._cancelLocReq.set(id, true);
+ runInAction(() => {
+ doc[`${fieldKey}-lat`] = oldLatLng?.lat;
+ doc[`${fieldKey}-lng`] = oldLatLng?.lng;
+ });
+ return false;
+ }
+ const { formatted_address } = response.results[0];
+ if (formatted_address !== doc[`${fieldKey}-address`]) {
+ this._cancelAddrReq.set(doc[Id], true);
+ Doc.SetInPlace(doc, `${fieldKey}-address`, formatted_address, true);
+ }
+ return true;
+ }
+
+ @computed get reactiveContents() {
+ this.responders.forEach(({ location, address }) => { location(); address(); });
+ this.responders = [];
+ return this.childLayoutPairs.map(({ layout }) => {
+ const fieldKey = Doc.LayoutFieldKey(layout);
+ const id = layout[Id];
+ this.responders.push({
+ location: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] }))
+ .observe(({ oldValue, newValue }) => {
+ if (this._cancelLocReq.get(id)) {
+ this._cancelLocReq.set(id, false);
+ } else if (newValue.lat !== undefined && newValue.lng !== undefined) {
+ this.respondToLocationChange(layout, fieldKey, newValue, oldValue);
+ }
+ }),
+ address: computed(() => Cast(layout[`${fieldKey}-address`], "string", null))
+ .observe(({ oldValue, newValue }) => {
+ if (this._cancelAddrReq.get(id)) {
+ this._cancelAddrReq.set(id, false);
+ } else if (newValue?.length) {
+ this.respondToAddressChange(layout, fieldKey, newValue, oldValue);
+ }
+ })
+ });
+ return this.renderMarker(layout);
+ });
+ }
+
+ render() {
+ const { childLayoutPairs } = this;
+ const { Document, fieldKey, active, google } = this.props;
+ let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false);
+ if (center === undefined) {
+ const childLocations = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false));
+ center = childLocations.find(location => location) || defaultLocation;
+ }
+ return <div className="collectionMapView" ref={this.createDashEventsTarget}>
+ <div className={"collectionMapView-contents"}
+ style={{ pointerEvents: active() ? undefined : "none" }}
+ onWheel={e => e.stopPropagation()}
+ onPointerDown={e => (e.button === 0 && !e.ctrlKey) && e.stopPropagation()} >
+ <GeoMap
+ google={google}
+ zoom={center.zoom || 10}
+ initialCenter={center}
+ center={center}
+ onIdle={(_props?: MapProps, map?: google.maps.Map) => {
+ if (this.layoutDoc.lockedTransform) {
+ // reset zoom (ideally, we could probably can tell the map to disallow zooming somehow instead)
+ map?.setZoom(center?.zoom || 10);
+ map?.setCenter({ lat: center?.lat!, lng: center?.lng! });
+ } else {
+ const zoom = map?.getZoom();
+ (center?.zoom !== zoom) && undoBatch(action(() => {
+ Document[`${fieldKey}-mapCenter-zoom`] = zoom;
+ }))();
+ }
+ }}
+ onDragend={(_props?: MapProps, map?: google.maps.Map) => {
+ if (this.layoutDoc.lockedTransform) {
+ // reset the drag (ideally, we could probably can tell the map to disallow dragging somehow instead)
+ map?.setCenter({ lat: center?.lat!, lng: center?.lng! });
+ } else {
+ undoBatch(action(({ lat, lng }) => {
+ Document[`${fieldKey}-mapCenter-lat`] = lat();
+ Document[`${fieldKey}-mapCenter-lng`] = lng();
+ }))(map?.getCenter());
+ }
+ }}
+ >
+ {this.reactiveContents}
+ </GeoMap>
+ </div>
+ </div>;
+ }
+
+}
+
+export default GoogleApiWrapper({
+ apiKey: process.env.GOOGLE_MAPS!,
+ LoadingContainer: () => (
+ <div className={"loadingWrapper"}>
+ <img className={"loadingGif"} src={"/assets/loading.gif"} />
+ </div>
+ )
+})(CollectionMapView) as any; \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index b272151c1..3bada43f0 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -2,14 +2,13 @@ import React = require("react");
import { library } from '@fortawesome/fontawesome-svg-core';
import { faPalette } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import Measure from "react-measure";
import { Doc } from "../../../new_fields/Doc";
import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
import { ScriptField } from "../../../new_fields/ScriptField";
import { StrCast, NumCast } from "../../../new_fields/Types";
-import { numberRange } from "../../../Utils";
+import { numberRange, setupMoveUpEvents, emptyFunction } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
import { CompileScript } from "../../util/Scripting";
@@ -45,39 +44,44 @@ interface CMVFieldRowProps {
export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowProps> {
@observable private _background = "inherit";
@observable private _createAliasSelected: boolean = false;
- @observable private _collapsed: boolean = false;
- @observable private _headingsHack: number = 1;
- @observable private _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
- @observable private _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+ @observable private heading: string = "";
+ @observable private color: string = "#f1efeb";
+ @observable private collapsed: boolean = false;
+ private set _heading(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.heading = this.heading = value)); }
+ private set _color(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.color = this.color = value)); }
+ private set _collapsed(value: boolean) { runInAction(() => this.props.headingObject && (this.props.headingObject.collapsed = this.collapsed = value)); }
private _dropDisposer?: DragManager.DragDropDisposer;
private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
private _contRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _sensitivity: number = 16;
- private _counter: number = 0;
private _ele: any;
createRowDropRef = (ele: HTMLDivElement | null) => {
- this._dropDisposer && this._dropDisposer();
+ this._dropDisposer?.();
if (ele) {
this._ele = ele;
this.props.observeHeight(ele);
this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
}
}
+ @action
+ componentDidMount() {
+ this.heading = this.props.headingObject?.heading || "";
+ this.color = this.props.headingObject?.color || "#f1efeb";
+ this.collapsed = this.props.headingObject?.collapsed || false;
+ }
componentWillUnmount() {
this.props.unobserveHeight(this._ele);
}
getTrueHeight = () => {
- if (this._collapsed) {
- this.props.setDocHeight(this._heading, 20);
+ if (this.collapsed) {
+ this.props.setDocHeight(this.heading, 20);
} else {
const rawHeight = this._contRef.current!.getBoundingClientRect().height + 15; //+ 15 accounts for the group header
const transformScale = this.props.screenToLocalTransform().Scale;
const trueHeight = rawHeight * transformScale;
- this.props.setDocHeight(this._heading, trueHeight);
+ this.props.setDocHeight(this.heading, trueHeight);
}
}
@@ -89,7 +93,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
(this.props.parent.Document.dropConverter instanceof ScriptField) &&
this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData });
const key = StrCast(this.props.parent.props.Document._pivotField);
- const castedValue = this.getValue(this._heading);
+ const castedValue = this.getValue(this.heading);
de.complete.docDragData.droppedDocuments.forEach(d => d[key] = castedValue);
this.props.parent.onInternalDrop(e, de);
e.stopPropagation();
@@ -116,10 +120,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
}
}
this.props.docList.forEach(d => d[key] = castedValue);
- if (this.props.headingObject) {
- this.props.headingObject.setHeading(castedValue.toString());
- this._heading = this.props.headingObject.heading;
- }
+ this._heading = castedValue.toString();
return true;
}
return false;
@@ -128,10 +129,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
@action
changeColumnColor = (color: string) => {
this._createAliasSelected = false;
- if (this.props.headingObject) {
- this.props.headingObject.setColor(color);
- this._color = color;
- }
+ this._color = color;
}
pointerEnteredRow = action(() => SelectionManager.GetIsDragging() && (this._background = "#b4b4b4"));
@@ -140,7 +138,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
pointerLeaveRow = () => {
this._createAliasSelected = false;
this._background = "inherit";
- document.removeEventListener("pointermove", this.startDrag);
}
@action
@@ -164,62 +161,34 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
}));
@action
- collapseSection = () => {
+ collapseSection = (e: any) => {
this._createAliasSelected = false;
- if (this.props.headingObject) {
- this._headingsHack++;
- this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed);
- this.toggleVisibility();
- }
+ this.toggleVisibility();
+ e.stopPropagation();
}
- startDrag = (e: PointerEvent) => {
- const [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
- if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
- const alias = Doc.MakeAlias(this.props.parent.props.Document);
- const key = StrCast(this.props.parent.props.Document._pivotField);
- let value = this.getValue(this._heading);
- value = typeof value === "string" ? `"${value}"` : value;
- const script = `return doc.${key} === ${value}`;
- const compiled = CompileScript(script, { params: { doc: Doc.name } });
- if (compiled.compiled) {
- alias.viewSpecScript = new ScriptField(compiled);
- DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
- }
-
- e.stopPropagation();
- document.removeEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.pointerUp);
+ headerMove = (e: PointerEvent) => {
+ const alias = Doc.MakeAlias(this.props.parent.props.Document);
+ const key = StrCast(this.props.parent.props.Document._pivotField);
+ let value = this.getValue(this.heading);
+ value = typeof value === "string" ? `"${value}"` : value;
+ const script = `return doc.${key} === ${value}`;
+ const compiled = CompileScript(script, { params: { doc: Doc.name } });
+ if (compiled.compiled) {
+ alias.viewSpecScript = new ScriptField(compiled);
+ DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
}
- }
-
- pointerUp = (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
-
- document.removeEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.pointerUp);
+ return true;
}
@action
headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
- e.stopPropagation();
- e.preventDefault();
-
- const [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX, e.clientY);
- this._startDragPosition = { x: dx, y: dy };
-
- if (this._createAliasSelected) {
- document.removeEventListener("pointermove", this.startDrag);
- document.addEventListener("pointermove", this.startDrag);
- document.removeEventListener("pointerup", this.pointerUp);
- document.addEventListener("pointerup", this.pointerUp);
- }
+ setupMoveUpEvents(this, e, this.headerMove, emptyFunction, () => (this.props.parent.props.Document._chromeStatus === "disabled") && this.collapseSection(e));
this._createAliasSelected = false;
}
renderColorPicker = () => {
- const selected = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+ const selected = this.color;
const pink = PastelSchemaPalette.get("pink2");
const purple = PastelSchemaPalette.get("purple4");
@@ -249,7 +218,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
}
toggleAlias = action(() => this._createAliasSelected = true);
- toggleVisibility = action(() => this._collapsed = !this._collapsed);
+ toggleVisibility = () => this._collapsed = !this.collapsed;
renderMenu = () => {
const selected = this._createAliasSelected;
@@ -261,27 +230,19 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
</div>);
}
- handleResize = (size: any) => {
- if (++this._counter !== 1) {
- this.getTrueHeight();
- }
- }
-
@computed get contentLayout() {
const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
const style = this.props.parent;
- const collapsed = this._collapsed;
const chromeStatus = this.props.parent.props.Document._chromeStatus;
const newEditableViewProps = {
GetValue: () => "",
SetValue: this.addDocument,
contents: "+ NEW",
HeadingObject: this.props.headingObject,
- HeadingsHack: this._headingsHack,
toggle: this.toggleVisibility,
- color: this._color
+ color: this.color
};
- return collapsed ? (null) :
+ return this.collapsed ? (null) :
<div style={{ position: "relative" }}>
{(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ?
<div className="collectionStackingView-addDocumentButton"
@@ -307,18 +268,17 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
}
@computed get headingView() {
- const heading = this._heading;
+ const noChrome = this.props.parent.props.Document._chromeStatus === "disabled";
const key = StrCast(this.props.parent.props.Document._pivotField);
- const evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
+ const evContents = this.heading ? this.heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
const headerEditableViewProps = {
GetValue: () => evContents,
SetValue: this.headingChanged,
contents: evContents,
oneLine: true,
HeadingObject: this.props.headingObject,
- HeadingsHack: this._headingsHack,
toggle: this.toggleVisibility,
- color: this._color
+ color: this.color
};
return this.props.parent.props.Document.miniHeaders ?
<div className="collectionStackingView-miniHeader">
@@ -329,9 +289,9 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
<div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
title={evContents === `NO ${key.toUpperCase()} VALUE` ?
`Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
- style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey" }}>
- <EditableView {...headerEditableViewProps} />
- {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
+ style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this.color : "lightgrey" }}>
+ {noChrome ? evContents : <EditableView {...headerEditableViewProps} />}
+ {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
<div className="collectionStackingView-sectionColor">
<Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
<button className="collectionStackingView-sectionColorButton">
@@ -340,10 +300,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
</ Flyout >
</div>
}
- <button className="collectionStackingView-sectionDelete" onClick={this.collapseSection}>
- <FontAwesomeIcon icon={this._collapsed ? "chevron-down" : "chevron-up"} size="lg" />
- </button>
- {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
+ {noChrome ? (null) : <button className="collectionStackingView-sectionDelete" onClick={noChrome ? undefined : this.collapseSection}>
+ <FontAwesomeIcon icon={this.collapsed ? "chevron-down" : "chevron-up"} size="lg" />
+ </button>}
+ {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
<div className="collectionStackingView-sectionOptions">
<Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
<button className="collectionStackingView-sectionOptionButton">
@@ -356,23 +316,15 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
</div>;
}
render() {
- const background = this._background; //to account for observables in Measure
- const contentlayout = this.contentLayout;
- const headingview = this.headingView;
- return <Measure offset onResize={this.handleResize}>
- {({ measureRef }) => {
- return <div ref={measureRef}>
- <div className="collectionStackingView-masonrySection"
- style={{ width: this.props.parent.NodeWidth, background }}
- ref={this.createRowDropRef}
- onPointerEnter={this.pointerEnteredRow}
- onPointerLeave={this.pointerLeaveRow}
- >
- {headingview}
- {contentlayout}
- </div >
- </div>;
- }}
- </Measure>;
+ const background = this._background;
+ return <div className="collectionStackingView-masonrySection"
+ style={{ width: this.props.parent.NodeWidth, background }}
+ ref={this.createRowDropRef}
+ onPointerEnter={this.pointerEnteredRow}
+ onPointerLeave={this.pointerLeaveRow}
+ >
+ {this.headingView}
+ {this.contentLayout}
+ </div >;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionPileView.scss b/src/client/views/collections/CollectionPileView.scss
new file mode 100644
index 000000000..ac874b663
--- /dev/null
+++ b/src/client/views/collections/CollectionPileView.scss
@@ -0,0 +1,8 @@
+.collectionPileView {
+ display: flex;
+ flex-direction: row;
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ overflow: visible;
+}
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
new file mode 100644
index 000000000..3bbfcc4d7
--- /dev/null
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -0,0 +1,127 @@
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
+import { CollectionSubView } from "./CollectionSubView";
+import "./CollectionPileView.scss";
+import React = require("react");
+import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils";
+import { SelectionManager } from "../../util/SelectionManager";
+import { UndoManager } from "../../util/UndoManager";
+
+@observer
+export class CollectionPileView extends CollectionSubView(doc => doc) {
+ _lastTap = 0;
+ _doubleTap: boolean | undefined = false;
+ _originalChrome: string = "";
+ @observable _contentsActive = true;
+ @observable _layoutEngine = "pass";
+ @observable _collapsed: boolean = false;
+ @observable _childClickedScript: Opt<ScriptField>;
+ componentDidMount() {
+ this._originalChrome = StrCast(this.layoutDoc._chromeStatus);
+ this.layoutDoc._chromeStatus = "disabled";
+ this.layoutDoc.hideFilterView = true;
+ }
+ componentWillUnmount() {
+ this.layoutDoc.hideFilterView = false;
+ this.layoutDoc._chromeStatus = this._originalChrome;
+ }
+
+ layoutEngine = () => this._layoutEngine;
+
+ @computed get contents() {
+ return <div className="collectionPileView-innards" style={{
+ width: "100%",
+ pointerEvents: this.layoutEngine() !== "pass" && (this.props.active() || this.layoutEngine() === "starburst") ? undefined : "none"
+ }} >
+ <CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine} />
+ </div>;
+ }
+
+ specificMenu = (e: React.MouseEvent) => {
+ const layoutItems: ContextMenuProps[] = [];
+ const doc = this.props.Document;
+
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
+ }
+
+ toggleStarburst = action(() => {
+ if (this._layoutEngine === 'starburst') {
+ const defaultSize = 110;
+ this.layoutDoc.overflow = undefined;
+ this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
+ this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
+ this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
+ this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
+ this._layoutEngine = 'pass';
+ } else {
+ const defaultSize = 25;
+ this.layoutDoc.overflow = 'visible';
+ !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500);
+ !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5);
+ if (this._layoutEngine === 'pass') {
+ this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2;
+ this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2;
+ this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym]();
+ this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym]();
+ }
+ this.layoutDoc._width = this.layoutDoc._height = defaultSize;
+ this._layoutEngine = 'starburst';
+ }
+ });
+
+ _undoBatch: UndoManager.Batch | undefined;
+ pointerDown = (e: React.PointerEvent) => {
+ let dist = 0;
+ SelectionManager.SetIsDragging(true);
+ // this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header
+ setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => {
+ if (this.layoutEngine() === "pass" && this.childDocs.length && this.props.isSelected(true)) {
+ dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
+ if (dist > 100) {
+ if (!this._undoBatch) {
+ this._undoBatch = UndoManager.StartBatch("layout pile");
+ }
+ const doc = this.childDocs[0];
+ doc.x = e.clientX;
+ doc.y = e.clientY;
+ this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc);
+ dist = 0;
+ }
+ }
+ return false;
+ }, () => {
+ this._undoBatch?.end();
+ this._undoBatch = undefined;
+ SelectionManager.SetIsDragging(false);
+ if (!this.childDocs.length) {
+ this.props.ContainingCollectionView?.removeDocument(this.props.Document);
+ }
+ }, emptyFunction, false, this.layoutEngine() === "pass" && this.props.isSelected(true)); // this sets _doubleTap
+ }
+
+ onClick = (e: React.MouseEvent) => {
+ if (e.button === 0 && (this._doubleTap || this.layoutEngine() === "starburst")) {
+ SelectionManager.DeselectAll();
+ this.toggleStarburst();
+ e.stopPropagation();
+ }
+ // else if (this.layoutEngine() === "pass") {
+ // runInAction(() => this._contentsActive = false);
+ // setTimeout(action(() => this._contentsActive = true), 300);
+ // }
+ }
+
+ render() {
+
+ return <div className={"collectionPileView"} onContextMenu={this.specificMenu} onClick={this.onClick} onPointerDown={this.pointerDown}
+ style={{ width: this.props.PanelWidth(), height: `calc(100% - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
+ {this.contents}
+ </div>;
+ }
+}
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index ae71c54f7..82204ca7b 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -4,8 +4,9 @@ import { observer } from "mobx-react";
import { CellInfo } from "react-table";
import "react-table/react-table.css";
import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
-import { Doc, DocListCast, DocListCastAsync, Field, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
+import { KeyCodes } from "../../util/KeyCodes";
import { SetupDrag, DragManager } from "../../util/DragManager";
import { CompileScript } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
@@ -21,9 +22,7 @@ import { SelectionManager } from "../../util/SelectionManager";
import { library } from '@fortawesome/fontawesome-svg-core';
import { faExpand } from '@fortawesome/free-solid-svg-icons';
import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { KeyCodes } from "../../northstar/utils/KeyCodes";
import { undoBatch } from "../../util/UndoManager";
-import { List } from "lodash";
library.add(faExpand);
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index 670d6dbb2..972714e34 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -54,7 +54,7 @@ export class MovableColumn extends React.Component<MovableColumnProps> {
}
createColDropTarget = (ele: HTMLDivElement) => {
- this._colDropDisposer && this._colDropDisposer();
+ this._colDropDisposer?.();
if (ele) {
this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index e835811c9..380d91d2f 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -14,7 +14,6 @@ import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
import { ComputedField } from "../../../new_fields/ScriptField";
import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
import { Docs, DocumentOptions } from "../../documents/Documents";
-import { Gateway } from "../../northstar/manager/Gateway";
import { CompileScript, Transformer, ts } from "../../util/Scripting";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
@@ -673,27 +672,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
}
- @action
- makeDB = async () => {
- let csv: string = this.columns.reduce((val, col) => val + col + ",", "");
- csv = csv.substr(0, csv.length - 1) + "\n";
- const self = this;
- this.childDocs.map(doc => {
- csv += self.columns.reduce((val, col) => val + (doc[col.heading] ? doc[col.heading]!.toString() : "0") + ",", "");
- csv = csv.substr(0, csv.length - 1) + "\n";
- });
- csv.substring(0, csv.length - 1);
- const dbName = StrCast(this.props.Document.title);
- const res = await Gateway.Instance.PostSchema(csv, dbName);
- if (self.props.CollectionView && self.props.CollectionView.props.addDocument) {
- const schemaDoc = await Docs.Create.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }, { dbDoc: self.props.Document });
- if (schemaDoc) {
- //self.props.CollectionView.props.addDocument(schemaDoc, false);
- self.props.Document.schemaDoc = schemaDoc;
- }
- }
- }
-
getField = (row: number, col?: number) => {
const docs = this.childDocs;
@@ -758,7 +736,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
return (doc as any)[key][row + ${row}][(doc as any).schemaColumns[col + ${col}].heading];
}
return ${script}`;
- const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: true, transformer: this.createTransformer(row, col) });
+ const compiled = CompileScript(script, { params: { this: Doc.name }, capturedVariables: { doc: this.props.Document, key: this.props.fieldKey }, typecheck: false, transformer: this.createTransformer(row, col) });
if (compiled.compiled) {
doc[field] = new ComputedField(compiled);
return true;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index da53888fc..e3720bf01 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -49,7 +49,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
@computed get columnWidth() {
TraceMobx();
return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
- this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
+ this.isStackingView ? Number.MAX_VALUE : this.props.Document.columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.props.Document.columnWidth, 250));
}
@computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
@@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
const dxf = () => this.getDocTransform(d, dref.current!);
this._docXfs.push({ dxf: dxf, width: width, height: height });
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
- const style = this.isStackingView ? { width: width(), marginTop: this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
+ const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
{this.getDisplayDoc(d, (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc, dxf, width)}
</div>;
@@ -153,6 +153,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
@computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
@computed get onClickHandler() { return ScriptCast(this.Document.onChildClick); }
+ addDocTab = (doc: Doc, where: string) => {
+ if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+ this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+ return true;
+ }
+ return this.props.addDocTab(doc, where);
+ }
getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
const height = () => this.getDocHeight(doc);
@@ -181,9 +188,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
removeDocument={this.props.removeDocument}
active={this.props.active}
whenActiveChanged={this.props.whenActiveChanged}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.pinToPres}>
- </ContentFittingDocumentView>;
+ addDocTab={this.addDocTab}
+ pinToPres={this.props.pinToPres}
+ />;
}
getDocWidth(d?: Doc) {
@@ -296,7 +303,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
this.observer = new _global.ResizeObserver(action((entries: any) => {
if (this.props.Document._autoHeight && ref && this.refList.length && !SelectionManager.GetIsDragging()) {
- Doc.Layout(doc)._height = Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", ""))));
+ Doc.Layout(doc)._height = Math.min(1200, Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
}
}));
this.observer.observe(ref);
@@ -390,7 +397,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
if (!e.isPropagationStopped()) {
const subItems: ContextMenuProps[] = [];
subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
- ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
}
}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 5d926b7c7..323d7be25 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -156,7 +156,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
@action
collapseSection = () => {
if (this.props.headingObject) {
- this._headingsHack++;
this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed);
this.toggleVisibility();
}
@@ -225,8 +224,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
private toggleVisibility = action(() => this.collapsed = !this.collapsed);
- @observable _headingsHack: number = 1;
-
menuCallback = (x: number, y: number) => {
ContextMenu.Instance.clearItems();
const layoutItems: ContextMenuProps[] = [];
@@ -300,7 +297,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
contents: evContents,
oneLine: true,
HeadingObject: this.props.headingObject,
- HeadingsHack: this._headingsHack,
toggle: this.toggleVisibility,
color: this._color
};
@@ -309,7 +305,6 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
SetValue: this.addDocument,
contents: "+ NEW",
HeadingObject: this.props.headingObject,
- HeadingsHack: this._headingsHack,
toggle: this.toggleVisibility,
color: this._color
};
@@ -364,7 +359,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
<div className="collectionStackingViewFieldColumn" key={heading}
style={{
width: `${100 / ((uniqueHeadings.length + ((chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? 1 : 0)) || 1)}%`,
- height: SelectionManager.GetIsDragging() ? "100%" : undefined,
+ height: undefined, // SelectionManager.GetIsDragging() ? "100%" : undefined,
background: this._background
}}
ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 746b2e174..49abc6ee6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -11,7 +11,7 @@ import { Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
import { DocumentType } from "../../documents/DocumentTypes";
import { Docs, DocumentOptions } from "../../documents/Documents";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
import { undoBatch, UndoManager } from "../../util/UndoManager";
import { DocComponent } from "../DocComponent";
import { FieldViewProps } from "../nodes/FieldView";
@@ -64,7 +64,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.multiTouchDisposer?.();
if (ele) {
this._mainCont = ele;
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
}
@@ -99,8 +99,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
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
}
- rootSelected = (outsideReaction: boolean) => {
- return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected(outsideReaction) : false);
+ rootSelected = (outsideReaction?: boolean) => {
+ return this.props.isSelected(outsideReaction) || (this.rootDoc && this.props.rootSelected(outsideReaction));
}
// 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.
@@ -120,8 +120,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
return Cast(this.dataField, listSpec(Doc));
}
@computed get childDocs() {
- const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), []);
- const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ const docFilters = this.props.ignoreFields?.includes("_docFilters") ? [] : Cast(this.props.Document._docFilters, listSpec("string"), []);
+ const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
for (let i = 0; i < docFilters.length; i += 3) {
const [key, value, modifiers] = docFilters.slice(i, i + 3);
@@ -381,13 +381,14 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
alert(`Upload failed: ${result.message}`);
return;
}
- const full = { ...options, _width: 300, title: name };
+ const full = { ...options, _width: 400, title: name };
const pathname = Utils.prepend(result.accessPaths.agnostic.client);
const doc = await Docs.Get.DocumentFromType(type, pathname, full);
if (!doc) {
continue;
}
const proto = Doc.GetProto(doc);
+ proto.text = result.rawText;
proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
if (Upload.isImageInformation(result)) {
proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400;
@@ -397,8 +398,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
generatedDocuments.push(doc);
}
if (generatedDocuments.length) {
- generatedDocuments.forEach(addDocument);
- completed && completed();
+ const set = generatedDocuments.length > 1 && generatedDocuments.map(d => Doc.iconify(d));
+ if (set) {
+ addDocument(Doc.pileup(generatedDocuments, options.x!, options.y!));
+ } else {
+ generatedDocuments.forEach(addDocument);
+ }
+ completed?.();
} else {
if (text && !text.includes("https://")) {
addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 53de2fbbe..045134225 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -1,11 +1,11 @@
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt, DocCastAsync } from "../../../new_fields/Doc";
import { List } from "../../../new_fields/List";
import { ObjectField } from "../../../new_fields/ObjectField";
import { RichTextField } from "../../../new_fields/RichTextField";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
+import { NumCast, StrCast, BoolCast, Cast } from "../../../new_fields/Types";
import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
import { Scripting } from "../../util/Scripting";
import { ContextMenu } from "../ContextMenu";
@@ -25,17 +25,15 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
_changing = false;
@observable _layoutEngine = "pivot";
@observable _collapsed: boolean = false;
- componentWillUnmount() {
- this.props.Document.onChildClick = undefined;
- }
- componentDidMount() {
- const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked;
- const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(thisContainer.childDetailed, alias, 'layout_detailView'); alias.layoutKey='layout_detailedView'; alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
- this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", thisContainer: Doc.name, shiftKey: "boolean" });
- this.props.Document._fitToBox = true;
- if (!this.props.Document.onViewDefClick) {
- this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" });
- }
+ @observable _childClickedScript: Opt<ScriptField>;
+ @observable _viewDefDivClick: Opt<ScriptField>;
+ async componentDidMount() {
+ const detailView = (await DocCastAsync(this.props.Document.childDetailView)) || Doc.findTemplate("detailView", StrCast(this.props.Document.type), "");
+ const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
+ runInAction(() => {
+ this._childClickedScript = ScriptField.MakeScript(childText, { this: Doc.name, shiftKey: "boolean" }, { detailView: detailView! });
+ this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" });
+ });
}
layoutEngine = () => this._layoutEngine;
@@ -70,15 +68,29 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
}), returnFalse, emptyFunction);
}
+ contentsDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e, returnFalse, returnFalse, action(() => {
+ let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex);
+ if (prevFilterIndex > 0) {
+ prevFilterIndex--;
+ this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField);
+ this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField);
+ this.props.Document._prevFilterIndex = prevFilterIndex;
+ } else {
+ this.props.Document._docFilters = new List([]);
+ }
+ }), false);
+ }
+
@computed get contents() {
- return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }}>
- <CollectionFreeFormView {...this.props} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
+ return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%", pointerEvents: this.props.active() ? undefined : "none" }} onPointerDown={this.contentsDown}>
+ <CollectionFreeFormView {...this.props} childClickScript={this._childClickedScript} viewDefDivClick={this._viewDefDivClick} fitToBox={true} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
</div>;
}
public static SyncTimelineToPresentation(doc: Doc) {
const fieldKey = Doc.LayoutFieldKey(doc);
- doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(curPresentationItem()[this._pivotField || 'year'] || 0)");
+ doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)");
}
specificMenu = (e: React.MouseEvent) => {
const layoutItems: ContextMenuProps[] = [];
@@ -89,7 +101,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" });
layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" });
- ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
}
@computed get _allFacets() {
const facets = new Set<string>();
@@ -130,20 +142,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
color: "#f1efeb" // this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
};
return <div className={"pivotKeyEntry"}>
- <button className="collectionTimeView-backBtn"
- onClick={action(() => {
- let prevFilterIndex = NumCast(this.props.Document._prevFilterIndex);
- if (prevFilterIndex > 0) {
- prevFilterIndex--;
- this.props.Document._docFilters = ObjectField.MakeCopy(this.props.Document["_prevDocFilter" + prevFilterIndex] as ObjectField);
- this.props.Document._docRangeFilters = ObjectField.MakeCopy(this.props.Document["_prevDocRangeFilters" + prevFilterIndex] as ObjectField);
- this.props.Document._prevFilterIndex = prevFilterIndex;
- } else {
- this.props.Document._docFilters = new List([]);
- }
- })}>
- back
- </button>
<EditableView {...newEditableViewProps} display={"inline"} menuCallback={this.menuCallback} />
</div>;
}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 8e95f7fbe..a00bb6bfb 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -82,6 +82,7 @@
text-overflow: ellipsis;
white-space: pre-wrap;
overflow: hidden;
+ min-width: 10px;
// width:100%;//width: max-content;
}
@@ -100,10 +101,29 @@
border-left: dashed 1px #00000042;
}
+.treeViewItem-header {
+ border: transparent 1px solid;
+ display: flex;
+
+ .editableView-container-editing-oneLine {
+ min-width: 15px;
+ }
+ .documentView-node-topmost {
+ width: unset;
+ }
+ > svg {
+ display: none;
+ }
+
+}
+
.treeViewItem-header:hover {
.collectionTreeView-keyHeader {
display: inherit;
}
+ > svg {
+ display: inherit;
+ }
.treeViewItem-openRight {
display: inline-block;
@@ -119,18 +139,6 @@
}
}
-.treeViewItem-header {
- border: transparent 1px solid;
- display: flex;
-
- .editableView-container-editing-oneLine {
- min-width: 15px;
- }
- .documentView-node-topmost {
- width: unset;
- }
-}
-
.treeViewItem-header-above {
border-top: black 1px solid;
}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7edda5a4f..d938bd7ad 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -3,14 +3,14 @@ import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, runInAction, untracked } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, Field, HeightSym, WidthSym, DataSym, Opt } from '../../../new_fields/Doc';
+import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc';
import { Id } from '../../../new_fields/FieldSymbols';
import { List } from '../../../new_fields/List';
-import { Document, listSpec, createSchema, makeInterface } from '../../../new_fields/Schema';
+import { RichTextField } from '../../../new_fields/RichTextField';
+import { Document, listSpec } from '../../../new_fields/Schema';
import { ComputedField, ScriptField } from '../../../new_fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { emptyFunction, emptyPath, returnFalse, Utils, returnOne, returnZero, returnTransparent, returnTrue } from '../../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from "../../documents/DocumentTypes";
import { DocumentManager } from '../../util/DocumentManager';
@@ -19,22 +19,20 @@ import { makeTemplate } from '../../util/DropConverter';
import { Scripting } from '../../util/Scripting';
import { SelectionManager } from '../../util/SelectionManager';
import { Transform } from '../../util/Transform';
-import { undoBatch } from '../../util/UndoManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { EditableView } from "../EditableView";
import { MainView } from '../MainView';
import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
+import { DocumentView } from '../nodes/DocumentView';
import { ImageBox } from '../nodes/ImageBox';
import { KeyValueBox } from '../nodes/KeyValueBox';
-import { ScriptBox } from '../ScriptBox';
import { Templates } from '../Templates';
-import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView";
+import { CollectionSubView } from "./CollectionSubView";
import "./CollectionTreeView.scss";
-import React = require("react");
import { CollectionViewType } from './CollectionView';
-import { RichTextField } from '../../../new_fields/RichTextField';
-import { DocumentView } from '../nodes/DocumentView';
+import React = require("react");
export interface TreeViewProps {
@@ -139,13 +137,15 @@ class TreeView extends React.Component<TreeViewProps> {
@undoBatch @action remove = (document: Document, key: string) => {
return Doc.RemoveDocFromList(this.dataDoc, key, document);
}
+ @undoBatch @action removeDoc = (document: Document) => {
+ return Doc.RemoveDocFromList(this.props.containingCollection, Doc.LayoutFieldKey(this.props.containingCollection), document);
+ }
protected createTreeDropTarget = (ele: HTMLDivElement) => {
this._treedropDisposer && this._treedropDisposer();
- ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)));
+ ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)), this.props.document);
}
- onPointerDown = (e: React.PointerEvent) => e.stopPropagation();
onPointerEnter = (e: React.PointerEvent): void => {
this.props.active(true) && Doc.BrushDoc(this.dataDoc);
if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
@@ -182,19 +182,18 @@ class TreeView extends React.Component<TreeViewProps> {
GetValue={() => StrCast(this.props.document[key])}
SetValue={undoBatch((value: string) => {
Doc.SetInPlace(this.props.document, key, value, false) || true;
- this.props.document.editTitle = undefined;
+ Doc.SetInPlace(this.props.document, "editTitle", undefined, false);
})}
OnFillDown={undoBatch((value: string) => {
Doc.SetInPlace(this.props.document, key, value, false);
const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
- //EditableView.loadId = doc[Id];
- this.props.document.editTitle = undefined;
- doc.editTitle = true;
+ Doc.SetInPlace(this.props.document, "editTitle", undefined, false);
+ Doc.SetInPlace(doc, "editTitle", true, false);
return this.props.addDocument(doc);
})}
onClick={() => {
SelectionManager.DeselectAll();
- Doc.UserDoc().SelectedDocs = new List([this.props.document]);
+ Doc.UserDoc().activeSelection = new List([this.props.document]);
return false;
}}
OnTab={undoBatch((shift?: boolean) => {
@@ -208,33 +207,6 @@ class TreeView extends React.Component<TreeViewProps> {
})}
/>)
- onWorkspaceContextMenu = (e: React.MouseEvent): void => {
- if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view
- const sort = this.props.document[`${this.fieldKey}-sortAscending`];
- if (this.props.document === CurrentUserUtils.UserDocument.recentlyClosed) {
- ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List<Doc>(), icon: "plus" });
- } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) {
- ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" });
- ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab", this.props.libraryPath), icon: "folder" });
- ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath), icon: "caret-square-right" });
- if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) {
- ContextMenu.Instance.addItem({ description: "Focus", event: () => (view => view && view.props.focus(this.props.document, true))(DocumentManager.Instance.getFirstDocumentView(this.props.document)), icon: "camera" });
- }
- ContextMenu.Instance.addItem({ description: "Delete Item", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
- } else {
- ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
- ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
- }
- ContextMenu.Instance.addItem({ description: (sort ? "Sort Descending" : (sort === false ? "Unsort" : "Sort Ascending")), event: () => this.props.document[`${this.fieldKey}-sortAscending`] = (sort ? false : (sort === false ? undefined : true)), icon: "minus" });
- ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" });
- ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, "onRight"); }, icon: "layer-group" });
- ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
- ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
- e.stopPropagation();
- e.preventDefault();
- }
- }
-
@undoBatch
treeDrop = (e: Event, de: DragManager.DropEvent) => {
const pt = [de.x, de.y];
@@ -255,7 +227,8 @@ class TreeView extends React.Component<TreeViewProps> {
addDoc = (doc: Doc) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc) || addDoc(doc);
}
const movedDocs = (de.complete.docDragData.treeViewId === this.props.treeViewId[Id] ? de.complete.docDragData.draggedDocuments : de.complete.docDragData.droppedDocuments);
- return ((de.complete.docDragData.dropAction && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ?
+ const move = de.complete.docDragData.dropAction === "move" || de.complete.docDragData.dropAction;
+ return ((!move && (de.complete.docDragData.treeViewId !== this.props.treeViewId[Id])) || de.complete.docDragData.userDropAction) ?
de.complete.docDragData.droppedDocuments.reduce((added, d) => addDoc(d) || added, false)
: de.complete.docDragData.moveDocument ?
movedDocs.reduce((added, d) => de.complete.docDragData?.moveDocument?.(d, undefined, addDoc) || added, false)
@@ -288,7 +261,7 @@ class TreeView extends React.Component<TreeViewProps> {
docHeight = () => {
const layoutDoc = Doc.Layout(this.props.document);
const bounds = this.boundsOfCollectionDocument;
- return Math.min(this.MAX_EMBED_HEIGHT, (() => {
+ return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
if (aspect) return this.docWidth() * aspect;
if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x);
@@ -296,7 +269,7 @@ class TreeView extends React.Component<TreeViewProps> {
Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
NumCast(this.props.containingCollection._height)))) :
NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
- })());
+ })()));
}
@computed get expandedField() {
@@ -306,7 +279,7 @@ class TreeView extends React.Component<TreeViewProps> {
const rows: JSX.Element[] = [];
for (const key of Object.keys(ids).slice().sort()) {
- if (this.props.ignoreFields?.includes(key)) continue;
+ if (this.props.ignoreFields?.includes(key) || key === "title" || key === "treeViewOpen") continue;
const contents = doc[key];
let contentElement: (JSX.Element | null)[] | JSX.Element = [];
@@ -348,17 +321,24 @@ class TreeView extends React.Component<TreeViewProps> {
return rows;
}
+ rtfWidth = () => Math.min(Doc.Layout(this.props.document)?.[WidthSym](), this.props.panelWidth() - 20);
+ rtfHeight = () => this.rtfWidth() < Doc.Layout(this.props.document)?.[WidthSym]() ? Math.min(Doc.Layout(this.props.document)?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
+
@computed get renderContent() {
const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
if (expandKey !== undefined) {
const remDoc = (doc: Doc) => this.remove(doc, expandKey);
const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true);
const docs = expandKey === "links" ? this.childLinks : this.childDocs;
- return <ul key={expandKey + "more"}>
+ const sortKey = `${this.fieldKey}-sortAscending`;
+ return <ul key={expandKey + "more"} onClick={(e) => {
+ this.props.document[sortKey] = (this.props.document[sortKey] ? false : (this.props.document[sortKey] === false ? undefined : true));
+ e.stopPropagation();
+ }}>
{!docs ? (null) :
TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
- this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
+ StrCast(this.props.document.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
[...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields)}
</ul >;
@@ -368,7 +348,9 @@ class TreeView extends React.Component<TreeViewProps> {
</div></ul>;
} else {
const layoutDoc = Doc.Layout(this.props.document);
- return <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
+ const panelHeight = layoutDoc.type === DocumentType.RTF ? this.rtfHeight : this.docHeight;
+ const panelWidth = layoutDoc.type === DocumentType.RTF ? this.rtfWidth : this.docWidth;
+ return <div ref={this._dref} style={{ display: "inline-block", height: panelHeight() }} key={this.props.document[Id] + this.props.document.title}>
<ContentFittingDocumentView
Document={layoutDoc}
DataDocument={this.templateDataDoc}
@@ -378,8 +360,10 @@ class TreeView extends React.Component<TreeViewProps> {
backgroundColor={this.props.backgroundColor}
fitToBox={this.boundsOfCollectionDocument !== undefined}
FreezeDimensions={true}
- PanelWidth={this.docWidth}
- PanelHeight={this.docHeight}
+ NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
+ NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
+ PanelWidth={panelWidth}
+ PanelHeight={panelHeight}
getTransform={this.docTransform}
CollectionDoc={this.props.containingCollection}
CollectionView={undefined}
@@ -394,11 +378,13 @@ class TreeView extends React.Component<TreeViewProps> {
}
}
+ get onCheckedClick() { return this.props.onCheckedClick || ScriptCast(this.props.document.onCheckedClick); }
+
@action
bulletClick = (e: React.MouseEvent) => {
- if (this.props.onCheckedClick && this.props.document.type !== DocumentType.COL) {
+ if (this.onCheckedClick && this.props.document.type !== DocumentType.COL) {
// this.props.document.treeViewChecked = this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check";
- ScriptCast(this.props.onCheckedClick).script.run({
+ this.onCheckedClick.script.run({
this: this.props.document.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.props.document,
heading: this.props.containingCollection.title,
checked: this.props.document.treeViewChecked === "check" ? "x" : this.props.document.treeViewChecked === "x" ? undefined : "check",
@@ -412,33 +398,47 @@ class TreeView extends React.Component<TreeViewProps> {
@computed
get renderBullet() {
- const checked = this.props.document.type === DocumentType.COL ? undefined : this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
+ const checked = this.props.document.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "inherit"), opacity: checked === "unchecked" ? undefined : 0.4 }}>
{<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
</div>;
}
+
+ showContextMenu = (e: React.MouseEvent) => {
+ simulateMouseClick(this._docRef.current!.ContentDiv!, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+ e.stopPropagation();
+ }
+ focusOnDoc = (doc: Doc) => DocumentManager.Instance.getFirstDocumentView(doc)?.props.focus(doc, true);
+ contextMenuItems = () => {
+ const focusScript = ScriptField.MakeFunction(`DocFocus(self)`);
+ return [{ script: focusScript!, label: "Focus" }];
+ }
+ _docRef = React.createRef<DocumentView>();
/**
* Renders the EditableView title element for placement into the tree.
*/
@computed
get renderTitle() {
const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
- const editTitle = ScriptField.MakeFunction("this.editTitle=true", { this: Doc.name });
+ const editTitle = ScriptField.MakeFunction("setInPlace(this, 'editTitle', true)");
const headerElements = (
- <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
- onPointerDown={action(() => {
- if (this.treeViewOpen) {
- this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
- this.treeViewExpandedView === "fields" && Doc.Layout(this.props.document) ? "layout" :
- this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
- this.childDocs ? this.fieldKey : "fields";
- }
- this.treeViewOpen = true;
- })}>
- {this.treeViewExpandedView}
- </span>);
- const openRight = (<div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
+ <>
+ <FontAwesomeIcon icon="cog" size="sm" onClick={e => this.showContextMenu(e)}></FontAwesomeIcon>
+ <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
+ onPointerDown={action(() => {
+ if (this.treeViewOpen) {
+ this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
+ this.treeViewExpandedView === "fields" && Doc.Layout(this.props.document) ? "layout" :
+ this.treeViewExpandedView === "layout" && this.props.document.links ? "links" :
+ this.childDocs ? this.fieldKey : "fields";
+ }
+ this.treeViewOpen = true;
+ })}>
+ {this.treeViewExpandedView}
+ </span>
+ </>);
+ const openRight = (<div className="treeViewItem-openRight" onClick={this.openRight}>
<FontAwesomeIcon title="open in pane on right" icon="angle-right" size="lg" />
</div>);
return <>
@@ -446,12 +446,14 @@ class TreeView extends React.Component<TreeViewProps> {
style={{
background: Doc.IsHighlighted(this.props.document) ? "orange" : Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
fontWeight: this.props.document.searchMatch ? "bold" : undefined,
+ textDecoration: Doc.GetT(this.props.document, "title", "string", true) ? "underline" : undefined,
outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
- pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
+ pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? undefined : "none"
}} >
- {this.props.document.editTitle ?
+ {Doc.GetT(this.props.document, "editTitle", "boolean", true) ?
this.editableView("title") :
<DocumentView
+ ref={this._docRef}
Document={this.props.document}
DataDoc={undefined}
LibraryPath={this.props.libraryPath || []}
@@ -461,14 +463,15 @@ class TreeView extends React.Component<TreeViewProps> {
pinToPres={emptyFunction}
onClick={this.props.onChildClick || editTitle}
dropAction={this.props.dropAction}
- moveDocument={this.props.moveDocument}
- removeDocument={undefined}
+ moveDocument={this.move}
+ removeDocument={this.removeDoc}
ScreenToLocalTransform={this.getTransform}
ContentScaling={returnOne}
PanelWidth={returnZero}
PanelHeight={returnZero}
NativeHeight={returnZero}
NativeWidth={returnZero}
+ contextMenuItems={this.contextMenuItems}
renderDepth={1}
focus={emptyFunction}
parentActive={returnTrue}
@@ -476,7 +479,7 @@ class TreeView extends React.Component<TreeViewProps> {
bringToFront={emptyFunction}
dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildren)}
ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
+ ContainingCollectionDoc={this.props.containingCollection}
/>}
</div >
{this.props.treeViewHideHeaderFields() ? (null) : headerElements}
@@ -485,14 +488,25 @@ class TreeView extends React.Component<TreeViewProps> {
}
render() {
+ const sorting = this.props.document[`${this.fieldKey}-sortAscending`];
setTimeout(() => runInAction(() => untracked(() => this._overrideTreeViewOpen = this.treeViewOpen)), 0);
- return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onContextMenu={this.onWorkspaceContextMenu}>
+ return <div className="treeViewItem-container" ref={this.createTreeDropTarget}>
<li className="collection-child">
- <div className="treeViewItem-header" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
+ <div className="treeViewItem-header" ref={this._header} onClick={e => {
+ if (this.props.active(true)) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }} onPointerDown={e => {
+ if (this.props.active(true)) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
{this.renderBullet}
{this.renderTitle}
</div>
- <div className="treeViewItem-border">
+ <div className="treeViewItem-border" style={{ borderColor: sorting === undefined ? undefined : sorting ? "crimson" : "blue" }}>
{!this.treeViewOpen || this.props.renderedIds.indexOf(this.props.document[Id]) !== -1 ? (null) : this.renderContent}
</div>
</li>
@@ -647,22 +661,22 @@ export type collectionTreeViewProps = {
};
@observer
-export class CollectionTreeView extends CollectionSubView(Document, undefined as any as collectionTreeViewProps) {
+export class CollectionTreeView extends CollectionSubView<Document, Partial<collectionTreeViewProps>>(Document) {
private treedropDisposer?: DragManager.DragDropDisposer;
private _mainEle?: HTMLDivElement;
@computed get dataDoc() { return this.props.DataDoc || this.props.Document; }
protected createTreeDropTarget = (ele: HTMLDivElement) => {
- this.treedropDisposer && this.treedropDisposer();
+ this.treedropDisposer?.();
if (this._mainEle = ele) {
- this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+ this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.props.Document);
}
}
componentWillUnmount() {
super.componentWillUnmount();
- this.treedropDisposer && this.treedropDisposer();
+ this.treedropDisposer?.();
}
@action
@@ -687,14 +701,14 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
}
onContextMenu = (e: React.MouseEvent): void => {
// need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
- if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.workspaces) {
+ if (!e.isPropagationStopped() && this.props.Document === Doc.UserDoc().myWorkspaces) {
ContextMenu.Instance.addItem({ description: "Create Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.remove(this.props.Document), icon: "minus" });
e.stopPropagation();
e.preventDefault();
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
- } else if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.recentlyClosed) {
- ContextMenu.Instance.addItem({ description: "Clear All", event: () => CurrentUserUtils.UserDocument.recentlyClosed = new List<Doc>(), icon: "plus" });
+ } else if (!e.isPropagationStopped() && this.props.Document === Doc.UserDoc().myRecentlyClosed) {
+ ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.UserDoc().myRecentlyClosed = new List<Doc>(), icon: "plus" });
e.stopPropagation();
e.preventDefault();
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
@@ -703,7 +717,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
layoutItems.push({ description: (this.props.Document.treeViewPreventOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.treeViewPreventOpen = !this.props.Document.treeViewPreventOpen, icon: "paint-brush" });
layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" });
layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" });
- ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
}
ContextMenu.Instance.addItem({
description: "Buxton Layout", icon: "eye", event: () => {
@@ -715,40 +729,31 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
}
});
});
- const { TextDocument, ImageDocument, CarouselDocument, TreeDocument } = Docs.Create;
+ const { ImageDocument } = Docs.Create;
const { Document } = this.props;
const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif";
- const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`;
-
- const textDoc = TextDocument("", { title: "details", _autoHeight: true });
- const detailView = Docs.Create.StackingDocument([
- CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }),
- textDoc,
- TextDocument("", { title: "shortDescription", _autoHeight: true }),
- TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true })
- ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" });
- textDoc.data = new RichTextField(detailedTemplate, "year company");
- detailView.isTemplateDoc = makeTemplate(detailView);
-
+ const detailView = Cast(Cast(Doc.UserDoc()["template-button-detail"], Doc, null)?.dragFactory, Doc, null);
const heroView = ImageDocument(fallbackImg, { title: "heroView", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work?
heroView.proto!.layout = ImageBox.LayoutString("hero");
heroView._showTitle = "title";
heroView._showTitleHover = "titlehover";
- Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data",
+ Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data",
Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
- dragFactory: heroView, removeDropProperties: new List<string>(["dropAction"]), title: "hero view", icon: "portrait"
+ title: "hero view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias",
+ dragFactory: heroView, removeDropProperties: new List<string>(["dropAction"]), icon: "portrait",
+ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
}));
- Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data",
+ Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data",
Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
- dragFactory: detailView, removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "file-alt"
+ title: "detail view", _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias",
+ dragFactory: detailView, removeDropProperties: new List<string>(["dropAction"]), icon: "file-alt",
+ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
}));
Document.childLayout = heroView;
- Document.childDetailed = detailView;
+ Document.childDetailView = detailView;
Document._viewType = CollectionViewType.Time;
Document._forceActive = true;
Document._pivotField = "company";
@@ -758,8 +763,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
onClicks.push({
- description: "Edit onChecked Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Checked Changed ...", this.props.Document,
- "onCheckedClick", obj.x, obj.y, { heading: "boolean", checked: "boolean", treeViewContainer: Doc.name })
+ description: "Edit onChecked Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onCheckedClick"), "edit onCheckedClick"), icon: "edit"
});
!existingOnClick && ContextMenu.Instance.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
}
@@ -776,6 +780,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
}
render() {
+ if (!(this.props.Document instanceof Doc)) return (null);
const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType;
const addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
@@ -804,6 +809,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
Doc.SetInPlace(this.dataDoc, "title", value, false);
const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
EditableView.loadId = doc[Id];
+ Doc.SetInPlace(doc, "editTitle", true, false);
this.addDoc(doc, childDocs.length ? childDocs[0] : undefined, true);
})} />)}
{this.props.Document.allowClear ? this.renderClearButton : (null)}
@@ -812,7 +818,7 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
TreeView.GetChildElements(childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.props.Document.treeViewHideHeaderFields),
- BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, this.props.onCheckedClick || ScriptCast(this.props.Document.onCheckedClick),
+ BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, this.props.onCheckedClick,
this.props.onChildClick || ScriptCast(this.props.Document.onChildClick), this.props.ignoreFields)
}
</ul>
@@ -833,13 +839,12 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey
nonNumbers++;
}
});
- const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue =>
- Docs.Create.TextDocument("", {
- title: facetValue.toString(),
- treeViewChecked: ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)",
- { layoutDoc: Doc.name, facetHeader: "string", facetValue: "string" },
- { layoutDoc, facetHeader, facetValue })
- }));
+ const facetValueDocSet = (nonNumbers / facetValues.length > .1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2))).map(facetValue => {
+ const doc = new Doc();
+ doc.title = facetValue.toString();
+ doc.treeViewChecked = ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", {}, { layoutDoc, facetHeader, facetValue });
+ return doc;
+ });
return new List<Doc>(facetValueDocSet);
});
diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss
index b92c5fdd1..d43dd387a 100644
--- a/src/client/views/collections/CollectionView.scss
+++ b/src/client/views/collections/CollectionView.scss
@@ -11,7 +11,6 @@
height: 100%;
overflow: hidden; // bcz: used to be 'auto' which would create scrollbars when there's a floating doc that's not visible. not sure if that's better, but the scrollbars are annoying...
-
.collectionTimeView-dragger {
background-color: lightgray;
height: 40px;
@@ -21,7 +20,7 @@
top: 55%;
border: 1px black solid;
z-index: 2;
- left: -10px;
+ right: -10px;
}
.collectionTimeView-treeView {
display: flex;
@@ -29,7 +28,7 @@
width: 200px;
height: 100%;
position: absolute;
- left: 0;
+ right: 0;
top: 0;
.collectionTimeView-addfacet {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c7ab66c9f..801704673 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,7 +1,7 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faEye, faEdit } from '@fortawesome/free-regular-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
+import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree, faGlobeAmericas } from '@fortawesome/free-solid-svg-icons';
import { action, observable, computed } from 'mobx';
import { observer } from "mobx-react";
import * as React from 'react';
@@ -13,7 +13,7 @@ import { List } from '../../../new_fields/List';
import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types';
import { ImageField } from '../../../new_fields/URLField';
import { TraceMobx } from '../../../new_fields/util';
-import { Utils, setupMoveUpEvents, returnFalse, returnZero } from '../../../Utils';
+import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { ImageUtils } from '../../util/Import & Export/ImageUtils';
@@ -44,47 +44,32 @@ import { Docs } from '../../documents/Documents';
import { ScriptField, ComputedField } from '../../../new_fields/ScriptField';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ObjectField } from '../../../new_fields/ObjectField';
+import CollectionMapView from './CollectionMapView';
+import { Transform } from 'prosemirror-transform';
+import { CollectionPileView } from './CollectionPileView';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
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);
+library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faGlobeAmericas, faEllipsisV, faImage, faEye as any, faCopy);
export enum CollectionViewType {
- Invalid,
- Freeform,
- Schema,
- Docking,
- Tree,
- Stacking,
- Masonry,
- Multicolumn,
- Multirow,
- Time,
- Carousel,
- Linear,
- Staff
-}
-
-export namespace CollectionViewType {
- const stringMapping = new Map<string, CollectionViewType>([
- ["invalid", CollectionViewType.Invalid],
- ["freeform", CollectionViewType.Freeform],
- ["schema", CollectionViewType.Schema],
- ["docking", CollectionViewType.Docking],
- ["tree", CollectionViewType.Tree],
- ["stacking", CollectionViewType.Stacking],
- ["masonry", CollectionViewType.Masonry],
- ["multicolumn", CollectionViewType.Multicolumn],
- ["multirow", CollectionViewType.Multirow],
- ["time", CollectionViewType.Time],
- ["carousel", CollectionViewType.Carousel],
- ["linear", CollectionViewType.Linear],
- ]);
-
- export const valueOf = (value: string) => stringMapping.get(value.toLowerCase());
- export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)?.[0];
+ Invalid = "invalid",
+ Freeform = "freeform",
+ Schema = "schema",
+ Docking = "docking",
+ Tree = 'tree',
+ Stacking = "stacking",
+ Masonry = "masonry",
+ Multicolumn = "multicolumn",
+ Multirow = "multirow",
+ Time = "time",
+ Carousel = "carousel",
+ Linear = "linear",
+ Staff = "staff",
+ Map = "map",
+ Pile = "pileup"
}
export interface CollectionRenderProps {
@@ -110,7 +95,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
get collectionViewType(): CollectionViewType | undefined {
- const viewField = NumCast(this.props.Document._viewType);
+ const viewField = StrCast(this.props.Document._viewType);
if (CollectionView._safeMode) {
if (viewField === CollectionViewType.Freeform) {
return CollectionViewType.Tree;
@@ -119,10 +104,10 @@ export class CollectionView extends Touchable<FieldViewProps> {
return CollectionViewType.Freeform;
}
}
- return viewField;
+ return viewField as any as CollectionViewType;
}
- active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected(outsideReaction) && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
+ active = (outsideReaction?: boolean) => (this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.props.Document.forceActive || this._isChildActive || this.props.renderDepth === 0) ? true : false;
whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
@@ -163,7 +148,6 @@ export class CollectionView extends Touchable<FieldViewProps> {
// moving it into the target.
@action.bound
moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean {
- doc.context = targetCollection;
if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
return true;
}
@@ -187,10 +171,12 @@ export class CollectionView extends Touchable<FieldViewProps> {
case CollectionViewType.Multicolumn: return (<CollectionMulticolumnView key="collview" {...props} />);
case CollectionViewType.Multirow: return (<CollectionMultirowView key="rpwview" {...props} />);
case CollectionViewType.Linear: { return (<CollectionLinearView key="collview" {...props} />); }
+ case CollectionViewType.Pile: { return (<CollectionPileView key="collview" {...props} />); }
case CollectionViewType.Carousel: { return (<CollectionCarouselView key="collview" {...props} />); }
case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); }
case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView key="collview" {...props} />); }
case CollectionViewType.Time: { return (<CollectionTimeView key="collview" {...props} />); }
+ case CollectionViewType.Map: return (<CollectionMapView key="collview" {...props} />);
case CollectionViewType.Freeform:
default: { this.props.Document._freeformLayoutEngine = undefined; return (<CollectionFreeFormView key="collview" {...props} />); }
}
@@ -209,54 +195,55 @@ export class CollectionView extends Touchable<FieldViewProps> {
}
+ setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) {
+ const existingVm = ContextMenu.Instance.findByDescription(category);
+ const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : [];
+
+ subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" });
+ if (addExtras && CollectionView._safeMode) {
+ ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => func(CollectionViewType.Invalid), icon: "project-diagram" });
+ }
+ subItems.push({ description: "Schema", event: () => func(CollectionViewType.Schema), icon: "th-list" });
+ subItems.push({ description: "Tree", event: () => func(CollectionViewType.Tree), icon: "tree" });
+ subItems.push({ description: "Stacking", event: () => func(CollectionViewType.Stacking), icon: "ellipsis-v" });
+ subItems.push({ description: "Stacking (AutoHeight)", event: () => func(CollectionViewType.Stacking)._autoHeight = true, icon: "ellipsis-v" });
+ subItems.push({ description: "Staff", event: () => func(CollectionViewType.Staff), icon: "music" });
+ subItems.push({ description: "Multicolumn", event: () => func(CollectionViewType.Multicolumn), icon: "columns" });
+ subItems.push({ description: "Multirow", event: () => func(CollectionViewType.Multirow), icon: "columns" });
+ subItems.push({ description: "Masonry", event: () => func(CollectionViewType.Masonry), icon: "columns" });
+ subItems.push({ description: "Carousel", event: () => func(CollectionViewType.Carousel), icon: "columns" });
+ subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" });
+ subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" });
+ if (addExtras && this.props.Document._viewType === CollectionViewType.Freeform) {
+ subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) });
+ }
+ addExtras && subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" });
+ !existingVm && ContextMenu.Instance.addItem({ description: category, subitems: subItems, icon: "eye" });
+ }
+
onContextMenu = (e: React.MouseEvent): void => {
if (!e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
- const existingVm = ContextMenu.Instance.findByDescription("View Modes...");
- const subItems = existingVm && "subitems" in existingVm ? existingVm.subitems : [];
- subItems.push({ description: "Freeform", event: () => { this.props.Document._viewType = CollectionViewType.Freeform; }, icon: "signature" });
- if (CollectionView._safeMode) {
- ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document._viewType = CollectionViewType.Invalid, icon: "project-diagram" });
- }
- subItems.push({ description: "Schema", event: () => this.props.Document._viewType = CollectionViewType.Schema, icon: "th-list" });
- subItems.push({ description: "Treeview", event: () => this.props.Document._viewType = CollectionViewType.Tree, icon: "tree" });
- subItems.push({ description: "Stacking", event: () => this.props.Document._viewType = CollectionViewType.Stacking, icon: "ellipsis-v" });
- subItems.push({
- description: "Stacking (AutoHeight)", event: () => {
- this.props.Document._viewType = CollectionViewType.Stacking;
- this.props.Document._autoHeight = true;
- }, icon: "ellipsis-v"
- });
- subItems.push({ description: "Staff", event: () => this.props.Document._viewType = CollectionViewType.Staff, icon: "music" });
- subItems.push({ description: "Multicolumn", event: () => this.props.Document._viewType = CollectionViewType.Multicolumn, icon: "columns" });
- subItems.push({ description: "Multirow", event: () => this.props.Document._viewType = CollectionViewType.Multirow, icon: "columns" });
- subItems.push({ description: "Masonry", event: () => this.props.Document._viewType = CollectionViewType.Masonry, icon: "columns" });
- subItems.push({ description: "Carousel", event: () => this.props.Document._viewType = CollectionViewType.Carousel, icon: "columns" });
- subItems.push({ description: "Pivot/Time", event: () => this.props.Document._viewType = CollectionViewType.Time, icon: "columns" });
- switch (this.props.Document._viewType) {
- case CollectionViewType.Freeform: {
- subItems.push({ description: "Custom", icon: "fingerprint", event: AddCustomFreeFormLayout(this.props.Document, this.props.fieldKey) });
- break;
- }
- }
- subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" });
- !existingVm && ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" });
- const existing = ContextMenu.Instance.findByDescription("Layout...");
+ this.setupViewTypes("Change Perspective...", (vtype => { this.props.Document._viewType = vtype; return this.props.Document; }), true);
+ this.setupViewTypes("Add a Perspective...", vtype => {
+ const newRendition = Doc.MakeAlias(this.props.Document);
+ newRendition._viewType = vtype;
+ this.props.addDocTab(newRendition, "onRight");
+ return newRendition;
+ }, false);
+
+ const existing = ContextMenu.Instance.findByDescription("Options...");
const layoutItems = existing && "subitems" in existing ? existing.subitems : [];
layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
if (this.props.Document.childLayout instanceof Doc) {
layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
}
- if (this.props.Document.childDetailed instanceof Doc) {
- layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" });
+ if (this.props.Document.childDetailView instanceof Doc) {
+ layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailView as Doc, "onRight"), icon: "project-diagram" });
}
- layoutItems.push({ description: "Toggle is inPlace Container", event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
-
- !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" });
+ layoutItems.push({ description: `${this.props.Document.isInPlaceContainer ? "Unset" : "Set"} inPlace Container`, event: () => this.props.Document.isInPlaceContainer = !this.props.Document.isInPlaceContainer, icon: "project-diagram" });
- const open = ContextMenu.Instance.findByDescription("Open...");
- const openItems = open && "subitems" in open ? open.subitems : [];
- !open && ContextMenu.Instance.addItem({ description: "Open...", subitems: openItems, icon: "hand-point-right" });
+ !existing && ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "hand-point-right" });
const existingOnClick = ContextMenu.Instance.findByDescription("OnClick...");
const onClicks = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
@@ -294,10 +281,10 @@ export class CollectionView extends Touchable<FieldViewProps> {
onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)}
onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />);
}
- @observable _facetWidth = 0;
+ get _facetWidth() { return NumCast(this.props.Document._facetWidth); }
+ set _facetWidth(value) { this.props.Document._facetWidth = value; }
bodyPanelWidth = () => this.props.PanelWidth() - this.facetWidth();
- getTransform = () => this.props.ScreenToLocalTransform().translate(-this.facetWidth(), 0);
facetWidth = () => Math.max(0, Math.min(this.props.PanelWidth() - 25, this._facetWidth));
@computed get dataDoc() {
@@ -375,42 +362,46 @@ export class CollectionView extends Touchable<FieldViewProps> {
let newFacet: Opt<Doc>;
if (nonNumbers / allCollectionDocs.length < .1) {
newFacet = Docs.Create.SliderDocument({ title: facetHeader });
+ const newFacetField = Doc.LayoutFieldKey(newFacet);
const ranged = Doc.readDocRangeFilter(this.props.Document, facetHeader);
Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
newFacet.treeViewExpandedView = "layout";
newFacet.treeViewOpen = true;
- newFacet._sliderMin = ranged === undefined ? minVal : ranged[0];
- newFacet._sliderMax = ranged === undefined ? maxVal : ranged[1];
- newFacet._sliderMinThumb = minVal;
- newFacet._sliderMaxThumb = maxVal;
+ const extendedMinVal = minVal - Math.min(1, Math.abs(maxVal - minVal) * .05);
+ const extendedMaxVal = maxVal + Math.min(1, Math.abs(maxVal - minVal) * .05);
+ newFacet[newFacetField + "-min"] = ranged === undefined ? extendedMinVal : ranged[0];
+ newFacet[newFacetField + "-max"] = ranged === undefined ? extendedMaxVal : ranged[1];
+ Doc.GetProto(newFacet)[newFacetField + "-minThumb"] = extendedMinVal;
+ Doc.GetProto(newFacet)[newFacetField + "-maxThumb"] = extendedMaxVal;
newFacet.target = this.props.Document;
const scriptText = `setDocFilterRange(this.target, "${facetHeader}", range)`;
newFacet.onThumbChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, range: "number" });
Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
} else {
- newFacet = Docs.Create.TreeDocument([], { title: facetHeader, treeViewOpen: true, isFacetFilter: true });
+ newFacet = new Doc();
+ newFacet.title = facetHeader;
+ newFacet.treeViewOpen = true;
+ newFacet.type = DocumentType.COL;
const capturedVariables = { layoutDoc: this.props.Document, dataDoc: this.dataDoc };
- const params = { layoutDoc: Doc.name, dataDoc: Doc.name, };
- newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, params, capturedVariables);
+ newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, dataDoc, "${this.props.fieldKey}", "${facetHeader}")`, {}, capturedVariables);
}
- Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
+ newFacet && Doc.AddDocToList(facetCollection, this.props.fieldKey + "-filter", newFacet);
}
}
-
onPointerDown = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
- this._facetWidth = Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
+ this._facetWidth = this.props.PanelWidth() - Math.max(this.props.ScreenToLocalTransform().transformPoint(e.clientX, 0)[0], 0);
return false;
}), returnFalse, action(() => this._facetWidth = this.facetWidth() < 15 ? Math.min(this.props.PanelWidth() - 25, 200) : 0));
}
- filterBackground = () => "dimGray";
+ filterBackground = () => "rgba(105, 105, 105, 0.432)";
+ get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves)
@computed get scriptField() {
const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
return ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
}
- @computed get treeIgnoreFields() { return ["_facetCollection", "_docFilters"]; }
@computed get filterView() {
const facetCollection = this.props.Document;
const flyout = (
@@ -427,27 +418,44 @@ export class CollectionView extends Touchable<FieldViewProps> {
<div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
<Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
<div className="collectionTimeView-button">
- <span className="collectionTimeView-span">Facet Filters</span>
<FontAwesomeIcon icon={faEdit} size={"lg"} />
+ <span className="collectionTimeView-span">Facet Filters</span>
</div>
</Flyout>
</div>
<div className="collectionTimeView-tree" key="tree">
- <CollectionTreeView {...this.props}
+ <CollectionTreeView
+ Document={facetCollection}
+ DataDoc={facetCollection}
+ fieldKey={`${this.props.fieldKey}-filter`}
CollectionView={this}
- treeViewHideTitle={true}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ PanelWidth={this.facetWidth}
+ PanelHeight={this.props.PanelHeight}
NativeHeight={returnZero}
NativeWidth={returnZero}
+ LibraryPath={emptyPath}
+ rootSelected={this.props.rootSelected}
+ renderDepth={1}
+ dropAction={this.props.dropAction}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ isSelected={returnFalse}
+ select={returnFalse}
+ bringToFront={emptyFunction}
+ active={this.props.active}
+ whenActiveChanged={returnFalse}
+ treeViewHideTitle={true}
+ ContentScaling={returnOne}
+ focus={returnFalse}
treeViewHideHeaderFields={true}
onCheckedClick={this.scriptField!}
- ignoreFields={this.treeIgnoreFields}
+ ignoreFields={this.ignoreFields}
annotationsKey={""}
dontRegisterView={true}
- PanelWidth={this.facetWidth}
- DataDoc={facetCollection}
- Document={facetCollection}
backgroundColor={this.filterBackground}
- fieldKey={`${this.props.fieldKey}-filter`}
moveDocument={returnFalse}
removeDocument={returnFalse}
addDocument={returnFalse} />
@@ -467,13 +475,13 @@ export class CollectionView extends Touchable<FieldViewProps> {
};
return (<div className={"collectionView"}
style={{
- pointerEvents: this.props.Document.isBackground ? "none" : "all",
+ pointerEvents: this.props.Document.isBackground ? "none" : undefined,
boxShadow: this.props.Document.isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
`${Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "rgb(30, 32, 31)" : "#9c9396"} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`
}}
onContextMenu={this.onContextMenu}>
{this.showIsTagged()}
- <div style={{ width: `calc(100% - ${this.facetWidth()}px)`, marginLeft: `${this.facetWidth()}px` }}>
+ <div style={{ width: `calc(100% - ${this.facetWidth()}px)` }}>
{this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
</div>
{this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => d.type === DocumentType.IMG).map(d =>
@@ -483,11 +491,9 @@ export class CollectionView extends Touchable<FieldViewProps> {
:
""))}
{!this.props.isSelected() || this.props.PanelHeight() < 100 || this.props.Document.hideFilterView ? (null) :
- <div className="collectionTimeView-dragger" key="dragger" onPointerDown={this.onPointerDown} style={{ transform: `translate(${this.facetWidth()}px, 0px)` }} >
- <span title="library View Dragger" style={{ width: "5px", position: "absolute", top: "0" }} />
- </div>
+ <div className="collectionTimeView-dragger" title="library View Dragger" onPointerDown={this.onPointerDown} style={{ right: this.facetWidth() - 10 }} />
}
- {this.filterView}
+ {this.facetWidth() < 10 ? (null) : this.filterView}
</div>);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index a691b4805..5203eb55f 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -61,16 +61,21 @@
pointer-events: all;
// margin-top: 10px;
}
- .collectionViewBaseChrome-template {
+ .collectionViewBaseChrome-template,
+ .collectionViewBaseChrome-viewModes {
display: grid;
background: rgb(238, 238, 238);
color:grey;
margin-top:auto;
margin-bottom:auto;
+ margin-left: 5px;
+ }
+ .collectionViewBaseChrome-viewModes {
+ margin-left: 25px;
}
.collectionViewBaseChrome-viewSpecs {
- margin-left: 10px;
+ margin-left: 5px;
display: grid;
.collectionViewBaseChrome-filterIcon {
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 9bade1c82..d26e3a38b 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -6,7 +6,6 @@ import { Doc, DocListCast } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
-import { ScriptField } from "../../../new_fields/ScriptField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { Utils, emptyFunction, setupMoveUpEvents } from "../../../Utils";
import { DragManager } from "../../util/DragManager";
@@ -16,9 +15,6 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss";
import { CollectionViewType } from "./CollectionView";
import { CollectionView } from "./CollectionView";
import "./CollectionViewChromes.scss";
-import * as Autosuggest from 'react-autosuggest';
-import KeyRestrictionRow from "./KeyRestrictionRow";
-import { ObjectField } from "../../../new_fields/ObjectField";
const datepicker = require('js-datepicker');
interface CollectionViewChromeProps {
@@ -43,14 +39,14 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
get target() { return this.props.CollectionView.props.Document; }
_templateCommand = {
params: ["target", "source"], title: "=> item view",
- script: "target.childLayout = getDocTemplate(this.source?.[0])",
+ script: "this.target.childLayout = getDocTemplate(this.source?.[0])",
immediate: (source: Doc[]) => this.target.childLayout = Doc.getDocTemplate(source?.[0]),
initialize: emptyFunction,
};
_narrativeCommand = {
params: ["target", "source"], title: "=> click item view",
- script: "this.target.childDetailed = getDocTemplate(this.source?.[0])",
- immediate: (source: Doc[]) => this.target.childDetailed = Doc.getDocTemplate(source?.[0]),
+ script: "this.target.childDetailView = getDocTemplate(this.source?.[0])",
+ immediate: (source: Doc[]) => this.target.childDetailView = Doc.getDocTemplate(source?.[0]),
initialize: emptyFunction,
};
_contentCommand = {
@@ -85,62 +81,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
private _picker: any;
private _commandRef = React.createRef<HTMLInputElement>();
private _viewRef = React.createRef<HTMLInputElement>();
- private _autosuggestRef = React.createRef<Autosuggest>();
@observable private _currentKey: string = "";
- @observable private _viewSpecsOpen: boolean = false;
- @observable private _dateWithinValue: string = "";
- @observable private _dateValue: Date | string = "";
- @observable private _keyRestrictions: [JSX.Element, string][] = [];
- @observable private suggestions: string[] = [];
- @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); }
-
- getFilters = (script: string) => {
- const re: any = /(!)?\(\(\(doc\.(\w+)\s+&&\s+\(doc\.\w+\s+as\s+\w+\)\.includes\(\"(\w+)\"\)/g;
- const arr: any[] = re.exec(script);
- const toReturn: Filter[] = [];
- if (arr !== null) {
- const filter: Filter = {
- key: arr[2],
- value: arr[3],
- contains: (arr[1] === "!") ? false : true,
- };
- toReturn.push(filter);
- script = script.replace(arr[0], "");
- if (re.exec(script) !== null) {
- toReturn.push(...this.getFilters(script));
- }
- else { return toReturn; }
- }
- return toReturn;
- }
-
- addKeyRestrictions = (fields: Filter[]) => {
-
- if (fields.length !== 0) {
- for (let i = 0; i < fields.length; i++) {
- this._keyRestrictions.push([<KeyRestrictionRow field={fields[i].key} value={fields[i].value} key={Utils.GenerateGuid()} contains={fields[i].contains} script={(value: string) => runInAction(() => this._keyRestrictions[i][1] = value)} />, ""]);
-
- }
- if (this._keyRestrictions.length === 1) {
- this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={true} script={(value: string) => runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]);
- }
- }
- else {
- this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={true} script={(value: string) => runInAction(() => this._keyRestrictions[0][1] = value)} />, ""]);
- this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={false} script={(value: string) => runInAction(() => this._keyRestrictions[1][1] = value)} />, ""]);
- }
- }
componentDidMount = () => {
-
- let fields: Filter[] = [];
- if (this.filterValue) {
- const string = this.filterValue.script.originalScript;
- fields = this.getFilters(string);
- }
-
runInAction(() => {
- this.addKeyRestrictions(fields);
// chrome status is one of disabled, collapsed, or visible. this determines initial state from document
const chromeStatus = this.props.CollectionView.props.Document._chromeStatus;
if (chromeStatus) {
@@ -159,7 +103,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
@undoBatch
viewChanged = (e: React.ChangeEvent) => {
//@ts-ignore
- this.props.CollectionView.props.Document._viewType = parseInt(e.target.selectedOptions[0].value);
+ this.document._viewType = e.target.selectedOptions[0].value;
}
commandChanged = (e: React.ChangeEvent) => {
@@ -168,104 +112,93 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
}
@action
- openViewSpecs = (e: React.SyntheticEvent) => {
- if (this._viewSpecsOpen) this.closeViewSpecs();
- else {
- this._viewSpecsOpen = true;
-
- //@ts-ignore
- if (!e.target?.classList[0]?.startsWith("qs")) {
- this.closeDatePicker();
- }
-
- e.stopPropagation();
- document.removeEventListener("pointerdown", this.closeViewSpecs);
- document.addEventListener("pointerdown", this.closeViewSpecs);
- }
+ toggleViewSpecs = (e: React.SyntheticEvent) => {
+ this.document._facetWidth = this.document._facetWidth ? 0 : 200;
+ e.stopPropagation();
}
@action closeViewSpecs = () => {
- this._viewSpecsOpen = false;
- document.removeEventListener("pointerdown", this.closeViewSpecs);
- }
-
- @action
- openDatePicker = (e: React.PointerEvent) => {
- this.openViewSpecs(e);
- if (this._picker) {
- this._picker.alwaysShow = true;
- this._picker.show();
- // TODO: calendar is offset when zoomed in/out
- // this._picker.calendar.style.position = "absolute";
- // let transform = this.props.CollectionView.props.ScreenToLocalTransform();
- // let x = parseInt(this._picker.calendar.style.left) / transform.Scale;
- // let y = parseInt(this._picker.calendar.style.top) / transform.Scale;
- // this._picker.calendar.style.left = x;
- // this._picker.calendar.style.top = y;
+ this.document._facetWidth = 0;
+ }
+
+ // @action
+ // openDatePicker = (e: React.PointerEvent) => {
+ // if (this._picker) {
+ // this._picker.alwaysShow = true;
+ // this._picker.show();
+ // // TODO: calendar is offset when zoomed in/out
+ // // this._picker.calendar.style.position = "absolute";
+ // // let transform = this.props.CollectionView.props.ScreenToLocalTransform();
+ // // let x = parseInt(this._picker.calendar.style.left) / transform.Scale;
+ // // let y = parseInt(this._picker.calendar.style.top) / transform.Scale;
+ // // this._picker.calendar.style.left = x;
+ // // this._picker.calendar.style.top = y;
+
+ // e.stopPropagation();
+ // }
+ // }
+
+ // <input className="collectionViewBaseChrome-viewSpecsMenu-rowRight"
+ // id={Utils.GenerateGuid()}
+ // ref={this.datePickerRef}
+ // value={this._dateValue instanceof Date ? this._dateValue.toLocaleDateString() : this._dateValue}
+ // onChange={(e) => runInAction(() => this._dateValue = e.target.value)}
+ // onPointerDown={this.openDatePicker}
+ // placeholder="Value" />
+ // @action.bound
+ // applyFilter = (e: React.MouseEvent) => {
+ // const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")";
+ // const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0;
+ // const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0;
+ // const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0;
+ // const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7;
+ // let dateRestrictionScript = "";
+ // if (this._dateValue instanceof Date) {
+ // const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset);
+ // const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1);
+ // dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
+ // }
+ // else {
+ // const createdDate = new Date(this._dateValue);
+ // if (!isNaN(createdDate.getTime())) {
+ // const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset);
+ // const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1);
+ // dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
+ // }
+ // }
+ // const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ?
+ // `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` :
+ // `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` :
+ // "true";
+
+ // this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name });
+ // }
+
+ // datePickerRef = (node: HTMLInputElement) => {
+ // if (node) {
+ // try {
+ // this._picker = datepicker("#" + node.id, {
+ // disabler: (date: Date) => date > new Date(),
+ // onSelect: (instance: any, date: Date) => runInAction(() => {}), // this._dateValue = date),
+ // dateSelected: new Date()
+ // });
+ // } catch (e) {
+ // console.log("date picker exception:" + e);
+ // }
+ // }
+ // }
- e.stopPropagation();
- }
- }
-
- @action
- addKeyRestriction = (e: React.MouseEvent) => {
- const index = this._keyRestrictions.length;
- this._keyRestrictions.push([<KeyRestrictionRow field="" value="" key={Utils.GenerateGuid()} contains={true} script={(value: string) => runInAction(() => this._keyRestrictions[index][1] = value)} />, ""]);
-
- this.openViewSpecs(e);
- }
-
- @action.bound
- applyFilter = (e: React.MouseEvent) => {
-
- this.openViewSpecs(e);
-
- const keyRestrictionScript = "(" + this._keyRestrictions.map(i => i[1]).filter(i => i.length > 0).join(" && ") + ")";
- const yearOffset = this._dateWithinValue[1] === 'y' ? 1 : 0;
- const monthOffset = this._dateWithinValue[1] === 'm' ? parseInt(this._dateWithinValue[0]) : 0;
- const weekOffset = this._dateWithinValue[1] === 'w' ? parseInt(this._dateWithinValue[0]) : 0;
- const dayOffset = (this._dateWithinValue[1] === 'd' ? parseInt(this._dateWithinValue[0]) : 0) + weekOffset * 7;
- let dateRestrictionScript = "";
- if (this._dateValue instanceof Date) {
- const lowerBound = new Date(this._dateValue.getFullYear() - yearOffset, this._dateValue.getMonth() - monthOffset, this._dateValue.getDate() - dayOffset);
- const upperBound = new Date(this._dateValue.getFullYear() + yearOffset, this._dateValue.getMonth() + monthOffset, this._dateValue.getDate() + dayOffset + 1);
- dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
- }
- else {
- const createdDate = new Date(this._dateValue);
- if (!isNaN(createdDate.getTime())) {
- const lowerBound = new Date(createdDate.getFullYear() - yearOffset, createdDate.getMonth() - monthOffset, createdDate.getDate() - dayOffset);
- const upperBound = new Date(createdDate.getFullYear() + yearOffset, createdDate.getMonth() + monthOffset, createdDate.getDate() + dayOffset + 1);
- dateRestrictionScript = `((doc.creationDate as any).date >= ${lowerBound.valueOf()} && (doc.creationDate as any).date <= ${upperBound.valueOf()})`;
- }
- }
- const fullScript = dateRestrictionScript.length || keyRestrictionScript.length ? dateRestrictionScript.length ?
- `${dateRestrictionScript} ${keyRestrictionScript.length ? "&&" : ""} (${keyRestrictionScript})` :
- `(${keyRestrictionScript}) ${dateRestrictionScript.length ? "&&" : ""} ${dateRestrictionScript}` :
- "true";
-
- this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction(fullScript, { doc: Doc.name });
- }
-
- @action
- closeDatePicker = () => {
- if (this._picker) {
- this._picker.alwaysShow = false;
- this._picker.hide();
- }
- document.removeEventListener("pointerdown", this.closeDatePicker);
- }
@action
toggleCollapse = () => {
- this.props.CollectionView.props.Document._chromeStatus = this.props.CollectionView.props.Document._chromeStatus === "enabled" ? "collapsed" : "enabled";
+ this.document._chromeStatus = this.document._chromeStatus === "enabled" ? "collapsed" : "enabled";
if (this.props.collapse) {
this.props.collapse(this.props.CollectionView.props.Document._chromeStatus !== "enabled");
}
}
subChrome = () => {
- const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
+ const collapsed = this.document._chromeStatus !== "enabled";
if (collapsed) return null;
switch (this.props.type) {
case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
@@ -280,18 +213,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
return this.props.CollectionView.props.Document;
}
- @action.bound
- clearFilter = () => {
- this.props.CollectionView.props.Document.viewSpecScript = ScriptField.MakeFunction("true", { doc: Doc.name });
- this._keyRestrictions = [];
- this.addKeyRestrictions([]);
- }
-
private dropDisposer?: DragManager.DragDropDisposer;
protected createDropTarget = (ele: HTMLDivElement) => {
- this.dropDisposer && this.dropDisposer();
+ this.dropDisposer?.();
if (ele) {
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.document);
}
}
@@ -305,55 +231,13 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
return true;
}
- datePickerRef = (node: HTMLInputElement) => {
- if (node) {
- try {
- this._picker = datepicker("#" + node.id, {
- disabler: (date: Date) => date > new Date(),
- onSelect: (instance: any, date: Date) => runInAction(() => this._dateValue = date),
- dateSelected: new Date()
- });
- } catch (e) {
- console.log("date picker exception:" + e);
- }
- }
- }
-
- renderSuggestion = (suggestion: string) => {
- return <p>{suggestion}</p>;
- }
- getSuggestionValue = (suggestion: string) => suggestion;
-
- @action
- onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
- this._currentKey = newValue;
- }
- onSuggestionFetch = async ({ value }: { value: string }) => {
- const sugg = await this.getKeySuggestions(value);
- runInAction(() => this.suggestions = sugg);
- }
- @action
- onSuggestionClear = () => {
- this.suggestions = [];
- }
- getKeySuggestions = async (value: string): Promise<string[]> => {
- return this._buttonizableCommands.filter(c => c.title.indexOf(value) !== -1).map(c => c.title);
- }
-
- autoSuggestDown = (e: React.PointerEvent) => {
- e.stopPropagation();
- }
-
- private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
- private _sensitivity: number = 16;
-
dragViewDown = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, (e, down, delta) => {
- const vtype = NumCast(this.props.CollectionView.props.Document._viewType) as CollectionViewType;
+ const vtype = this.props.CollectionView.collectionViewType;
const c = {
- params: ["target"], title: CollectionViewType.stringFor(vtype),
- script: `this.target._viewType = ${NumCast(this.props.CollectionView.props.Document._viewType)}`,
- immediate: (source: Doc[]) => this.target = Doc.getTemplateDoc(source?.[0]),
+ params: ["target"], title: vtype,
+ script: `this.target._viewType = ${StrCast(this.props.CollectionView.props.Document._viewType)}`,
+ immediate: (source: Doc[]) => this.props.CollectionView.props.Document._viewType = Doc.getDocTemplate(source?.[0]),
initialize: emptyFunction,
};
DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title),
@@ -362,28 +246,12 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
}, emptyFunction, emptyFunction);
}
dragCommandDown = (e: React.PointerEvent) => {
- this._startDragPosition = { x: e.clientX, y: e.clientY };
- document.addEventListener("pointermove", this.dragPointerMove);
- document.addEventListener("pointerup", this.dragPointerUp);
- e.stopPropagation();
- e.preventDefault();
- }
-
- dragPointerMove = (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
- const [dx, dy] = [e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y];
- if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
+ setupMoveUpEvents(this, e, (e, down, delta) => {
this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c =>
DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title,
{ target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY));
- document.removeEventListener("pointermove", this.dragPointerMove);
- document.removeEventListener("pointerup", this.dragPointerUp);
- }
- }
- dragPointerUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.dragPointerMove);
- document.removeEventListener("pointerup", this.dragPointerUp);
+ return true;
+ }, emptyFunction, emptyFunction);
}
render() {
@@ -408,7 +276,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
title="Collapse collection chrome" onClick={this.toggleCollapse}>
<FontAwesomeIcon icon="caret-up" size="2x" />
</button>
- <div className="collectionViewBaseChrome-template" style={{ marginLeft: 25, display: collapsed ? "none" : undefined }}>
+ <div className="collectionViewBaseChrome-viewModes" style={{ display: collapsed ? "none" : undefined }}>
<div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._viewRef} onPointerDown={this.dragViewDown}>
<div className="commandEntry-drop">
<FontAwesomeIcon icon="bullseye" size="2x"></FontAwesomeIcon>
@@ -417,61 +285,23 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
className="collectionViewBaseChrome-viewPicker"
onPointerDown={stopPropagation}
onChange={this.viewChanged}
- value={NumCast(this.props.CollectionView.props.Document._viewType)}>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="1">Freeform</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="2">Schema</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="4">Tree</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="5">Stacking</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="6">Masonry</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="7">MultiCol</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="8">MultiRow</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="9">Pivot/Time</option>
- <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="10">Carousel</option>
+ value={StrCast(this.props.CollectionView.props.Document._viewType)}>
+ {Object.values(CollectionViewType).map(type => ["invalid", "docking"].includes(type) ? (null) : (
+ <option
+ key={Utils.GenerateGuid()}
+ className="collectionViewBaseChrome-viewOption"
+ onPointerDown={stopPropagation}
+ value={type}>
+ {type[0].toUpperCase() + type.substring(1)}
+ </option>
+ ))}
</select>
</div>
</div>
<div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}>
- <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.openViewSpecs} >
+ <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.toggleViewSpecs} >
<FontAwesomeIcon icon="filter" size="2x" />
</div>
- <div className="collectionViewBaseChrome-viewSpecsMenu"
- onPointerDown={this.openViewSpecs}
- style={{
- height: this._viewSpecsOpen ? "fit-content" : "0px",
- overflow: this._viewSpecsOpen ? "initial" : "hidden"
- }}>
- {this._keyRestrictions.map(i => i[0])}
- <div className="collectionViewBaseChrome-viewSpecsMenu-row">
- <div className="collectionViewBaseChrome-viewSpecsMenu-rowLeft">
- CREATED WITHIN:
- </div>
- <select className="collectionViewBaseChrome-viewSpecsMenu-rowMiddle"
- style={{ textTransform: "uppercase", textAlign: "center" }}
- value={this._dateWithinValue}
- onChange={(e) => runInAction(() => this._dateWithinValue = e.target.value)}>
- <option value="1d">1 day of</option>
- <option value="3d">3 days of</option>
- <option value="1w">1 week of</option>
- <option value="2w">2 weeks of</option>
- <option value="1m">1 month of</option>
- <option value="2m">2 months of</option>
- <option value="6m">6 months of</option>
- <option value="1y">1 year of</option>
- </select>
- <input className="collectionViewBaseChrome-viewSpecsMenu-rowRight"
- id={Utils.GenerateGuid()}
- ref={this.datePickerRef}
- value={this._dateValue instanceof Date ? this._dateValue.toLocaleDateString() : this._dateValue}
- onChange={(e) => runInAction(() => this._dateValue = e.target.value)}
- onPointerDown={this.openDatePicker}
- placeholder="Value" />
- </div>
- <div className="collectionViewBaseChrome-viewSpecsMenu-lastRow">
- <button className="collectonViewBaseChrome-viewSpecsMenu-lastRowButton" onClick={this.addKeyRestriction}> ADD KEY RESTRICTION </button>
- <button className="collectonViewBaseChrome-viewSpecsMenu-lastRowButton" onClick={this.applyFilter}> APPLY FILTER </button>
- <button className="collectonViewBaseChrome-viewSpecsMenu-lastRowButton" onClick={this.clearFilter}> CLEAR </button>
- </div>
- </div>
</div>
<div className="collectionViewBaseChrome-template" ref={this.createDropTarget} style={{ display: collapsed ? "none" : undefined }}>
<div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index afe269ec3..10c6ead1a 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -2,7 +2,7 @@ import * as React from "react";
import './ParentDocumentSelector.scss';
import { Doc } from "../../../new_fields/Doc";
import { observer } from "mobx-react";
-import { observable, action, runInAction, trace, computed } from "mobx";
+import { observable, action, runInAction, trace, computed, reaction, IReactionDisposer } from "mobx";
import { Id } from "../../../new_fields/FieldSymbols";
import { SearchUtil } from "../../util/SearchUtil";
import { CollectionDockingView } from "./CollectionDockingView";
@@ -31,13 +31,14 @@ type SelectorProps = {
export class SelectorContextMenu extends React.Component<SelectorProps> {
@observable private _docs: { col: Doc, target: Doc }[] = [];
@observable private _otherDocs: { col: Doc, target: Doc }[] = [];
+ _reaction: IReactionDisposer | undefined;
- constructor(props: SelectorProps) {
- super(props);
-
- this.fetchDocuments();
+ componentDidMount() {
+ this._reaction = reaction(() => this.props.Document, () => this.fetchDocuments(), { fireImmediately: true });
+ }
+ componentWillUnmount() {
+ this._reaction?.();
}
-
async fetchDocuments() {
const aliases = (await SearchUtil.GetAliasesOfDocument(this.props.Document)).filter(doc => doc !== this.props.Document);
const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${this.props.Document[Id]}"` });
@@ -54,7 +55,7 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
getOnClick({ col, target }: { col: Doc, target: Doc }) {
return () => {
col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
- if (NumCast(col._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
+ if (col._viewType === CollectionViewType.Freeform) {
const newPanX = NumCast(target.x) + NumCast(target._width) / 2;
const newPanY = NumCast(target.y) + NumCast(target._height) / 2;
col._panX = newPanX;
@@ -94,8 +95,6 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
@observer
export class DockingViewButtonSelector extends React.Component<{ views: DocumentView[], Stack: any }> {
- @observable hover = false;
-
customStylesheet(styles: any) {
return {
...styles,
@@ -105,17 +104,24 @@ export class DockingViewButtonSelector extends React.Component<{ views: Document
},
};
}
+ _ref = React.createRef<HTMLDivElement>();
@computed get flyout() {
return (
- <div className="ParentDocumentSelector-flyout" title=" ">
+ <div className="ParentDocumentSelector-flyout" title=" " ref={this._ref}>
<DocumentButtonBar views={this.props.views} stack={this.props.Stack} />
</div>
);
}
render() {
- return <span title="Tap for menu, drag tab as document" onPointerDown={e => { this.props.views[0].select(false); e.stopPropagation(); }} className="buttonSelector">
+ return <span title="Tap for menu, drag tab as document"
+ onPointerDown={e => {
+ if (getComputedStyle(this._ref.current!).width !== "100%") {
+ e.stopPropagation(); e.preventDefault();
+ }
+ this.props.views[0]?.select(false);
+ }} className="buttonSelector">
<Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
<FontAwesomeIcon icon={"cog"} size={"sm"} />
</Flyout>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index bd4db89ec..9a864078a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -1,4 +1,4 @@
-import { Doc, Field, FieldResult } from "../../../../new_fields/Doc";
+import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../new_fields/Doc";
import { NumCast, StrCast, Cast } from "../../../../new_fields/Types";
import { ScriptBox } from "../../ScriptBox";
import { CompileScript } from "../../../util/Scripting";
@@ -9,13 +9,15 @@ import React = require("react");
import { Id, ToString } from "../../../../new_fields/FieldSymbols";
import { ObjectField } from "../../../../new_fields/ObjectField";
import { RefField } from "../../../../new_fields/RefField";
+import { listSpec } from "../../../../new_fields/Schema";
export interface ViewDefBounds {
type: string;
- text?: string;
+ payload: any;
x: number;
y: number;
z?: number;
+ text?: string;
zIndex?: number;
width?: number;
height?: number;
@@ -23,12 +25,13 @@ export interface ViewDefBounds {
fontSize?: number;
highlight?: boolean;
color?: string;
- payload: any;
+ replica?: string;
+ pair?: { layout: Doc, data?: Doc };
}
export interface PoolData {
- x?: number;
- y?: number;
+ x: number;
+ y: number;
z?: number;
zIndex?: number;
width?: number;
@@ -36,6 +39,8 @@ export interface PoolData {
color?: string;
transition?: string;
highlight?: boolean;
+ replica: string;
+ pair: { layout: Doc, data?: Doc };
}
export interface ViewDefResult {
@@ -72,38 +77,103 @@ function getTextWidth(text: string, font: string): number {
interface PivotColumn {
docs: Doc[];
+ replicas: string[];
filters: string[];
}
+export function computerPassLayout(
+ poolData: Map<string, PoolData>,
+ pivotDoc: Doc,
+ childPairs: { layout: Doc, data?: Doc }[],
+ panelDim: number[],
+ viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
+) {
+ const docMap = new Map<string, PoolData>();
+ childPairs.forEach(({ layout, data }, i) => {
+ docMap.set(layout[Id], {
+ x: NumCast(layout.x),
+ y: NumCast(layout.y),
+ width: layout[WidthSym](),
+ height: layout[HeightSym](),
+ pair: { layout, data },
+ replica: ""
+ });
+ });
+ return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []);
+}
+
+export function computerStarburstLayout(
+ poolData: Map<string, PoolData>,
+ pivotDoc: Doc,
+ childPairs: { layout: Doc, data?: Doc }[],
+ panelDim: number[],
+ viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
+) {
+ const docMap = new Map<string, PoolData>();
+ const burstRadius = [NumCast(pivotDoc._starburstRadius, panelDim[0]), NumCast(pivotDoc._starburstRadius, panelDim[1])];
+ const docScale = NumCast(pivotDoc._starburstDocScale);
+ const docSize = docScale * 100; // assume a icon sized at 100
+ const scaleDim = [burstRadius[0] + docSize, burstRadius[1] + docSize];
+ childPairs.forEach(({ layout, data }, i) => {
+ const deg = i / childPairs.length * Math.PI * 2;
+ docMap.set(layout[Id], {
+ x: Math.cos(deg) * (burstRadius[0] / 3) - docScale * layout[WidthSym]() / 2,
+ y: Math.sin(deg) * (burstRadius[1] / 3) - docScale * layout[HeightSym]() / 2,
+ width: docScale * layout[WidthSym](),
+ height: docScale * layout[HeightSym](),
+ pair: { layout, data },
+ replica: ""
+ });
+ });
+ return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []);
+}
+
export function computePivotLayout(
poolData: Map<string, PoolData>,
pivotDoc: Doc,
- childDocs: Doc[],
- filterDocs: Doc[],
childPairs: { layout: Doc, data?: Doc }[],
panelDim: number[],
viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
) {
+ const docMap = new Map<string, PoolData>();
const fieldKey = "data";
const pivotColumnGroups = new Map<FieldResult<Field>, PivotColumn>();
const pivotFieldKey = toLabel(pivotDoc._pivotField);
- for (const doc of filterDocs) {
- const val = Field.toString(doc[pivotFieldKey] as Field);
- if (val) {
- !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val] });
- pivotColumnGroups.get(val)!.docs.push(doc);
+ childPairs.map(pair => {
+ const lval = Cast(pair.layout[pivotFieldKey], listSpec("string"), null);
+ const val = Field.toString(pair.layout[pivotFieldKey] as Field);
+ if (lval) {
+ lval.forEach((val, i) => {
+ !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] });
+ pivotColumnGroups.get(val)!.docs.push(pair.layout);
+ pivotColumnGroups.get(val)!.replicas.push(i.toString());
+ });
+ } else if (val) {
+ !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] });
+ pivotColumnGroups.get(val)!.docs.push(pair.layout);
+ pivotColumnGroups.get(val)!.replicas.push("");
+ } else {
+ docMap.set(pair.layout[Id], {
+ x: 0,
+ y: 0,
+ zIndex: -99,
+ width: 0,
+ height: 0,
+ pair,
+ replica: ""
+ });
}
- }
+ });
let nonNumbers = 0;
- childDocs.map(doc => {
- const num = toNumber(doc[pivotFieldKey]);
+ childPairs.map(pair => {
+ const num = toNumber(pair.layout[pivotFieldKey]);
if (num === undefined || Number.isNaN(num)) {
nonNumbers++;
}
});
- const pivotNumbers = nonNumbers / childDocs.length < .1;
+ const pivotNumbers = nonNumbers / childPairs.length < .1;
if (pivotColumnGroups.size > 10) {
const arrayofKeys = Array.from(pivotColumnGroups.keys());
const sortedKeys = pivotNumbers ? arrayofKeys.sort((n1: FieldResult, n2: FieldResult) => toNumber(n1)! - toNumber(n2)!) : arrayofKeys.sort();
@@ -115,6 +185,7 @@ export function computePivotLayout(
const newgrp = pivotColumnGroups.get(sortedKeys[j])!;
curgrp.docs.push(...newgrp.docs);
curgrp.filters.push(...newgrp.filters);
+ curgrp.replicas.push(...newgrp.replicas);
pivotColumnGroups.delete(sortedKeys[j]);
}
}
@@ -142,7 +213,6 @@ export function computePivotLayout(
}
}
- const docMap = new Map<Doc, ViewDefBounds>();
const groupNames: ViewDefBounds[] = [];
const expander = 1.05;
@@ -165,7 +235,7 @@ export function computePivotLayout(
fontSize,
payload: val
});
- for (const doc of val.docs) {
+ val.docs.forEach((doc, i) => {
const layoutDoc = Doc.Layout(doc);
let wid = pivotAxisWidth;
let hgt = layoutDoc._nativeWidth ? (NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth)) * pivotAxisWidth : pivotAxisWidth;
@@ -173,27 +243,27 @@ export function computePivotLayout(
hgt = pivotAxisWidth;
wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
}
- docMap.set(doc, {
- type: "doc",
+ docMap.set(doc[Id] + (val.replicas || ""), {
x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? (numCols - val.docs.length) * pivotAxisWidth / 2 : 0),
y: -y + (pivotAxisWidth - hgt) / 2,
width: wid,
height: hgt,
- payload: undefined
+ pair: { layout: doc },
+ replica: val.replicas[i]
});
xCount++;
if (xCount >= numCols) {
xCount = 0;
y += pivotAxisWidth * expander;
}
- }
+ });
x += pivotAxisWidth * (numCols * expander + gap);
});
const dividers = sortedPivotKeys.map((key, i) =>
({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters }));
groupNames.push(...dividers);
- return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childDocs.filter(c => !filterDocs.includes(c)));
+ return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []);
}
function toNumber(val: FieldResult<Field>) {
@@ -203,15 +273,13 @@ function toNumber(val: FieldResult<Field>) {
export function computeTimelineLayout(
poolData: Map<string, PoolData>,
pivotDoc: Doc,
- childDocs: Doc[],
- filterDocs: Doc[],
childPairs: { layout: Doc, data?: Doc }[],
panelDim: number[],
viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
) {
const fieldKey = "data";
const pivotDateGroups = new Map<number, Doc[]>();
- const docMap = new Map<Doc, ViewDefBounds>();
+ const docMap = new Map<string, PoolData>();
const groupNames: ViewDefBounds[] = [];
const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field);
const curTime = toNumber(pivotDoc[fieldKey + "-timelineCur"]);
@@ -227,11 +295,11 @@ export function computeTimelineLayout(
let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq;
let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq;
- filterDocs.map(doc => {
- const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey])));
+ childPairs.forEach(pair => {
+ const num = NumCast(pair.layout[timelineFieldKey], Number(StrCast(pair.layout[timelineFieldKey])));
if (!Number.isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) {
!pivotDateGroups.get(num) && pivotDateGroups.set(num, []);
- pivotDateGroups.get(num)!.push(doc);
+ pivotDateGroups.get(num)!.push(pair.layout);
minTime = Math.min(num, minTime);
maxTime = Math.max(num, maxTime);
}
@@ -290,7 +358,7 @@ export function computeTimelineLayout(
}
const divider = { type: "div", color: Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "dimGray" : "black", x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined };
- return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider], childDocs.filter(c => !filterDocs.includes(c)));
+ return normalizeResults(panelDim, fontHeight, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
function layoutDocsAtTime(keyDocs: Doc[], key: number) {
keyDocs.forEach(doc => {
@@ -302,44 +370,55 @@ export function computeTimelineLayout(
hgt = pivotAxisWidth;
wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
}
- docMap.set(doc, {
- type: "doc",
+ docMap.set(doc[Id], {
x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
- zIndex: (curTime === key ? 1000 : zind++), highlight: curTime === key, width: wid / (Math.max(stack, 1)), height: hgt / (Math.max(stack, 1)), payload: undefined
+ zIndex: (curTime === key ? 1000 : zind++),
+ highlight: curTime === key,
+ width: wid / (Math.max(stack, 1)),
+ height: hgt / (Math.max(stack, 1)),
+ pair: { layout: doc },
+ replica: ""
});
stacking[stack] = x + pivotAxisWidth;
});
}
}
-function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map<Doc, ViewDefBounds>,
- poolData: Map<string, PoolData>, viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[],
- extraDocs: Doc[]): ViewDefResult[] {
-
+function normalizeResults(
+ panelDim: number[],
+ fontHeight: number,
+ docMap: Map<string, PoolData>,
+ poolData: Map<string, PoolData>,
+ viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
+ groupNames: ViewDefBounds[],
+ minWidth: number,
+ extras: ViewDefBounds[]
+): ViewDefResult[] {
const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds);
- const docEles = childPairs.filter(d => docMap.get(d.layout)).map(pair => docMap.get(pair.layout) as ViewDefBounds);
- const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0);
+ const docEles = Array.from(docMap.entries()).map(ele => ele[1]);
+ const aggBounds = aggregateBounds(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" }))).filter(e => e.zIndex !== -99), 0, 0);
aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x);
const wscale = panelDim[0] / (aggBounds.r - aggBounds.x);
let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale;
if (Number.isNaN(scale)) scale = 1;
- childPairs.filter(d => docMap.get(d.layout)).map(pair => {
- const newPosRaw = docMap.get(pair.layout);
+ Array.from(docMap.entries()).filter(ele => ele[1].pair).map(ele => {
+ const newPosRaw = ele[1];
if (newPosRaw) {
const newPos = {
x: newPosRaw.x * scale,
y: newPosRaw.y * scale,
z: newPosRaw.z,
+ replica: newPosRaw.replica,
highlight: newPosRaw.highlight,
zIndex: newPosRaw.zIndex,
width: (newPosRaw.width || 0) * scale,
- height: newPosRaw.height! * scale
+ height: newPosRaw.height! * scale,
+ pair: ele[1].pair
};
- poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos });
+ poolData.set(newPos.pair.layout[Id] + (newPos.replica || ""), { transition: "transform 1s", ...newPos });
}
});
- extraDocs.map(ed => poolData.set(ed[Id], { x: 0, y: 0, zIndex: -99 }));
return viewDefsToJSX(extras.concat(groupNames).map(gname => ({
type: gname.type,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
index 75af11537..05111adb4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
@@ -4,6 +4,7 @@
pointer-events: all;
stroke-width: 3px;
transition: opacity 0.5s ease-in;
+ fill: transparent;
}
.collectionfreeformlinkview-linkCircle {
stroke: rgb(0,0,0);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index a33146388..cf12ef382 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -25,9 +25,9 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform(), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document), this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document)],
action(() => {
setTimeout(action(() => this._opacity = 1), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
- setTimeout(action(() => this._opacity = 0.05), 750); // this will unhighlight the link line.
- const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
- const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
+ setTimeout(action(() => (!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line.
+ const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
+ const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
const adiv = (acont.length ? acont[0] : this.props.A.ContentDiv!);
const bdiv = (bcont.length ? bcont[0] : this.props.B.ContentDiv!);
const a = adiv.getBoundingClientRect();
@@ -43,7 +43,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const afield = StrCast(this.props.A.props.Document[StrCast(this.props.A.props.layoutKey, "layout")]).indexOf("anchor1") === -1 ? "anchor2" : "anchor1";
const bfield = afield === "anchor1" ? "anchor2" : "anchor1";
- // really hacky stuff to make the DocuLinkBox display where we want it to:
+ // really hacky stuff to make the LinkAnchorBox display where we want it to:
// if there's an element in the DOM with the id of the opposite anchor, then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right
// otherwise, we just use the computed nearest point on the document boundary to the target Document
const targetAhyperlink = window.document.getElementById(this.props.LinkDocs[0][Id] + (this.props.LinkDocs[0][afield] as Doc)[Id]);
@@ -81,8 +81,9 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
}
render() {
- const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
- const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("docuLinkBox-cont") : [];
+ this.props.A.props.ScreenToLocalTransform().transform(this.props.B.props.ScreenToLocalTransform());
+ const acont = this.props.A.props.Document.type === DocumentType.LINK ? this.props.A.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
+ const bcont = this.props.B.props.Document.type === DocumentType.LINK ? this.props.B.ContentDiv!.getElementsByClassName("linkAnchorBox-cont") : [];
const a = (acont.length ? acont[0] : this.props.A.ContentDiv!).getBoundingClientRect();
const b = (bcont.length ? bcont[0] : this.props.B.ContentDiv!).getBoundingClientRect();
const apt = Utils.closestPtBetweenRectangles(a.left, a.top, a.width, a.height,
@@ -93,17 +94,26 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
apt.point.x, apt.point.y);
const pt1 = [apt.point.x, apt.point.y];
const pt2 = [bpt.point.x, bpt.point.y];
+ const pt1vec = [pt1[0] - (a.left + a.width / 2), pt1[1] - (a.top + a.height / 2)];
+ const pt2vec = [pt2[0] - (b.left + b.width / 2), pt2[1] - (b.top + b.height / 2)];
+ const pt1len = Math.sqrt((pt1vec[0] * pt1vec[0]) + (pt1vec[1] * pt1vec[1]));
+ const pt2len = Math.sqrt((pt2vec[0] * pt2vec[0]) + (pt2vec[1] * pt2vec[1]));
+ const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 3;
+ const pt1norm = [pt1vec[0] / pt1len * ptlen, pt1vec[1] / pt1len * ptlen];
+ const pt2norm = [pt2vec[0] / pt2len * ptlen, pt2vec[1] / pt2len * ptlen];
const aActive = this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document);
const bActive = this.props.A.isSelected() || Doc.IsBrushed(this.props.A.props.Document);
const text = StrCast(this.props.A.props.Document.linkRelationship);
- return !aActive && !bActive ? (null) : (<>
+ return !a.width || !b.width || ((!this.props.LinkDocs.length || !this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
<text x={(pt1[0] + pt2[0]) / 2} y={(pt1[1] + pt2[1]) / 2}>
{text !== "-ungrouped-" ? text : ""}
</text>
- <line key="linkLine" className="collectionfreeformlinkview-linkLine"
+ <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2" }}
+ d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} />
+ {/* <line key="linkLine" className="collectionfreeformlinkview-linkLine"
style={{ opacity: this._opacity, strokeDasharray: "2 2" }}
x1={`${pt1[0]}`} y1={`${pt1[1]}`}
- x2={`${pt2[0]}`} y2={`${pt2[1]}`} />
+ x2={`${pt2[0]}`} y2={`${pt2[1]}`} /> */}
</>);
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 49ca024a2..4b5e977df 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -31,72 +31,16 @@ export class CollectionFreeFormLinksView extends React.Component {
}, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]);
return connections.filter(c =>
c.a.props.layoutKey && c.b.props.layoutKey && c.a.props.Document.type === DocumentType.LINK &&
- c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed
+ c.a.props.bringToFront !== emptyFunction && c.b.props.bringToFront !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed
).map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />);
}
render() {
- return <div className="collectionfreeformlinksview-container">
+ return SelectionManager.GetIsDragging() ? (null) : <div className="collectionfreeformlinksview-container">
<svg className="collectionfreeformlinksview-svgCanvas">
- {SelectionManager.GetIsDragging() ? (null) : this.uniqueConnections}
+ {this.uniqueConnections}
</svg>
{this.props.children}
</div>;
}
- // _brushReactionDisposer?: IReactionDisposer;
- // componentDidMount() {
- // this._brushReactionDisposer = reaction(
- // () => {
- // let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
- // return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
- // },
- // () => {
- // let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
- // let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
- // views.forEach((dstDoc, i) => {
- // views.forEach((srcDoc, j) => {
- // let dstTarg = dstDoc;
- // let srcTarg = srcDoc;
- // let x1 = NumCast(srcDoc.x);
- // let x2 = NumCast(dstDoc.x);
- // let x1w = NumCast(srcDoc.width, -1);
- // let x2w = NumCast(dstDoc.width, -1);
- // if (x1w < 0 || x2w < 0 || i === j) { }
- // else {
- // let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
- // let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
- // return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
- // });
- // let brushAction = (field: (Doc | Promise<Doc>)[]) => {
- // let found = findBrush(field);
- // if (found !== -1) {
- // field.splice(found, 1);
- // }
- // };
- // if (Math.abs(x1 + x1w - x2) < 20) {
- // let linkDoc: Doc = new Doc();
- // linkDoc.title = "Histogram Brush";
- // linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
- // linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
-
- // brushAction = (field: (Doc | Promise<Doc>)[]) => {
- // if (findBrush(field) === -1) {
- // field.push(linkDoc);
- // }
- // };
- // }
- // if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
- // if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
- // let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
- // let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
- // brushAction(dstBrushDocs);
- // brushAction(srcBrushDocs);
- // }
- // });
- // });
- // });
- // }
- // componentWillUnmount() {
- // this._brushReactionDisposer?.();
- // }
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 730392ab5..60c39c825 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -9,10 +9,21 @@
height: 100%;
transform-origin: left top;
border-radius: inherit;
+ touch-action: none;
+ border-radius: inherit;
+}
+
+.collectionfreeformview-viewdef {
+ > .collectionFreeFormDocumentView-container {
+ pointer-events: none;
+ .contentFittingDocumentDocumentView-previewDoc {
+ pointer-events: all;
+ }
+ }
}
.collectionfreeformview-ease {
- transition: transform 1s;
+ transition: transform 500ms;
}
.collectionfreeformview-none {
@@ -36,6 +47,7 @@
height: 100%;
display: flex;
align-items: center;
+ overflow: hidden;
.collectionfreeformview-placeholderSpan {
font-size: 32;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f12dd76d8..28b461313 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -4,7 +4,7 @@ import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrows
import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
-import { Doc, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc";
+import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc";
import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas";
import { Id } from "../../../../new_fields/FieldSymbols";
import { InkData, InkField, InkTool } from "../../../../new_fields/InkField";
@@ -15,7 +15,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
import { TraceMobx } from "../../../../new_fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnOne, Utils, returnZero } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs } from "../../../documents/Documents";
@@ -31,18 +31,19 @@ import { ContextMenu } from "../../ContextMenu";
import { ContextMenuProps } from "../../ContextMenuItem";
import { InkingControl } from "../../InkingControl";
import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
-import { DocumentViewProps } from "../../nodes/DocumentView";
+import { DocumentViewProps, DocumentView } from "../../nodes/DocumentView";
import { FormattedTextBox } from "../../nodes/FormattedTextBox";
import { pageSchema } from "../../nodes/ImageBox";
import PDFMenu from "../../pdf/PDFMenu";
import { CollectionDockingView } from "../CollectionDockingView";
import { CollectionSubView } from "../CollectionSubView";
-import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
+import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult, computerStarburstLayout, computerPassLayout } from "./CollectionFreeFormLayoutEngines";
import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
import "./CollectionFreeFormView.scss";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
+import { CollectionViewType } from "../CollectionView";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -66,19 +67,27 @@ export const panZoomSchema = createSchema({
type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchema, typeof positionSchema, typeof pageSchema]>;
const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema);
+export type collectionFreeformViewProps = {
+ forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox)
+ childClickScript?: ScriptField;
+ viewDefDivClick?: ScriptField;
+};
@observer
-export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
+export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, Partial<collectionFreeformViewProps>>(PanZoomDocument) {
private _lastX: number = 0;
private _lastY: number = 0;
+ private _downX: number = 0;
+ private _downY: number = 0;
private _inkToTextStartX: number | undefined;
private _inkToTextStartY: number | undefined;
private _wordPalette: Map<string, string> = new Map<string, string>();
private _clusterDistance: number = 75;
private _hitCluster = false;
private _layoutComputeReaction: IReactionDisposer | undefined;
- private _layoutPoolData = new ObservableMap<string, any>();
- private _cachedPool: Map<string, any> = new Map();
+ private _layoutPoolData = new ObservableMap<string, PoolData>();
+ private _layoutSizeData = new ObservableMap<string, { width?: number, height?: number }>();
+ private _cachedPool: Map<string, PoolData> = new Map();
@observable private _pullCoords: number[] = [0, 0];
@observable private _pullDirection: string = "";
@@ -86,6 +95,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables
@observable _clusterSets: (Doc[])[] = [];
+ @computed get fitToContentScaling() { return this.fitToContent ? NumCast(this.layoutDoc.fitToContentScaling, 1) : 1; }
@computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
@computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
@computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); }
@@ -96,8 +106,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private easing = () => this.props.Document.panTransformType === "Ease";
private panX = () => this.fitToContent ? (this.contentBounds.x + this.contentBounds.r) / 2 : this.Document._panX || 0;
private panY = () => this.fitToContent ? (this.contentBounds.y + this.contentBounds.b) / 2 : this.Document._panY || 0;
- private zoomScaling = () => (1 / this.parentScaling) * (this.fitToContent ?
- Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
+ private zoomScaling = () => (this.fitToContentScaling / this.parentScaling) * (this.fitToContent ?
+ Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y),
+ this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
this.Document.scale || 1)
private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0; // shift so pan position is at center of window for non-overlay collections
@@ -135,7 +146,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@undoBatch
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
- if (this.props.Document.isBackground) return false;
+ // if (this.props.Document.isBackground) return false;
const xf = this.getTransform();
const xfo = this.getTransformOverlay();
const [xp, yp] = xf.transformPoint(de.x, de.y);
@@ -161,7 +172,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
const nh = NumCast(layoutDoc._nativeHeight);
layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300;
}
- this.bringToFront(d);
+ d.isBackground === undefined && this.bringToFront(d);
}));
(de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments);
@@ -319,17 +330,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
document.removeEventListener("pointerup", this.onPointerUp);
document.addEventListener("pointermove", this.onPointerMove);
document.addEventListener("pointerup", this.onPointerUp);
- // if physically using a pen or we're in pen or highlighter mode
- // if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) {
- // e.stopPropagation();
- // e.preventDefault();
- // const point = this.getTransform().transformPoint(e.pageX, e.pageY);
- // this._points.push({ X: point[0], Y: point[1] });
- // }
// if not using a pen and in no ink mode
if (InkingControl.Instance.selectedTool === InkTool.None) {
- this._lastX = e.pageX;
- this._lastY = e.pageY;
+ this._downX = this._lastX = e.pageX;
+ this._downY = this._lastY = e.pageY;
}
// eraser plus anything else mode
else {
@@ -489,6 +493,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
}
+ _lastTap = 0;
+
@action
onPointerUp = (e: PointerEvent): void => {
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) return;
@@ -499,6 +505,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
this.removeEndListeners();
}
+ onClick = (e: React.MouseEvent) => {
+ if (this.layoutDoc.targetScale && (Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
+ if (Date.now() - this._lastTap < 300) {
+ const docpt = this.getTransform().transformPoint(e.clientX, e.clientY);
+ this.scaleAtPt(docpt, 1);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ this._lastTap = Date.now();
+ }
+ }
+
@action
pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => {
// bcz: theres should be a better way of doing these than referencing these static instances directly
@@ -506,31 +524,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
PDFMenu.Instance.fadeOut(true);
const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
- let x = (this.Document._panX || 0) - dx;
- let y = (this.Document._panY || 0) - dy;
- if (!this.isAnnotationOverlay) {
- // this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds
- const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout);
- const measuredDocs = docs.filter(doc => doc && this.childDataProvider(doc)).map(doc => this.childDataProvider(doc));
- if (measuredDocs.length) {
- const ranges = measuredDocs.reduce(({ xrange, yrange }, { x, y, width, height }) => // computes range of content
- ({
- xrange: { min: Math.min(xrange.min, x), max: Math.max(xrange.max, x + width) },
- yrange: { min: Math.min(yrange.min, y), max: Math.max(yrange.max, y + height) }
- })
- , {
- xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
- yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }
- });
-
- const panelDim = [this.props.PanelWidth() / this.zoomScaling(), this.props.PanelHeight() / this.zoomScaling()];
- if (ranges.xrange.min > (this.panX() + panelDim[0] / 2)) x = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds
- if (ranges.xrange.max < (this.panX() - panelDim[0] / 2)) x = ranges.xrange.min - panelDim[0] / 2;
- if (ranges.yrange.min > (this.panY() + panelDim[1] / 2)) y = ranges.yrange.max + panelDim[1] / 2;
- if (ranges.yrange.max < (this.panY() - panelDim[1] / 2)) y = ranges.yrange.min - panelDim[1] / 2;
- }
- }
- this.setPan(x, y);
+ this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true);
this._lastX = e.clientX;
this._lastY = e.clientY;
}
@@ -727,10 +721,33 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
e.stopPropagation();
this.zoom(e.clientX, e.clientY, e.deltaY);
}
+ this.props.Document.targetScale = NumCast(this.props.Document.scale);
}
@action
- setPan(panX: number, panY: number, panType: string = "None") {
+ setPan(panX: number, panY: number, panType: string = "None", clamp: boolean = false) {
+ if (!this.isAnnotationOverlay && clamp) {
+ // this section wraps the pan position, horizontally and/or vertically whenever the content is panned out of the viewing bounds
+ const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc).map(pair => pair.layout);
+ const measuredDocs = docs.filter(doc => doc && this.childDataProvider(doc, "")).map(doc => this.childDataProvider(doc, ""));
+ if (measuredDocs.length) {
+ const ranges = measuredDocs.reduce(({ xrange, yrange }, { x, y, width, height }) => // computes range of content
+ ({
+ xrange: { min: Math.min(xrange.min, x), max: Math.max(xrange.max, x + width) },
+ yrange: { min: Math.min(yrange.min, y), max: Math.max(yrange.max, y + height) }
+ })
+ , {
+ xrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE },
+ yrange: { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }
+ });
+
+ const panelDim = [this.props.PanelWidth() / this.zoomScaling(), this.props.PanelHeight() / this.zoomScaling()];
+ if (ranges.xrange.min >= (panX + panelDim[0] / 2)) panX = ranges.xrange.max + panelDim[0] / 2; // snaps pan position of range of content goes out of bounds
+ else if (ranges.xrange.max <= (panX - panelDim[0] / 2)) panX = ranges.xrange.min - panelDim[0] / 2;
+ if (ranges.yrange.min >= (panY + panelDim[1] / 2)) panY = ranges.yrange.max + panelDim[1] / 2;
+ else if (ranges.yrange.max <= (panY - panelDim[1] / 2)) panY = ranges.yrange.min - panelDim[1] / 2;
+ }
+ }
if (!this.Document.lockedTransform || this.Document.inOverlay) {
this.Document.panTransformType = panType;
const scale = this.getLocalTransform().inverse().Scale;
@@ -756,6 +773,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
}
+ scaleAtPt(docpt: number[], scale: number) {
+ const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
+ this.Document.panTransformType = "Ease";
+ this.layoutDoc.scale = scale;
+ const newScreenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]);
+ const scrDelta = { x: screenXY[0] - newScreenXY[0], y: screenXY[1] - newScreenXY[1] };
+ const newpan = this.getTransform().transformDirection(scrDelta.x, scrDelta.y);
+ this.layoutDoc._panX = NumCast(this.layoutDoc._panX) - newpan[0];
+ this.layoutDoc._panY = NumCast(this.layoutDoc._panY) - newpan[1];
+ }
+
focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => {
const state = HistoryUtil.getState();
@@ -778,7 +806,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
if (!annotOn) {
this.props.focus(doc);
} else {
- const contextHgt = Doc.AreProtosEqual(annotOn, this.props.Document) && this.props.VisibleHeight ? this.props.VisibleHeight() : NumCast(annotOn.height);
+ const contextHgt = Doc.AreProtosEqual(annotOn, this.props.Document) && this.props.VisibleHeight ? this.props.VisibleHeight() : NumCast(annotOn._height);
const offset = annotOn && (contextHgt / 2 * 96 / 72);
this.props.Document.scrollY = NumCast(doc.y) - offset;
}
@@ -794,11 +822,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document.scale, pt: this.Document.panTransformType };
- if (!doc.z) this.setPan(newPanX, newPanY, "Ease"); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+ // if (!willZoom && DocumentView._focusHack.length) {
+ // Doc.BrushDoc(this.props.Document);
+ // !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1);
+ // } else {
+ if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
+ if (!doc.z) this.setPan(newPanX, newPanY, "Ease", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+ }
Doc.BrushDoc(this.props.Document);
this.props.focus(this.props.Document);
willZoom && this.setScaleToZoom(layoutdoc, scale);
Doc.linkFollowHighlight(doc);
+ //}
afterFocus && setTimeout(() => {
if (afterFocus?.()) {
@@ -807,7 +842,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
this.Document.scale = savedState.s;
this.Document.panTransformType = savedState.pt;
}
- }, 1000);
+ }, 500);
}
}
@@ -817,9 +852,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
@computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
- @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+ @computed get onChildClickHandler() { return this.props.childClickScript || ScriptCast(this.Document.onChildClick); }
backgroundHalo = () => BoolCast(this.Document.useClusters);
-
+ @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); }
+ parentActive = () => this.props.active() || this.backgroundActive ? true : false;
getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
return {
...this.props,
@@ -831,7 +867,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
LibraryPath: this.libraryPath,
FreezeDimensions: this.props.freezeChildDimensions,
layoutKey: undefined,
- rootSelected: this.rootSelected,
+ rootSelected: childData ? this.rootSelected : returnFalse,
dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
//onClick: undefined, // this.props.onClick, // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
onClick: this.onChildClickHandler,
@@ -845,29 +881,36 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
focus: this.focusDocument,
backgroundColor: this.getClusterColor,
backgroundHalo: this.backgroundHalo,
- parentActive: this.props.active,
+ parentActive: this.parentActive,
bringToFront: this.bringToFront,
addDocTab: this.addDocTab,
};
}
- addDocTab = (doc: Doc, where: string) => {
+ addDocTab = action((doc: Doc, where: string) => {
+ if (where === "inParent") {
+ const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = pt[0];
+ doc.y = pt[1];
+ this.props.addDocument(doc);
+ return true;
+ }
if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
return true;
}
return this.props.addDocTab(doc, where);
- }
- getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): PoolData {
+ });
+ getCalculatedPositions(params: { pair: { layout: Doc, data?: Doc }, index: number, collection: Doc, docs: Doc[], state: any }): PoolData {
const result = this.Document.arrangeScript?.script.run(params, console.log);
if (result?.success) {
- return { ...result, transition: "transform 1s" };
+ return { x: 0, y: 0, transition: "transform 1s", ...result, pair: params.pair, replica: "" };
}
- const layoutDoc = Doc.Layout(params.doc);
- const { x, y, z, color, zIndex } = params.doc;
+ const layoutDoc = Doc.Layout(params.pair.layout);
+ const { x, y, z, color, zIndex } = params.pair.layout;
return {
x: NumCast(x), y: NumCast(y), z: Cast(z, "number"), color: StrCast(color), zIndex: Cast(zIndex, "number"),
- width: Cast(layoutDoc._width, "number"), height: Cast(layoutDoc._height, "number")
+ width: Cast(layoutDoc._width, "number"), height: Cast(layoutDoc._height, "number"), pair: params.pair, replica: ""
};
}
@@ -876,7 +919,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
onViewDefDivClick = (e: React.MouseEvent, payload: any) => {
- (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload });
+ (this.props.viewDefDivClick || ScriptCast(this.props.Document.onViewDefDivClick))?.script.run({ this: this.props.Document, payload });
+ e.stopPropagation();
}
private viewDefToJSX(viewDef: ViewDefBounds): Opt<ViewDefResult> {
const { x, y, z } = viewDef;
@@ -904,18 +948,22 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
}
- childDataProvider = computedFn(function childDataProvider(this: any, doc: Doc) {
- return this._layoutPoolData.get(doc[Id]);
+ childDataProvider = computedFn(function childDataProvider(this: any, doc: Doc, replica: string) {
+ return this._layoutPoolData.get(doc[Id] + (replica || ""));
+ }.bind(this));
+ childSizeProvider = computedFn(function childSizeProvider(this: any, doc: Doc, replica: string) {
+ return this._layoutSizeData.get(doc[Id] + (replica || ""));
}.bind(this));
- doTimelineLayout(poolData: Map<string, PoolData>) {
- return computeTimelineLayout(poolData, this.props.Document, this.childDocs, this.childDocs,
- this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
- }
-
- doPivotLayout(poolData: Map<string, PoolData>) {
- return computePivotLayout(poolData, this.props.Document, this.childDocs, this.childDocs,
- this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
+ doEngineLayout(poolData: Map<string, PoolData>,
+ engine: (
+ poolData: Map<string, PoolData>,
+ pivotDoc: Doc,
+ childPairs: { layout: Doc, data?: Doc }[],
+ panelDim: number[],
+ viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[]
+ ) {
+ return engine(poolData, this.props.Document, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
}
doFreeformLayout(poolData: Map<string, PoolData>) {
@@ -925,17 +973,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
const elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : [];
this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => {
- const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state });
+ const pos = this.getCalculatedPositions({ pair, index: i, collection: this.Document, docs: layoutDocs, state });
poolData.set(pair.layout[Id], pos);
});
return elements;
}
@computed get doInternalLayoutComputation() {
- const newPool = new Map<string, any>();
- switch (this.props.layoutEngine?.()) {
- case "timeline": return { newPool, computedElementData: this.doTimelineLayout(newPool) };
- case "pivot": return { newPool, computedElementData: this.doPivotLayout(newPool) };
+ TraceMobx();
+
+
+ const newPool = new Map<string, PoolData>();
+ const engine = this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine);
+ switch (engine) {
+ case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) };
+ case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) };
+ case "pivot": return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) };
+ case "starburst": return { newPool, computedElementData: this.doEngineLayout(newPool, computerStarburstLayout) };
}
return { newPool, computedElementData: this.doFreeformLayout(newPool) };
}
@@ -944,28 +998,39 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
get doLayoutComputation() {
const { newPool, computedElementData } = this.doInternalLayoutComputation;
runInAction(() =>
- Array.from(newPool.keys()).map(key => {
- const lastPos = this._cachedPool.get(key); // last computed pos
- const newPos = newPool.get(key);
- if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex || newPos.width !== lastPos.width || newPos.height !== lastPos.height) {
- this._layoutPoolData.set(key, newPos);
+ Array.from(newPool.entries()).map(entry => {
+ const lastPos = this._cachedPool.get(entry[0]); // last computed pos
+ const newPos = entry[1];
+ if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) {
+ this._layoutPoolData.set(entry[0], newPos);
+ }
+ if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) {
+ this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height });
}
}));
this._cachedPool.clear();
- Array.from(newPool.keys()).forEach(k => this._cachedPool.set(k, newPool.get(k)));
+ Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1]));
const elements: ViewDefResult[] = computedElementData.slice();
- this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair =>
+ const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
+ Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry =>
elements.push({
ele: <CollectionFreeFormDocumentView
- key={pair.layout[Id]}
- {...this.getChildDocumentViewProps(pair.layout, pair.data)}
+ key={entry[1].pair.layout[Id] + (entry[1].replica || "")}
+ {...this.getChildDocumentViewProps(entry[1].pair.layout, entry[1].pair.data)}
+ replica={entry[1].replica}
dataProvider={this.childDataProvider}
+ sizeProvider={this.childSizeProvider}
LayoutDoc={this.childLayoutDocFunc}
- jitterRotation={NumCast(this.props.Document.jitterRotation)}
- fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)}
+ pointerEvents={
+ this.backgroundActive ?
+ true :
+ (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? false : undefined}
+ jitterRotation={NumCast(this.props.Document._jitterRotation)}
+ //fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
+ fitToBox={BoolCast(this.props.freezeChildDimensions)} // bcz: check this
FreezeDimensions={BoolCast(this.props.freezeChildDimensions)}
/>,
- bounds: this.childDataProvider(pair.layout)
+ bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica)
}));
return elements;
@@ -988,6 +1053,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
}
+ promoteCollection = undoBatch(action(() => {
+ this.childDocs.forEach(doc => {
+ const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y));
+ doc.x = scr?.[0];
+ doc.y = scr?.[1];
+ this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc);
+ });
+ this.props.ContainingCollectionView?.removeDocument(this.props.Document);
+ }));
layoutDocsInGrid = () => {
UndoManager.RunInBatch(() => {
const docs = this.childLayoutPairs;
@@ -1012,59 +1086,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private thumbIdentifier?: number;
- // @action
- // handleHandDown = (e: React.TouchEvent) => {
- // const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true);
- // const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
- // this.thumbIdentifier = thumb?.identifier;
- // const others = fingers.filter(f => f !== thumb);
- // const minX = Math.min(...others.map(f => f.clientX));
- // const minY = Math.min(...others.map(f => f.clientY));
- // const t = this.getTransform().transformPoint(minX, minY);
- // const th = this.getTransform().transformPoint(thumb.clientX, thumb.clientY);
-
- // const thumbDoc = FieldValue(Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc));
- // if (thumbDoc) {
- // this._palette = <Palette x={t[0]} y={t[1]} thumb={th} thumbDoc={thumbDoc} />;
- // }
-
- // document.removeEventListener("touchmove", this.onTouch);
- // document.removeEventListener("touchmove", this.handleHandMove);
- // document.addEventListener("touchmove", this.handleHandMove);
- // document.removeEventListener("touchend", this.handleHandUp);
- // document.addEventListener("touchend", this.handleHandUp);
- // }
-
- // @action
- // handleHandMove = (e: TouchEvent) => {
- // for (let i = 0; i < e.changedTouches.length; i++) {
- // const pt = e.changedTouches.item(i);
- // if (pt?.identifier === this.thumbIdentifier) {
- // }
- // }
- // }
-
- // @action
- // handleHandUp = (e: TouchEvent) => {
- // this.onTouchEnd(e);
- // if (this.prevPoints.size < 3) {
- // this._palette = undefined;
- // document.removeEventListener("touchend", this.handleHandUp);
- // }
- // }
-
onContextMenu = (e: React.MouseEvent) => {
if (this.props.children && this.props.annotationsKey) return;
- const layoutItems: ContextMenuProps[] = [];
-
- layoutItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
- layoutItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
- layoutItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
- layoutItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
- layoutItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
+ const options = ContextMenu.Instance.findByDescription("Options...");
+ const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
+
+ optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
+ optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
+ optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
+ optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
+ this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
+ optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
// layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
- layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" });
- layoutItems.push({
+ optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document._jitterRotation = (this.props.Document._jitterRotation ? 0 : 10)), icon: "paint-brush" });
+ optionItems.push({
description: "Import document", icon: "upload", event: ({ x, y }) => {
const input = document.createElement("input");
input.type = "file";
@@ -1092,7 +1127,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
});
- ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
}
private childViews = () => {
@@ -1114,24 +1149,37 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
<span className="collectionfreeformview-placeholderSpan">{this.props.Document.title?.toString()}</span>
</div>;
}
+
+ _nudgeTime = 0;
+ nudge = action((x: number, y: number) => {
+ if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform) { // bcz: this isn't ideal, but want to try it out...
+ this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(),
+ NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "Ease", true);
+ this._nudgeTime = Date.now();
+ setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document.panTransformType = undefined), 500);
+ return true;
+ }
+ return false;
+ });
@computed get marqueeView() {
- return <MarqueeView {...this.props} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument}
+ return <MarqueeView {...this.props} nudge={this.nudge} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument}
addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform} isAnnotationOverlay={this.isAnnotationOverlay}>
- <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
- easing={this.easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
+ <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} shifted={!this.nativeHeight && !this.isAnnotationOverlay}
+ easing={this.easing} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
{this.children}
</CollectionFreeFormViewPannableContents>
</MarqueeView>;
}
@computed get contentScaling() {
- if (this.props.annotationsKey) return 0;
+ if (this.props.annotationsKey && !this.props.forceScaling) return 0;
const nw = NumCast(this.Document._nativeWidth, this.props.NativeWidth());
const nh = NumCast(this.Document._nativeHeight, this.props.NativeHeight());
const hscale = nh ? this.props.PanelHeight() / nh : 1;
const wscale = nw ? this.props.PanelWidth() / nw : 1;
return wscale < hscale ? wscale : hscale;
}
+ @computed get backgroundEvents() { return this.layoutDoc.isBackground && SelectionManager.GetIsDragging(); }
render() {
TraceMobx();
const clientRect = this._mainCont?.getBoundingClientRect();
@@ -1144,10 +1192,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
// otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document
return <div className={"collectionfreeformview-container"}
ref={this.createDashEventsTarget}
- onWheel={this.onPointerWheel}//pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
+ onWheel={this.onPointerWheel} onClick={this.onClick} //pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu}
style={{
- pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
+ pointerEvents: this.backgroundEvents ? "all" : undefined,
transform: this.contentScaling ? `scale(${this.contentScaling})` : "",
transformOrigin: this.contentScaling ? "left top" : "",
width: this.contentScaling ? `${100 / this.contentScaling}%` : "",
@@ -1191,19 +1239,25 @@ interface CollectionFreeFormViewPannableContentsProps {
panY: () => number;
zoomScaling: () => number;
easing: () => boolean;
+ viewDefDivClick?: ScriptField;
children: () => JSX.Element[];
+ shifted: boolean;
}
@observer
class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
render() {
- const freeformclass = "collectionfreeformview" + (this.props.easing() ? "-ease" : "-none");
+ const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : (this.props.easing() ? "-ease" : "-none"));
const cenx = this.props.centeringShiftX();
const ceny = this.props.centeringShiftY();
const panx = -this.props.panX();
const pany = -this.props.panY();
const zoom = this.props.zoomScaling();
- return <div className={freeformclass} style={{ touchAction: "none", borderRadius: "inherit", transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)` }}>
+ return <div className={freeformclass}
+ style={{
+ width: this.props.shifted ? 0 : undefined, height: this.props.shifted ? 0 : undefined,
+ transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`
+ }}>
{this.props.children()}
</div>;
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
index 18d6da0da..1291e7dc1 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss
@@ -6,7 +6,6 @@
width:100%;
height:100%;
overflow: hidden;
- pointer-events: inherit;
border-radius: inherit;
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 503df10c2..cd8166309 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,12 +1,12 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, DataSym, WidthSym, HeightSym } from "../../../../new_fields/Doc";
+import { Doc, DocListCast, DataSym, WidthSym, HeightSym, Opt } from "../../../../new_fields/Doc";
import { InkField, InkData } from "../../../../new_fields/InkField";
import { List } from "../../../../new_fields/List";
import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
import { Utils } from "../../../../Utils";
-import { Docs, DocUtils } from "../../../documents/Documents";
+import { Docs, DocUtils, DocumentOptions } from "../../../documents/Documents";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
import { undoBatch } from "../../../util/UndoManager";
@@ -20,6 +20,7 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices
import { RichTextField } from "../../../../new_fields/RichTextField";
import { CollectionView } from "../CollectionView";
import { FormattedTextBox } from "../../nodes/FormattedTextBox";
+import { ScriptField } from "../../../../new_fields/ScriptField";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -31,6 +32,7 @@ interface MarqueeViewProps {
addLiveTextDocument: (doc: Doc) => void;
isSelected: () => boolean;
isAnnotationOverlay?: boolean;
+ nudge: (x: number, y: number) => boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
}
@@ -46,7 +48,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
_commandExecuted = false;
componentDidMount() {
- this.props.setPreviewCursor && this.props.setPreviewCursor(this.setPreviewCursor);
+ this.props.setPreviewCursor?.(this.setPreviewCursor);
}
@action
@@ -243,15 +245,16 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this._downX = x;
this._downY = y;
- PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument);
+ PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
}
});
@action
onClick = (e: React.MouseEvent): void => {
- if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
+ if (
+ Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
- this.setPreviewCursor(e.clientX, e.clientY, false);
+ !(e.nativeEvent as any).formattedHandled && this.setPreviewCursor(e.clientX, e.clientY, false);
// let the DocumentView stopPropagation of this event when it selects this document
} else { // why do we get a click event when the cursor have moved a big distance?
// let's cut it off here so no one else has to deal with it.
@@ -307,11 +310,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
- getCollection = (selected: Doc[], asTemplate: boolean, isBackground: boolean = false) => {
+ getCollection = (selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => {
const bounds = this.Bounds;
// const inkData = this.ink ? this.ink.inkData : undefined;
- const creator = asTemplate ? Docs.Create.StackingDocument : Docs.Create.FreeformDocument;
- const newCollection = creator(selected, {
+ const newCollection = (creator || Docs.Create.FreeformDocument)(selected, {
x: bounds.left,
y: bounds.top,
_panX: 0,
@@ -331,6 +333,18 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
@action
+ pileup = (e: KeyboardEvent | React.PointerEvent | undefined) => {
+ const selected = this.marqueeSelect(false);
+ SelectionManager.DeselectAll();
+ selected.forEach(d => this.props.removeDocument(d));
+ const newCollection = Doc.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2);
+ this.props.addDocument(newCollection);
+ this.props.selectDocuments([newCollection], []);
+ MarqueeOptionsMenu.Instance.fadeOut(true);
+ this.hideMarquee();
+ }
+
+ @action
collection = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const bounds = this.Bounds;
const selected = this.marqueeSelect(false);
@@ -343,7 +357,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
return d;
});
}
- const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t");
+ const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined);
this.props.addDocument(newCollection);
this.props.selectDocuments([newCollection], []);
MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -454,7 +468,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
@action
background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
- const newCollection = this.getCollection([], false, true);
+ const newCollection = this.getCollection([], undefined, true);
this.props.addDocument(newCollection);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
@@ -474,7 +488,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.delete();
e.stopPropagation();
}
- if (e.key === "c" || e.key === "b" || e.key === "t" || e.key === "s" || e.key === "S") {
+ if (e.key === "c" || e.key === "b" || e.key === "t" || e.key === "s" || e.key === "S" || e.key === "p") {
this._commandExecuted = true;
e.stopPropagation();
e.preventDefault();
@@ -488,6 +502,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (e.key === "b") {
this.background(e);
}
+ if (e.key === "p") {
+ this.pileup(e);
+ }
this.cleanupInteractions(false);
}
}
@@ -585,13 +602,19 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
* This contains the "C for collection, ..." text on marquees.
* Commented out by syip2 when the marquee menu was added.
*/
- return <div className="marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}`, zIndex: 2000 }} >
+ return <div className="marquee" style={{
+ transform: `translate(${p[0]}px, ${p[1]}px)`,
+ width: `${Math.abs(v[0])}`,
+ height: `${Math.abs(v[1])}`, zIndex: 2000
+ }} >
{/* <span className="marquee-legend" /> */}
</div>;
}
render() {
- return <div className="marqueeView" onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
+ return <div className="marqueeView"
+ style={{ overflow: StrCast(this.props.Document.overflow), }}
+ onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
{this._visible ? this.marqueeDiv : null}
{this.props.children}
</div>;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 7e511ae34..9d09ecc3b 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -5,7 +5,7 @@ import { Doc } from '../../../../new_fields/Doc';
import { documentSchema } from '../../../../new_fields/documentSchemas';
import { makeInterface } from '../../../../new_fields/Schema';
import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../new_fields/Types';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView';
@@ -204,22 +204,42 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
@computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+
+ addDocTab = (doc: Doc, where: string) => {
+ if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+ this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+ return true;
+ }
+ return this.props.addDocTab(doc, where);
+ }
getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
return <ContentFittingDocumentView
- {...this.props}
Document={layout}
DataDocument={layout.resolvedDataDoc as Doc}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
- FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
backgroundColor={this.props.backgroundColor}
- CollectionDoc={this.props.Document}
+ LayoutDoc={this.props.childLayoutTemplate}
+ LibraryPath={this.props.LibraryPath}
+ FreezeDimensions={this.props.freezeChildDimensions}
+ renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
- getTransform={dxf}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+ rootSelected={this.rootSelected}
+ dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
onClick={this.onChildClickHandler}
- renderDepth={this.props.renderDepth + 1}
+ getTransform={dxf}
+ focus={this.props.focus}
+ CollectionDoc={this.props.CollectionView?.props.Document}
+ CollectionView={this.props.CollectionView}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ removeDocument={this.props.removeDocument}
+ active={this.props.active}
+ whenActiveChanged={this.props.whenActiveChanged}
+ addDocTab={this.addDocTab}
+ pinToPres={this.props.pinToPres}
/>;
}
/**
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index daf1fda6c..af0cc3b5c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -13,7 +13,8 @@ import { Transform } from '../../../util/Transform';
import HeightLabel from './MultirowHeightLabel';
import ResizeBar from './MultirowResizer';
import { undoBatch } from '../../../util/UndoManager';
-import { DragManager } from '../../../util/DragManager';
+import { DragManager, dropActionType } from '../../../util/DragManager';
+import { List } from '../../../../new_fields/List';
type MultirowDocument = makeInterface<[typeof documentSchema]>;
const MultirowDocument = makeInterface(documentSchema);
@@ -203,22 +204,42 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
@computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+
+ addDocTab = (doc: Doc, where: string) => {
+ if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) {
+ this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]);
+ return true;
+ }
+ return this.props.addDocTab(doc, where);
+ }
getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
return <ContentFittingDocumentView
- {...this.props}
Document={layout}
DataDocument={layout.resolvedDataDoc as Doc}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
- FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
backgroundColor={this.props.backgroundColor}
- CollectionDoc={this.props.Document}
+ LayoutDoc={this.props.childLayoutTemplate}
+ LibraryPath={this.props.LibraryPath}
+ FreezeDimensions={this.props.freezeChildDimensions}
+ renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
- getTransform={dxf}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+ rootSelected={this.rootSelected}
+ dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
onClick={this.onChildClickHandler}
- renderDepth={this.props.renderDepth + 1}
+ getTransform={dxf}
+ focus={this.props.focus}
+ CollectionDoc={this.props.CollectionView?.props.Document}
+ CollectionView={this.props.CollectionView}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ removeDocument={this.props.removeDocument}
+ active={this.props.active}
+ whenActiveChanged={this.props.whenActiveChanged}
+ addDocTab={this.addDocTab}
+ pinToPres={this.props.pinToPres}
/>;
}
/**
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index fb16b8365..53b54d7e4 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -88,7 +88,7 @@
opacity:0.9;
background-color: transparent;
box-shadow: black 2px 2px 1px;
- .docuLinkBox-cont {
+ .linkAnchorBox-cont {
position: relative !important;
height: 100% !important;
width: 100% !important;
@@ -103,7 +103,7 @@
box-shadow: black 1px 1px 1px;
margin-left: -1;
margin-top: -2;
- .docuLinkBox-cont {
+ .linkAnchorBox-cont {
position: relative !important;
height: 100% !important;
width: 100% !important;
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index ff9630273..6ff6d1b42 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
import "./AudioBox.scss";
import { Cast, DateCast, NumCast } from "../../../new_fields/Types";
import { AudioField, nullAudio } from "../../../new_fields/URLField";
-import { DocExtendableComponent } from "../DocComponent";
+import { ViewBoxBaseComponent } from "../DocComponent";
import { makeInterface, createSchema } from "../../../new_fields/Schema";
import { documentSchema } from "../../../new_fields/documentSchemas";
import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero } from "../../../Utils";
@@ -20,6 +20,7 @@ import { DocumentView } from "./DocumentView";
import { Docs } from "../../documents/Documents";
import { ComputedField } from "../../../new_fields/ScriptField";
import { Networking } from "../../Network";
+import { Upload } from "../../../server/SharedMediaTypes";
// testing testing
@@ -39,7 +40,7 @@ type AudioDocument = makeInterface<[typeof documentSchema, typeof audioSchema]>;
const AudioDocument = makeInterface(documentSchema, audioSchema);
@observer
-export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocument>(AudioDocument) {
+export class AudioBox extends ViewBoxBaseComponent<FieldViewProps, AudioDocument>(AudioDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); }
public static Enabled = false;
@@ -71,7 +72,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
scrollLinkId => {
if (scrollLinkId) {
DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => {
- const linkTime = Doc.AreProtosEqual(l.anchor1 as Doc, this.dataDoc) ? NumCast((l.anchor1 as Doc).timecode) : NumCast((l.anchor2 as Doc).timecode);
+ const linkTime = Doc.AreProtosEqual(l.anchor1 as Doc, this.dataDoc) ? NumCast(l.anchor1_timecode) : NumCast(l.anchor2_timecode);
setTimeout(() => { this.playFromTime(linkTime); Doc.linkFollowHighlight(l); }, 250);
});
Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
@@ -80,10 +81,10 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(),
selected => {
const sel = selected.length ? selected[0].props.Document : undefined;
- this.Document.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
- this.Document.playOnSelect && this.recordingStart && !sel && this.pause();
+ this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime());
+ this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause();
});
- this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.Document.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+ this._scrubbingDisposer = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
}
timecodeChanged = () => {
@@ -92,17 +93,16 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration);
DocListCast(this.dataDoc.links).map(l => {
let la1 = l.anchor1 as Doc;
- const la2 = l.anchor2 as Doc;
- let linkTime = NumCast(la2.timecode);
+ let linkTime = NumCast(l.anchor2_timecode);
if (Doc.AreProtosEqual(la1, this.dataDoc)) {
- linkTime = NumCast(la1.timecode);
+ linkTime = NumCast(l.anchor1_timecode);
la1 = l.anchor2 as Doc;
}
- if (linkTime > NumCast(this.Document.currentTimecode) && linkTime < htmlEle.currentTime) {
+ if (linkTime > NumCast(this.layoutDoc.currentTimecode) && linkTime < htmlEle.currentTime) {
Doc.linkFollowHighlight(la1);
}
});
- this.Document.currentTimecode = htmlEle.currentTime;
+ this.layoutDoc.currentTimecode = htmlEle.currentTime;
}
}
@@ -136,7 +136,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
updateRecordTime = () => {
if (this.audioState === "recording") {
setTimeout(this.updateRecordTime, 30);
- this.Document.currentTimecode = (new Date().getTime() - this._recordStart) / 1000;
+ this.layoutDoc.currentTimecode = (new Date().getTime() - this._recordStart) / 1000;
}
}
@@ -147,7 +147,9 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
AudioBox.ActiveRecordings.push(this.props.Document);
this._recorder.ondataavailable = async (e: any) => {
const [{ result }] = await Networking.UploadFilesToServer(e.data);
- this.props.Document[this.props.fieldKey] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client));
+ if (!(result instanceof Error)) {
+ this.props.Document[this.props.fieldKey] = new AudioField(Utils.prepend(result.accessPaths.agnostic.client));
+ }
};
this._recordStart = new Date().getTime();
runInAction(() => this.audioState = "recording");
@@ -158,9 +160,9 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
specificContextMenu = (e: React.MouseEvent): void => {
const funcs: ContextMenuProps[] = [];
- funcs.push({ description: (this.Document.playOnSelect ? "Don't play" : "Play") + " when document selected", event: () => this.Document.playOnSelect = !this.Document.playOnSelect, icon: "expand-arrows-alt" });
+ funcs.push({ description: (this.layoutDoc.playOnSelect ? "Don't play" : "Play") + " when document selected", event: () => this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" });
- ContextMenu.Instance.addItem({ description: "Audio Funcs...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
}
stopRecording = action(() => {
@@ -185,7 +187,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
e.stopPropagation();
}
onStop = (e: any) => {
- this.Document.playOnSelect = !this.Document.playOnSelect;
+ this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect;
e.stopPropagation();
}
onFile = (e: any) => {
@@ -195,8 +197,8 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
_width: NumCast(this.props.Document._width), _height: 3 * NumCast(this.props.Document._height)
});
Doc.GetProto(newDoc).recordingSource = this.dataDoc;
- Doc.GetProto(newDoc).recordingStart = ComputedField.MakeFunction(`this.recordingSource["${this.props.fieldKey}-recordingStart"]`);
- Doc.GetProto(newDoc).audioState = ComputedField.MakeFunction("this.recordingSource.audioState");
+ Doc.GetProto(newDoc).recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.props.fieldKey}-recordingStart"]`);
+ Doc.GetProto(newDoc).audioState = ComputedField.MakeFunction("self.recordingSource.audioState");
this.props.addDocument?.(newDoc);
e.stopPropagation();
}
@@ -227,7 +229,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
{!this.path ?
<div className="audiobox-buttons">
<div className="audiobox-dictation" onClick={this.onFile}>
- <FontAwesomeIcon style={{ width: "30px", background: this.Document.playOnSelect ? "yellow" : "dimGray" }} icon="file-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
+ <FontAwesomeIcon style={{ width: "30px", background: this.layoutDoc.playOnSelect ? "yellow" : "dimGray" }} icon="file-alt" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
</div>
<button className={`audiobox-record${interactive}`} style={{ backgroundColor: this.audioState === "recording" ? "red" : "black" }}>
{this.audioState === "recording" ? "STOP" : "RECORD"}
@@ -236,13 +238,13 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
<div className="audiobox-controls">
<div className="audiobox-player" onClick={this.onPlay}>
<div className="audiobox-playhead"> <FontAwesomeIcon style={{ width: "100%" }} icon={this.audioState === "paused" ? "play" : "pause"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
- <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon style={{ width: "100%", background: this.Document.playOnSelect ? "yellow" : "dimGray" }} icon="hand-point-left" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
+ <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon style={{ width: "100%", background: this.layoutDoc.playOnSelect ? "yellow" : "dimGray" }} icon="hand-point-left" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
<div className="audiobox-timeline" onClick={e => e.stopPropagation()}
onPointerDown={e => {
if (e.button === 0 && !e.ctrlKey) {
const rect = (e.target as any).getBoundingClientRect();
const wasPaused = this.audioState === "paused";
- this._ele!.currentTime = this.Document.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+ this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
wasPaused && this.pause();
e.stopPropagation();
}
@@ -250,11 +252,11 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
{DocListCast(this.dataDoc.links).map((l, i) => {
let la1 = l.anchor1 as Doc;
let la2 = l.anchor2 as Doc;
- let linkTime = NumCast(la2.timecode);
+ let linkTime = NumCast(l.anchor2_timecode);
if (Doc.AreProtosEqual(la1, this.dataDoc)) {
la1 = l.anchor2 as Doc;
la2 = l.anchor1 as Doc;
- linkTime = NumCast(la1.timecode);
+ linkTime = NumCast(l.anchor1_timecode);
}
return !linkTime ? (null) :
<div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
@@ -274,7 +276,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { const wasPaused = this.audioState === "paused"; this.playFrom(linkTime); wasPaused && this.pause(); e.stopPropagation(); } }} />
</div>;
})}
- <div className="audiobox-current" style={{ left: `${NumCast(this.Document.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%` }} />
+ <div className="audiobox-current" style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%` }} />
{this.audio}
</div>
</div>
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
deleted file mode 100644
index 1b70ff824..000000000
--- a/src/client/views/nodes/ButtonBox.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit } from '@fortawesome/free-regular-svg-icons';
-import { action, computed } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { Doc, DocListCast } from '../../../new_fields/Doc';
-import { List } from '../../../new_fields/List';
-import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema';
-import { ScriptField } from '../../../new_fields/ScriptField';
-import { BoolCast, StrCast, Cast, FieldValue } from '../../../new_fields/Types';
-import { DragManager } from '../../util/DragManager';
-import { undoBatch } from '../../util/UndoManager';
-import { DocComponent } from '../DocComponent';
-import './ButtonBox.scss';
-import { FieldView, FieldViewProps } from './FieldView';
-import { ContextMenuProps } from '../ContextMenuItem';
-import { ContextMenu } from '../ContextMenu';
-import { documentSchema } from '../../../new_fields/documentSchemas';
-
-
-library.add(faEdit as any);
-
-const ButtonSchema = createSchema({
- onClick: ScriptField,
- buttonParams: listSpec("string"),
- text: "string"
-});
-
-type ButtonDocument = makeInterface<[typeof ButtonSchema, typeof documentSchema]>;
-const ButtonDocument = makeInterface(ButtonSchema, documentSchema);
-
-@observer
-export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(ButtonDocument) {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ButtonBox, fieldKey); }
- private dropDisposer?: DragManager.DragDropDisposer;
-
- @computed get dataDoc() {
- return this.props.DataDoc &&
- (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
- this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document);
- }
-
-
- protected createDropTarget = (ele: HTMLDivElement) => {
- this.dropDisposer?.();
- if (ele) {
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
- }
- }
-
- specificContextMenu = (e: React.MouseEvent): void => {
- const funcs: ContextMenuProps[] = [];
- funcs.push({
- description: "Clear Script Params", event: () => {
- const params = FieldValue(this.Document.buttonParams);
- params?.map(p => this.props.Document[p] = undefined);
- }, icon: "trash"
- });
-
- ContextMenu.Instance.addItem({ description: "OnClick...", subitems: funcs, icon: "asterisk" });
- }
-
- @undoBatch
- @action
- drop = (e: Event, de: DragManager.DropEvent) => {
- const docDragData = de.complete.docDragData;
- const params = this.Document.buttonParams;
- const missingParams = params?.filter(p => this.props.Document[p] === undefined);
- if (docDragData && missingParams?.includes((e.target as any).textContent)) {
- this.props.Document[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) =>
- d.onDragStart ? docDragData.draggedDocuments[i] : d));
- e.stopPropagation();
- }
- }
- // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
- render() {
- const params = this.Document.buttonParams;
- const missingParams = params?.filter(p => this.props.Document[p] === undefined);
- params?.map(p => DocListCast(this.props.Document[p])); // bcz: really hacky form of prefetching ...
- return (
- <div className="buttonBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
- style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
- <div className="buttonBox-mainButton" style={{
- background: this.Document.backgroundColor, color: this.Document.color || "inherit",
- fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: (this.Document.textTransform as any) || ""
- }} >
- <div className="buttonBox-mainButtonCenter">
- {(this.Document.text || this.Document.title)}
- </div>
- </div>
- <div className="buttonBox-params" >
- {!missingParams || !missingParams.length ? (null) : missingParams.map(m => <div key={m} className="buttonBox-missingParam">{m}</div>)}
- </div>
- </div>
- );
- }
-} \ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index f9f5f449c..1c7d116c5 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,3 @@
-import anime from "animejs";
import { computed, IReactionDisposer, observable, reaction, trace } from "mobx";
import { observer } from "mobx-react";
import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
@@ -13,7 +12,8 @@ import { TraceMobx } from "../../../new_fields/util";
import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
- dataProvider?: (doc: Doc) => { x: number, y: number, zIndex?: number, highlight?: boolean, width: number, height: number, z: number, transition?: string } | undefined;
+ dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, highlight?: boolean, z: number, transition?: string } | undefined;
+ sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined;
x?: number;
y?: number;
z?: number;
@@ -24,24 +24,32 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
jitterRotation: number;
transition?: string;
fitToBox?: boolean;
+ replica: string;
}
@observer
export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps, PositionDocument>(PositionDocument) {
@observable _animPos: number[] | undefined = undefined;
+ random(min: number, max: number) { // min should not be equal to max
+ const mseed = Math.abs(this.X * this.Y);
+ const seed = (mseed * 9301 + 49297) % 233280;
+ const rnd = seed / 233280;
+ return min + rnd * (max - min);
+ }
get displayName() { return "CollectionFreeFormDocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
- get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${anime.random(-1, 1) * this.props.jitterRotation}deg)`; }
+ get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); }
get Highlight() { return this.dataProvider?.highlight; }
- get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.dataProvider && this.dataProvider ? this.dataProvider.width : this.layoutDoc[WidthSym](); }
+ get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.sizeProvider && this.sizeProvider ? this.sizeProvider.width : this.layoutDoc[WidthSym](); }
get height() {
- const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym]();
+ const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.sizeProvider && this.sizeProvider ? this.sizeProvider.height : this.layoutDoc[HeightSym]();
return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt;
}
@computed get freezeDimensions() { return this.props.FreezeDimensions; }
- @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document) ? this.props.dataProvider(this.props.Document) : undefined; }
+ @computed get dataProvider() { return this.props.dataProvider?.(this.props.Document, this.props.replica); }
+ @computed get sizeProvider() { return this.props.sizeProvider?.(this.props.Document, this.props.replica); }
@computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
@computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
@@ -59,10 +67,14 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
}
return undefined;
}
+ nudge = (x: number, y: number) => {
+ this.props.Document.x = NumCast(this.props.Document.x) + x;
+ this.props.Document.y = NumCast(this.props.Document.y) + y;
+ }
contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1;
- panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth?.());
- panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight?.());
+ panelWidth = () => (this.sizeProvider?.width || this.props.PanelWidth?.());
+ panelHeight = () => (this.sizeProvider?.height || this.props.PanelHeight?.());
getTransform = (): Transform => this.props.ScreenToLocalTransform()
.translate(-this.X, -this.Y)
.scale(1 / this.contentScaling())
@@ -88,11 +100,12 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
height: this.height,
zIndex: this.ZInd,
display: this.ZInd === -99 ? "none" : undefined,
- pointerEvents: this.props.Document.isBackground ? "none" : undefined
+ pointerEvents: this.props.Document.isBackground ? "none" : this.props.pointerEvents ? "all" : undefined
}} >
{!this.props.fitToBox ?
<DocumentView {...this.props}
+ nudge={this.nudge}
dragDivName={"collectionFreeFormDocumentView-container"}
ContentScaling={this.contentScaling}
ScreenToLocalTransform={this.getTransform}
diff --git a/src/client/views/nodes/ColorBox.scss b/src/client/views/nodes/ColorBox.scss
index bf334c939..da3266dc1 100644
--- a/src/client/views/nodes/ColorBox.scss
+++ b/src/client/views/nodes/ColorBox.scss
@@ -3,6 +3,7 @@
height:100%;
position: relative;
pointer-events: none;
+ transform-origin: top left;
.sketch-picker {
margin:auto;
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index d34d63d01..6e4341b27 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -6,7 +6,7 @@ import { makeInterface } from "../../../new_fields/Schema";
import { StrCast } from "../../../new_fields/Types";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { SelectionManager } from "../../util/SelectionManager";
-import { DocExtendableComponent } from "../DocComponent";
+import { ViewBoxBaseComponent } from "../DocComponent";
import { InkingControl } from "../InkingControl";
import "./ColorBox.scss";
import { FieldView, FieldViewProps } from './FieldView';
@@ -15,14 +15,14 @@ type ColorDocument = makeInterface<[typeof documentSchema]>;
const ColorDocument = makeInterface(documentSchema);
@observer
-export class ColorBox extends DocExtendableComponent<FieldViewProps, ColorDocument>(ColorDocument) {
+export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument>(ColorDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ColorBox, fieldKey); }
render() {
- const selDoc = SelectionManager.SelectedDocuments()?.[0]?.Document;
+ const selDoc = SelectionManager.SelectedDocuments()?.[0]?.rootDoc;
return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`}
onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
- style={{ transformOrigin: "top left", transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
+ style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
<SketchPicker onChange={InkingControl.Instance.switchColor}
color={StrCast(CurrentUserUtils.ActivePen ? CurrentUserUtils.ActivePen.backgroundColor : undefined,
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 0e2685d41..0d18baaed 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -9,7 +9,7 @@ import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { emptyPath } from "../../../Utils";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
-import { DocAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import "./DocumentBox.scss";
import { FieldView, FieldViewProps } from "./FieldView";
@@ -18,12 +18,12 @@ import { TraceMobx } from "../../../new_fields/util";
import { DocumentView } from "./DocumentView";
import { Docs } from "../../documents/Documents";
-type DocBoxSchema = makeInterface<[typeof documentSchema]>;
-const DocBoxDocument = makeInterface(documentSchema);
+type DocHolderBoxSchema = makeInterface<[typeof documentSchema]>;
+const DocHolderBoxDocument = makeInterface(documentSchema);
@observer
-export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxSchema>(DocBoxDocument) {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocumentBox, fieldKey); }
+export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, DocHolderBoxSchema>(DocHolderBoxDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocHolderBox, fieldKey); }
_prevSelectionDisposer: IReactionDisposer | undefined;
_selections: Doc[] = [];
_curSelection = -1;
@@ -45,7 +45,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
funcs.push({ description: (this.props.Document.excludeCollections ? "Include" : "Exclude") + " Collections", event: () => Doc.GetProto(this.props.Document).excludeCollections = !this.props.Document.excludeCollections, icon: "expand-arrows-alt" });
funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
- ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
}
@computed get contentDoc() {
return (this.props.Document.isTemplateDoc || this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document));
@@ -54,7 +54,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
this.contentDoc[this.props.fieldKey] = this.props.Document[this.props.fieldKey];
}
showSelection = () => {
- this.contentDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(this,this.excludeCollections,[_last_])?.[0]`);
+ this.contentDoc[this.props.fieldKey] = ComputedField.MakeFunction(`selectedDocs(self,this.excludeCollections,[_last_])?.[0]`);
}
isSelectionLocked = () => {
const kvpstring = Field.toKeyValueString(this.contentDoc, this.props.fieldKey);
@@ -111,7 +111,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
const childTemplateName = StrCast(this.props.Document.childTemplateName);
if (containedDoc && childTemplateName && !containedDoc["layout_" + childTemplateName]) {
setTimeout(() => {
- DocumentView.createCustomView(containedDoc, Docs.Create.StackingDocument, childTemplateName);
+ Doc.createCustomView(containedDoc, Docs.Create.StackingDocument, childTemplateName);
Doc.expandTemplateLayout(Cast(containedDoc["layout_" + childTemplateName], Doc, null), containedDoc, undefined);
}, 0);
}
@@ -120,8 +120,8 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
DataDocument={undefined}
LibraryPath={emptyPath}
CollectionView={this as any} // bcz: hack! need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked. currently, the up selector allows only a containing collection to be selected
- fitToBox={this.props.fitToBox}
- layoutKey={"layout_" + childTemplateName}
+ fitToBox={true}
+ layoutKey={childTemplateName ? "layout_" + childTemplateName : "layout"}
rootSelected={this.props.isSelected}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dc71ba280..cd78ac7b3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,9 +1,8 @@
import { computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc, Opt } from "../../../new_fields/Doc";
-import { Cast, StrCast } from "../../../new_fields/Types";
-import { OmitKeys, Without } from "../../../Utils";
-import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
+import { Doc, Opt, Field } from "../../../new_fields/Doc";
+import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
+import { OmitKeys, Without, emptyPath } from "../../../Utils";
import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
@@ -11,10 +10,11 @@ import { CollectionSchemaView } from "../collections/CollectionSchemaView";
import { CollectionView } from "../collections/CollectionView";
import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
import { AudioBox } from "./AudioBox";
-import { ButtonBox } from "./ButtonBox";
+import { LabelBox } from "./LabelBox";
import { SliderBox } from "./SliderBox";
import { LinkBox } from "./LinkBox";
-import { DocumentBox } from "./DocumentBox";
+import { ScriptingBox } from "./ScriptingBox";
+import { DocHolderBox } from "./DocumentBox";
import { DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
import { FontIconBox } from "./FontIconBox";
@@ -27,7 +27,7 @@ import { PresBox } from "./PresBox";
import { QueryBox } from "./QueryBox";
import { ColorBox } from "./ColorBox";
import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
-import { DocuLinkBox } from "./DocuLinkBox";
+import { LinkAnchorBox } from "./LinkAnchorBox";
import { PresElementBox } from "../presentationview/PresElementBox";
import { ScreenshotBox } from "./ScreenshotBox";
import { VideoBox } from "./VideoBox";
@@ -35,8 +35,10 @@ import { WebBox } from "./WebBox";
import { InkingStroke } from "../InkingStroke";
import React = require("react");
import { RecommendationsBox } from "../RecommendationsBox";
-
import { TraceMobx } from "../../../new_fields/util";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import XRegExp = require("xregexp");
+
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -53,6 +55,42 @@ class ObserverJsxParser1 extends JsxParser {
const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any;
+
+interface HTMLtagProps {
+ Document: Doc;
+ RootDoc: Doc;
+ htmltag: string;
+ onClick?: ScriptField;
+ onInput?: ScriptField;
+}
+//"<HTMLdiv borderRadius='100px' onClick={this.bannerColor=this.bannerColor==='red'?'green':'red'} width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)'><ImageBox {...props} fieldKey={'data'}/><HTMLspan width='100%' marginTop='50%' height='10%' position='absolute' backgroundColor='{this.bannerColor===`green`?`dark`:`light`}grey'>{this.title}</HTMLspan></HTMLdiv>"@observer
+@observer
+export class HTMLtag extends React.Component<HTMLtagProps> {
+ click = (e: React.MouseEvent) => {
+ const clickScript = (this.props as any).onClick as Opt<ScriptField>;
+ clickScript?.script.run({ this: this.props.Document, self: this.props.RootDoc });
+ }
+ onInput = (e: React.FormEvent<HTMLDivElement>) => {
+ const onInputScript = (this.props as any).onInput as Opt<ScriptField>;
+ onInputScript?.script.run({ this: this.props.Document, self: this.props.RootDoc, value: (e.target as any).textContent });
+ }
+ render() {
+ const style: { [key: string]: any } = {};
+ const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "Document", "key", "onInput", "onClick", "__proto__"]).omit;
+ Object.keys(divKeys).map((prop: string) => {
+ const p = (this.props as any)[prop] as string;
+ const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string: { script } into a value
+ return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ self: this.props.RootDoc, this: this.props.Document }).result as string || "";
+ };
+ style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer);
+ });
+ const Tag = this.props.htmltag as keyof JSX.IntrinsicElements;
+ return <Tag style={style} onClick={this.click} onInput={this.onInput as any}>
+ {this.props.children}
+ </Tag>;
+ }
+}
+
@observer
export class DocumentContentsView extends React.Component<DocumentViewProps & {
isSelected: (outsideReaction: boolean) => boolean,
@@ -66,7 +104,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
@computed get layout(): string {
TraceMobx();
if (!this.layoutDoc) return "<p>awaiting layout</p>";
- const layout = Cast(this.layoutDoc[StrCast(this.layoutDoc.layoutKey, this.layoutDoc === this.props.Document ? this.props.layoutKey : "layout")], "string");
+ // const layout = Cast(this.layoutDoc[StrCast(this.layoutDoc.layoutKey, this.layoutDoc === this.props.Document ? this.props.layoutKey : "layout")], "string"); // bcz: replaced this with below... is it right?
+ const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, "layout")], "string");
if (this.props.layoutKey === "layout_keyValue") {
return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data"));
} else
@@ -87,36 +126,82 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
}
get layoutDoc() {
const params = StrCast(this.props.Document.PARAMS);
- const template: Doc = this.props.LayoutDoc?.() || Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
+ // bcz: replaced this with below : is it correct? change was made to accommodate passing fieldKey's from a layout script
+ // const template: Doc = this.props.LayoutDoc?.() || Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
+ const template: Doc = this.props.LayoutDoc?.() ||
+ (this.props.layoutKey && StrCast(this.props.Document[this.props.layoutKey]) && this.props.Document) ||
+ Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
return Doc.expandTemplateLayout(template, this.props.Document, params ? "(" + params + ")" : this.props.layoutKey);
}
- CreateBindings(): JsxBindings {
+ CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings {
const list = {
...OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive).omit,
+ RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc,
Document: this.layoutDoc,
DataDoc: this.dataDoc,
+ onClick: onClick,
+ onInput: onInput
};
return { props: list };
}
render() {
TraceMobx();
- return (this.props.renderDepth > 12 || !this.layout || !this.layoutDoc) ? (null) :
+ let layoutFrame = this.layout;
+
+ // replace code content with a script >{content}< as in <HTMLdiv>{this.title}</HTMLdiv>
+ const replacer = (match: any, prefix: string, expr: string, postfix: string, offset: any, string: any) => {
+ return prefix + (ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ this: this.props.Document }).result as string || "") + postfix;
+ };
+ layoutFrame = layoutFrame.replace(/(>[^{]*)\{([^.'][^<}]+)\}([^}]*<)/g, replacer);
+
+ // replace HTML<tag> with corresponding HTML tag as in: <HTMLdiv> becomes <HTMLtag Document={props.Document} htmltag='div'>
+ const replacer2 = (match: any, p1: string, offset: any, string: any) => {
+ return `<HTMLtag RootDoc={props.RootDoc} Document={props.Document} htmltag='${p1}'`;
+ };
+ layoutFrame = layoutFrame.replace(/<HTML([a-zA-Z0-9_-]+)/g, replacer2);
+
+ // replace /HTML<tag> with </HTMLdiv> as in: </HTMLdiv> becomes </HTMLtag>
+ const replacer3 = (match: any, p1: string, offset: any, string: any) => {
+ return `</HTMLtag`;
+ };
+ layoutFrame = layoutFrame.replace(/<\/HTML([a-zA-Z0-9_-]+)/g, replacer3);
+
+ // add onClick function to props
+ const makeFuncProp = (func: string) => {
+ const splits = layoutFrame.split(`func=`);
+ if (splits.length > 1) {
+ const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] });
+ layoutFrame = splits[0] + ` ${func}={props.onClick} ` + splits[1].substring(code[1].end + 1);
+ return ScriptField.MakeScript(code[1].value, { this: Doc.name, self: Doc.name, value: "string" });
+ }
+ return undefined;
+ // add input function to props
+ };
+ const onClick = makeFuncProp("onClick");
+ const onInput = makeFuncProp("onInput");
+
+ const bindings = this.CreateBindings(onClick, onInput);
+ // layoutFrame = splits.length > 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns
+
+ return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) :
this.props.forceLayout === "FormattedTextBox" && this.props.forceFieldKey ?
- <FormattedTextBox {...this.CreateBindings().props} fieldKey={this.props.forceFieldKey} />
+ <FormattedTextBox {...bindings.props} fieldKey={this.props.forceFieldKey} />
:
<ObserverJsxParser
+ key={42}
blacklistedAttrs={[]}
+ renderInWrapper={false}
components={{
- FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, ButtonBox, SliderBox, FieldView,
+ FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
- PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
- ColorBox, DashWebRTCVideo, DocuLinkBox, InkingStroke, DocumentBox, LinkBox,
- RecommendationsBox, ScreenshotBox
+ PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
+ ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
+ RecommendationsBox, ScreenshotBox, HTMLtag
}}
- bindings={this.CreateBindings()}
- jsx={this.layout}
+ bindings={bindings}
+ jsx={layoutFrame}
showWarnings={true}
onError={(test: any) => { console.log(test); }}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index ce7bcd206..dea09cb30 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -34,19 +34,13 @@
overflow-y: scroll;
height: calc(100% - 20px);
}
- .documentView-docuLinkAnchor {
+ .documentView-linkAnchorBoxAnchor {
display:flex;
overflow: hidden;
- }
- .documentView-docuLinkWrapper {
- pointer-events: none;
- position: absolute;
- transform-origin: top left;
- width: 100%;
- height: 100%;
- top:0;
- left:0;
- z-index: 1;
+
+ .documentView-node {
+ width:10px !important;
+ }
}
.documentView-lock {
@@ -81,7 +75,7 @@
display: inline-block;
width: 100%;
height: 100%;
- pointer-events: none;
+ border-radius: inherit;
.documentView-styleContentWrapper {
width: 100%;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2df5c9bbd..83eb12436 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,21 +1,24 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import * as fa from '@fortawesome/free-solid-svg-icons';
-import { action, computed, runInAction, trace, observable } from "mobx";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
import * as rp from "request-promise";
-import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
import { Document, PositionDocument } from '../../../new_fields/documentSchemas';
import { Id } from '../../../new_fields/FieldSymbols';
import { InkTool } from '../../../new_fields/InkField';
import { RichTextField } from '../../../new_fields/RichTextField';
import { listSpec } from "../../../new_fields/Schema";
+import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField';
import { ScriptField } from '../../../new_fields/ScriptField';
import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField';
import { TraceMobx } from '../../../new_fields/util';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys, returnZero } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
+import { ClientRecommender } from '../../ClientRecommender';
import { DocServer } from "../../DocServer";
import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
@@ -24,6 +27,7 @@ import { DocumentManager } from "../../util/DocumentManager";
import { DragManager, dropActionType } from "../../util/DragManager";
import { InteractionUtils } from '../../util/InteractionUtils';
import { Scripting } from '../../util/Scripting';
+import { SearchUtil } from '../../util/SearchUtil';
import { SelectionManager } from "../../util/SelectionManager";
import SharingManager from '../../util/SharingManager';
import { Transform } from "../../util/Transform";
@@ -35,18 +39,11 @@ import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from "../DocComponent";
import { EditableView } from '../EditableView';
import { InkingControl } from '../InkingControl';
-import { OverlayView } from '../OverlayView';
-import { ScriptBox } from '../ScriptBox';
-import { ScriptingRepl } from '../ScriptingRepl';
+import { KeyphraseQueryView } from '../KeyphraseQueryView';
import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
-import React = require("react");
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField';
-import { ClientRecommender } from '../../ClientRecommender';
-import { SearchUtil } from '../../util/SearchUtil';
import { RadialMenu } from './RadialMenu';
-import { KeyphraseQueryView } from '../KeyphraseQueryView';
+import React = require("react");
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -64,12 +61,14 @@ export interface DocumentViewProps {
LayoutDoc?: () => Opt<Doc>;
LibraryPath: Doc[];
fitToBox?: boolean;
+ contextMenuItems?: () => { script: ScriptField, label: string }[];
rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
onClick?: ScriptField;
onPointerDown?: ScriptField;
onPointerUp?: ScriptField;
dropAction?: dropActionType;
dragDivName?: string;
+ nudge?: (x: number, y: number) => void;
addDocument?: (doc: Doc) => boolean;
removeDocument?: (doc: Doc) => boolean;
moveDocument?: (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
@@ -78,6 +77,7 @@ export interface DocumentViewProps {
ContentScaling: () => number;
PanelWidth: () => number;
PanelHeight: () => number;
+ pointerEvents?: boolean;
focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: DocFocusFunc) => void;
parentActive: (outsideReaction: boolean) => boolean;
whenActiveChanged: (isActive: boolean) => void;
@@ -115,7 +115,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@computed get freezeDimensions() { return this.props.FreezeDimensions; }
@computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
@computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
- @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; }
+ @computed get onClickHandler() { return this.props.onClick || Cast(this.layoutDoc.onClick, ScriptField, null) || this.Document.onClick; }
@computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
@computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
NativeWidth = () => this.nativeWidth;
@@ -191,32 +191,36 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@action
componentDidMount() {
- this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)));
+ this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document));
this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
// this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
- !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.push(this);
+ if (!this.props.dontRegisterView) {
+ DocumentManager.Instance.DocumentViews.push(this);
+ }
}
@action
componentDidUpdate() {
- this._dropDisposer && this._dropDisposer();
- this._gestureEventDisposer && this._gestureEventDisposer();
- this.multiTouchDisposer && this.multiTouchDisposer();
- this.holdDisposer && this.holdDisposer();
- this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)));
- this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
- this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
- this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
+ this._dropDisposer?.();
+ this._gestureEventDisposer?.();
+ this.multiTouchDisposer?.();
+ this.holdDisposer?.();
+ if (this._mainCont.current) {
+ this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
+ this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this));
+ this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
+ this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
+ }
}
@action
componentWillUnmount() {
- this._dropDisposer && this._dropDisposer();
- this._gestureEventDisposer && this._gestureEventDisposer();
- this.multiTouchDisposer && this.multiTouchDisposer();
- this.holdDisposer && this.holdDisposer();
+ this._dropDisposer?.();
+ this._gestureEventDisposer?.();
+ this.multiTouchDisposer?.();
+ this.holdDisposer?.();
Doc.UnBrushDoc(this.props.Document);
if (!this.props.dontRegisterView) {
const index = DocumentManager.Instance.DocumentViews.indexOf(this);
@@ -230,6 +234,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0);
dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top);
dragData.dropAction = dropAction;
+ dragData.removeDocument = this.props.removeDocument;
dragData.moveDocument = this.props.moveDocument;// this.Document.onDragStart ? undefined : this.props.moveDocument;
dragData.dragDivName = this.props.dragDivName;
DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.Document.onDragStart });
@@ -276,46 +281,55 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
- onClick = (e: React.MouseEvent | React.PointerEvent) => {
+ onClick = action((e: React.MouseEvent | React.PointerEvent) => {
if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
(Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
let stopPropagate = true;
let preventDefault = true;
- this.props.bringToFront(this.props.Document);
+ !this.props.Document.isBackground && this.props.bringToFront(this.props.Document);
if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
- const fullScreenAlias = Doc.MakeAlias(this.props.Document);
- if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) {
- fullScreenAlias.layoutKey = "layout_fullScreen";
+ if (!(e.nativeEvent as any).formattedHandled) {
+ const fullScreenAlias = Doc.MakeAlias(this.props.Document);
+ if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) {
+ fullScreenAlias.layoutKey = "layout_fullScreen";
+ }
+ UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap");
+ SelectionManager.DeselectAll();
+ Doc.UnBrushDoc(this.props.Document);
}
- UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap");
- SelectionManager.DeselectAll();
- Doc.UnBrushDoc(this.props.Document);
- } else if (this.onClickHandler?.script) {
- SelectionManager.DeselectAll();
- const func = () => this.onClickHandler!.script.run({
- this: this.props.Document,
- self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document,
+ } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
+ //SelectionManager.DeselectAll();
+ const func = () => this.onClickHandler.script.run({
+ this: this.layoutDoc,
+ self: this.rootDoc,
thisContainer: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
- }, console.log);// && !this.props.Document.isButton && this.select(false);
- if (this.props.Document !== Doc.UserDoc().undoBtn && this.props.Document !== Doc.UserDoc().redoBtn) {
+ }, console.log);
+ if (this.props.Document !== Doc.UserDoc()["dockedBtn-undo"] && this.props.Document !== Doc.UserDoc()["dockedBtn-redo"]) {
UndoManager.RunInBatch(func, "on click");
} else func();
- } else if (this.Document.type === DocumentType.BUTTON) {
- UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click");
- } else if (this.Document.isButton) {
+ } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself
+ UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick");
+ //ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click");
+ } else if (this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
} else {
- if (this.props.Document.isTemplateForField && !(e.ctrlKey || e.button > 0)) {
+ if ((this.props.Document.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) { // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
} else {
- SelectionManager.SelectDoc(this, e.ctrlKey);
+ // if (this.props.Document.type === DocumentType.RTF) {
+ // DocumentView._focusHack = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY) || [0, 0];
+ // DocumentView._focusHack = [DocumentView._focusHack[0] + NumCast(this.props.Document.x), DocumentView._focusHack[1] + NumCast(this.props.Document.y)];
+
+ // this.props.focus(this.props.Document, false);
+ // }
+ SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey);
}
preventDefault = false;
}
stopPropagate && e.stopPropagation();
preventDefault && e.preventDefault();
}
- }
+ });
// follows a link - if the target is on screen, it highlights/pans to it.
// if the target isn't onscreen, then it will open up the target in a tab, on the right, or in place
@@ -327,14 +341,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const targetFocusAfterDocFocus = () => {
const where = StrCast(this.Document.followLinkLocation) || followLoc;
const hackToCallFinishAfterFocus = () => {
- setTimeout(() => finished?.(), 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout.
+ finished && setTimeout(finished, 0); // finished() needs to be called right after hackToCallFinishAfterFocus(), but there's no callback for that so we use the hacky timeout.
return false; // we must return false here so that the zoom to the document is not reversed. If it weren't for needing to call finished(), we wouldn't need this function at all since not having it is equivalent to returning false
};
- this.props.addDocTab(doc, where) && this.props.focus(doc, true, undefined, hackToCallFinishAfterFocus); // add the target and focus on it.
+ this.props.addDocTab(doc, where) && this.props.focus(doc, BoolCast(this.Document.followLinkZoom, true), undefined, hackToCallFinishAfterFocus); // add the target and focus on it.
return where !== "inPlace"; // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target)
};
- // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target
- this.props.focus(this.props.Document, true, 1, targetFocusAfterDocFocus);
+ if (!this.Document.followLinkZoom) {
+ targetFocusAfterDocFocus();
+ } else {
+ // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target
+ this.props.focus(this.props.Document, BoolCast(this.Document.followLinkZoom, true), 1, targetFocusAfterDocFocus);
+ }
};
await DocumentManager.Instance.FollowLink(undefined, this.props.Document, createViewFunc, shiftKey, this.props.ContainingCollectionDoc, batch.end, altKey ? true : undefined);
}
@@ -389,6 +407,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
+ public iconify() {
+ const layoutKey = Cast(this.props.Document.layoutKey, "string", null);
+ const collapse = layoutKey !== "layout_icon";
+ if (collapse) {
+ this.switchViews(collapse, "icon");
+ if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") this.props.Document.deiconifyLayout = layoutKey.replace("layout_", "");
+ } else {
+ const deiconifyLayout = Cast(this.props.Document.deiconifyLayout, "string", null);
+ this.switchViews(deiconifyLayout ? true : false, deiconifyLayout);
+ this.props.Document.deiconifyLayout = undefined;
+ }
+ }
+
@action
handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
@@ -465,15 +496,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
return;
}
- if (!e.nativeEvent.cancelBubble || this.onClickHandler || this.Document.onDragStart) {
- this._downX = e.clientX;
- this._downY = e.clientY;
+ this._downX = e.clientX;
+ this._downY = e.clientY;
+ if ((!e.nativeEvent.cancelBubble || this.onClickHandler || this.Document.onDragStart) &&
+ // if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
+ !((this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0))) {
if ((this.active || this.Document.onDragStart || this.onClickHandler) &&
!e.ctrlKey &&
(e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
- !this.Document.lockedPosition &&
!this.Document.inOverlay) {
e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag);
+
}
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
@@ -507,8 +540,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onPointerUp = (e: PointerEvent): void => {
this.cleanUpInteractions();
- if (this.onPointerUpHandler && this.onPointerUpHandler.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
- this.onPointerUpHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
+ if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
+ this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
document.removeEventListener("pointerup", this.onPointerUp);
return;
}
@@ -531,74 +564,45 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@undoBatch
deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument?.(this.props.Document); }
- // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView)
- static makeCustomViewClicked = (doc: Doc, creator: (documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => {
- const batch = UndoManager.StartBatch("makeCustomViewClicked");
- runInAction(() => {
- doc.layoutKey = "layout_" + templateSignature;
- if (doc[doc.layoutKey] === undefined) {
- DocumentView.createCustomView(doc, creator, templateSignature, docLayoutTemplate);
- }
- });
- batch.end();
- }
- static createCustomView = (doc: Doc, creator: (documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc, templateSignature: string = "custom", docLayoutTemplate?: Doc) => {
- const iconViews = DocListCast(Cast(Doc.UserDoc().iconViews, Doc, null)?.data);
- const templBtns = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data);
- const noteTypes = DocListCast(Cast(Doc.UserDoc().noteTypes, Doc, null)?.data);
- const allTemplates = iconViews.concat(templBtns).concat(noteTypes).map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc);
- const templateName = templateSignature.replace(/\(.*\)/, "");
- // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized
- // first try to find a template that matches the specific document type (<typeName>_<templateName>). otherwise, fallback to a general match on <templateName>
- !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === doc.type + "_" + templateName && (docLayoutTemplate = tempDoc));
- !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc));
-
- const customName = "layout_" + templateSignature;
- const _width = NumCast(doc._width);
- const _height = NumCast(doc._height);
- const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false };
-
- let fieldTemplate: Opt<Doc>;
- if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
- fieldTemplate = Docs.Create.TextDocument("", options);
- } else if (doc.data instanceof PdfField) {
- fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
- } else if (doc.data instanceof VideoField) {
- fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
- } else if (doc.data instanceof AudioField) {
- fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
- } else if (doc.data instanceof ImageField) {
- fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
- }
- const docTemplate = docLayoutTemplate || creator(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
-
- fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate));
- Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
- }
@undoBatch
- toggleButtonBehavior = (): void => {
- if (this.Document.isButton || this.Document.onClick || this.Document.ignoreClick) {
- this.Document.isButton = false;
+ toggleLinkButtonBehavior = (): void => {
+ if (this.Document.isLinkButton || this.Document.onClick || this.Document.ignoreClick) {
+ this.Document.isLinkButton = false;
this.Document.ignoreClick = false;
this.Document.onClick = undefined;
} else {
- this.Document.isButton = true;
+ this.Document.isLinkButton = true;
+ this.Document.followLinkZoom = false;
this.Document.followLinkLocation = undefined;
}
}
@undoBatch
toggleFollowInPlace = (): void => {
- if (this.Document.isButton) {
- this.Document.isButton = false;
+ if (this.Document.isLinkButton) {
+ this.Document.isLinkButton = false;
} else {
- this.Document.isButton = true;
+ this.Document.isLinkButton = true;
+ this.Document.followLinkZoom = true;
this.Document.followLinkLocation = "inPlace";
}
}
@undoBatch
+ toggleFollowOnRight = (): void => {
+ if (this.Document.isLinkButton) {
+ this.Document.isLinkButton = false;
+ } else {
+ this.Document.isLinkButton = true;
+ this.Document.followLinkZoom = false;
+ const first = DocListCast(this.Document.links).find(d => d instanceof Doc);
+ first && (first.hidden = true);
+ this.Document.followLinkLocation = "onRight";
+ }
+ }
+
+ @undoBatch
@action
drop = async (e: Event, de: DragManager.DropEvent) => {
if (de.complete.annoDragData) {
@@ -639,25 +643,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
makeIntoPortal = async () => {
const portalLink = DocListCast(this.Document.links).find(d => d.anchor1 === this.props.Document);
if (!portalLink) {
- const portal = Docs.Create.FreeformDocument([], { _width: (this.layoutDoc._width || 0) + 10, _height: this.layoutDoc._height || 0, title: StrCast(this.props.Document.title) + ".portal" });
+ const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), title: StrCast(this.props.Document.title) + ".portal" });
DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to");
}
- this.Document.isButton = true;
+ this.Document.followLinkZoom = true;
+ this.Document.isLinkButton = true;
}
@undoBatch
@action
- setCustomView = (custom: boolean, layout: string): void => {
- Doc.setNativeView(this.props.Document);
- if (custom) {
- DocumentView.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined);
- }
- }
-
- @undoBatch
- @action
- makeBackground = (): void => {
- this.Document.isBackground = !this.Document.isBackground;
+ toggleBackground = (temporary: boolean): void => {
+ this.Document.overflow = temporary ? "visible" : "hidden";
+ this.Document.isBackground = !temporary ? !this.Document.isBackground : (this.Document.isBackground ? undefined : true);
this.Document.isBackground && this.props.bringToFront(this.Document, true);
}
@@ -695,41 +692,44 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const cm = ContextMenu.Instance;
const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null);
- const existing = cm.findByDescription("Layout...");
- const layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
- layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: this.makeBackground, icon: this.Document.lockedPosition ? "unlock" : "lock" });
- layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
-
- layoutItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
- layoutItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
- layoutItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" });
- layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
- layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
- layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
- layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
- !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" });
-
- const open = ContextMenu.Instance.findByDescription("Open...");
+ const customScripts = Cast(this.props.Document.contextMenuScripts, listSpec(ScriptField), []);
+ Cast(this.props.Document.contextMenuLabels, listSpec("string"), []).forEach((label, i) =>
+ cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" }));
+ this.props.contextMenuItems?.().forEach(item =>
+ cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, self: this.rootDoc }), icon: "sticky-note" }));
+
+
+ let open = cm.findByDescription("Add a Perspective...");
const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
- openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" });
- openItems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, "inTab", this.props.LibraryPath), icon: "folder" });
- openItems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, "onRight", this.props.LibraryPath), icon: "caret-square-right" });
- openItems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" });
- openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" });
openItems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
templateDoc && openItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
- openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
- !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" });
+ if (!open) {
+ open = { description: "Add a Perspective....", subitems: openItems, icon: "external-link-alt" };
+ cm.addItem(open);
+ }
+ let options = cm.findByDescription("Options...");
+ const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
+ optionItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
+ optionItems.push({ description: `${this.Document._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
+ optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
+ optionItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" });
+ if (!options) {
+ options = { description: "Options...", subitems: optionItems, icon: "compass" };
+ cm.addItem(options);
+ }
+
+ cm.moveAfter(options, open);
const existingOnClick = cm.findByDescription("OnClick...");
const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
- onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" });
+ onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.props.Document.layoutKey}")`), icon: "window-restore" });
onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
- onClicks.push({ description: this.Document.isButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
- onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleButtonBehavior, icon: "concierge-bell" });
- onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) });
+ onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link in Place", event: this.toggleFollowInPlace, icon: "concierge-bell" });
+ onClicks.push({ description: this.Document.isLinkButton ? "Remove Follow Behavior" : "Follow Link on Right", event: this.toggleFollowOnRight, icon: "concierge-bell" });
+ onClicks.push({ description: this.Document.isLinkButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.toggleLinkButtonBehavior, icon: "concierge-bell" });
+ onClicks.push({ description: "Edit onClick Script", event: () => UndoManager.RunInBatch(() => Doc.makeCustomViewClicked(this.props.Document, undefined, "onClick"), "edit onClick"), icon: "edit" });
!existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
const funcs: ContextMenuProps[] = [];
@@ -742,6 +742,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const more = cm.findByDescription("More...");
const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : [];
+ moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
+ moreItems.push({ description: !this.Document._nativeWidth || !this.Document._nativeHeight ? "Freeze" : "Unfreeze", event: this.toggleNativeDimensions, icon: "snowflake" });
if (!ClientUtils.RELEASE) {
// let copies: ContextMenuProps[] = [];
@@ -794,11 +796,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
icon: "brain"
});
- cm.addItem({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" });
-
-
- moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+ moreItems.push({ description: "Recommender System", subitems: recommender_subitems, icon: "brain" });
+ moreItems.push({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" });
moreItems.push({ description: "Undo Debug Test", event: () => UndoManager.TraceOpenBatches(), icon: "exclamation" });
!more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
runInAction(() => {
@@ -841,7 +841,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
SelectionManager.SelectDoc(this, false);
}
});
- const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc().LibraryBtn as Doc).sourcePanel as Doc) ? "" : d.title), "");
+ const path = this.props.LibraryPath.reduce((p: string, d: Doc) => p + "/" + (Doc.AreProtosEqual(d, (Doc.UserDoc()["tabs-button-library"] as Doc).sourcePanel as Doc) ? "" : d.title), "");
cm.addItem({
description: `path: ${path}`, event: () => {
this.props.LibraryPath.map(lp => Doc.GetProto(lp).treeViewOpen = lp.treeViewOpen = true);
@@ -861,7 +861,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
await Promise.all(allDocs.map((doc: Doc) => {
let isMainDoc: boolean = false;
const dataDoc = Doc.GetProto(doc);
- if (doc.type === DocumentType.TEXT) {
+ if (doc.type === DocumentType.RTF) {
if (dataDoc === Doc.GetProto(this.props.Document)) {
isMainDoc = true;
}
@@ -964,8 +964,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const fallback = Cast(this.props.Document.layoutKey, "string");
return typeof fallback === "string" ? fallback : "layout";
}
- rootSelected = (outsideReaction: boolean) => {
- return this.isSelected(outsideReaction) || (this.props.Document.forceActive && this.props.rootSelected?.(outsideReaction) ? true : false);
+ rootSelected = (outsideReaction?: boolean) => {
+ return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
}
childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
panelWidth = () => this.props.PanelWidth();
@@ -973,37 +973,42 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
screenToLocalTransform = () => this.props.ScreenToLocalTransform();
@computed get contents() {
TraceMobx();
- return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- NativeWidth={this.NativeWidth}
- NativeHeight={this.NativeHeight}
- Document={this.props.Document}
- DataDoc={this.props.DataDoc}
- LayoutDoc={this.props.LayoutDoc}
- makeLink={this.makeLink}
- rootSelected={this.rootSelected}
- fitToBox={this.props.fitToBox}
- LibraryPath={this.props.LibraryPath}
- addDocument={this.props.addDocument}
- removeDocument={this.props.removeDocument}
- moveDocument={this.props.moveDocument}
- ScreenToLocalTransform={this.screenToLocalTransform}
- renderDepth={this.props.renderDepth}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
- focus={this.props.focus}
- parentActive={this.props.parentActive}
- whenActiveChanged={this.props.whenActiveChanged}
- bringToFront={this.props.bringToFront}
- addDocTab={this.props.addDocTab}
- pinToPres={this.props.pinToPres}
- backgroundColor={this.props.backgroundColor}
- ContentScaling={this.childScaling}
- ChromeHeight={this.chromeHeight}
- isSelected={this.isSelected}
- select={this.select}
- onClick={this.onClickHandler}
- layoutKey={this.finalLayoutKey} />);
+ return (<>
+ <DocumentContentsView key={1} ContainingCollectionView={this.props.ContainingCollectionView}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ NativeWidth={this.NativeWidth}
+ NativeHeight={this.NativeHeight}
+ Document={this.props.Document}
+ DataDoc={this.props.DataDoc}
+ LayoutDoc={this.props.LayoutDoc}
+ makeLink={this.makeLink}
+ rootSelected={this.rootSelected}
+ dontRegisterView={this.props.dontRegisterView}
+ fitToBox={this.props.fitToBox}
+ LibraryPath={this.props.LibraryPath}
+ addDocument={this.props.addDocument}
+ removeDocument={this.props.removeDocument}
+ moveDocument={this.props.moveDocument}
+ ScreenToLocalTransform={this.screenToLocalTransform}
+ renderDepth={this.props.renderDepth}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight}
+ focus={this.props.focus}
+ parentActive={this.props.parentActive}
+ whenActiveChanged={this.props.whenActiveChanged}
+ bringToFront={this.props.bringToFront}
+ addDocTab={this.props.addDocTab}
+ pinToPres={this.props.pinToPres}
+ backgroundColor={this.props.backgroundColor}
+ ContentScaling={this.childScaling}
+ ChromeHeight={this.chromeHeight}
+ isSelected={this.isSelected}
+ select={this.select}
+ onClick={this.onClickHandler}
+ layoutKey={this.finalLayoutKey} />
+ {this.anchors}
+ </>
+ );
}
linkEndpoint = (linkDoc: Doc) => Doc.LinkEndpoint(linkDoc, this.props.Document);
@@ -1012,36 +1017,39 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
// would be good to generalize this some way.
isNonTemporalLink = (linkDoc: Doc) => {
const anchor = Cast(Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1 : linkDoc.anchor2, Doc) as Doc;
- return anchor.type === DocumentType.AUDIO ? false : true;
+ const ept = Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1_timecode : linkDoc.anchor2_timecode;
+ return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true;
}
- @observable _link: Opt<Doc>;
- makeLink = () => {
- return this._link;
- }
- hideLinkAnchor = (doc: Doc) => undoBatch(doc => doc.hidden = true)();
+ @observable _link: Opt<Doc>; // see DocumentButtonBar for explanation of how this works
+ makeLink = () => this._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined.
+
+ @undoBatch
+ hideLinkAnchor = (doc: Doc) => doc.hidden = true
anchorPanelWidth = () => this.props.PanelWidth() || 1;
anchorPanelHeight = () => this.props.PanelHeight() || 1;
@computed get anchors() {
TraceMobx();
- return DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
- <div className="documentView-docuLinkWrapper" key={d[Id]}>
- <DocumentView {...this.props}
- Document={d}
- ContainingCollectionDoc={this.props.Document} // bcz: hack this.props.Document is not a collection Need a better prop for passing the containing document to the DocuLinkBox
- PanelWidth={this.anchorPanelWidth}
- PanelHeight={this.anchorPanelHeight}
- layoutKey={this.linkEndpoint(d)}
- ContentScaling={returnOne}
- backgroundColor={returnTransparent}
- removeDocument={this.hideLinkAnchor} />
- </div>);
+ return this.layoutDoc.presBox ? (null) : DocListCast(this.Document.links).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
+ <DocumentView {...this.props} key={i + 1}
+ Document={d}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ ContainingCollectionDoc={this.props.Document} // bcz: hack this.props.Document is not a collection Need a better prop for passing the containing document to the LinkAnchorBox
+ PanelWidth={this.anchorPanelWidth}
+ PanelHeight={this.anchorPanelHeight}
+ layoutKey={this.linkEndpoint(d)}
+ ContentScaling={returnOne}
+ backgroundColor={returnTransparent}
+ removeDocument={this.hideLinkAnchor}
+ pointerEvents={false}
+ LayoutDoc={undefined}
+ />);
}
@computed get innards() {
TraceMobx();
if (!this.props.PanelWidth()) { // this happens when the document is a tree view label
- return <div className="documentView-docuLinkAnchor" >
+ return <div className="documentView-linkAnchorBoxAnchor" >
{StrCast(this.props.Document.title)}
{this.anchors}
</div>;
@@ -1051,7 +1059,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const showCaption = StrCast(this.layoutDoc._showCaption);
const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("PresBox") !== -1 || StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined;
const captionView = (!showCaption ? (null) :
- <div className="documentView-captionWrapper">
+ <div className="documentView-captionWrapper" style={{ backgroundColor: StrCast(this.layoutDoc["caption-backgroundColor"]), color: StrCast(this.layoutDoc["caption-color"]) }}>
<DocumentContentsView {...OmitKeys(this.props, ['children']).omit}
hideOnLeave={true}
forceLayout={"FormattedTextBox"}
@@ -1064,9 +1072,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
layoutKey={this.finalLayoutKey} />
</div>);
const titleView = (!showTitle ? (null) :
- <div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} style={{
+ <div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{
position: showTextTitle ? "relative" : "absolute",
- pointerEvents: SelectionManager.GetIsDragging() || this.onClickHandler || this.Document.ignoreClick ? "none" : "all",
+ pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : undefined,
}}>
<EditableView ref={this._titleRef}
contents={(this.props.DataDoc || this.props.Document)[showTitle]?.toString()}
@@ -1075,24 +1083,26 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
SetValue={undoBatch((value: string) => (Doc.GetProto(this.props.DataDoc || this.props.Document)[showTitle] = value) ? true : true)}
/>
</div>);
- return <>
- {this.anchors}
- {!showTitle && !showCaption ?
- this.contents :
- <div className="documentView-styleWrapper" >
- <div className="documentView-styleContentWrapper" style={{ height: showTextTitle ? `calc(100% - ${this.chromeHeight()}px)` : "100%", top: showTextTitle ? this.chromeHeight() : undefined }}>
- {this.contents}
- </div>
- {titleView}
- {captionView}
- </div>
- }
- </>;
+ return !showTitle && !showCaption ?
+ this.contents :
+ <div className="documentView-styleWrapper" >
+ {this.Document.type !== DocumentType.RTF ? <> {this.contents} {titleView} </> : <> {titleView} {this.contents} </>}
+ {captionView}
+ </div>;
}
@computed get ignorePointerEvents() {
- return (this.Document.isBackground && !this.isSelected()) || this.props.layoutKey?.includes("layout_key") || (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None);
+ return this.props.pointerEvents === false ||
+ (this.Document.isBackground && !this.isSelected() && !SelectionManager.GetIsDragging()) ||
+ (this.Document.type === DocumentType.INK && InkingControl.Instance.selectedTool !== InkTool.None);
+ }
+ @undoBatch
+ @action
+ setCustomView = (custom: boolean, layout: string): void => {
+ Doc.setNativeView(this.props.Document);
+ if (custom) {
+ Doc.makeCustomViewClicked(this.props.Document, Docs.Create.StackingDocument, layout, undefined);
+ }
}
-
@observable _animate = 0;
switchViews = action((custom: boolean, view: string) => {
SelectionManager.SetIsDragging(true);
@@ -1128,20 +1138,24 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
transformOrigin: this._animate ? "center center" : undefined,
transform: this._animate ? `scale(${this._animate})` : undefined,
transition: !this._animate ? StrCast(this.Document.transition) : this._animate < 1 ? "transform 0.5s ease-in" : "transform 0.5s ease-out",
- pointerEvents: this.ignorePointerEvents ? "none" : "all",
+ pointerEvents: this.ignorePointerEvents ? "none" : undefined,
color: StrCast(this.layoutDoc.color, "inherit"),
outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
background: finalColor,
- opacity: this.Document.opacity
+ opacity: this.Document.opacity,
+ fontFamily: StrCast(this.Document._fontFamily, "inherit"),
+ fontSize: Cast(this.Document._fontSize, "number", null)
}}>
- {this.Document.isBackground ? <div className="documentView-lock"> <FontAwesomeIcon icon="unlock" size="lg" /> </div> : (null)}
{this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <>
{this.innards}
<div className="documentView-contentBlocker" />
</> :
this.innards}
+ {(this.Document.isBackground !== undefined || this.isSelected(false)) && this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ?
+ <div className="documentView-lock" onClick={() => this.toggleBackground(true)}> <FontAwesomeIcon icon={this.Document.isBackground ? "unlock" : "lock"} size="lg" /> </div>
+ : (null)}
</div>;
{ this._showKPQuery ? <KeyphraseQueryView keyphrases={this._queries}></KeyphraseQueryView> : undefined; }
}
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index f0fe7a54e..68b00a5be 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -8,6 +8,18 @@
border-radius: 100%;
transform-origin: top left;
+ .fontIconBox-label {
+ background: gray;
+ color:white;
+ margin-left: -10px;
+ border-radius: 8px;
+ width:100%;
+ position: absolute;
+ text-align: center;
+ font-size: 8px;
+ margin-top:4px;
+ }
+
svg {
width: 95% !important;
height: 95%;
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index d4da21239..c6ea6a882 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -56,7 +56,8 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
background: StrCast(referenceLayout.backgroundColor),
boxShadow: this.props.Document.ischecked ? `4px 4px 12px black` : undefined
}}>
- <FontAwesomeIcon className="fontIconBox-icon" icon={this.Document.icon as any} color={this._foregroundColor} size="sm" />
+ <FontAwesomeIcon className="fontIconBox-icon" icon={this.dataDoc.icon as any} color={this._foregroundColor} size="sm" />
+ {!this.rootDoc.label ? (null) : <div className="fontIconBox-label"> {StrCast(this.rootDoc.label).substring(0, 5)} </div>}
</button>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 7d40b3149..3bedb7127 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -24,8 +24,6 @@
overflow-y: auto;
overflow-x: hidden;
color: initial;
- height: 100%;
- pointer-events: all;
max-height: 100%;
display: flex;
flex-direction: row;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index fd19f14f8..2c4d3f1d9 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -13,22 +13,24 @@ import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "
import { ReplaceStep } from 'prosemirror-transform';
import { EditorView } from "prosemirror-view";
import { DateField } from '../../../new_fields/DateField';
-import { DataSym, Doc, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
import { documentSchema } from '../../../new_fields/documentSchemas';
import { Id } from '../../../new_fields/FieldSymbols';
import { InkTool } from '../../../new_fields/InkField';
+import { PrefetchProxy } from '../../../new_fields/Proxy';
import { RichTextField } from "../../../new_fields/RichTextField";
import { RichTextUtils } from '../../../new_fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../new_fields/Schema";
-import { Cast, NumCast, StrCast, BoolCast, DateCast } from "../../../new_fields/Types";
+import { Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types";
import { TraceMobx } from '../../../new_fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue, returnZero } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils } from '../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
import { DocServer } from "../../DocServer";
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { DictationManager } from '../../util/DictationManager';
import { DragManager } from "../../util/DragManager";
+import { makeTemplate } from '../../util/DropConverter';
import buildKeymap from "../../util/ProsemirrorExampleTransfer";
import RichTextMenu from '../../util/RichTextMenu';
import { RichTextRules } from "../../util/RichTextRules";
@@ -49,7 +51,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager";
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { DocumentButtonBar } from '../DocumentButtonBar';
import { InkingControl } from "../InkingControl";
import { AudioBox } from './AudioBox';
@@ -57,8 +59,6 @@ import { FieldView, FieldViewProps } from "./FieldView";
import "./FormattedTextBox.scss";
import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment';
import React = require("react");
-import { PrefetchProxy } from '../../../new_fields/Proxy';
-import { makeTemplate } from '../../util/DropConverter';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -66,6 +66,8 @@ library.add(faSmile, faTextHeight, faUpload);
export interface FormattedTextBoxProps {
hideOnLeave?: boolean;
makeLink?: () => Opt<Doc>;
+ xMargin?: number;
+ yMargin?: number;
}
const richTextSchema = createSchema({
@@ -80,7 +82,7 @@ const RichTextDocument = makeInterface(richTextSchema, documentSchema);
type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void;
@observer
-export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
+export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
public static Instance: FormattedTextBox;
@@ -94,17 +96,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
private _lastX = 0;
private _lastY = 0;
private _undoTyping?: UndoManager.Batch;
- private _searchReactionDisposer?: Lambda;
- private _recordReactionDisposer: Opt<IReactionDisposer>;
- private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>;
- private _reactionDisposer: Opt<IReactionDisposer>;
- private _heightReactionDisposer: Opt<IReactionDisposer>;
- private _proxyReactionDisposer: Opt<IReactionDisposer>;
- private _pullReactionDisposer: Opt<IReactionDisposer>;
- private _pushReactionDisposer: Opt<IReactionDisposer>;
- private _buttonBarReactionDisposer: Opt<IReactionDisposer>;
- private _linkMakerDisposer: Opt<IReactionDisposer>;
- private _scrollDisposer: Opt<IReactionDisposer>;
+ private _disposers: { [name: string]: IReactionDisposer } = {};
private dropDisposer?: DragManager.DragDropDisposer;
@computed get _recording() { return this.dataDoc.audioState === "recording"; }
@@ -205,7 +197,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
const tsel = this._editorView.state.selection.$from;
tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000)));
- const curText = state.doc.textBetween(0, state.doc.content.size, "\n\n");
+ const curText = state.doc.textBetween(0, state.doc.content.size, " \n");
const curTemp = Cast(this.props.Document[this.props.fieldKey + "-textTemplate"], RichTextField);
if (!this._applyingChange) {
this._applyingChange = true;
@@ -226,13 +218,30 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
updateTitle = () => {
if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing
- StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.Document.customTitle) {
+ StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.rootDoc.customTitle) {
const str = this._editorView.state.doc.textContent;
const titlestr = str.substr(0, Math.min(40, str.length));
this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
}
}
+ // needs a better API for taking in a set of words with target documents instead of just one target
+ public hyperlinkTerms = (terms: string[], target: Doc) => {
+ if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
+ const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+ const tr = this._editorView.state.tr;
+ const flattened: TextSelection[] = [];
+ res.map(r => r.map(h => flattened.push(h)));
+ const lastSel = Math.min(flattened.length - 1, this._searchIndex);
+ this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+ const alink = DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, "automatic")!;
+ const link = this._editorView.state.schema.marks.link.create({
+ href: Utils.prepend("/doc/" + alink[Id]),
+ title: "a link", location: location, linkId: alink[Id], targetId: target[Id]
+ });
+ this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
+ }
+ }
public highlightSearchTerms = (terms: string[]) => {
if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -264,7 +273,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
protected createDropTarget = (ele: HTMLDivElement) => {
this.ProseRef = ele;
this.dropDisposer?.();
- ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
+ ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
}
@undoBatch
@@ -273,7 +282,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (de.complete.docDragData) {
const draggedDoc = de.complete.docDragData.draggedDocuments.length && de.complete.docDragData.draggedDocuments[0];
// replace text contents whend dragging with Alt
- if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) {
+ if (draggedDoc && draggedDoc.type === DocumentType.RTF && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) {
if (draggedDoc.data instanceof RichTextField) {
Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
e.stopPropagation();
@@ -352,10 +361,10 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
updateHighlights = () => {
clearStyleSheetRules(FormattedTextBox._userStyleSheet);
if (FormattedTextBox._highlights.indexOf("Text from Others") !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, "userMark-remote", { background: "yellow" });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-remote", { background: "yellow" });
}
if (FormattedTextBox._highlights.indexOf("My Text") !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, "userMark-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { background: "moccasin" });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { background: "moccasin" });
}
if (FormattedTextBox._highlights.indexOf("Todo Items") !== -1) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, "userTag-" + "todo", { outline: "black solid 1px" });
@@ -370,15 +379,15 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
addStyleSheetRule(FormattedTextBox._userStyleSheet, "userTag-" + "ignore", { "font-size": "1" });
}
if (FormattedTextBox._highlights.indexOf("By Recent Minute") !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, "userMark-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { opacity: "0.1" });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { opacity: "0.1" });
const min = Math.round(Date.now() / 1000 / 60);
- numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, "userMark-min-" + (min - i), { opacity: ((10 - i - 1) / 10).toString() }));
+ numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-min-" + (min - i), { opacity: ((10 - i - 1) / 10).toString() }));
setTimeout(() => this.updateHighlights());
}
if (FormattedTextBox._highlights.indexOf("By Recent Hour") !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, "userMark-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { opacity: "0.1" });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-" + Doc.CurrentUserEmail.replace(".", "").replace("@", ""), { opacity: "0.1" });
const hr = Math.round(Date.now() / 1000 / 60 / 60);
- numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, "userMark-hr-" + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }));
+ numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, "UM-hr-" + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }));
}
}
@@ -407,21 +416,25 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
}
specificContextMenu = (e: React.MouseEvent): void => {
+ const cm = ContextMenu.Instance;
+
const funcs: ContextMenuProps[] = [];
this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" });
funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
!this.props.Document.rootDocument && funcs.push({
description: "Make Template", event: () => {
- this.props.Document.isTemplateDoc = makeTemplate(this.props.Document, true);
- Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document);
+ this.props.Document.isTemplateDoc = makeTemplate(this.props.Document);
+ Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.props.Document);
}, icon: "eye"
});
funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" });
- funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Toggle Dictation Icon", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Menubar", event: () => this.toggleMenubar(), icon: "expand-arrows-alt" });
+
+ const highlighting: ContextMenuProps[] = [];
["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
- funcs.push({
+ highlighting.push({
description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => {
e.stopPropagation();
if (FormattedTextBox._highlights.indexOf(option) === -1) {
@@ -432,8 +445,37 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.updateHighlights();
}, icon: "expand-arrows-alt"
}));
+ funcs.push({ description: "highlighting...", subitems: highlighting, icon: "hand-point-right" });
+
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
+
+ const change = cm.findByDescription("Change Perspective...");
+ const changeItems: ContextMenuProps[] = change && "subitems" in change ? change.subitems : [];
+
+ const noteTypesDoc = Cast(Doc.UserDoc()["template-notes"], Doc, null);
+ DocListCast(noteTypesDoc?.data).forEach(note => {
+ changeItems.push({
+ description: StrCast(note.title), event: undoBatch(() => {
+ Doc.setNativeView(this.props.Document);
+ Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note);
+ }), icon: "eye"
+ });
+ });
+ changeItems.push({ description: "FreeForm", event: undoBatch(() => Doc.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), "change view"), icon: "eye" });
+ !change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" });
+
+ const open = cm.findByDescription("Add a Perspective...");
+ const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
+
+ openItems.push({
+ description: "FreeForm", event: undoBatch(() => {
+ const alias = Doc.MakeAlias(this.rootDoc);
+ Doc.makeCustomViewClicked(alias, Docs.Create.FreeformDocument, "freeform");
+ this.props.addDocTab(alias, "onRight");
+ }), icon: "eye"
+ });
+ !open && cm.addItem({ description: "Add a Perspective...", subitems: openItems, icon: "external-link-alt" });
- ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: funcs, icon: "asterisk" });
}
recordDictation = () => {
@@ -542,7 +584,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}
componentDidMount() {
- this._buttonBarReactionDisposer = reaction(
+ this._disposers.buttonBar = reaction(
() => DocumentButtonBar.Instance,
instance => {
if (instance) {
@@ -551,7 +593,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}
);
- this._linkMakerDisposer = reaction(
+ this._disposers.linkMaker = reaction(
() => this.props.makeLink?.(),
(linkDoc: Opt<Doc>) => {
if (linkDoc) {
@@ -562,8 +604,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
},
{ fireImmediately: true }
);
-
- this._reactionDisposer = reaction(
+ this._disposers.editorState = reaction(
() => {
if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document[this.props.fieldKey + "-textTemplate"]) {
return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data;
@@ -578,8 +619,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}
);
-
- this._pullReactionDisposer = reaction(
+ this._disposers.pullDoc = reaction(
() => this.props.Document[Pulls],
() => {
if (!DocumentButtonBar.hasPulledHack) {
@@ -589,8 +629,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}
);
-
- this._pushReactionDisposer = reaction(
+ this._disposers.pushDoc = reaction(
() => this.props.Document[Pushes],
() => {
if (!DocumentButtonBar.hasPushedHack) {
@@ -599,19 +638,18 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}
);
-
- this._heightReactionDisposer = reaction(
+ this._disposers.height = reaction(
() => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight],
() => this.tryUpdateHeight()
);
this.setupEditor(this.config, this.props.fieldKey);
- this._searchReactionDisposer = reaction(() => this.layoutDoc.searchMatch,
+ this._disposers.search = reaction(() => this.rootDoc.searchMatch,
search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(),
{ fireImmediately: true });
- this._recordReactionDisposer = reaction(() => this._recording,
+ this._disposers.record = reaction(() => this._recording,
() => {
if (this._recording) {
setTimeout(action(() => {
@@ -621,8 +659,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
} else setTimeout(() => this.stopDictation(true), 0);
}
);
-
- this._scrollToRegionReactionDisposer = reaction(
+ this._disposers.scrollToRegion = reaction(
() => StrCast(this.layoutDoc.scrollToLinkID),
async (scrollToLinkID) => {
const findLinkFrag = (frag: Fragment, editor: EditorView) => {
@@ -667,8 +704,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
},
{ fireImmediately: true }
);
-
- this._scrollDisposer = reaction(() => NumCast(this.props.Document.scrollPos),
+ this._disposers.scroll = reaction(() => NumCast(this.props.Document.scrollPos),
pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true }
);
@@ -734,7 +770,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
}, 0);
dataDoc.title = exportState.title;
- this.Document.customTitle = true;
+ this.rootDoc.customTitle = true;
dataDoc.unchanged = true;
} else {
delete dataDoc[GoogleRef];
@@ -832,13 +868,10 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this._editorView = new EditorView(this.ProseRef, {
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 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);
+ const docPos = editorView.coordsAtPos(editorView.state.selection.from);
+ const viewRect = self._ref.current!.getBoundingClientRect();
+ if (docPos.top < viewRect.top || docPos.top > viewRect.bottom) {
+ docPos && (self._scrollRef.current!.scrollTop += (docPos.top - viewRect.top) * self.props.ScreenToLocalTransform().Scale);
}
return true;
},
@@ -867,11 +900,12 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
});
const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
if (startupText) {
- this._editorView.dispatch(this._editorView.state.tr.insertText(startupText));
+ const { state: { tr }, dispatch } = this._editorView;
+ dispatch(tr.insertText(startupText));
}
}
- const selectOnLoad = (Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document)[Id] === FormattedTextBox.SelectOnLoad;
+ const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad;
if (selectOnLoad && !this.props.dontRegisterView) {
FormattedTextBox.SelectOnLoad = "";
this.props.select(false);
@@ -897,17 +931,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
componentWillUnmount() {
- this._scrollDisposer?.();
- this._scrollToRegionReactionDisposer?.();
- this._reactionDisposer?.();
- this._proxyReactionDisposer?.();
- this._pushReactionDisposer?.();
- this._pullReactionDisposer?.();
- this._heightReactionDisposer?.();
- this._searchReactionDisposer?.();
- this._recordReactionDisposer?.();
- this._buttonBarReactionDisposer?.();
- this._linkMakerDisposer?.();
+ Object.values(this._disposers).forEach(disposer => disposer?.());
this._editorView?.destroy();
}
@@ -932,7 +956,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.doLinkOnDeselect();
FormattedTextBox._downEvent = true;
FormattedTextBoxComment.textBox = this;
- if (this.props.onClick && e.button === 0) {
+ if (this.props.onClick && e.button === 0 && !this.props.isSelected(false)) {
e.preventDefault();
}
if (e.button === 0 && this.active(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
@@ -1176,7 +1200,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
this.layoutDoc.limitHeight = undefined;
this.layoutDoc._autoHeight = false;
}
- const nh = this.Document.isTemplateForField ? 0 : NumCast(this.dataDoc._nativeHeight, 0);
+ const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.dataDoc._nativeHeight, 0);
const dh = NumCast(this.layoutDoc._height, 0);
const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0));
if (Math.abs(newHeight - dh) > 1) { // bcz: Argh! without this, we get into a React crash if the same document is opened in a freeform view and in the treeview. no idea why, but after dragging the freeform document, selecting it, and selecting text, it will compute to 1 pixel higher than the treeview which causes a cycle
@@ -1202,13 +1226,13 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
return (
<div className={`formattedTextBox-cont`} ref={this._ref}
style={{
- height: this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : undefined,
- background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"]),
+ height: this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : `calc(100% - ${this.props.ChromeHeight?.() || 0}px`,
+ background: StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : ""),
opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
- color: this.props.hideOnLeave ? "white" : "inherit",
- pointerEvents: interactive ? "none" : "all",
- fontSize: NumCast(this.layoutDoc.fontSize, 13),
- fontFamily: StrCast(this.layoutDoc.fontFamily, "Crimson Text"),
+ color: StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.hideOnLeave ? "white" : "inherit"),
+ pointerEvents: interactive ? "none" : undefined,
+ fontSize: Cast(this.layoutDoc._fontSize, "number", null),
+ fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyPress}
@@ -1226,8 +1250,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
<div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} onScroll={this.onscrolled} ref={this._scrollRef}>
<div className={`formattedTextBox-inner${rounded}`} ref={this.createDropTarget}
style={{
- padding: `${NumCast(this.Document._xMargin, 0)}px ${NumCast(this.Document._yMargin, 0)}px`,
- pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
+ padding: `${NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0)}px`,
+ pointerEvents: ((this.layoutDoc.isLinkButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined
}} />
</div>
{!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 4f6244d9a..dfea0f6bb 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -2,7 +2,7 @@ import { Mark, ResolvedPos } from "prosemirror-model";
import { EditorState, Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import * as ReactDOM from 'react-dom';
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DocCastAsync } from "../../../new_fields/Doc";
import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath } from "../../../Utils";
import { DocServer } from "../../DocServer";
@@ -15,6 +15,7 @@ import './FormattedTextBoxComment.scss';
import React = require("react");
import { Docs } from "../../documents/Documents";
import wiki from "wikijs";
+import { DocumentType } from "../../documents/DocumentTypes";
export let formattedTextBoxCommentPlugin = new Plugin({
view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -83,8 +84,12 @@ export class FormattedTextBoxComment {
const keep = e.target && (e.target as any).type === "checkbox" ? true : false;
const textBox = FormattedTextBoxComment.textBox;
if (FormattedTextBoxComment.linkDoc && !keep && textBox) {
- DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
- (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation));
+ if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) {
+ textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight");
+ } else {
+ DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
+ (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation));
+ }
} else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), "onRight");
}
@@ -100,6 +105,7 @@ export class FormattedTextBoxComment {
public static Hide() {
FormattedTextBoxComment.textBox = undefined;
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
+ ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
}
public static SetState(textBox: any, start: number, end: number, mark: Mark) {
FormattedTextBoxComment.textBox = textBox;
@@ -167,14 +173,18 @@ export class FormattedTextBoxComment {
FormattedTextBoxComment.tooltipText.textContent = "target not found...";
(FormattedTextBoxComment.tooltipText as any).href = "";
const docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0];
- docTarget && DocServer.GetRefField(docTarget).then(linkDoc => {
+ try {
+ ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
+ } catch (e) { }
+ docTarget && DocServer.GetRefField(docTarget).then(async linkDoc => {
if (linkDoc instanceof Doc) {
(FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href;
FormattedTextBoxComment.linkDoc = linkDoc;
- const target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc);
- try {
- ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
- } catch (e) { }
+ const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc);
+ const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
+ if (anchor !== target && anchor && target) {
+ target.scrollY = NumCast(anchor?.y);
+ }
if (target) {
ReactDOM.render(<ContentFittingDocumentView
Document={target}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 7bbf4a368..15148d01d 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -1,6 +1,4 @@
-.imageBox,
-.imageBox-dragging {
- pointer-events: all;
+.imageBox {
border-radius: inherit;
width: 100%;
height: 100%;
@@ -12,12 +10,6 @@
}
}
-.imageBox-dragging {
- .imageBox-fader {
- pointer-events: none;
- }
-}
-
#upload-icon {
position: absolute;
bottom: 0;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 8818b8098..08917d281 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -24,7 +24,7 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocAnnotatableComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import FaceRectangles from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
@@ -65,7 +65,7 @@ const uploadIcons = {
};
@observer
-export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) {
+export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) {
protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
@@ -76,11 +76,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
protected createDropTarget = (ele: HTMLDivElement) => {
this._dropDisposer && this._dropDisposer();
- ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
- }
-
- get fieldKey() {
- return this.props.fieldKey.startsWith("@") ? StrCast(this.props.Document[this.props.fieldKey]) : this.props.fieldKey;
+ ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
}
@undoBatch
@@ -146,19 +142,19 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
@undoBatch
rotate = action(() => {
- const nw = NumCast(this.Document[this.fieldKey + "-nativeWidth"]);
- const nh = NumCast(this.Document[this.fieldKey + "-nativeHeight"]);
- const w = this.Document._width;
- const h = this.Document._height;
+ const nw = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
+ const nh = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
+ const w = this.layoutDoc._width;
+ const h = this.layoutDoc._height;
this.dataDoc[this.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.fieldKey + "-rotation"]) + 90) % 360;
this.dataDoc[this.fieldKey + "-nativeWidth"] = nh;
this.dataDoc[this.fieldKey + "-nativeHeight"] = nw;
- this.Document._width = h;
- this.Document._height = w;
+ this.layoutDoc._width = h;
+ this.layoutDoc._height = w;
});
specificContextMenu = (e: React.MouseEvent): void => {
- const field = Cast(this.Document[this.fieldKey], ImageField);
+ const field = Cast(this.dataDoc[this.fieldKey], ImageField);
if (field) {
const funcs: ContextMenuProps[] = [];
funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
@@ -184,15 +180,13 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
//modes.push({ description: "Recommend", event: this.extractText, icon: "brain" });
!existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" });
- ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
}
}
extractFaces = () => {
const converter = (results: any) => {
- const faceDocs = new List<Doc>();
- results.reduce((face: CognitiveServices.Image.Face, faceDocs: List<Doc>) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!), new List<Doc>());
- return faceDocs;
+ return results.map((face: CognitiveServices.Image.Face) => Docs.Get.FromJson({ data: face, title: `Face: ${face.faceId}` })!);
};
this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-faces"], this.url, Service.Face, converter);
}
@@ -229,8 +223,8 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
return url.href;//Why is this here
}
const ext = path.extname(url.href);
- const suffix = this.props.renderDepth < 1 ? "_o" : this._curSuffix;
- return url.href.replace(ext, suffix + ext);
+ this._curSuffix = this.props.renderDepth < 1 ? "_o" : this.layoutDoc[WidthSym]() < 100 ? "_s" : "_m";
+ return url.href.replace(ext, this._curSuffix + ext);
}
@observable _smallRetryCount = 1;
@@ -243,46 +237,46 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
@action onError = (error: any) => {
const timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount;
- if (timeout < 10) {
- // setTimeout(this.retryPath, 500);
- }
- const original = StrCast(this.dataDoc.originalUrl);
- if (error.type === "error" && original) {
- this.dataDoc[this.fieldKey] = new ImageField(original);
+ if (timeout < 5) {
+ setTimeout(this.retryPath, 500);
+ } else {
+ const original = StrCast(this.dataDoc[this.fieldKey + "-originalUrl"]);
+ if (error.type === "error" && original) {
+ this.dataDoc[this.fieldKey] = new ImageField(original);
+ }
}
}
_curSuffix = "_m";
resize = (imgPath: string) => {
const cachedNativeSize = {
- width: NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]),
- height: NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"])
+ width: imgPath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0,
+ height: imgPath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0,
};
- const docAspect = this.Document[HeightSym]() / this.Document[WidthSym]();
+ const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym]();
const cachedAspect = cachedNativeSize.height / cachedNativeSize.width;
if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) {
if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) {
- requestImageSize(imgPath).then((inquiredSize: any) => {
+ requestImageSize(imgPath).then(action((inquiredSize: any) => {
const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180;
const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize;
const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width;
- setTimeout(action(() => {
- if (this.Document[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) {
- this.Document._height = this.Document[WidthSym]() * rotatedAspect;
- this.dataDoc[this.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width;
- this.dataDoc[this.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height;
- }
- }), 0);
- }).catch((err: any) => console.log(err));
+ if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) {
+ this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect;
+ this.dataDoc[this.fieldKey + "-nativeWidth"] = this.layoutDoc._nativeWidth = this.layoutDoc._width;
+ this.dataDoc[this.fieldKey + "-nativeHeight"] = this.layoutDoc._nativeHeight = this.layoutDoc._height;
+ this.dataDoc[this.fieldKey + "-path"] = imgPath;
+ }
+ })).catch(console.log);
} else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) {
- this.Document._width = this.Document[WidthSym]() || cachedNativeSize.width;
- this.Document._height = this.Document[WidthSym]() * cachedAspect;
+ this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width;
+ this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect;
}
- } else if (this.Document._nativeWidth !== cachedNativeSize.width || this.Document._nativeHeight !== cachedNativeSize.height) {
- !(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc) && setTimeout(() => {
- if (!(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc)) {
- this.Document._nativeWidth = cachedNativeSize.width;
- this.Document._nativeHeight = cachedNativeSize.height;
+ } else if (this.layoutDoc._nativeWidth !== cachedNativeSize.width || this.layoutDoc._nativeHeight !== cachedNativeSize.height) {
+ !(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc) && setTimeout(() => {
+ if (!(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc)) {
+ this.layoutDoc._nativeWidth = cachedNativeSize.width;
+ this.layoutDoc._nativeHeight = cachedNativeSize.height;
}
}, 0);
}
@@ -311,8 +305,9 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
audioDown = () => this.recordAudioAnnotation();
considerGooglePhotosLink = () => {
- const remoteUrl = this.Document.googlePhotosUrl;
+ const remoteUrl = this.dataDoc.googlePhotosUrl;
return !remoteUrl ? (null) : (<img
+ style={{ transform: `scale(${this.props.ContentScaling()})`, transformOrigin: "bottom right" }}
id={"google-photos"}
src={"/assets/google_photos.png"}
onClick={() => window.open(remoteUrl)}
@@ -320,7 +315,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
considerGooglePhotosTags = () => {
- const tags = this.Document.googlePhotosTags;
+ const tags = this.dataDoc.googlePhotosTags;
return !tags ? (null) : (<img id={"google-tags"} src={"/assets/google_tags.png"} />);
}
@@ -337,13 +332,14 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
return (
<img
id={"upload-icon"}
+ style={{ transform: `scale(${1 / this.props.ContentScaling()})`, transformOrigin: "bottom right" }}
src={`/assets/${this.uploadIcon}`}
onClick={async () => {
const { dataDoc } = this;
const { success, failure, idle, loading } = uploadIcons;
runInAction(() => this.uploadIcon = loading);
const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] });
- dataDoc.originalUrl = primary;
+ dataDoc[this.props.fieldKey + "-originalUrl"] = primary;
let succeeded = true;
let data: ImageField | undefined;
try {
@@ -364,46 +360,42 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
@computed get nativeSize() {
- const pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
+ TraceMobx();
+ const pw = this.props.PanelWidth?.() || 50;
const nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], pw);
const nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], 1);
return { nativeWidth, nativeHeight };
}
+ // this._curSuffix = "";
+ // if (w > 20) {
+ // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
+ // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m";
+ // else if (this._largeRetryCount < 10) this._curSuffix = "_l";
@computed get paths() {
- let paths = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
- // this._curSuffix = "";
- // if (w > 20) {
- const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]);
- const altpaths = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url));
- const field = this.dataDoc[this.fieldKey];
- // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
- // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m";
- // else if (this._largeRetryCount < 10) this._curSuffix = "_l";
- if (field instanceof ImageField) paths = [this.choosePath(field.url)];
- paths.push(...altpaths);
- return paths;
+ const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc
+ const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images
+ const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents
+ const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
+ return paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
}
@computed get content() {
TraceMobx();
- const srcpath = this.paths[NumCast(this.props.Document.curPage, 0)];
+ const srcpath = this.paths[0];
const fadepath = this.paths[Math.min(1, this.paths.length - 1)];
const { nativeWidth, nativeHeight } = this.nativeSize;
const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1;
- const pwidth = this.props.PanelWidth();
- const pheight = this.props.PanelHeight();
- const shift = (rotation % 180) ? (pheight - pwidth) / aspect / 2 + (pheight - pwidth) / 2 : 0;
-
+ const shift = (rotation % 180) ? (nativeHeight - nativeWidth) * (1 - 1 / aspect) : 0;
this.resize(srcpath);
- return <div className="imageBox-cont" key={this.props.Document[Id]} ref={this.createDropTarget}>
+ return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget}>
<div className="imageBox-fader" >
<img key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={srcpath}
- style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }}
+ style={{ transform: `scale(${aspect}) translate(0px, ${shift}px) rotate(${rotation}deg)` }}
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} />
@@ -416,7 +408,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
ref={this._imgRef}
onError={this.onError} /></div>}
</div>
- {!this.props.Document._showAudio ? (null) :
+ {!this.layoutDoc._showAudio ? (null) :
<div className="imageBox-audioBackground"
onPointerDown={this.audioDown}
onPointerEnter={this.onPointerEnter}
@@ -432,21 +424,31 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
</div>;
}
+ // adjust y position to center image in panel aspect is bigger than image aspect.
+ // bcz :note, this is broken for rotated images
+ get ycenter() {
+ const { nativeWidth, nativeHeight } = this.nativeSize;
+ const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
+ const aspect = (rotation % 180) ? nativeWidth / nativeHeight : nativeHeight / nativeWidth;
+ return this.props.PanelHeight() / this.props.PanelWidth() > aspect ?
+ (this.props.PanelHeight() - this.props.PanelWidth() * aspect) / 2 : 0;
+ }
+
+ screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.ycenter / this.props.ContentScaling());
+
contentFunc = () => [this.content];
render() {
TraceMobx();
- const { nativeWidth, nativeHeight } = this.nativeSize;
- const aspect = nativeWidth / nativeHeight;
- const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
- return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
+ return (<div className={`imageBox`} onContextMenu={this.specificContextMenu}
style={{
- transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
- width: this.props.PanelWidth() ? `${this.props.PanelWidth()}px` : `${100 / this.props.ContentScaling()}%`,
- height: this.props.PanelWidth() ? `${this.props.PanelWidth() / aspect}px` : `${100 / this.props.ContentScaling()}%`,
- pointerEvents: this.props.Document.isBackground ? "none" : undefined,
- borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
+ transform: this.props.PanelWidth() ? `translate(0px, ${this.ycenter}px)` : `scale(${this.props.ContentScaling()})`,
+ width: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
+ height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
+ pointerEvents: this.layoutDoc.isBackground ? "none" : undefined,
+ borderRadius: `${Number(StrCast(this.layoutDoc.borderRoundisng).replace("px", "")) / this.props.ContentScaling()}px`
}} >
<CollectionFreeFormView {...this.props}
+ forceScaling={true}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
NativeHeight={returnZero}
@@ -463,7 +465,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
moveDocument={this.moveDocument}
addDocument={this.addDocument}
CollectionView={undefined}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ ScreenToLocalTransform={this.screenToLocalTransform}
renderDepth={this.props.renderDepth + 1}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
{this.contentFunc}
diff --git a/src/client/views/nodes/KeyValueBox.scss b/src/client/views/nodes/KeyValueBox.scss
index a26880c9e..eb7c2f32b 100644
--- a/src/client/views/nodes/KeyValueBox.scss
+++ b/src/client/views/nodes/KeyValueBox.scss
@@ -8,7 +8,6 @@
border-radius: $border-radius;
box-sizing: border-box;
display: inline-block;
- pointer-events: all;
cursor: default;
.imageBox-cont img {
width: auto;
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 7aad6f90e..2970674a2 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -16,6 +16,8 @@ import { FieldView, FieldViewProps } from './FieldView';
import "./KeyValueBox.scss";
import { KeyValuePair } from "./KeyValuePair";
import React = require("react");
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
export type KVPScript = {
script: CompiledScript;
@@ -34,11 +36,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
@observable private _keyInput: string = "";
@observable private _valueInput: string = "";
@computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); }
- get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; }
-
- constructor(props: FieldViewProps) {
- super(props);
- }
+ get fieldDocToLayout() { return this.props.fieldKey ? Cast(this.props.Document[this.props.fieldKey], Doc, null) : this.props.Document; }
@action
onEnterKey = (e: React.KeyboardEvent): void => {
@@ -234,13 +232,26 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
return new Doc;
}
+ specificContextMenu = (e: React.MouseEvent): void => {
+ const cm = ContextMenu.Instance;
+ const open = cm.findByDescription("Change Perspective...");
+ const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
+ openItems.push({
+ description: "Default Perspective", event: () => {
+ this.props.addDocTab(this.fieldDocToLayout, "inTab");
+ this.props.addDocTab(this.props.Document, "close");
+ }, icon: "image"
+ });
+ !open && cm.addItem({ description: "Change Perspective...", subitems: openItems, icon: "external-link-alt" });
+ }
+
render() {
const dividerDragger = this.splitPercentage === 0 ? (null) :
<div className="keyValueBox-dividerDragger" style={{ transform: `translate(calc(${100 - this.splitPercentage}% - 5px), 0px)` }}>
<div className="keyValueBox-dividerDraggerThumb" onPointerDown={this.onDividerDown} />
</div>;
- return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel} ref={this._mainCont}>
+ return (<div className="keyValueBox-cont" onWheel={this.onPointerWheel} onContextMenu={this.specificContextMenu} ref={this._mainCont}>
<table className="keyValueBox-table">
<tbody className="keyValueBox-tbody">
<tr className="keyValueBox-header">
diff --git a/src/client/views/nodes/ButtonBox.scss b/src/client/views/nodes/LabelBox.scss
index 293af289d..7c7e92379 100644
--- a/src/client/views/nodes/ButtonBox.scss
+++ b/src/client/views/nodes/LabelBox.scss
@@ -1,13 +1,12 @@
-.buttonBox-outerDiv {
+.labelBox-outerDiv {
width: 100%;
height: 100%;
- pointer-events: all;
border-radius: inherit;
display: flex;
flex-direction: column;
}
-.buttonBox-mainButton {
+.labelBox-mainButton {
width: 100%;
height: 100%;
border-radius: inherit;
@@ -17,21 +16,19 @@
display:flex;
}
-.buttonBox-mainButtonCenter {
+.labelBox-mainButtonCenter {
overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
display: inline;
align-items: center;
margin: auto;
}
-.buttonBox-params {
+.labelBox-params {
display: flex;
flex-direction: row;
}
-.buttonBox-missingParam {
+.labelBox-missingParam {
width: 100%;
background: lightgray;
border: dimGray solid 1px;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
new file mode 100644
index 000000000..3cdec8acb
--- /dev/null
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -0,0 +1,96 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEdit } from '@fortawesome/free-regular-svg-icons';
+import { action } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc, DocListCast } from '../../../new_fields/Doc';
+import { documentSchema } from '../../../new_fields/documentSchemas';
+import { List } from '../../../new_fields/List';
+import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
+import { Cast, NumCast, StrCast } from '../../../new_fields/Types';
+import { DragManager } from '../../util/DragManager';
+import { undoBatch } from '../../util/UndoManager';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
+import { ViewBoxBaseComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './LabelBox.scss';
+
+
+library.add(faEdit as any);
+
+const LabelSchema = createSchema({});
+
+type LabelDocument = makeInterface<[typeof LabelSchema, typeof documentSchema]>;
+const LabelDocument = makeInterface(LabelSchema, documentSchema);
+
+@observer
+export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument>(LabelDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); }
+ private dropDisposer?: DragManager.DragDropDisposer;
+
+ protected createDropTarget = (ele: HTMLDivElement) => {
+ this.dropDisposer?.();
+ if (ele) {
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document);
+ }
+ }
+
+ get paramsDoc() { return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc; }
+ specificContextMenu = (e: React.MouseEvent): void => {
+ const funcs: ContextMenuProps[] = [];
+ funcs.push({
+ description: "Clear Script Params", event: () => {
+ const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
+ params?.map(p => this.paramsDoc[p] = undefined);
+ }, icon: "trash"
+ });
+
+ ContextMenu.Instance.addItem({ description: "OnClick...", subitems: funcs, icon: "asterisk" });
+ }
+
+ @undoBatch
+ @action
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ const docDragData = de.complete.docDragData;
+ const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
+ const missingParams = params?.filter(p => !this.paramsDoc[p]);
+ if (docDragData && missingParams?.includes((e.target as any).textContent)) {
+ this.paramsDoc[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) =>
+ d.onDragStart ? docDragData.draggedDocuments[i] : d));
+ e.stopPropagation();
+ }
+ }
+ // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
+ render() {
+ const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
+ const missingParams = params?.filter(p => !this.paramsDoc[p]);
+ params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
+ return (
+ <div className="labelBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu}
+ style={{ boxShadow: this.layoutDoc.opacity ? StrCast(this.layoutDoc.boxShadow) : "" }}>
+ <div className="labelBox-mainButton" style={{
+ background: StrCast(this.layoutDoc.backgroundColor),
+ color: StrCast(this.layoutDoc.color, "inherit"),
+ fontSize: NumCast(this.layoutDoc._fontSize) || "inherit",
+ fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit",
+ letterSpacing: StrCast(this.layoutDoc.letterSpacing),
+ textTransform: StrCast(this.layoutDoc.textTransform) as any,
+ paddingLeft: NumCast(this.layoutDoc._xPadding),
+ paddingRight: NumCast(this.layoutDoc._xPadding),
+ paddingTop: NumCast(this.layoutDoc._yPadding),
+ paddingBottom: NumCast(this.layoutDoc._yPadding),
+ textOverflow: this.layoutDoc._singleLine ? "ellipsis" : undefined,
+ whiteSpace: this.layoutDoc._singleLine ? "nowrap" : "pre-wrap"
+ }} >
+ <div className="labelBox-mainButtonCenter">
+ {StrCast(this.rootDoc.text, StrCast(this.rootDoc.title))}
+ </div>
+ </div>
+ <div className="labelBox-fieldKeyParams" >
+ {!missingParams?.length ? (null) : missingParams.map(m => <div key={m} className="labelBox-missingParam">{m}</div>)}
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocuLinkBox.scss b/src/client/views/nodes/LinkAnchorBox.scss
index f2c203548..710f2178b 100644
--- a/src/client/views/nodes/DocuLinkBox.scss
+++ b/src/client/views/nodes/LinkAnchorBox.scss
@@ -1,13 +1,13 @@
-.docuLinkBox-cont, .docuLinkBox-cont-small {
+.linkAnchorBox-cont, .linkAnchorBox-cont-small {
cursor: default;
position: absolute;
width: 15;
height: 15;
border-radius: 20px;
- pointer-events: all;
user-select: none;
+ pointer-events: all;
- .docuLinkBox-linkCloser {
+ .linkAnchorBox-linkCloser {
position: absolute;
width: 18;
height: 18;
@@ -23,7 +23,7 @@
}
}
-.docuLinkBox-cont-small {
+.linkAnchorBox-cont-small {
width:5px;
height:5px;
} \ No newline at end of file
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 31ce58079..6c50abf21 100644
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -4,11 +4,11 @@ import { Doc, DocListCast } from "../../../new_fields/Doc";
import { documentSchema } from "../../../new_fields/documentSchemas";
import { makeInterface } from "../../../new_fields/Schema";
import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { Utils, setupMoveUpEvents } from '../../../Utils';
+import { Utils, setupMoveUpEvents, emptyFunction } from '../../../Utils';
import { DocumentManager } from "../../util/DocumentManager";
import { DragManager } from "../../util/DragManager";
-import { DocComponent } from "../DocComponent";
-import "./DocuLinkBox.scss";
+import { ViewBoxBaseComponent } from "../DocComponent";
+import "./LinkAnchorBox.scss";
import { FieldView, FieldViewProps } from "./FieldView";
import React = require("react");
import { ContextMenuProps } from "../ContextMenuItem";
@@ -17,16 +17,17 @@ import { LinkEditor } from "../linking/LinkEditor";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { SelectionManager } from "../../util/SelectionManager";
import { TraceMobx } from "../../../new_fields/util";
+import { DocumentView } from "./DocumentView";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
-type DocLinkSchema = makeInterface<[typeof documentSchema]>;
-const DocLinkDocument = makeInterface(documentSchema);
+type LinkAnchorSchema = makeInterface<[typeof documentSchema]>;
+const LinkAnchorDocument = makeInterface(documentSchema);
@observer
-export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(DocLinkDocument) {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocuLinkBox, fieldKey); }
+export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnchorSchema>(LinkAnchorDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); }
_doubleTap = false;
_lastTap: number = 0;
_ref = React.createRef<HTMLDivElement>();
@@ -39,7 +40,7 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
@observable _forceOpen = false;
onPointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, this.onPointerMove, () => { }, this.onClick);
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, false);
}
onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => {
const cdiv = this._ref && this._ref.current && this._ref.current.parentElement;
@@ -49,47 +50,48 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
const dragdist = Math.sqrt((pt[0] - down[0]) * (pt[0] - down[0]) + (pt[1] - down[1]) * (pt[1] - down[1]));
if (separation > 100) {
- const dragData = new DragManager.DocumentDragData([this.props.Document]);
+ const dragData = new DragManager.DocumentDragData([this.rootDoc]);
dragData.dropAction = "alias";
- dragData.removeDropProperties = ["anchor1_x", "anchor1_y", "anchor2_x", "anchor2_y", "isButton"];
+ dragData.removeDropProperties = ["anchor1_x", "anchor1_y", "anchor2_x", "anchor2_y", "isLinkButton"];
DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
return true;
} else if (dragdist > separation) {
- this.props.Document[this.props.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
- this.props.Document[this.props.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
+ this.layoutDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
+ this.layoutDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
}
}
return false;
});
@action
- onClick = (e: PointerEvent) => {
- this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0);
- this._lastTap = Date.now();
- if ((e.button === 2 || e.ctrlKey || !this.props.Document.isButton)) {
+ onClick = (e: React.MouseEvent) => {
+ if ((e.button === 2 || e.ctrlKey || !this.layoutDoc.isLinkButton)) {
this.props.select(false);
}
- if (!this._doubleTap) {
+ if (!this._doubleTap && !e.ctrlKey && e.button < 2) {
const anchorContainerDoc = this.props.ContainingCollectionDoc; // bcz: hack! need a better prop for passing the anchor's container
this._editing = true;
anchorContainerDoc && this.props.bringToFront(anchorContainerDoc, false);
- if (anchorContainerDoc && !this.props.Document.onClick && !this._isOpen) {
+ if (anchorContainerDoc && !this.layoutDoc.onClick && !this._isOpen) {
this._timeout = setTimeout(action(() => {
- DocumentManager.Instance.FollowLink(this.props.Document, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.props.Document.linkOpenLocation, "inTab")), false);
+ DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, "inTab")), false);
this._editing = false;
}), 300 - (Date.now() - this._lastTap));
}
} else {
this._timeout && clearTimeout(this._timeout);
this._timeout = undefined;
+ this._doubleTap = false;
+ this.openLinkEditor(e);
+ e.stopPropagation();
}
}
openLinkDocOnRight = (e: React.MouseEvent) => {
- this.props.addDocTab(this.props.Document, "onRight");
+ this.props.addDocTab(this.rootDoc, "onRight");
}
openLinkTargetOnRight = (e: React.MouseEvent) => {
- const alias = Doc.MakeAlias(Cast(this.props.Document[this.props.fieldKey], Doc, null));
- alias.isButton = undefined;
+ const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null));
+ alias.isLinkButton = undefined;
alias.isBackground = undefined;
alias.layoutKey = "layout";
this.props.addDocTab(alias, "onRight");
@@ -105,30 +107,31 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
funcs.push({ description: "Open Link Target on Right", event: () => this.openLinkTargetOnRight(e), icon: "eye" });
funcs.push({ description: "Open Link on Right", event: () => this.openLinkDocOnRight(e), icon: "eye" });
funcs.push({ description: "Open Link Editor", event: () => this.openLinkEditor(e), icon: "eye" });
+ funcs.push({ description: "Toggle Always Show Link", event: () => this.props.Document.linkDisplay = !this.props.Document.linkDisplay, icon: "eye" });
- ContextMenu.Instance.addItem({ description: "Link Funcs...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
}
render() {
TraceMobx();
- const x = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_x"], 100) : 0;
- const y = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_y"], 100) : 0;
- const c = StrCast(this.props.Document.backgroundColor, "lightblue");
- const anchor = this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1";
+ const x = this.props.PanelWidth() > 1 ? NumCast(this.layoutDoc[this.fieldKey + "_x"], 100) : 0;
+ const y = this.props.PanelWidth() > 1 ? NumCast(this.layoutDoc[this.fieldKey + "_y"], 100) : 0;
+ const c = StrCast(this.layoutDoc.backgroundColor, "lightblue");
+ const anchor = this.fieldKey === "anchor1" ? "anchor2" : "anchor1";
const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .15;
- const timecode = this.props.Document[anchor + "Timecode"];
- const targetTitle = StrCast((this.props.Document[anchor]! as Doc).title) + (timecode !== undefined ? ":" + timecode : "");
+ const timecode = this.dataDoc[anchor + "_timecode"];
+ const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title) + (timecode !== undefined ? ":" + timecode : "");
const flyout = (
- <div className="docuLinkBox-flyout" title=" " onPointerOver={() => Doc.UnBrushDoc(this.props.Document)}>
- <LinkEditor sourceDoc={Cast(this.props.Document[this.props.fieldKey], Doc, null)} hideback={true} linkDoc={this.props.Document} showLinks={action(() => { })} />
- {!this._forceOpen ? (null) : <div className="docuLinkBox-linkCloser" onPointerDown={action(() => this._isOpen = this._editing = this._forceOpen = false)}>
+ <div className="linkAnchorBoxBox-flyout" title=" " onPointerOver={() => Doc.UnBrushDoc(this.rootDoc)}>
+ <LinkEditor sourceDoc={Cast(this.dataDoc[this.fieldKey], Doc, null)} hideback={true} linkDoc={this.rootDoc} showLinks={action(() => { })} />
+ {!this._forceOpen ? (null) : <div className="linkAnchorBox-linkCloser" onPointerDown={action(() => this._isOpen = this._editing = this._forceOpen = false)}>
<FontAwesomeIcon color="dimGray" icon={"times"} size={"sm"} />
</div>}
</div>
);
const small = this.props.PanelWidth() <= 1;
- return <div className={`docuLinkBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} title={targetTitle} onContextMenu={this.specificContextMenu}
+ return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
ref={this._ref} style={{
background: c,
left: !small ? `calc(${x}% - 7.5px)` : undefined,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 542c86049..740f2ef04 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -4,7 +4,7 @@ import { documentSchema } from "../../../new_fields/documentSchemas";
import { makeInterface, listSpec } from "../../../new_fields/Schema";
import { returnFalse, returnZero } from "../../../Utils";
import { CollectionTreeView } from "../collections/CollectionTreeView";
-import { DocExtendableComponent } from "../DocComponent";
+import { ViewBoxBaseComponent } from "../DocComponent";
import { FieldView, FieldViewProps } from './FieldView';
import "./LinkBox.scss";
import { Cast } from "../../../new_fields/Types";
@@ -13,11 +13,10 @@ type LinkDocument = makeInterface<[typeof documentSchema]>;
const LinkDocument = makeInterface(documentSchema);
@observer
-export class LinkBox extends DocExtendableComponent<FieldViewProps, LinkDocument>(LinkDocument) {
+export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(LinkDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); }
render() {
return <div className={`linkBox-container${this.active() ? "-interactive" : ""}`}
- onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
style={{ background: this.props.backgroundColor?.(this.props.Document) }} >
<CollectionTreeView {...this.props}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 7a3d2e92b..bccf0f291 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -199,9 +199,6 @@
.pdfBox {
pointer-events: none;
- .collectionFreeFormView-none {
- pointer-events: none;
- }
.pdfViewer-text {
.textLayer {
span {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index f8c008a2d..3712c648e 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -9,25 +9,24 @@ import { ScriptField } from '../../../new_fields/ScriptField';
import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
import { PdfField, URLField } from "../../../new_fields/URLField";
import { Utils } from '../../../Utils';
-import { KeyCodes } from '../../northstar/utils/KeyCodes';
import { undoBatch } from '../../util/UndoManager';
import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { PDFViewer } from "../pdf/PDFViewer";
import { FieldView, FieldViewProps } from './FieldView';
import { pageSchema } from "./ImageBox";
+import { KeyCodes } from '../../util/KeyCodes';
import "./PDFBox.scss";
import React = require("react");
import { documentSchema } from '../../../new_fields/documentSchemas';
-import { url } from 'inspector';
type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>;
const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema);
@observer
-export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>(PdfDocument) {
+export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocument>(PdfDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); }
private _keyValue: string = "";
private _valueValue: string = "";
@@ -211,7 +210,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
pdfUrl && funcs.push({ description: "Copy path", event: () => Utils.CopyText(pdfUrl.url.pathname), icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Fit Width " + (this.Document._fitWidth ? "Off" : "On"), event: () => this.Document._fitWidth = !this.Document._fitWidth, icon: "expand-arrows-alt" });
- ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
}
@computed get contentScaling() { return this.props.ContentScaling(); }
@@ -249,7 +248,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
_pdfjsRequested = false;
render() {
const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null);
- if (this.props.isSelected() || this.props.Document.scrollY !== undefined) this._everActive = true;
+ if (this.props.isSelected() || this.props.renderDepth <= 1 || this.props.Document.scrollY !== undefined) this._everActive = true;
if (pdfUrl && (this._everActive || this.props.Document._scrollTop || (this.dataDoc[this.props.fieldKey + "-nativeWidth"] && this.props.ScreenToLocalTransform().Scale < 2.5))) {
if (pdfUrl instanceof PdfField && this._pdf) {
return this.renderPdfView;
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index ba8389fda..78c19f351 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -10,8 +10,12 @@
letter-spacing: 2px;
overflow: hidden;
transition: 0.7s opacity ease;
- pointer-events: all;
+ .presBox-listCont {
+ position: absolute;
+ height: calc(100% - 25px);
+ width: 100%;
+ }
.presBox-buttons {
padding: 10px;
width: 100%;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 73d09b4e1..80d043db1 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -4,10 +4,11 @@ import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faH
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc, DocListCast, DocCastAsync } from "../../../new_fields/Doc";
import { InkTool } from "../../../new_fields/InkField";
-import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
import { returnFalse } from "../../../Utils";
+import { documentSchema } from "../../../new_fields/documentSchemas";
import { DocumentManager } from "../../util/DocumentManager";
import { undoBatch } from "../../util/UndoManager";
import { CollectionDockingView } from "../collections/CollectionDockingView";
@@ -15,6 +16,8 @@ import { CollectionView, CollectionViewType } from "../collections/CollectionVie
import { InkingControl } from "../InkingControl";
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
+import { ViewBoxBaseComponent } from "../DocComponent";
+import { makeInterface } from "../../../new_fields/Schema";
library.add(faArrowLeft);
library.add(faArrowRight);
@@ -26,24 +29,27 @@ library.add(faTimes);
library.add(faMinus);
library.add(faEdit);
+type PresBoxSchema = makeInterface<[typeof documentSchema]>;
+const PresBoxDocument = makeInterface(documentSchema);
+
@observer
-export class PresBox extends React.Component<FieldViewProps> {
+export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
_childReaction: IReactionDisposer | undefined;
@observable _isChildActive = false;
componentDidMount() {
- this.props.Document._forceRenderEngine = "timeline";
- this.props.Document._replacedChrome = "replaced";
+ this.layoutDoc._forceRenderEngine = "timeline";
+ this.layoutDoc._replacedChrome = "replaced";
this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true });
}
componentWillUnmount() {
this._childReaction?.();
}
- @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); }
- @computed get currentIndex() { return NumCast(this.props.Document._itemIndex); }
+ @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
+ @computed get currentIndex() { return NumCast(this.layoutDoc._itemIndex); }
- updateCurrentPresentation = action(() => Doc.UserDoc().curPresentation = this.props.Document);
+ updateCurrentPresentation = action(() => Doc.UserDoc().activePresentation = this.rootDoc);
next = () => {
this.updateCurrentPresentation();
@@ -78,8 +84,8 @@ export class PresBox extends React.Component<FieldViewProps> {
}
whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
- active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
- (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+ active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.layoutDoc.isBackground) &&
+ (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
/**
* This is the method that checks for the actions that need to be performed
@@ -131,11 +137,10 @@ export class PresBox extends React.Component<FieldViewProps> {
*/
navigateToElement = async (curDoc: Doc, fromDocIndex: number) => {
this.updateCurrentPresentation();
- const fromDoc = this.childDocs[fromDocIndex].presentationTargetDoc as Doc;
let docToJump = curDoc;
let willZoom = false;
- const presDocs = DocListCast(this.props.Document[this.props.fieldKey]);
+ const presDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
let nextSelected = presDocs.indexOf(curDoc);
const currentDocGroups: Doc[] = [];
for (; nextSelected < presDocs.length - 1; nextSelected++) {
@@ -157,29 +162,28 @@ export class PresBox extends React.Component<FieldViewProps> {
});
//docToJump stayed same meaning, it was not in the group or was the last element in the group
- const aliasOf = await Cast(docToJump.aliasOf, Doc);
- const srcContext = aliasOf && await Cast(aliasOf.context, Doc);
+ const aliasOf = await DocCastAsync(docToJump.aliasOf);
+ const srcContext = aliasOf && await DocCastAsync(aliasOf.context);
if (docToJump === curDoc) {
//checking if curDoc has navigation open
- const target = await Cast(curDoc.presentationTargetDoc, Doc);
+ const target = await DocCastAsync(curDoc.presentationTargetDoc);
if (curDoc.navButton && target) {
DocumentManager.Instance.jumpToDocument(target, false, undefined, srcContext);
} else if (curDoc.zoomButton && target) {
//awaiting jump so that new scale can be found, since jumping is async
await DocumentManager.Instance.jumpToDocument(target, true, undefined, srcContext);
}
- return;
+ } else {
+ //awaiting jump so that new scale can be found, since jumping is async
+ const presTargetDoc = await DocCastAsync(docToJump.presentationTargetDoc);
+ presTargetDoc && await DocumentManager.Instance.jumpToDocument(presTargetDoc, willZoom, undefined, srcContext);
}
-
- //awaiting jump so that new scale can be found, since jumping is async
- const presTargetDoc = await docToJump.presentationTargetDoc as Doc;
- await DocumentManager.Instance.jumpToDocument(presTargetDoc, willZoom, undefined, srcContext);
}
@undoBatch
public removeDocument = (doc: Doc) => {
- return Doc.RemoveDocFromList(this.props.Document, this.props.fieldKey, doc);
+ return Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
}
//The function that is called when a document is clicked or reached through next or back.
@@ -188,10 +192,10 @@ export class PresBox extends React.Component<FieldViewProps> {
this.updateCurrentPresentation();
Doc.UnBrushAllDocs();
if (index >= 0 && index < this.childDocs.length) {
- this.props.Document._itemIndex = index;
+ this.layoutDoc._itemIndex = index;
- if (!this.props.Document.presStatus) {
- this.props.Document.presStatus = true;
+ if (!this.layoutDoc.presStatus) {
+ this.layoutDoc.presStatus = true;
this.startPresentation(index);
}
@@ -204,10 +208,10 @@ export class PresBox extends React.Component<FieldViewProps> {
//The function that starts or resets presentaton functionally, depending on status flag.
startOrResetPres = () => {
this.updateCurrentPresentation();
- if (this.props.Document.presStatus) {
+ if (this.layoutDoc.presStatus) {
this.resetPresentation();
} else {
- this.props.Document.presStatus = true;
+ this.layoutDoc.presStatus = true;
this.startPresentation(0);
this.gotoDocument(0, this.currentIndex);
}
@@ -216,7 +220,7 @@ export class PresBox extends React.Component<FieldViewProps> {
addDocument = (doc: Doc) => {
const newPinDoc = Doc.MakeAlias(doc);
newPinDoc.presentationTargetDoc = doc;
- return Doc.AddDocToList(this.props.Document, this.props.fieldKey, newPinDoc);
+ return Doc.AddDocToList(this.dataDoc, this.fieldKey, newPinDoc);
}
@@ -225,8 +229,8 @@ export class PresBox extends React.Component<FieldViewProps> {
resetPresentation = () => {
this.updateCurrentPresentation();
this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1);
- this.props.Document._itemIndex = 0;
- this.props.Document.presStatus = false;
+ this.layoutDoc._itemIndex = 0;
+ this.layoutDoc.presStatus = false;
}
//The function that starts the presentation, also checking if actions should be applied
@@ -246,31 +250,31 @@ export class PresBox extends React.Component<FieldViewProps> {
});
}
- updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: number) => {
- if (BoolCast(this.props.Document.inOverlay) !== (mode === CollectionViewType.Invalid)) {
- if (this.props.Document.inOverlay) {
- Doc.RemoveDocFromList((Doc.UserDoc().overlays as Doc), undefined, this.props.Document);
- CollectionDockingView.AddRightSplit(this.props.Document);
- this.props.Document.inOverlay = false;
+ updateMinimize = undoBatch(action((e: React.ChangeEvent, mode: CollectionViewType) => {
+ if (BoolCast(this.layoutDoc.inOverlay) !== (mode === CollectionViewType.Invalid)) {
+ if (this.layoutDoc.inOverlay) {
+ Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
+ CollectionDockingView.AddRightSplit(this.rootDoc);
+ this.layoutDoc.inOverlay = false;
} else {
- this.props.Document.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25;
- this.props.Document.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25;
- this.props.addDocTab?.(this.props.Document, "close");
- Doc.AddDocToList((Doc.UserDoc().overlays as Doc), undefined, this.props.Document);
+ this.layoutDoc.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25;
+ this.layoutDoc.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25;
+ this.props.addDocTab?.(this.rootDoc, "close");
+ Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
}
}
}));
- initializeViewAliases = (docList: Doc[], viewtype: number) => {
+ initializeViewAliases = (docList: Doc[], viewtype: CollectionViewType) => {
const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46;
docList.forEach(doc => {
- doc.presBox = this.props.Document; // give contained documents a reference to the presentation
+ doc.presBox = this.rootDoc; // give contained documents a reference to the presentation
doc.collapsedHeight = hgt; // set the collpased height for documents based on the type of view (Tree or Stack) they will be displaye din
});
}
selectElement = (doc: Doc) => {
- this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.props.Document._itemIndex));
+ this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.layoutDoc._itemIndex));
}
getTransform = () => {
@@ -283,17 +287,17 @@ export class PresBox extends React.Component<FieldViewProps> {
@undoBatch
viewChanged = action((e: React.ChangeEvent) => {
//@ts-ignore
- this.props.Document._viewType = Number(e.target.selectedOptions[0].value);
- this.props.Document._viewType === CollectionViewType.Stacking && (this.props.Document._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
- this.updateMinimize(e, Number(this.props.Document._viewType));
+ this.layoutDoc._viewType = e.target.selectedOptions[0].value;
+ this.layoutDoc._viewType === CollectionViewType.Stacking && (this.layoutDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
+ this.updateMinimize(e, StrCast(this.layoutDoc._viewType));
});
- childLayoutTemplate = () => this.props.Document._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc().presentationTemplate, Doc, null) : undefined;
+ childLayoutTemplate = () => this.layoutDoc._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc()["template-presentation"], Doc, null) : undefined;
render() {
- const mode = NumCast(this.props.Document._viewType, CollectionViewType.Invalid);
+ const mode = StrCast(this.layoutDoc._viewType) as CollectionViewType;
this.initializeViewAliases(this.childDocs, mode);
- return <div className="presBox-cont" style={{ minWidth: this.props.Document.inOverlay ? 240 : undefined, pointerEvents: this.active() || this.props.Document.inOverlay ? "all" : "none" }} >
- <div className="presBox-buttons" style={{ display: this.props.Document._chromeStatus === "disabled" ? "none" : undefined }}>
+ return <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined, pointerEvents: this.active() || this.layoutDoc.inOverlay ? "all" : "none" }} >
+ <div className="presBox-buttons" style={{ display: this.layoutDoc._chromeStatus === "disabled" ? "none" : undefined }}>
<select className="collectionViewBaseChrome-viewPicker"
onPointerDown={e => e.stopPropagation()}
onChange={this.viewChanged}
@@ -304,15 +308,21 @@ export class PresBox extends React.Component<FieldViewProps> {
<option className="collectionViewBaseChrome-viewOption" onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel}>Slides</option>
</select>
<button className="presBox-button" title="Back" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
- <button className="presBox-button" title={"Reset Presentation" + this.props.Document.presStatus ? "" : " From Start"} onClick={this.startOrResetPres}>
- <FontAwesomeIcon icon={this.props.Document.presStatus ? "stop" : "play"} />
+ <button className="presBox-button" title={"Reset Presentation" + this.layoutDoc.presStatus ? "" : " From Start"} onClick={this.startOrResetPres}>
+ <FontAwesomeIcon icon={this.layoutDoc.presStatus ? "stop" : "play"} />
</button>
<button className="presBox-button" title="Next" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
</div>
<div className="presBox-listCont" >
{mode !== CollectionViewType.Invalid ?
- <CollectionView {...this.props} PanelHeight={this.panelHeight} moveDocument={returnFalse} childLayoutTemplate={this.childLayoutTemplate}
- addDocument={this.addDocument} removeDocument={returnFalse} focus={this.selectElement} ScreenToLocalTransform={this.getTransform} />
+ <CollectionView {...this.props}
+ PanelHeight={this.panelHeight}
+ moveDocument={returnFalse}
+ childLayoutTemplate={this.childLayoutTemplate}
+ addDocument={this.addDocument}
+ removeDocument={returnFalse}
+ focus={this.selectElement}
+ ScreenToLocalTransform={this.getTransform} />
: (null)
}
</div>
diff --git a/src/client/views/nodes/QueryBox.scss b/src/client/views/nodes/QueryBox.scss
index 82f64054c..b5f90aa1e 100644
--- a/src/client/views/nodes/QueryBox.scss
+++ b/src/client/views/nodes/QueryBox.scss
@@ -2,5 +2,4 @@
width: 100%;
height: 100%;
position: absolute;
- pointer-events: all;
} \ No newline at end of file
diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx
index 7016b4f04..76885eada 100644
--- a/src/client/views/nodes/QueryBox.tsx
+++ b/src/client/views/nodes/QueryBox.tsx
@@ -3,19 +3,20 @@ import { IReactionDisposer } from "mobx";
import { observer } from "mobx-react";
import { documentSchema } from "../../../new_fields/documentSchemas";
import { Id } from '../../../new_fields/FieldSymbols';
-import { makeInterface } from "../../../new_fields/Schema";
-import { StrCast } from "../../../new_fields/Types";
+import { makeInterface, listSpec } from "../../../new_fields/Schema";
+import { StrCast, Cast } from "../../../new_fields/Types";
import { SelectionManager } from "../../util/SelectionManager";
-import { DocAnnotatableComponent } from '../DocComponent';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { SearchBox } from "../search/SearchBox";
import { FieldView, FieldViewProps } from './FieldView';
import "./QueryBox.scss";
+import { List } from "../../../new_fields/List";
type QueryDocument = makeInterface<[typeof documentSchema]>;
const QueryDocument = makeInterface(documentSchema);
@observer
-export class QueryBox extends DocAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
+export class QueryBox extends ViewBoxAnnotatableComponent<FieldViewProps, QueryDocument>(QueryDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(QueryBox, fieldKey); }
_docListChangedReaction: IReactionDisposer | undefined;
componentDidMount() {
@@ -28,7 +29,13 @@ export class QueryBox extends DocAnnotatableComponent<FieldViewProps, QueryDocum
render() {
const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
return <div className={`queryBox${dragging}`} onWheel={(e) => e.stopPropagation()} >
- <SearchBox id={this.props.Document[Id]} searchQuery={StrCast(this.dataDoc.searchQuery)} filterQquery={StrCast(this.dataDoc.filterQuery)} />
+ <SearchBox
+ id={this.props.Document[Id]}
+ setSearchQuery={q => this.dataDoc.searchQuery = q}
+ searchQuery={StrCast(this.dataDoc.searchQuery)}
+ setSearchFileTypes={q => this.dataDoc.searchFileTypes = new List<string>(q)}
+ searchFileTypes={Cast(this.dataDoc.searchFileTypes, listSpec("string"), [])}
+ filterQquery={StrCast(this.dataDoc.filterQuery)} />
</div >;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/RadialMenu.scss b/src/client/views/nodes/RadialMenu.scss
index ce0c263ef..daa620d12 100644
--- a/src/client/views/nodes/RadialMenu.scss
+++ b/src/client/views/nodes/RadialMenu.scss
@@ -67,17 +67,4 @@ s
margin-left: 5px;
text-align: left;
display: inline; //need this?
-}
-
-
-
-.icon-background {
- pointer-events: all;
- height:100%;
- margin-top: 15px;
- background-color: transparent;
- width: 35px;
- text-align: center;
- font-size: 20px;
- margin-left: 5px;
} \ No newline at end of file
diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx
index 0ffed78de..ddfdb67b4 100644
--- a/src/client/views/nodes/RadialMenu.tsx
+++ b/src/client/views/nodes/RadialMenu.tsx
@@ -1,12 +1,9 @@
import React = require("react");
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { action, observable, computed, IReactionDisposer, reaction, runInAction } from "mobx";
-import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import Measure from "react-measure";
-import "./RadialMenu.scss";
-import MobileInkOverlay from "../../../mobile/MobileInkOverlay";
import MobileInterface from "../../../mobile/MobileInterface";
+import "./RadialMenu.scss";
+import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem";
@observer
export class RadialMenu extends React.Component {
diff --git a/src/client/views/nodes/ScreenshotBox.scss b/src/client/views/nodes/ScreenshotBox.scss
index 6cc184948..141960f60 100644
--- a/src/client/views/nodes/ScreenshotBox.scss
+++ b/src/client/views/nodes/ScreenshotBox.scss
@@ -1,5 +1,4 @@
.screenshotBox {
- pointer-events: all;
transform-origin: top left;
background: white;
color: black;
@@ -21,10 +20,6 @@
height: Auto;
}
-.screenshotBox-content-interactive, .screenshotBox-content-fullScreen {
- pointer-events: all;
-}
-
.screenshotBox-uiButtons {
background:dimgray;
border: orange solid 1px;
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 58ff4971a..125690dc7 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -7,15 +7,14 @@ import { observer } from "mobx-react";
import * as rp from 'request-promise';
import { documentSchema, positionSchema } from "../../../new_fields/documentSchemas";
import { makeInterface } from "../../../new_fields/Schema";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast, StrCast } from "../../../new_fields/Types";
+import { Cast, NumCast } from "../../../new_fields/Types";
import { VideoField } from "../../../new_fields/URLField";
import { emptyFunction, returnFalse, returnOne, Utils, returnZero } from "../../../Utils";
import { Docs, DocUtils } from "../../documents/Documents";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
-import { DocAnnotatableComponent } from "../DocComponent";
+import { ViewBoxBaseComponent } from "../DocComponent";
import { InkingControl } from "../InkingControl";
import { FieldView, FieldViewProps } from './FieldView';
import "./ScreenshotBox.scss";
@@ -27,7 +26,7 @@ const ScreenshotDocument = makeInterface(documentSchema, positionSchema);
library.add(faVideo);
@observer
-export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
+export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
private _reactionDisposer?: IReactionDisposer;
private _videoRef: HTMLVideoElement | null = null;
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); }
@@ -38,22 +37,21 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
videoLoad = () => {
const aspect = this.player!.videoWidth / this.player!.videoHeight;
- const nativeWidth = (this.Document._nativeWidth || 0);
- const nativeHeight = (this.Document._nativeHeight || 0);
+ const nativeWidth = (this.layoutDoc._nativeWidth || 0);
+ const nativeHeight = (this.layoutDoc._nativeHeight || 0);
if (!nativeWidth || !nativeHeight) {
- if (!this.Document._nativeWidth) this.Document._nativeWidth = 400;
- this.Document._nativeHeight = (this.Document._nativeWidth || 0) / aspect;
- this.Document._height = (this.Document._width || 0) / aspect;
+ if (!this.layoutDoc._nativeWidth) this.layoutDoc._nativeWidth = 400;
+ this.layoutDoc._nativeHeight = NumCast(this.layoutDoc._nativeWidth) / aspect;
+ this.layoutDoc._height = NumCast(this.layoutDoc._width) / aspect;
}
- if (!this.Document.duration) this.Document.duration = this.player!.duration;
}
@action public Snapshot() {
- const width = this.Document._width || 0;
- const height = this.Document._height || 0;
+ const width = NumCast(this.layoutDoc._width);
+ const height = NumCast(this.layoutDoc._height);
const canvas = document.createElement('canvas');
canvas.width = 640;
- canvas.height = 640 * (this.Document._nativeHeight || 0) / (this.Document._nativeWidth || 1);
+ canvas.height = 640 * NumCast(this.layoutDoc._nativeHeight) / NumCast(this.layoutDoc._nativeWidth, 1);
const ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions
if (ctx) {
ctx.rect(0, 0, canvas.width, canvas.height);
@@ -71,7 +69,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
setTimeout(() => {
if (returnedFilename) {
const imageSummary = Docs.Create.ImageDocument(Utils.prepend(returnedFilename), {
- x: (this.Document.x || 0) + width, y: (this.Document.y || 0),
+ x: NumCast(this.layoutDoc.x) + width, y: NumCast(this.layoutDoc.y),
_width: 150, _height: height / width * 150, title: "--screenshot--"
});
this.props.addDocument?.(imageSummary);
@@ -111,7 +109,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
}
@observable _screenCapture = false;
specificContextMenu = (e: React.MouseEvent): void => {
- const field = Cast(this.dataDoc[this.props.fieldKey], VideoField);
+ const field = Cast(this.dataDoc[this.fieldKey], VideoField);
if (field) {
const url = field.url.href;
const subitems: ContextMenuProps[] = [];
@@ -122,7 +120,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
}), icon: "expand-arrows-alt"
});
- ContextMenu.Instance.addItem({ description: "Screenshot Funcs...", subitems: subitems, icon: "video" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" });
}
}
@@ -172,16 +170,16 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
PanelWidth={this.props.PanelWidth}
NativeHeight={returnZero}
NativeWidth={returnZero}
- annotationsKey={this.annotationKey}
+ annotationsKey={""}
focus={this.props.focus}
isSelected={this.props.isSelected}
isAnnotationOverlay={true}
select={emptyFunction}
- active={this.annotationsActive}
+ active={returnFalse}
ContentScaling={returnOne}
- whenActiveChanged={this.whenActiveChanged}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
+ whenActiveChanged={emptyFunction}
+ removeDocument={returnFalse}
+ moveDocument={returnFalse}
addDocument={returnFalse}
CollectionView={undefined}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
@@ -190,7 +188,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
{this.contentFunc}
</CollectionFreeFormView>
</div>
- {this.active() ? this.uIButtons : (null)}
+ {this.props.isSelected() ? this.uIButtons : (null)}
</div >);
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/ScriptingBox.scss b/src/client/views/nodes/ScriptingBox.scss
new file mode 100644
index 000000000..43695f00d
--- /dev/null
+++ b/src/client/views/nodes/ScriptingBox.scss
@@ -0,0 +1,35 @@
+.scriptingBox-outerDiv {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ background-color: rgb(241, 239, 235);
+ padding: 10px;
+ .scriptingBox-inputDiv {
+ display: flex;
+ flex-direction: column;
+ height: calc(100% - 30px);
+ .scriptingBox-errorMessage {
+ overflow: auto;
+ }
+ .scripting-params {
+ background: "beige";
+ }
+ .scriptingBox-textArea {
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+ resize: none;
+ padding: 7px;
+ }
+ }
+
+ .scriptingBox-toolbar {
+ width: 100%;
+ height: 30px;
+ .scriptingBox-button {
+ width: 50%
+ }
+ }
+}
+
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
new file mode 100644
index 000000000..c607d6614
--- /dev/null
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -0,0 +1,98 @@
+import { action, observable, computed } from "mobx";
+import { observer } from "mobx-react";
+import * as React from "react";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { StrCast, ScriptCast, Cast } from "../../../new_fields/Types";
+import { InteractionUtils } from "../../util/InteractionUtils";
+import { CompileScript, isCompileError, ScriptParam } from "../../util/Scripting";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import { EditableView } from "../EditableView";
+import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import "./ScriptingBox.scss";
+import { OverlayView } from "../OverlayView";
+import { DocumentIconContainer } from "./DocumentIcon";
+import { List } from "../../../new_fields/List";
+
+const ScriptingSchema = createSchema({});
+type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>;
+const ScriptingDocument = makeInterface(ScriptingSchema, documentSchema);
+
+@observer
+export class ScriptingBox extends ViewBoxAnnotatableComponent<FieldViewProps, ScriptingDocument>(ScriptingDocument) {
+ protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer | undefined;
+ public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); }
+
+ _overlayDisposer?: () => void;
+
+ @observable private _errorMessage: string = "";
+
+ @computed get rawScript() { return StrCast(this.dataDoc[this.props.fieldKey + "-rawScript"], StrCast(this.layoutDoc[this.props.fieldKey + "-rawScript"])); }
+ @computed get compileParams() { return Cast(this.dataDoc[this.props.fieldKey + "-params"], listSpec("string"), Cast(this.layoutDoc[this.props.fieldKey + "-params"], listSpec("string"), [])); }
+ set rawScript(value) { this.dataDoc[this.props.fieldKey + "-rawScript"] = value; }
+ set compileParams(value) { this.dataDoc[this.props.fieldKey + "-params"] = value; }
+
+ @action
+ componentDidMount() {
+ this.rawScript = ScriptCast(this.dataDoc[this.props.fieldKey])?.script?.originalScript || this.rawScript;
+ }
+
+ componentWillUnmount() { this._overlayDisposer?.(); }
+
+ @action
+ onCompile = () => {
+ const params = this.compileParams.reduce((o: ScriptParam, p: string) => { o[p] = "any"; return o; }, {} as ScriptParam);
+ const result = CompileScript(this.rawScript, {
+ editable: true,
+ transformer: DocumentIconContainer.getTransformer(),
+ params,
+ typecheck: false
+ });
+ this._errorMessage = isCompileError(result) ? result.errors.map(e => e.messageText).join("\n") : "";
+ return this.dataDoc[this.props.fieldKey] = result.compiled ? new ScriptField(result) : undefined;
+ }
+
+ @action
+ onRun = () => {
+ this.onCompile()?.script.run({}, err => this._errorMessage = err.map((e: any) => e.messageText).join("\n"));
+ }
+
+ onFocus = () => {
+ this._overlayDisposer?.();
+ this._overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+ }
+
+ render() {
+ const params = <EditableView
+ contents={this.compileParams.join(" ")}
+ display={"block"}
+ maxHeight={72}
+ height={35}
+ fontSize={28}
+ GetValue={() => ""}
+ SetValue={value => { this.compileParams = new List<string>(value.split(" ").filter(s => s !== " ")); return true; }}
+ />;
+ return (
+ <div className="scriptingBox-outerDiv"
+ onWheel={e => this.props.isSelected(true) && e.stopPropagation()}>
+ <div className="scriptingBox-inputDiv"
+ onPointerDown={e => this.props.isSelected(true) && e.stopPropagation()} >
+ <textarea className="scriptingBox-textarea"
+ placeholder="write your script here"
+ onChange={e => this.rawScript = e.target.value}
+ value={this.rawScript}
+ onFocus={this.onFocus}
+ onBlur={e => this._overlayDisposer?.()} />
+ <div className="scriptingBox-errorMessage" style={{ background: this._errorMessage ? "red" : "" }}>{this._errorMessage}</div>
+ <div className="scriptingBox-params" >{params}</div>
+ </div>
+ {this.rootDoc.layout === "layout" ? <div></div> : (null)}
+ <div className="scriptingBox-toolbar">
+ <button className="scriptingBox-button" onPointerDown={e => { this.onCompile(); e.stopPropagation(); }}>Compile</button>
+ <button className="scriptingBox-button" onPointerDown={e => { this.onRun(); e.stopPropagation(); }}>Run</button>
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/src/client/views/nodes/SliderBox.scss b/src/client/views/nodes/SliderBox.scss
index 4ef277d8c..78015bd70 100644
--- a/src/client/views/nodes/SliderBox.scss
+++ b/src/client/views/nodes/SliderBox.scss
@@ -1,7 +1,6 @@
.sliderBox-outerDiv {
width: 100%;
height: 100%;
- pointer-events: all;
border-radius: inherit;
display: flex;
flex-direction: column;
diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx
index 844d95d11..cb2526769 100644
--- a/src/client/views/nodes/SliderBox.tsx
+++ b/src/client/views/nodes/SliderBox.tsx
@@ -1,22 +1,20 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faEdit } from '@fortawesome/free-regular-svg-icons';
-import { computed, runInAction } from 'mobx';
+import { runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Handles, Rail, Slider, Tracks, Ticks } from 'react-compound-slider';
-import { Doc } from '../../../new_fields/Doc';
+import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider';
import { documentSchema } from '../../../new_fields/documentSchemas';
-import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
+import { createSchema, makeInterface } from '../../../new_fields/Schema';
import { ScriptField } from '../../../new_fields/ScriptField';
-import { BoolCast, FieldValue, StrCast, NumCast, Cast } from '../../../new_fields/Types';
-import { DragManager } from '../../util/DragManager';
+import { Cast, NumCast, StrCast } from '../../../new_fields/Types';
import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
-import { DocComponent } from '../DocComponent';
-import './SliderBox.scss';
-import { Handle, TooltipRail, Track, Tick } from './SliderBox-components';
-import { FieldView, FieldViewProps } from './FieldView';
+import { ViewBoxBaseComponent } from '../DocComponent';
import { ScriptBox } from '../ScriptBox';
+import { FieldView, FieldViewProps } from './FieldView';
+import { Handle, Tick, TooltipRail, Track } from './SliderBox-components';
+import './SliderBox.scss';
library.add(faEdit as any);
@@ -32,36 +30,33 @@ type SliderDocument = makeInterface<[typeof SliderSchema, typeof documentSchema]
const SliderDocument = makeInterface(SliderSchema, documentSchema);
@observer
-export class SliderBox extends DocComponent<FieldViewProps, SliderDocument>(SliderDocument) {
+export class SliderBox extends ViewBoxBaseComponent<FieldViewProps, SliderDocument>(SliderDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SliderBox, fieldKey); }
- private dropDisposer?: DragManager.DragDropDisposer;
-
- @computed get dataDoc() {
- return this.props.DataDoc &&
- (this.Document.isTemplateForField || BoolCast(this.props.DataDoc.isTemplateForField) ||
- this.props.DataDoc.layout === this.Document) ? this.props.DataDoc : Doc.GetProto(this.Document);
- }
+ get minThumbKey() { return this.fieldKey + "-minThumb"; }
+ get maxThumbKey() { return this.fieldKey + "-maxThumb"; }
+ get minKey() { return this.fieldKey + "-min"; }
+ get maxKey() { return this.fieldKey + "-max"; }
specificContextMenu = (e: React.MouseEvent): void => {
const funcs: ContextMenuProps[] = [];
funcs.push({ description: "Edit Thumb Change Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Thumb Change ...", this.props.Document, "onThumbChange", obj.x, obj.y) });
- ContextMenu.Instance.addItem({ description: "Slider Funcs...", subitems: funcs, icon: "asterisk" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
}
onChange = (values: readonly number[]) => runInAction(() => {
- this.Document._sliderMinThumb = values[0];
- this.Document._sliderMaxThumb = values[1];
- Cast(this.Document.onThumbChanged, ScriptField, null)?.script.run({ range: values, this: this.props.Document });
+ this.dataDoc[this.minThumbKey] = values[0];
+ this.dataDoc[this.maxThumbKey] = values[1];
+ Cast(this.layoutDoc.onThumbChanged, ScriptField, null)?.script.run({ self: this.rootDoc, range: values, this: this.layoutDoc });
})
render() {
- const domain = [NumCast(this.props.Document._sliderMin), NumCast(this.props.Document._sliderMax)];
- const defaultValues = [NumCast(this.props.Document._sliderMinThumb), NumCast(this.props.Document._sliderMaxThumb)];
- return (
+ const domain = [NumCast(this.layoutDoc[this.minKey]), NumCast(this.layoutDoc[this.maxKey])];
+ const defaultValues = [NumCast(this.dataDoc[this.minThumbKey]), NumCast(this.dataDoc[this.maxThumbKey])];
+ return domain[1] <= domain[0] ? (null) : (
<div className="sliderBox-outerDiv" onContextMenu={this.specificContextMenu} onPointerDown={e => e.stopPropagation()}
- style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
+ style={{ boxShadow: this.layoutDoc.opacity === 0 ? undefined : StrCast(this.layoutDoc.boxShadow, "") }}>
<div className="sliderBox-mainButton" onContextMenu={this.specificContextMenu} style={{
- background: this.Document.backgroundColor, color: this.Document.color || "black",
- fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || ""
+ background: StrCast(this.layoutDoc.backgroundColor), color: StrCast(this.layoutDoc.color, "black"),
+ fontSize: NumCast(this.layoutDoc._fontSize), letterSpacing: StrCast(this.layoutDoc.letterSpacing)
}} >
<Slider
mode={2}
@@ -77,7 +72,7 @@ export class SliderBox extends DocComponent<FieldViewProps, SliderDocument>(Slid
{({ handles, activeHandleID, getHandleProps }) => (
<div className="slider-handles">
{handles.map((handle, i) => {
- const value = i === 0 ? this.Document._sliderMinThumb : this.Document._sliderMaxThumb;
+ const value = i === 0 ? defaultValues[0] : defaultValues[1];
return (
<div title={String(value)}>
<Handle
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index fabbf5196..0c0854ac2 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,5 +1,4 @@
.videoBox {
- pointer-events: all;
transform-origin: top left;
.videoBox-viewer {
opacity: 0.99; // hack! overcomes some kind of Chrome weirdness where buttons (e.g., snapshot) disappear at some point as the video is resized larger
@@ -24,9 +23,9 @@
height: 100%;
}
-.videoBox-content-interactive, .videoBox-content-fullScreen, .videoBox-content-YouTube-fullScreen {
- pointer-events: all;
-}
+// .videoBox-content-interactive, .videoBox-content-fullScreen, .videoBox-content-YouTube-fullScreen {
+// pointer-events: all;
+// }
.videoBox-time{
color : white;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index d384ad12f..613929bca 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -9,14 +9,14 @@ import { Doc } from "../../../new_fields/Doc";
import { InkTool } from "../../../new_fields/InkField";
import { createSchema, makeInterface } from "../../../new_fields/Schema";
import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
+import { Cast, StrCast } from "../../../new_fields/Types";
import { VideoField } from "../../../new_fields/URLField";
import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils";
import { Docs, DocUtils } from "../../documents/Documents";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
-import { DocAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { DocumentDecorations } from "../DocumentDecorations";
import { InkingControl } from "../InkingControl";
import { FieldView, FieldViewProps } from './FieldView';
@@ -33,7 +33,7 @@ const VideoDocument = makeInterface(documentSchema, positionSchema, timeSchema);
library.add(faVideo);
@observer
-export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocument>(VideoDocument) {
+export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoDocument>(VideoDocument) {
static _youtubeIframeCounter: number = 0;
private _reactionDisposer?: IReactionDisposer;
private _youtubeReactionDisposer?: IReactionDisposer;
@@ -55,14 +55,10 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
videoLoad = () => {
const aspect = this.player!.videoWidth / this.player!.videoHeight;
- const nativeWidth = (this.Document._nativeWidth || 0);
- const nativeHeight = (this.Document._nativeHeight || 0);
- if (!nativeWidth || !nativeHeight) {
- if (!this.Document._nativeWidth) this.Document._nativeWidth = this.player!.videoWidth;
- this.Document._nativeHeight = (this.Document._nativeWidth || 0) / aspect;
- this.Document._height = (this.Document._width || 0) / aspect;
- }
- if (!this.Document.duration) this.Document.duration = this.player!.duration;
+ this.layoutDoc._nativeWidth = this.player!.videoWidth;
+ this.layoutDoc._nativeHeight = (this.layoutDoc._nativeWidth || 0) / aspect;
+ this.layoutDoc._height = (this.layoutDoc._width || 0) / aspect;
+ this.dataDoc[this.fieldKey + "-" + "duration"] = this.player!.duration;
}
@action public Play = (update: boolean = true) => {
@@ -90,7 +86,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
@action public FullScreen() {
this._fullScreen = true;
this.player && this.player.requestFullscreen();
- this._youtubePlayer && this.props.addDocTab(this.props.Document, "inTab");
+ this._youtubePlayer && this.props.addDocTab(this.rootDoc, "inTab");
}
choosePath(url: string) {
@@ -101,11 +97,11 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
}
@action public Snapshot() {
- const width = this.Document._width || 0;
- const height = this.Document._height || 0;
+ const width = (this.layoutDoc._width || 0);
+ const height = (this.layoutDoc._height || 0);
const canvas = document.createElement('canvas');
canvas.width = 640;
- canvas.height = 640 * (this.Document._nativeHeight || 0) / (this.Document._nativeWidth || 1);
+ canvas.height = 640 * (this.layoutDoc._nativeHeight || 0) / (this.layoutDoc._nativeWidth || 1);
const ctx = canvas.getContext('2d');//draw image to canvas. scale to target dimensions
if (ctx) {
ctx.rect(0, 0, canvas.width, canvas.height);
@@ -116,25 +112,28 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
if (!this._videoRef) { // can't find a way to take snapshots of videos
const b = Docs.Create.ButtonDocument({
- x: (this.Document.x || 0) + width, y: (this.Document.y || 0),
- _width: 150, _height: 50, title: (this.Document.currentTimecode || 0).toString()
+ x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 1),
+ _width: 150, _height: 50, title: (this.layoutDoc.currentTimecode || 0).toString()
});
- b.onClick = ScriptField.MakeScript(`this.currentTimecode = ${(this.Document.currentTimecode || 0)}`);
+ b.onClick = ScriptField.MakeScript(`this.currentTimecode = ${(this.layoutDoc.currentTimecode || 0)}`);
} else {
//convert to desired file format
const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png'
// if you want to preview the captured image,
- const filename = path.basename(encodeURIComponent("snapshot" + StrCast(this.Document.title).replace(/\..*$/, "") + "_" + (this.Document.currentTimecode || 0).toString().replace(/\./, "_")));
+ const filename = path.basename(encodeURIComponent("snapshot" + StrCast(this.rootDoc.title).replace(/\..*$/, "") + "_" + (this.layoutDoc.currentTimecode || 0).toString().replace(/\./, "_")));
VideoBox.convertDataUri(dataUrl, filename).then(returnedFilename => {
if (returnedFilename) {
const url = this.choosePath(Utils.prepend(returnedFilename));
const imageSummary = Docs.Create.ImageDocument(url, {
- x: (this.Document.x || 0) + width, y: (this.Document.y || 0),
- _width: 150, _height: height / width * 150, title: "--snapshot" + (this.Document.currentTimecode || 0) + " image-"
+ _nativeWidth: this.layoutDoc._nativeWidth, _nativeHeight: this.layoutDoc._nativeHeight,
+ x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 0),
+ _width: 150, _height: height / width * 150, title: "--snapshot" + (this.layoutDoc.currentTimecode || 0) + " image-"
});
- imageSummary.isButton = true;
+ Doc.GetProto(imageSummary)["data-nativeWidth"] = this.layoutDoc._nativeWidth;
+ Doc.GetProto(imageSummary)["data-nativeHeight"] = this.layoutDoc._nativeHeight;
+ imageSummary.isLinkButton = true;
this.props.addDocument && this.props.addDocument(imageSummary);
- DocUtils.MakeLink({ doc: imageSummary }, { doc: this.props.Document }, "video snapshot");
+ DocUtils.MakeLink({ doc: imageSummary }, { doc: this.rootDoc }, "video snapshot");
}
});
}
@@ -142,8 +141,8 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
@action
updateTimecode = () => {
- this.player && (this.Document.currentTimecode = this.player.currentTime);
- this._youtubePlayer && (this.Document.currentTimecode = this._youtubePlayer.getCurrentTime());
+ this.player && (this.layoutDoc.currentTimecode = this.player.currentTime);
+ this._youtubePlayer && (this.layoutDoc.currentTimecode = this._youtubePlayer.getCurrentTime());
}
componentDidMount() {
@@ -151,12 +150,12 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
if (this.youtubeVideoId) {
const youtubeaspect = 400 / 315;
- const nativeWidth = (this.Document._nativeWidth || 0);
- const nativeHeight = (this.Document._nativeHeight || 0);
+ const nativeWidth = (this.layoutDoc._nativeWidth || 0);
+ const nativeHeight = (this.layoutDoc._nativeHeight || 0);
if (!nativeWidth || !nativeHeight) {
- if (!this.Document._nativeWidth) this.Document._nativeWidth = 600;
- this.Document._nativeHeight = (this.Document._nativeWidth || 0) / youtubeaspect;
- this.Document._height = (this.Document._width || 0) / youtubeaspect;
+ if (!this.layoutDoc._nativeWidth) this.layoutDoc._nativeWidth = 600;
+ this.layoutDoc._nativeHeight = (this.layoutDoc._nativeWidth || 0) / youtubeaspect;
+ this.layoutDoc._height = (this.layoutDoc._width || 0) / youtubeaspect;
}
}
}
@@ -174,7 +173,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
this._videoRef!.ontimeupdate = this.updateTimecode;
vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
this._reactionDisposer && this._reactionDisposer();
- this._reactionDisposer = reaction(() => this.Document.currentTimecode || 0,
+ this._reactionDisposer = reaction(() => (this.layoutDoc.currentTimecode || 0),
time => !this._playing && (vref.currentTime = time), { fireImmediately: true });
}
}
@@ -210,12 +209,12 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
}), icon: "expand-arrows-alt"
});
- ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems, icon: "video" });
+ ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" });
}
}
@computed get content() {
- const field = Cast(this.dataDoc[this.props.fieldKey], VideoField);
+ const field = Cast(this.dataDoc[this.fieldKey], VideoField);
const interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive;
return !field ? <div>Loading</div> :
@@ -259,7 +258,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
const onYoutubePlayerReady = (event: any) => {
this._reactionDisposer && this._reactionDisposer();
this._youtubeReactionDisposer && this._youtubeReactionDisposer();
- this._reactionDisposer = reaction(() => this.Document.currentTimecode, () => !this._playing && this.Seek(this.Document.currentTimecode || 0));
+ this._reactionDisposer = reaction(() => this.layoutDoc.currentTimecode, () => !this._playing && this.Seek((this.layoutDoc.currentTimecode || 0)));
this._youtubeReactionDisposer = reaction(() => [this.props.isSelected(), DocumentDecorations.Instance.Interacting, InkingControl.Instance.selectedTool], () => {
const interactive = InkingControl.Instance.selectedTool === InkTool.None && this.props.isSelected(true) && !DocumentDecorations.Instance.Interacting;
iframe.style.pointerEvents = interactive ? "all" : "none";
@@ -274,7 +273,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
}
private get uIButtons() {
- const curTime = (this.Document.currentTimecode || 0);
+ const curTime = (this.layoutDoc.currentTimecode || 0);
return ([<div className="videoBox-time" key="time" onPointerDown={this.onResetDown} >
<span>{"" + Math.round(curTime)}</span>
<span style={{ fontSize: 8 }}>{" " + Math.round((curTime - Math.trunc(curTime)) * 100)}</span>
@@ -316,7 +315,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
onResetMove = (e: PointerEvent) => {
this._isResetClick += Math.abs(e.movementX) + Math.abs(e.movementY);
- this.Seek(Math.max(0, (this.Document.currentTimecode || 0) + Math.sign(e.movementX) * 0.0333));
+ this.Seek(Math.max(0, (this.layoutDoc.currentTimecode || 0) + Math.sign(e.movementX) * 0.0333));
e.stopImmediatePropagation();
}
@@ -324,22 +323,22 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
onResetUp = (e: PointerEvent) => {
document.removeEventListener("pointermove", this.onResetMove, true);
document.removeEventListener("pointerup", this.onResetUp, true);
- this._isResetClick < 10 && (this.Document.currentTimecode = 0);
+ this._isResetClick < 10 && (this.layoutDoc.currentTimecode = 0);
}
@computed get youtubeContent() {
this._youtubeIframeId = VideoBox._youtubeIframeCounter++;
this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true;
const style = "videoBox-content-YouTube" + (this._fullScreen ? "-fullScreen" : "");
- const start = untracked(() => Math.round(this.Document.currentTimecode || 0));
+ const start = untracked(() => Math.round((this.layoutDoc.currentTimecode || 0)));
return <iframe key={this._youtubeIframeId} id={`${this.youtubeVideoId + this._youtubeIframeId}-player`}
- onLoad={this.youtubeIframeLoaded} className={`${style}`} width={(this.Document._nativeWidth || 640)} height={(this.Document._nativeHeight || 390)}
+ onLoad={this.youtubeIframeLoaded} className={`${style}`} width={(this.layoutDoc._nativeWidth || 640)} height={(this.layoutDoc._nativeHeight || 390)}
src={`https://www.youtube.com/embed/${this.youtubeVideoId}?enablejsapi=1&rel=0&showinfo=1&autoplay=1&mute=1&start=${start}&modestbranding=1&controls=${VideoBox._showControls ? 1 : 0}`} />;
}
@action.bound
addDocumentWithTimestamp(doc: Doc): boolean {
- const curTime = (this.Document.currentTimecode || -1);
+ const curTime = (this.layoutDoc.currentTimecode || -1);
curTime !== -1 && (doc.displayTimecode = curTime);
return this.addDocument(doc);
}
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index b41687c11..af84a7d95 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -3,9 +3,22 @@
.webBox-container, .webBox-container-dragging {
transform-origin: top left;
+ .webBox-outerContent {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: auto;
+ .webBox-innerContent {
+ width:100%;
+ }
+ }
+ div.webBox-outerContent::-webkit-scrollbar-thumb {
+ display:none;
+ }
}
-.webBox-cont,
-.webBox-cont-dragging {
+.webBox-cont {
padding: 0vw;
position: absolute;
top: 0;
@@ -18,8 +31,6 @@
}
.webBox-cont-interactive {
- pointer-events: all;
-
span {
user-select: text !important;
}
@@ -35,22 +46,26 @@
width: 100%;
height: 100%;
position: absolute;
- pointer-events: all;
}
-.webBox-button {
- padding: 0vw;
- border: none;
+.webBox-buttons {
+ margin-left: 44;
+ background:lightGray;
width: 100%;
- height: 100%;
+}
+.webBox-freeze {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 5px;
+ width: 30px;
}
-.webView-urlEditor {
+.webBox-urlEditor {
position: relative;
opacity: 0.9;
z-index: 9001;
transition: top .5s;
- background: lightgrey;
padding: 10px;
@@ -101,7 +116,6 @@
width: 100%;
height: 100%;
position: absolute;
- pointer-events: all;
.indicator {
position: absolute;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index ea5d601ec..4e383e468 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,24 +1,22 @@
import { library } from "@fortawesome/fontawesome-svg-core";
-import { faStickyNote } from '@fortawesome/free-solid-svg-icons';
-import { action, computed, observable } from "mobx";
+import { faStickyNote, faPen, faMousePointer } from '@fortawesome/free-solid-svg-icons';
+import { action, computed, observable, trace, IReactionDisposer, reaction } from "mobx";
import { observer } from "mobx-react";
import { Doc, FieldResult } from "../../../new_fields/Doc";
import { documentSchema } from "../../../new_fields/documentSchemas";
import { HtmlField } from "../../../new_fields/HtmlField";
import { InkTool } from "../../../new_fields/InkField";
import { makeInterface } from "../../../new_fields/Schema";
-import { Cast, NumCast } from "../../../new_fields/Types";
+import { Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types";
import { WebField } from "../../../new_fields/URLField";
import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { DocAnnotatableComponent } from "../DocComponent";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { DocumentDecorations } from "../DocumentDecorations";
import { InkingControl } from "../InkingControl";
import { FieldView, FieldViewProps } from './FieldView';
-import { KeyValueBox } from "./KeyValueBox";
import "./WebBox.scss";
import React = require("react");
import * as WebRequest from 'web-request';
@@ -26,33 +24,62 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
const htmlToText = require("html-to-text");
-
library.add(faStickyNote);
type WebDocument = makeInterface<[typeof documentSchema]>;
const WebDocument = makeInterface(documentSchema);
@observer
-export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>(WebDocument) {
+export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocument>(WebDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
- @observable private collapsed: boolean = true;
- @observable private url: string = "hello";
+ get _collapsed() { return StrCast(this.layoutDoc._chromeStatus) === "disabled"; }
+ set _collapsed(value) { this.layoutDoc._chromeStatus = !value ? "enabled" : "disabled"; }
+ @observable private _url: string = "hello";
+ @observable private _pressX: number = 0;
+ @observable private _pressY: number = 0;
private _longPressSecondsHack?: NodeJS.Timeout;
+ private _outerRef = React.createRef<HTMLDivElement>();
private _iframeRef = React.createRef<HTMLIFrameElement>();
private _iframeIndicatorRef = React.createRef<HTMLDivElement>();
private _iframeDragRef = React.createRef<HTMLDivElement>();
- @observable private _pressX: number = 0;
- @observable private _pressY: number = 0;
-
+ private _reactionDisposer?: IReactionDisposer;
+ private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
+
+ iframeLoaded = action((e: any) => {
+ this._iframeRef.current!.contentDocument?.addEventListener('pointerdown', this.iframedown, false);
+ this._iframeRef.current!.contentDocument?.addEventListener('scroll', this.iframeScrolled, false);
+ this.layoutDoc.scrollHeight = this._iframeRef.current!.contentDocument?.children?.[0].scrollHeight || 1000;
+ this._iframeRef.current!.contentDocument!.children[0].scrollTop = NumCast(this.layoutDoc.scrollTop);
+ this._reactionDisposer?.();
+ this._reactionDisposer = reaction(() => this.layoutDoc.scrollY,
+ (scrollY) => {
+ if (scrollY !== undefined) {
+ this._outerRef.current!.scrollTop = scrollY;
+ this.layoutDoc.scrollY = undefined;
+ }
+ },
+ { fireImmediately: true }
+ );
+ });
+ setPreviewCursor = (func?: (x: number, y: number, drag: boolean) => void) => this._setPreviewCursor = func;
+ iframedown = (e: PointerEvent) => {
+ this._setPreviewCursor?.(e.screenX, e.screenY, false);
+ }
+ iframeScrolled = (e: any) => {
+ const scroll = e.target?.children?.[0].scrollTop;
+ this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = scroll;
+ }
async componentDidMount() {
this.setURL();
+ this._iframeRef.current!.setAttribute("enable-annotation", "true");
+
document.addEventListener("pointerup", this.onLongPressUp);
document.addEventListener("pointermove", this.onLongPressMove);
- const field = Cast(this.props.Document[this.props.fieldKey], WebField);
+ const field = Cast(this.rootDoc[this.props.fieldKey], WebField);
if (field?.url.href.indexOf("youtube") !== -1) {
const youtubeaspect = 400 / 315;
const nativeWidth = NumCast(this.layoutDoc._nativeWidth);
@@ -66,29 +93,31 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
const result = await WebRequest.get(Utils.CorsProxy(field.url.href));
this.dataDoc.text = htmlToText.fromString(result.content);
}
-
}
componentWillUnmount() {
+ this._reactionDisposer?.();
document.removeEventListener("pointerup", this.onLongPressUp);
document.removeEventListener("pointermove", this.onLongPressMove);
+ this._iframeRef.current!.contentDocument?.removeEventListener('pointerdown', this.iframedown);
+ this._iframeRef.current!.contentDocument?.removeEventListener('scroll', this.iframeScrolled);
}
@action
onURLChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this.url = e.target.value;
+ this._url = e.target.value;
}
@action
submitURL = () => {
- this.dataDoc[this.props.fieldKey] = new WebField(new URL(this.url));
+ this.dataDoc[this.props.fieldKey] = new WebField(new URL(this._url));
}
@action
setURL() {
const urlField: FieldResult<WebField> = Cast(this.dataDoc[this.props.fieldKey], WebField);
- if (urlField) this.url = urlField.url.toString();
- else this.url = "";
+ if (urlField) this._url = urlField.url.toString();
+ else this._url = "";
}
onValueKeyDown = async (e: React.KeyboardEvent) => {
@@ -98,47 +127,45 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
}
}
-
- switchToText = () => {
- let url: string = "";
- const field = Cast(this.props.Document[this.props.fieldKey], WebField);
- if (field) url = field.url.href;
-
- const newBox = Docs.Create.TextDocument(url, {
- x: NumCast(this.props.Document.x),
- y: NumCast(this.props.Document.y),
- title: url,
- _width: 200,
- _height: 70,
- });
-
- SelectionManager.SelectedDocuments().map(dv => {
- dv.props.addDocument && dv.props.addDocument(newBox);
- dv.props.removeDocument && dv.props.removeDocument(dv.props.Document);
- });
-
- Doc.BrushDoc(newBox);
+ toggleNativeDimensions = () => {
+ if (!this.layoutDoc.isAnnotating) {
+ //DocumentView.unfreezeNativeDimensions(this.layoutDoc);
+ this.layoutDoc.lockedTransform = false;
+ this.layoutDoc.isAnnotating = true;
+ }
+ else {
+ //Doc.freezeNativeDimensions(this.layoutDoc, this.props.PanelWidth(), this.props.PanelHeight());
+ this.layoutDoc.lockedTransform = true;
+ this.layoutDoc.isAnnotating = false;
+ }
}
urlEditor() {
+ const frozen = this.layoutDoc._nativeWidth && this.layoutDoc.isAnnotating;
return (
- <div className="webView-urlEditor" style={{ top: this.collapsed ? -70 : 0 }}>
+ <div className="webBox-urlEditor" style={{ top: this._collapsed ? -70 : 0 }}>
<div className="urlEditor">
<div className="editorBase">
<button className="editor-collapse"
style={{
- top: this.collapsed ? 70 : 10,
- transform: `rotate(${this.collapsed ? 180 : 0}deg) scale(${this.collapsed ? 0.5 : 1}) translate(${this.collapsed ? "-100%, -100%" : "0, 0"})`,
- opacity: (this.collapsed && !this.props.isSelected()) ? 0 : 0.9,
- left: (this.collapsed ? 0 : "unset"),
+ top: this._collapsed ? 70 : 10,
+ transform: `rotate(${this._collapsed ? 180 : 0}deg) scale(${this._collapsed ? 0.5 : 1}) translate(${this._collapsed ? "-100%, -100%" : "0, 0"})`,
+ opacity: (this._collapsed && !this.props.isSelected()) ? 0 : 0.9,
+ left: (this._collapsed ? 0 : "unset"),
}}
title="Collapse Url Editor" onClick={this.toggleCollapse}>
<FontAwesomeIcon icon="caret-up" size="2x" />
</button>
- <div style={{ marginLeft: 54, width: "100%", display: this.collapsed ? "none" : "flex" }}>
+ <div className="webBox-buttons" style={{ display: this._collapsed ? "none" : "flex" }}>
+ <div className="webBox-freeze" title={"Annotate"} style={{ background: frozen ? "lightBlue" : "gray" }} onClick={this.toggleNativeDimensions} >
+ <FontAwesomeIcon icon={faPen} size={"2x"} />
+ </div>
+ <div className="webBox-freeze" title={"Select"} style={{ background: !frozen ? "lightBlue" : "gray" }} onClick={this.toggleNativeDimensions} >
+ <FontAwesomeIcon icon={faMousePointer} size={"2x"} />
+ </div>
<input className="webpage-urlInput"
placeholder="ENTER URL"
- value={this.url}
+ value={this._url}
onChange={this.onURLChange}
onKeyDown={this.onValueKeyDown}
/>
@@ -151,9 +178,6 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
<button className="submitUrl" onClick={this.submitURL}>
SUBMIT
</button>
- <div className="switchToText" title="Convert web to text doc" onClick={this.switchToText} style={{ display: "flex", alignItems: "center", justifyContent: "center" }} >
- <FontAwesomeIcon icon={faStickyNote} size={"lg"} />
- </div>
</div>
</div>
</div>
@@ -164,7 +188,7 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
@action
toggleCollapse = () => {
- this.collapsed = !this.collapsed;
+ this._collapsed = !this._collapsed;
}
_ignore = 0;
@@ -293,7 +317,8 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
if (field instanceof HtmlField) {
view = <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />;
} else if (field instanceof WebField) {
- view = <iframe ref={this._iframeRef} src={Utils.CorsProxy(field.url.href)} style={{ position: "absolute", width: "100%", height: "100%", top: 0 }} />;
+ const url = this.layoutDoc.UseCors ? Utils.CorsProxy(field.url.href) : field.url.href;
+ view = <iframe ref={this._iframeRef} onLoad={this.iframeLoaded} src={url} style={{ position: "absolute", width: "100%", height: "100%", top: 0 }} />;
} else {
view = <iframe ref={this._iframeRef} src={"https://crossorigin.me/https://cs.brown.edu"} style={{ position: "absolute", width: "100%", height: "100%", top: 0 }} />;
}
@@ -303,56 +328,68 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
{view}
</div>;
- const decInteracting = DocumentDecorations.Instance && DocumentDecorations.Instance.Interacting;
+ const decInteracting = DocumentDecorations.Instance?.Interacting;
const frozen = !this.props.isSelected() || decInteracting;
- const classname = "webBox-cont" + (this.props.isSelected() && InkingControl.Instance.selectedTool === InkTool.None && !decInteracting ? "-interactive" : "");
- return (
- <>
- <div className={classname} >
- {content}
- </div>
- {!frozen ? (null) :
- <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer}>
- <div className="touch-iframe-overlay" onPointerDown={this.onLongPressDown} >
- <div className="indicator" ref={this._iframeIndicatorRef}></div>
- <div className="dragger" ref={this._iframeDragRef}></div>
- </div>
- </div>}
- </>);
+ return (<>
+ <div className={"webBox-cont" + (this.props.isSelected() && InkingControl.Instance.selectedTool === InkTool.None && !decInteracting ? "-interactive" : "")} >
+ {content}
+ </div>
+ {!frozen ? (null) :
+ <div className="webBox-overlay" style={{ pointerEvents: this.layoutDoc.isBackground ? undefined : "all" }}
+ onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer}>
+ <div className="touch-iframe-overlay" onPointerDown={this.onLongPressDown} >
+ <div className="indicator" ref={this._iframeIndicatorRef}></div>
+ <div className="dragger" ref={this._iframeDragRef}></div>
+ </div>
+ </div>}
+ </>);
}
+ scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.Document.scrollTop));
render() {
- const dragging = "";//</div>!SelectionManager.GetIsDragging() ? "" : "-dragging";
- return (<div className={`webBox-container${dragging}`}
+ return (<div className={`webBox-container`}
style={{
transform: `scale(${this.props.ContentScaling()})`,
width: `${100 / this.props.ContentScaling()}%`,
height: `${100 / this.props.ContentScaling()}%`,
- pointerEvents: this.props.Document.isBackground ? "none" : undefined
+ pointerEvents: this.layoutDoc.isBackground ? "none" : undefined
}} >
- <CollectionFreeFormView {...this.props}
- PanelHeight={this.props.PanelHeight}
- PanelWidth={this.props.PanelWidth}
- annotationsKey={this.annotationKey}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- focus={this.props.focus}
- isSelected={this.props.isSelected}
- isAnnotationOverlay={true}
- select={emptyFunction}
- active={this.active}
- ContentScaling={returnOne}
- whenActiveChanged={this.whenActiveChanged}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
- addDocument={this.addDocument}
- CollectionView={undefined}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
- renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
- {() => [this.content]}
- </CollectionFreeFormView>
+ {this.content}
+ <div className={"webBox-outerContent"} ref={this._outerRef}
+ style={{ pointerEvents: this.layoutDoc.isAnnotating && !this.layoutDoc.isBackground ? "all" : "none" }}
+ onWheel={e => e.stopPropagation()}
+ onScroll={e => {
+ if (this._iframeRef.current!.contentDocument!.children[0].scrollTop !== this._outerRef.current!.scrollTop) {
+ this._iframeRef.current!.contentDocument!.children[0].scrollTop = this._outerRef.current!.scrollTop;
+ }
+ //this._outerRef.current!.scrollTop !== this._scrollTop && (this._outerRef.current!.scrollTop = this._scrollTop)
+ }}>
+ <div className={"webBox-innerContent"} style={{ height: NumCast(this.layoutDoc.scrollHeight) }}>
+ <CollectionFreeFormView {...this.props}
+ PanelHeight={this.props.PanelHeight}
+ PanelWidth={this.props.PanelWidth}
+ annotationsKey={this.annotationKey}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ focus={this.props.focus}
+ setPreviewCursor={this.setPreviewCursor}
+ isSelected={this.props.isSelected}
+ isAnnotationOverlay={true}
+ select={emptyFunction}
+ active={this.active}
+ ContentScaling={returnOne}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={this.scrollXf}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
+ </CollectionFreeFormView>
+ </div>
+ </div>
</div >);
}
} \ No newline at end of file
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 71b19f3a6..672d3adb8 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -8,6 +8,7 @@ import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
import { DocumentManager } from "../../util/DocumentManager";
import PDFMenu from "./PDFMenu";
import "./Annotation.scss";
+import { DocumentView } from "../nodes/DocumentView";
interface IAnnotationProps {
anno: Doc;
@@ -97,7 +98,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
else if (e.button === 0) {
const annoGroup = await Cast(this.props.document.group, Doc);
if (annoGroup) {
- DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation), false, undefined);
+ DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation), false, undefined);
e.stopPropagation();
}
}
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 5cd2c4fe4..760f64a72 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -30,10 +30,6 @@
.page {
position: relative;
}
- .collectionfreeformview-container {
- pointer-events: none;
- }
-
.pdfViewer-text-selected {
.textLayer{
pointer-events: all;
@@ -61,12 +57,11 @@
display: inline-block;
width:100%;
pointer-events: none;
- }
- .pdfViewer-overlay-inking {
- .collectionfreeformview-container {
+ .collectionFreeFormDocumentView-container {
pointer-events: all;
}
}
+
.pdfViewer-annotationLayer {
position: absolute;
transform-origin: left top;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 720f09fe0..acaa4363e 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,37 +1,36 @@
-import { action, computed, IReactionDisposer, observable, reaction, trace, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import * as Pdfjs from "pdfjs-dist";
import "pdfjs-dist/web/pdf_viewer.css";
+import * as rp from "request-promise";
import { Dictionary } from "typescript-collections";
-import { Doc, DocListCast, FieldResult, WidthSym, Opt, HeightSym } from "../../../new_fields/Doc";
-import { Id, Copy } from "../../../new_fields/FieldSymbols";
+import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { InkTool } from "../../../new_fields/InkField";
import { List } from "../../../new_fields/List";
-import { makeInterface, createSchema } from "../../../new_fields/Schema";
-import { ScriptField, ComputedField } from "../../../new_fields/ScriptField";
-import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, returnZero } from "../../../Utils";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { Cast, NumCast } from "../../../new_fields/Types";
+import { PdfField } from "../../../new_fields/URLField";
+import { TraceMobx } from "../../../new_fields/util";
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils";
import { Docs, DocUtils } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
import { DragManager } from "../../util/DragManager";
import { CompiledScript, CompileScript } from "../../util/Scripting";
-import { Transform } from "../../util/Transform";
-import PDFMenu from "./PDFMenu";
-import "./PDFViewer.scss";
-import React = require("react");
-import * as rp from "request-promise";
-import { CollectionView } from "../collections/CollectionView";
-import Annotation from "./Annotation";
-import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { SelectionManager } from "../../util/SelectionManager";
+import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
-import { DocAnnotatableComponent } from "../DocComponent";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { documentSchema } from "../../../new_fields/documentSchemas";
+import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
+import { CollectionView } from "../collections/CollectionView";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { DocumentDecorations } from "../DocumentDecorations";
import { InkingControl } from "../InkingControl";
-import { InkTool } from "../../../new_fields/InkField";
-import { TraceMobx } from "../../../new_fields/util";
-import { PdfField } from "../../../new_fields/URLField";
-import { DocumentView } from "../nodes/DocumentView";
+import Annotation from "./Annotation";
+import PDFMenu from "./PDFMenu";
+import "./PDFViewer.scss";
+import React = require("react");
const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
const pdfjsLib = require("pdfjs-dist");
@@ -79,7 +78,7 @@ interface IViewerProps {
* Handles rendering and virtualization of the pdf
*/
@observer
-export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument>(PdfDocument) {
+export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocument>(PdfDocument) {
static _annotationStyle: any = addStyleSheet();
@observable private _pageSizes: { width: number, height: number }[] = [];
@observable private _annotations: Doc[] = [];
@@ -164,7 +163,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
}
componentWillUnmount = () => {
- this._reactionDisposer && this._reactionDisposer();
+ this._reactionDisposer?.();
this._scrollTopReactionDisposer?.();
this._annotationReactionDisposer?.();
this._filterReactionDisposer?.();
@@ -282,7 +281,6 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
if (anno.style.height) annoDoc._height = parseInt(anno.style.height);
if (anno.style.width) annoDoc._width = parseInt(anno.style.width);
annoDoc.group = mainAnnoDoc;
- annoDoc.isButton = true;
annoDocs.push(annoDoc);
anno.remove();
mainAnnoDoc = annoDoc;
@@ -419,7 +417,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
addStyleSheetRule(PDFViewer._annotationStyle, "pdfAnnotation", { "pointer-events": "none" });
if ((this.Document.scale || 1) !== 1) return;
if ((e.button !== 0 || e.altKey) && this.active(true)) {
- this._setPreviewCursor && this._setPreviewCursor(e.clientX, e.clientY, true);
+ this._setPreviewCursor?.(e.clientX, e.clientY, true);
//e.stopPropagation();
}
this._marqueeing = false;
@@ -554,7 +552,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
highlight = (color: string) => {
// creates annotation documents for current highlights
const annotationDoc = this.makeAnnotationDocument(color);
- annotationDoc && this.props.addDocument && this.props.addDocument(annotationDoc);
+ annotationDoc && this.props.addDocument?.(annotationDoc);
return annotationDoc;
}
@@ -574,7 +572,9 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
clipDoc._scrollTop = this.marqueeY();
const targetDoc = Docs.Create.TextDocument("", { _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title });
Doc.GetProto(targetDoc).data = new List<Doc>([clipDoc]);
- DocumentView.makeCustomViewClicked(targetDoc, Docs.Create.StackingDocument, "slideView", undefined);
+ clipDoc.rootDocument = targetDoc;
+ Doc.makeCustomViewClicked(targetDoc, Docs.Create.StackingDocument, "slideView", undefined);
+ targetDoc.layoutKey = "layout";
// const targetDoc = Docs.Create.TextDocument("", { _width: 200, _height: 200, title: "Note linked to " + this.props.Document.title });
// Doc.GetProto(targetDoc).snipped = this.dataDoc[this.props.fieldKey][Copy]();
// const snipLayout = Docs.Create.PdfDocument("http://www.msn.com", { title: "snippetView", isTemplateDoc: true, isTemplateForField: "snipped", _fitWidth: true, _width: this.marqueeWidth(), _height: this.marqueeHeight(), _scrollTop: this.marqueeY() });
@@ -585,6 +585,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
dragComplete: e => {
if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) {
const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
+ annotationDoc.isLinkButton = true;
if (link) link.followLinkLocation = "onRight";
}
}
@@ -607,7 +608,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
getCoverImage = () => {
- if (!this.props.Document[HeightSym]() || !this.props.Document.nativeHeight) {
+ if (!this.props.Document[HeightSym]() || !this.props.Document._nativeHeight) {
setTimeout((() => {
this.Document._height = this.Document[WidthSym]() * this._coverPath.height / this._coverPath.width;
this.Document._nativeHeight = (this.Document._nativeWidth || 0) * this._coverPath.height / this._coverPath.width;
@@ -632,7 +633,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
@computed get annotationLayer() {
TraceMobx();
- return <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.Document.nativeHeight), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
+ return <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.Document._nativeHeight), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
{this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) =>
<Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)}
</div>;
@@ -641,9 +642,10 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
panelWidth = () => (this.Document.scrollHeight || this.Document._nativeHeight || 0);
panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : (this.Document._nativeWidth || 0);
@computed get overlayLayer() {
- return <div className={`pdfViewer-overlay${InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : ""}`} id="overlay" style={{ transform: `scale(${this._zoomed})` }}>
+ return <div className={`pdfViewer-overlay${InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : ""}`} id="overlay"
+ style={{ transform: `scale(${this._zoomed})` }}>
<CollectionFreeFormView {...this.props}
- LibraryPath={this.props.ContainingCollectionView?.props.LibraryPath ?? []}
+ LibraryPath={this.props.ContainingCollectionView?.props.LibraryPath ?? emptyPath}
annotationsKey={this.annotationKey}
setPreviewCursor={this.setPreviewCursor}
PanelHeight={this.panelWidth}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 289d3a9a1..dd0cbf929 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -12,7 +12,7 @@ import { Cast, NumCast } from "../../../new_fields/Types";
import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils";
import { Transform } from "../../util/Transform";
import { CollectionViewType } from '../collections/CollectionView';
-import { DocExtendableComponent } from '../DocComponent';
+import { ViewBoxBaseComponent } from '../DocComponent';
import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView';
import { FieldView, FieldViewProps } from '../nodes/FieldView';
import "./PresElementBox.scss";
@@ -44,14 +44,14 @@ const PresDocument = makeInterface(presSchema, documentSchema);
* It involves some functionality for its buttons and options.
*/
@observer
-export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresDocument>(PresDocument) {
+export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDocument>(PresDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
_heightDisposer: IReactionDisposer | undefined;
@computed get indexInPres() { return NumCast(this.presElementDoc?.presentationIndex); }
@computed get presBoxDoc() { return Cast(this.presElementDoc?.presBox, Doc) as Doc; }
- @computed get presElementDoc() { return this.props.Document.rootDocument as Doc; }
- @computed get presLayoutDoc() { return this.props.Document; }
+ @computed get presElementDoc() { return this.rootDoc; }
+ @computed get presLayoutDoc() { return this.layoutDoc; }
@computed get targetDoc() { return this.presElementDoc?.presentationTargetDoc as Doc; }
@computed get currentIndex() { return NumCast(this.presBoxDoc?._itemIndex); }
@@ -205,7 +205,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
<strong className="presElementBox-name">
{`${this.indexInPres + 1}. ${this.targetDoc?.title}`}
</strong>
- <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => this.props.removeDocument && this.props.removeDocument(this.presElementDoc)}>X</button>
+ <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => this.props.removeDocument?.(this.presElementDoc)}>X</button>
<br />
</>}
<button title="Zoom" className={pbi + (this.presElementDoc.zoomButton ? "-selected" : "")} onPointerDown={e => e.stopPropagation()} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} /></button>
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
index 1c05ff864..662b37d77 100644
--- a/src/client/views/search/FilterBox.tsx
+++ b/src/client/views/search/FilterBox.tsx
@@ -33,7 +33,7 @@ export enum Keys {
export class FilterBox extends React.Component {
static Instance: FilterBox;
- public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+ public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
//if true, any keywords can be used. if false, all keywords are required.
//this also serves as an indicator if the word status filter is applied
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx
index 46c109934..9b7cf2fc6 100644
--- a/src/client/views/search/IconBar.tsx
+++ b/src/client/views/search/IconBar.tsx
@@ -24,9 +24,14 @@ library.add(faChartBar);
library.add(faGlobeAsia);
library.add(faBan);
+export interface IconBarProps {
+ setIcons: (icons: string[]) => void;
+}
+
+
@observer
-export class IconBar extends React.Component {
- public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+export class IconBar extends React.Component<IconBarProps> {
+ public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
@observable private _icons: string[] = this._allIcons;
@@ -38,7 +43,10 @@ export class IconBar extends React.Component {
@observable public _select: number = 0;
@action.bound
- updateIcon(newArray: string[]) { this._icons = newArray; }
+ updateIcon(newArray: string[]) {
+ this._icons = newArray;
+ this.props.setIcons?.(this._icons);
+ }
@action.bound
getIcons(): string[] { return this._icons; }
diff --git a/src/client/views/search/IconButton.tsx b/src/client/views/search/IconButton.tsx
index 4f94139d9..52641c543 100644
--- a/src/client/views/search/IconButton.tsx
+++ b/src/client/views/search/IconButton.tsx
@@ -86,15 +86,13 @@ export class IconButton extends React.Component<IconButtonProps>{
return faMusic;
case (DocumentType.COL):
return faObjectGroup;
- case (DocumentType.HIST):
- return faChartBar;
case (DocumentType.IMG):
return faImage;
case (DocumentType.LINK):
return faLink;
case (DocumentType.PDF):
return faFilePdf;
- case (DocumentType.TEXT):
+ case (DocumentType.RTF):
return faStickyNote;
case (DocumentType.VID):
return faVideo;
@@ -158,15 +156,13 @@ export class IconButton extends React.Component<IconButtonProps>{
return (<FontAwesomeIcon className="fontawesome-icon" icon={faMusic} />);
case (DocumentType.COL):
return (<FontAwesomeIcon className="fontawesome-icon" icon={faObjectGroup} />);
- case (DocumentType.HIST):
- return (<FontAwesomeIcon className="fontawesome-icon" icon={faChartBar} />);
case (DocumentType.IMG):
return (<FontAwesomeIcon className="fontawesome-icon" icon={faImage} />);
case (DocumentType.LINK):
return (<FontAwesomeIcon className="fontawesome-icon" icon={faLink} />);
case (DocumentType.PDF):
return (<FontAwesomeIcon className="fontawesome-icon" icon={faFilePdf} />);
- case (DocumentType.TEXT):
+ case (DocumentType.RTF):
return (<FontAwesomeIcon className="fontawesome-icon" icon={faStickyNote} />);
case (DocumentType.VID):
return (<FontAwesomeIcon className="fontawesome-icon" icon={faVideo} />);
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index f0223ca76..bb62113a1 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -9,7 +9,8 @@
position: absolute;
font-size: 10px;
line-height: 1;
- overflow: auto;
+ overflow-y: auto;
+ overflow-x: visible;
background: lightgrey,
}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 67af661c9..e41b725b1 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -19,13 +19,17 @@ import { FieldView } from '../nodes/FieldView';
import { DocumentType } from "../../documents/DocumentTypes";
import { DocumentView } from '../nodes/DocumentView';
import { SelectionManager } from '../../util/SelectionManager';
+import { listSpec } from '../../../new_fields/Schema';
library.add(faTimes);
export interface SearchProps {
id: string;
- searchQuery?: string;
+ searchQuery: string;
filterQquery?: string;
+ setSearchQuery: (q: string) => {};
+ searchFileTypes: string[];
+ setSearchFileTypes: (types: string[]) => {};
}
export enum Keys {
@@ -37,7 +41,8 @@ export enum Keys {
@observer
export class SearchBox extends React.Component<SearchProps> {
- @observable private _searchString: string = "";
+ private get _searchString() { return this.props.searchQuery; }
+ private set _searchString(value) { this.props.setSearchQuery(value); }
@observable private _resultsOpen: boolean = false;
@observable private _searchbarOpen: boolean = false;
@observable private _results: [Doc, string[], string[]][] = [];
@@ -72,20 +77,16 @@ export class SearchBox extends React.Component<SearchProps> {
this.resultsScrolled = this.resultsScrolled.bind(this);
}
- componentDidMount = () => {
+ componentDidMount = action(() => {
if (this.inputRef.current) {
this.inputRef.current.focus();
- runInAction(() => this._searchbarOpen = true);
+ this._searchbarOpen = true;
}
- if (this.props.searchQuery && this.props.filterQquery) {
- console.log(this.props.searchQuery);
- const sq = this.props.searchQuery;
- runInAction(() => {
- this._searchString = sq;
- this.submitSearch();
- });
+ if (this.props.searchQuery) { // bcz: why was this here? } && this.props.filterQquery) {
+ this._searchString = this.props.searchQuery;
+ this.submitSearch();
}
- }
+ });
@action
@@ -128,12 +129,15 @@ export class SearchBox extends React.Component<SearchProps> {
}
}
- public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
+ public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
//if true, any keywords can be used. if false, all keywords are required.
//this also serves as an indicator if the word status filter is applied
@observable private _filterOpen: boolean = false;
//if icons = all icons, then no icon filter is applied
- @observable private _icons: string[] = this._allIcons;
+ get _icons() { return this.props.searchFileTypes; }
+ set _icons(value) {
+ this.props.setSearchFileTypes(value);
+ }
//if all of these are true, no key filter is applied
@observable private _titleFieldStatus: boolean = true;
@observable private _authorFieldStatus: boolean = true;
@@ -167,15 +171,7 @@ export class SearchBox extends React.Component<SearchProps> {
}
basicRequireWords(query: string): string {
- const oldWords = query.split(" ");
- const newWords: string[] = [];
- oldWords.forEach(word => {
- const newWrd = "+" + word;
- newWords.push(newWrd);
- });
- query = newWords.join(" ");
-
- return query;
+ return query.split(" ").join(" + ").replace(/ + /, "");
}
@action
@@ -214,12 +210,6 @@ export class SearchBox extends React.Component<SearchProps> {
return this._icons.length === this._allIcons.length ? undefined : this._icons;
}
- @action.bound
- updateIcon(newArray: string[]) { this._icons = newArray; }
-
- @action.bound
- getIcons(): string[] { return this._icons; }
-
//TODO: basically all of this
//gets all of the collections of all the docviews that are selected
//if a collection is the only thing selected, search only in that collection (not its container)
@@ -316,9 +306,13 @@ export class SearchBox extends React.Component<SearchProps> {
private get filterQuery() {
const types = this.filterTypes;
- const includeDeleted = this.getDataStatus() ? "" : " AND NOT deleted_b:true";
- const includeIcons = this.getDataStatus() ? "" : " AND NOT type_t:fonticonbox";
- return "NOT baseProto_b:true" + includeDeleted + includeIcons + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : "");
+ const baseExpr = "NOT baseProto_b:true";
+ const includeDeleted = this.getDataStatus() ? "" : " NOT deleted_b:true";
+ const includeIcons = this.getDataStatus() ? "" : " NOT type_t:fonticonbox";
+ const typeExpr = !types ? "" : ` (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})`;
+ // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello
+ const query = [baseExpr, includeDeleted, includeIcons, typeExpr].join(" AND ").replace(/AND $/, "");
+ return query;
}
getDataStatus() { return this._deletedDocsStatus; }
@@ -652,7 +646,9 @@ export class SearchBox extends React.Component<SearchProps> {
<button className="filter-item" style={this._nodeStatus ? { background: "#aaaaa3" } : {}} onClick={this.handleNodeChange}>Nodes</button>
</div>
<div id={`node${this.props.id}`} className="filter-body" style={this._nodeStatus ? { borderTop: "grey 1px solid" } : { borderTop: "0px" }}>
- <IconBar />
+ <IconBar setIcons={(icons: string[]) => {
+ this._icons = icons;
+ }} />
</div>
<div className="filter-key" id={`key${this.props.id}`} style={this._keyStatus ? { borderTop: "grey 1px solid" } : { borderTop: "0px" }}>
<div className="filter-keybar">
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 0d77026ad..fe2000700 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -68,7 +68,7 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
getOnClick({ col, target }: { col: Doc, target: Doc }) {
return () => {
col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
- if (NumCast(col._viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
+ if (col._viewType === CollectionViewType.Freeform) {
const newPanX = NumCast(target.x) + NumCast(target._width) / 2;
const newPanY = NumCast(target.y) + NumCast(target._height) / 2;
col._panX = newPanX;
@@ -178,14 +178,13 @@ export class SearchItem extends React.Component<SearchItemProps> {
}
const button = layoutresult.indexOf(DocumentType.PDF) !== -1 ? faFilePdf :
layoutresult.indexOf(DocumentType.IMG) !== -1 ? faImage :
- layoutresult.indexOf(DocumentType.TEXT) !== -1 ? faStickyNote :
+ layoutresult.indexOf(DocumentType.RTF) !== -1 ? faStickyNote :
layoutresult.indexOf(DocumentType.VID) !== -1 ? faFilm :
layoutresult.indexOf(DocumentType.COL) !== -1 ? faObjectGroup :
layoutresult.indexOf(DocumentType.AUDIO) !== -1 ? faMusic :
layoutresult.indexOf(DocumentType.LINK) !== -1 ? faLink :
- layoutresult.indexOf(DocumentType.HIST) !== -1 ? faChartBar :
- layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia :
- faCaretUp;
+ layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia :
+ faCaretUp;
return <div onClick={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
<FontAwesomeIcon icon={button} size="2x" />
</div>;
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 1d52ba38f..2ea011316 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -3,7 +3,7 @@ import React = require("react");
import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView";
import { FieldViewProps, FieldView } from "../nodes/FieldView";
import { observable, action } from "mobx";
-import { DocumentDecorations, CloseCall } from "../DocumentDecorations";
+import { DocumentDecorations } from "../DocumentDecorations";
import { InkingControl } from "../InkingControl";
import "../../views/nodes/WebBox.scss";
import "./DashWebRTCVideo.scss";
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 5903a2ce9..295e82142 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -67,7 +67,7 @@ class Uploader extends React.Component {
const field = await DocServer.GetRefField(res);
let pending: Opt<Doc>;
if (field instanceof Doc) {
- pending = await Cast(field.optionalRightCollection, Doc);
+ pending = await Cast(field.rightSidebarCollection, Doc);
}
if (pending) {
this.status = "has pending docs";
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index c87ac719c..73ebbb303 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -1,51 +1,38 @@
import React = require('react');
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faEraser, faHighlighter, faLongArrowAltLeft, faMousePointer, faPenNib } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
-import { computed, action, observable } from 'mobx';
-import { CurrentUserUtils } from '../server/authentication/models/current_user_utils';
-import { FieldValue, Cast, StrCast } from '../new_fields/Types';
-import { Doc, DocListCast } from '../new_fields/Doc';
+import { DocServer } from '../client/DocServer';
import { Docs } from '../client/documents/Documents';
-import { CollectionView } from '../client/views/collections/CollectionView';
-import { DocumentView } from '../client/views/nodes/DocumentView';
-import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, returnZero } from '../Utils';
-import { Transform } from '../client/util/Transform';
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck, faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
+import { DocumentManager } from '../client/util/DocumentManager';
+import RichTextMenu from '../client/util/RichTextMenu';
import { Scripting } from '../client/util/Scripting';
-import { CollectionFreeFormView } from '../client/views/collections/collectionFreeForm/CollectionFreeFormView';
+import { Transform } from '../client/util/Transform';
+import { CollectionView } from '../client/views/collections/CollectionView';
+import { DocumentDecorations } from '../client/views/DocumentDecorations';
import GestureOverlay from '../client/views/GestureOverlay';
import { InkingControl } from '../client/views/InkingControl';
-import { InkTool } from '../new_fields/InkField';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import "./MobileInterface.scss";
-import { SelectionManager } from '../client/util/SelectionManager';
-import { DateField } from '../new_fields/DateField';
-import { GestureUtils } from '../pen-gestures/GestureUtils';
-import { DocServer } from '../client/DocServer';
-import { DocumentDecorations } from '../client/views/DocumentDecorations';
-import { OverlayView } from '../client/views/OverlayView';
-import { DictationOverlay } from '../client/views/DictationOverlay';
-import SharingManager from '../client/util/SharingManager';
-import { PreviewCursor } from '../client/views/PreviewCursor';
-import { ContextMenu } from '../client/views/ContextMenu';
+import { DocumentView } from '../client/views/nodes/DocumentView';
import { RadialMenu } from '../client/views/nodes/RadialMenu';
-import PDFMenu from '../client/views/pdf/PDFMenu';
-import MarqueeOptionsMenu from '../client/views/collections/collectionFreeForm/MarqueeOptionsMenu';
-import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationManager';
-import { listSpec } from '../new_fields/Schema';
+import { PreviewCursor } from '../client/views/PreviewCursor';
+import { Doc, DocListCast, FieldResult } from '../new_fields/Doc';
import { Id } from '../new_fields/FieldSymbols';
-import { DocumentManager } from '../client/util/DocumentManager';
-import RichTextMenu from '../client/util/RichTextMenu';
+import { InkTool } from '../new_fields/InkField';
+import { listSpec } from '../new_fields/Schema';
+import { Cast, FieldValue } from '../new_fields/Types';
import { WebField } from "../new_fields/URLField";
-import { FieldResult } from "../new_fields/Doc";
-import { List } from '../new_fields/List';
+import { CurrentUserUtils } from '../server/authentication/models/current_user_utils';
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from '../Utils';
+import "./MobileInterface.scss";
library.add(faLongArrowAltLeft);
@observer
export default class MobileInterface extends React.Component {
@observable static Instance: MobileInterface;
- @computed private get userDoc() { return CurrentUserUtils.UserDocument; }
+ @computed private get userDoc() { return Doc.UserDoc(); }
@computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; }
// @observable private currentView: "main" | "ink" | "upload" = "main";
private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc);
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index d381447c5..337274774 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -14,10 +14,11 @@ import { PrefetchProxy, ProxyField } from "./Proxy";
import { FieldId, RefField } from "./RefField";
import { RichTextField } from "./RichTextField";
import { listSpec } from "./Schema";
-import { ComputedField } from "./ScriptField";
+import { ComputedField, ScriptField } from "./ScriptField";
import { Cast, FieldValue, NumCast, StrCast, ToConstructor, ScriptCast } from "./Types";
import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
-import { Docs } from "../client/documents/Documents";
+import { Docs, DocumentOptions } from "../client/documents/Documents";
+import { PdfField, VideoField, AudioField, ImageField } from "./URLField";
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -80,7 +81,7 @@ export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
}
export async function DocCastAsync(field: FieldResult): Promise<Opt<Doc>> {
- return await Cast(field, Doc);
+ return Cast(field, Doc);
}
export function DocListCast(field: FieldResult): Doc[] {
@@ -565,8 +566,9 @@ export namespace Doc {
} else if (cfield instanceof ComputedField) {
copy[key] = ComputedField.MakeFunction(cfield.script.originalScript);
} else if (field instanceof ObjectField) {
- copy[key] = key.includes("layout[") && doc[key] instanceof Doc ? Doc.MakeCopy(doc[key] as Doc, false) :
- doc[key] instanceof Doc ? doc[key] : ObjectField.MakeCopy(field);
+ copy[key] = doc[key] instanceof Doc ?
+ key.includes("layout[") ? Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields
+ ObjectField.MakeCopy(field);
} else if (field instanceof Promise) {
debugger; //This shouldn't happend...
} else {
@@ -578,6 +580,44 @@ export namespace Doc {
return copy;
}
+ export function MakeClone(doc: Doc, cloneProto: boolean = true): Doc {
+ const copy = new Doc(undefined, true);
+ const exclude = Cast(doc.excludeFields, listSpec("string"), []);
+ Object.keys(doc).forEach(key => {
+ if (exclude.includes(key)) return;
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key]));
+ const field = ProxyField.WithoutProxy(() => doc[key]);
+ if (key === "proto" && cloneProto) {
+ if (doc[key] instanceof Doc) {
+ copy[key] = Doc.MakeClone(doc[key]!, false);
+ }
+ } else {
+ if (field instanceof RefField) {
+ copy[key] = field;
+ } else if (cfield instanceof ComputedField) {
+ copy[key] = ComputedField.MakeFunction(cfield.script.originalScript);
+ } else if (field instanceof ObjectField) {
+ const list = Cast(doc[key], listSpec(Doc));
+ if (list !== undefined && !(list instanceof Promise)) {
+ copy[key] = new List<Doc>(list.filter(d => d instanceof Doc).map(d => Doc.MakeCopy(d as Doc, false)));
+ } else {
+ copy[key] = doc[key] instanceof Doc ?
+ key.includes("layout[") ?
+ Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields
+ ObjectField.MakeCopy(field);
+ }
+ } else if (field instanceof Promise) {
+ debugger; //This shouldn't happend...
+ } else {
+ copy[key] = field;
+ }
+ }
+ });
+ Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true);
+ copy.cloneOf = doc;
+ return copy;
+ }
+
export function MakeDelegate(doc: Doc, id?: string, title?: string): Doc;
export function MakeDelegate(doc: Opt<Doc>, id?: string, title?: string): Opt<Doc>;
export function MakeDelegate(doc: Opt<Doc>, id?: string, title?: string): Opt<Doc> {
@@ -603,14 +643,6 @@ export namespace Doc {
return undefined;
}
export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) {
- if (!templateDoc) {
- target.layout = undefined;
- target._nativeWidth = undefined;
- target._nativeHeight = undefined;
- target.type = undefined;
- return;
- }
-
if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) {
if (target.resolvedDataDoc) {
target[targetKey] = new PrefetchProxy(templateDoc);
@@ -645,11 +677,12 @@ export namespace Doc {
Cast(templateFieldValue, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc));
(Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateFieldValue));
}
- if (templateCaptionValue instanceof RichTextField && (templateCaptionValue.Text || templateCaptionValue.Data.toString().includes("dashField"))) {
- templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`, { this: Doc.name });
+ // copy the textTemplates from 'this' (not 'self') because the layout contains the template info, not the original doc
+ if (templateCaptionValue instanceof RichTextField && !templateCaptionValue.Empty()) {
+ templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`);
}
- if (templateFieldValue instanceof RichTextField && (templateFieldValue.Text || templateFieldValue.Data.toString().includes("dashField"))) {
- templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name });
+ if (templateFieldValue instanceof RichTextField && !templateFieldValue.Empty()) {
+ templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`);
}
// get the layout string that the template uses to specify its layout
@@ -713,7 +746,7 @@ export namespace Doc {
export function SetUserDoc(doc: Doc) { manager._user_doc = doc; }
export function IsBrushed(doc: Doc) {
return computedFn(function IsBrushed(doc: Doc) {
- return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
+ return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
})(doc);
}
// don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
@@ -872,6 +905,102 @@ export namespace Doc {
return id;
}
+ export function isDocPinned(doc: Doc) {
+ //add this new doc to props.Document
+ const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
+ if (curPres) {
+ return DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1;
+ }
+ return false;
+ }
+
+ // applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView)
+ export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) {
+ const batch = UndoManager.StartBatch("makeCustomViewClicked");
+ runInAction(() => {
+ doc.layoutKey = "layout_" + templateSignature;
+ if (doc[doc.layoutKey] === undefined) {
+ createCustomView(doc, creator, templateSignature, docLayoutTemplate);
+ }
+ });
+ batch.end();
+ }
+ export function findTemplate(templateName: string, type: string, signature: string) {
+ let docLayoutTemplate: Opt<Doc>;
+ const iconViews = DocListCast(Cast(Doc.UserDoc()["template-icons"], Doc, null)?.data);
+ const templBtns = DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data);
+ const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)?.data);
+ const clickFuncs = DocListCast(Cast(Doc.UserDoc().clickFuncs, Doc, null)?.data);
+ const allTemplates = iconViews.concat(templBtns).concat(noteTypes).concat(clickFuncs).map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc);
+ // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized
+ // first try to find a template that matches the specific document type (<typeName>_<templateName>). otherwise, fallback to a general match on <templateName>
+ !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName + "_" + type && (docLayoutTemplate = tempDoc));
+ !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc));
+ return docLayoutTemplate;
+ }
+ export function createCustomView(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) {
+ const templateName = templateSignature.replace(/\(.*\)/, "");
+ docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.type), templateSignature);
+
+ const customName = "layout_" + templateSignature;
+ const _width = NumCast(doc._width);
+ const _height = NumCast(doc._height);
+ const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false };
+
+ let fieldTemplate: Opt<Doc>;
+ if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
+ fieldTemplate = Docs.Create.TextDocument("", options);
+ } else if (doc.data instanceof PdfField) {
+ fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
+ } else if (doc.data instanceof VideoField) {
+ fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
+ } else if (doc.data instanceof AudioField) {
+ fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
+ } else if (doc.data instanceof ImageField) {
+ fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
+ }
+ const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
+
+ fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
+ docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+ }
+ export function makeCustomView(doc: Doc, custom: boolean, layout: string) {
+ Doc.setNativeView(doc);
+ if (custom) {
+ makeCustomViewClicked(doc, Docs.Create.StackingDocument, layout, undefined);
+ }
+ }
+ export function iconify(doc: Doc) {
+ const layoutKey = Cast(doc.layoutKey, "string", null);
+ Doc.makeCustomViewClicked(doc, Docs.Create.StackingDocument, "icon", undefined);
+ if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", "");
+ }
+
+ export function pileup(selected: Doc[], x: number, y: number) {
+ const newCollection = Docs.Create.PileDocument(selected, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true });
+ let w = 0, h = 0;
+ selected.forEach((d, i) => {
+ Doc.iconify(d);
+ w = Math.max(d[WidthSym](), w);
+ h = Math.max(d[HeightSym](), h);
+ });
+ h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable
+ selected.forEach((d, i) => {
+ d.x = Math.cos(Math.PI * 2 * i / selected.length) * 10 - w / 2;
+ d.y = Math.sin(Math.PI * 2 * i / selected.length) * 10 - h / 2;
+ d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+ });
+ newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55;
+ newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55;
+ newCollection._width = newCollection._height = 110;
+ //newCollection.borderRounding = "40px";
+ newCollection._jitterRotation = 10;
+ newCollection._backgroundColor = "gray";
+ newCollection.overflow = "visible";
+ return newCollection;
+ }
+
+
export async function addFieldEnumerations(doc: Opt<Doc>, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) {
let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey);
if (!(optionsCollection instanceof Doc)) {
@@ -899,12 +1028,13 @@ export namespace Doc {
Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; });
Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); });
-Scripting.addGlobal(function getDocTemplate(doc?: any) { Doc.getDocTemplate(doc); });
+Scripting.addGlobal(function getDocTemplate(doc?: any) { return Doc.getDocTemplate(doc); });
Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); });
Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); });
Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); });
Scripting.addGlobal(function aliasDocs(field: any) { return Doc.aliasDocs(field); });
Scripting.addGlobal(function docList(field: any) { return DocListCast(field); });
+Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); });
Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); });
Scripting.addGlobal(function deiconifyView(doc: any) { Doc.deiconifyView(doc); });
Scripting.addGlobal(function undo() { return UndoManager.Undo(); });
@@ -912,14 +1042,14 @@ Scripting.addGlobal(function redo() { return UndoManager.Redo(); });
Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; });
Scripting.addGlobal(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); });
Scripting.addGlobal(function docCast(doc: FieldResult): any { return DocCastAsync(doc); });
-Scripting.addGlobal(function curPresentationItem() {
- const curPres = Doc.UserDoc().curPresentation as Doc;
+Scripting.addGlobal(function activePresentationItem() {
+ const curPres = Doc.UserDoc().activePresentation as Doc;
return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)];
});
-Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); });
+Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().activeSelection = new List([doc]); });
Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) {
- const docs = DocListCast(Doc.UserDoc().SelectedDocs).
- filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCUMENT && d.type !== DocumentType.KVP &&
+ const docs = DocListCast(Doc.UserDoc().activeSelection).
+ filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCHOLDER && d.type !== DocumentType.KVP &&
(!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null)));
return docs.length ? new List(docs) : prevValue;
});
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index ad4a5a252..5cf0e0cc3 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,9 +4,6 @@ import { Deserializable } from "../client/util/SerializationHelper";
import { Copy, ToScriptString, ToPlainText, ToString } from "./FieldSymbols";
import { scriptingGlobal } from "../client/util/Scripting";
-const delimiter = "\n";
-const joiner = "";
-
@scriptingGlobal
@Deserializable("RichTextField")
export class RichTextField extends ObjectField {
@@ -22,6 +19,10 @@ export class RichTextField extends ObjectField {
this.Text = text;
}
+ Empty() {
+ return !(this.Text || this.Data.toString().includes("dashField"));
+ }
+
[Copy]() {
return new RichTextField(this.Data, this.Text);
}
diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts
index 7b4a50f59..c9960e783 100644
--- a/src/new_fields/RichTextUtils.ts
+++ b/src/new_fields/RichTextUtils.ts
@@ -1,23 +1,21 @@
-import { EditorState, Transaction, TextSelection } from "prosemirror-state";
-import { Node, Fragment, Mark } from "prosemirror-model";
-import { RichTextField } from "./RichTextField";
+import { AssertionError } from "assert";
import { docs_v1 } from "googleapis";
-import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils";
-import { FormattedTextBox } from "../client/views/nodes/FormattedTextBox";
-import { Opt, Doc } from "./Doc";
-import Color = require('color');
+import { Fragment, Mark, Node } from "prosemirror-model";
import { sinkListItem } from "prosemirror-schema-list";
import { Utils } from "../Utils";
import { Docs } from "../client/documents/Documents";
import { schema } from "../client/util/schema_rts";
import { GooglePhotos } from "../client/apis/google_docs/GooglePhotosClientUtils";
import { DocServer } from "../client/DocServer";
-import { Cast, StrCast } from "./Types";
-import { Id } from "./FieldSymbols";
-import { DocumentView } from "../client/views/nodes/DocumentView";
-import { AssertionError } from "assert";
import { Networking } from "../client/Network";
-import { extname } from "path";
+import { FormattedTextBox } from "../client/views/nodes/FormattedTextBox";
+import { Doc, Opt } from "./Doc";
+import { Id } from "./FieldSymbols";
+import { RichTextField } from "./RichTextField";
+import { Cast, StrCast } from "./Types";
+import Color = require('color');
+import { EditorState, TextSelection, Transaction } from "prosemirror-state";
+import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils";
export namespace RichTextUtils {
@@ -274,7 +272,7 @@ export namespace RichTextUtils {
const backingDocId = StrCast(textNote[guid]);
if (!backingDocId) {
const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 });
- DocumentView.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument);
+ Doc.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument);
docid = backingDoc[Id];
textNote[guid] = docid;
} else {
@@ -403,7 +401,7 @@ export namespace RichTextUtils {
let exported = (await Cast(linkDoc.anchor2, Doc))!;
if (!exported.customLayout) {
exported = Doc.MakeAlias(exported);
- DocumentView.makeCustomViewClicked(exported, Docs.Create.FreeformDocument);
+ Doc.makeCustomViewClicked(exported, Docs.Create.FreeformDocument);
linkDoc.anchor2 = exported;
}
url = Utils.shareUrl(exported[Id]);
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 4a3119aeb..8d0ddf94c 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -98,12 +98,15 @@ export class ScriptField extends ObjectField {
[Copy](): ObjectField {
return new ScriptField(this.script);
}
+ toString() {
+ return `${this.script.originalScript}`;
+ }
[ToScriptString]() {
return "script field";
}
[ToString]() {
- return "script field";
+ return this.script.originalScript;
}
public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) {
const compiled = CompileScript(script, {
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 0ca35fab2..aa44cefa0 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -87,6 +87,7 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false)
export function DateCast(field: FieldResult) {
return Cast(field, DateField, null);
}
+
export function ScriptCast(field: FieldResult) {
return Cast(field, ScriptField, null);
}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 03519cb94..7a0be8863 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -8,7 +8,8 @@ export const documentSchema = createSchema({
layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below
layoutKey: "string", // holds the field key for the field that actually holds the current lyoat
title: "string", // document title (can be on either data document or layout)
- dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy")
+ dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move")
+ targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move")
childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy")
_autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents
_nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set
@@ -29,10 +30,13 @@ export const documentSchema = createSchema({
_replacedChrome: "string", // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's.
_chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed'
_freezeChildDimensions: "boolean", // freezes child document dimensions (e.g., used by time/pivot view to make sure all children will be scaled to fit their display rectangle)
+ _fontSize: "number",
+ _fontFamily: "string",
isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations
color: "string", // foreground color of document
backgroundColor: "string", // background color of document
opacity: "number", // opacity of document
+ overflow: "string", // sets overflow behvavior for CollectionFreeForm views
creationDate: DateField, // when the document was created
links: listSpec(Doc), // computed (readonly) list of links associated with this document
onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
@@ -53,15 +57,17 @@ export const documentSchema = createSchema({
inOverlay: "boolean", // whether the document is rendered in an OverlayView which handles selection/dragging differently
borderRounding: "string", // border radius rounding of document
heading: "number", // the logical layout 'heading' of this document (used by rule provider to stylize h1 header elements, from h2, etc)
- isButton: "boolean", // whether document functions as a button (overiding native interactions of its content)
+ isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked
ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events)
scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc.
+ scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that )
+ scrollTop: "number", // scroll position of a scrollable document (pdf, text, web)
strokeWidth: "number",
fontSize: "string",
fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view
letterSpacing: "string",
textTransform: "string",
- childTemplateName: "string" // the name of a template to use to override the layoutKey when rendering a document in DocumentBox
+ childTemplateName: "string" // the name of a template to use to override the layoutKey when rendering a document in DocHolderBox
});
export const positionSchema = createSchema({
@@ -73,7 +79,7 @@ export const positionSchema = createSchema({
export const collectionSchema = createSchema({
childLayout: Doc, // layout template for children of a collecion
- childDetailed: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field)
+ childDetailView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to use this field)
onChildClick: ScriptField, // script to run for each child when its clicked
onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view
});
diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts
index f14c573c3..b8a82ab4d 100644
--- a/src/pen-gestures/GestureUtils.ts
+++ b/src/pen-gestures/GestureUtils.ts
@@ -43,12 +43,4 @@ export namespace GestureUtils {
}
export const GestureRecognizer = new NDollarRecognizer(false);
-
- export function GestureOptions(name: string, gestureData?: any): (params: {}) => any {
- switch (name) {
- case Gestures.Box:
- break;
- }
- throw new Error("This means that you're trying to do something with the gesture that hasn't been defined yet. Define it in GestureUtils.ts");
- }
} \ No newline at end of file
diff --git a/src/pen-gestures/ndollar.ts b/src/pen-gestures/ndollar.ts
index bb92f62e1..e5740d105 100644
--- a/src/pen-gestures/ndollar.ts
+++ b/src/pen-gestures/ndollar.ts
@@ -161,6 +161,9 @@ const AngleSimilarityThreshold = Deg2Rad(30.0);
export class NDollarRecognizer {
public Multistrokes: Multistroke[];
+ /**
+ * @IMPORTANT - IF YOU'RE ADDING A NEW GESTURE, BE SURE TO INCREMENT THE NumMultiStrokes CONST RIGHT ABOVE THIS CLASS.
+ */
constructor(useBoundedRotationInvariance: boolean) // constructor
{
//
diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts
index e7a0d367d..713207a07 100644
--- a/src/scraping/buxton/final/BuxtonImporter.ts
+++ b/src/scraping/buxton/final/BuxtonImporter.ts
@@ -16,6 +16,7 @@ interface DocumentContents {
hyperlinks: string[];
captions: string[];
embeddedFileNames: string[];
+ longDescription: string;
}
export interface DeviceDocument {
@@ -186,10 +187,6 @@ const RegexMap = new Map<keyof DeviceDocument, Processor<any>>([
exp: /Short Description:\s+(.*)Bill Buxton[’']s Notes/,
transformer: Utilities.correctSentences
}],
- ["longDescription", {
- exp: /Bill Buxton[’']s Notes(.*)Device Details/,
- transformer: Utilities.correctSentences
- }],
]);
const sourceDir = path.resolve(__dirname, "source");
@@ -267,7 +264,12 @@ async function extractFileContents(pathToDocument: string): Promise<DocumentCont
const body = document.root()?.text() ?? "No body found. Check the import script's XML parser.";
const captions: string[] = [];
const embeddedFileNames: string[] = [];
- const captionTargets = document.find(tableCellXPath).map(node => node.text());
+ const captionTargets = document.find(tableCellXPath).map(node => node.text().trim());
+
+ const paragraphs = document.find('//*[name()="w:p"]').map(node => Utilities.correctSentences(node.text()).transformed!);
+ const start = paragraphs.indexOf(paragraphs.find(el => /Bill Buxton[’']s Notes/.test(el))!) + 1;
+ const end = paragraphs.indexOf("Device Details");
+ const longDescription = paragraphs.slice(start, end).filter(paragraph => paragraph.length).join("\n\n");
const { length } = captionTargets;
strictEqual(length > 3, true, "No captions written.");
@@ -275,8 +277,8 @@ async function extractFileContents(pathToDocument: string): Promise<DocumentCont
for (let i = 3; i < captionTargets.length; i += 3) {
const row = captionTargets.slice(i, i + 3);
- captions.push(row[1]);
- embeddedFileNames.push(row[2]);
+ embeddedFileNames.push(row[1]);
+ captions.push(row[2]);
}
// extract all hyperlinks embedded in the document
@@ -290,7 +292,7 @@ async function extractFileContents(pathToDocument: string): Promise<DocumentCont
zip.close();
- return { body, imageData, captions, embeddedFileNames, hyperlinks };
+ return { body, longDescription, imageData, captions, embeddedFileNames, hyperlinks };
}
const imageEntry = /^word\/media\/\w+\.(jpeg|jpg|png|gif)/;
@@ -306,26 +308,30 @@ async function writeImages(zip: any): Promise<ImageData[]> {
const imageEntries = allEntries.filter(name => imageEntry.test(name));
const imageUrls: ImageData[] = [];
- for (const mediaPath of imageEntries) {
- const getImageStream = () => new Promise<Readable>((resolve, reject) => {
- zip.stream(mediaPath, (error: any, stream: any) => error ? reject(error) : resolve(stream));
- });
+ const valid: any[] = [];
+ const getImageStream = (mediaPath: string) => new Promise<Readable>((resolve, reject) => {
+ zip.stream(mediaPath, (error: any, stream: any) => error ? reject(error) : resolve(stream));
+ });
+
+ for (const mediaPath of imageEntries) {
const { width, height, type } = await new Promise<Dimensions>(async resolve => {
const sizeStream = (createImageSizeStream() as PassThrough).on('size', (dimensions: Dimensions) => {
readStream.destroy();
resolve(dimensions);
}).on("error", () => readStream.destroy());
- const readStream = await getImageStream();
+ const readStream = await getImageStream(mediaPath);
readStream.pipe(sizeStream);
});
- if (Math.abs(width - height) < 10) {
- continue;
+
+ if (Math.abs(width - height) > 10) {
+ valid.push({ width, height, type, mediaPath });
}
+ }
+ for (const { type, width, height, mediaPath } of valid) {
const generatedFileName = `upload_${Utils.GenerateGuid()}.${type.toLowerCase()}`;
- await DashUploadUtils.outputResizedImages(getImageStream, generatedFileName, imageDir);
-
+ await DashUploadUtils.outputResizedImages(() => getImageStream(mediaPath), generatedFileName, imageDir);
imageUrls.push({
url: `/files/images/buxton/${generatedFileName}`,
nativeWidth: width,
@@ -337,11 +343,12 @@ async function writeImages(zip: any): Promise<ImageData[]> {
}
function analyze(fileName: string, contents: DocumentContents): AnalysisResult {
- const { body, imageData, captions, hyperlinks, embeddedFileNames } = contents;
+ const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescription } = contents;
const device: any = {
hyperlinks,
captions,
embeddedFileNames,
+ longDescription,
__images: imageData
};
const errors: { [key: string]: string } = { fileName };
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
index 5f7d1cf6d..753c31fcf 100644
--- a/src/server/ApiManagers/SearchManager.ts
+++ b/src/server/ApiManagers/SearchManager.ts
@@ -1,18 +1,14 @@
-import ApiManager, { Registration } from "./ApiManager";
-import { Method } from "../RouteManager";
-import { Search } from "../Search";
-const findInFiles = require('find-in-files');
+import { exec } from "child_process";
+import { cyan, green, red, yellow } from "colors";
import * as path from 'path';
-import { pathToDirectory, Directory } from "./UploadManager";
-import { red, cyan, yellow, green } from "colors";
-import RouteSubscriber from "../RouteSubscriber";
-import { exec, execSync } from "child_process";
-import { onWindows } from "..";
-import { get } from "request-promise";
import { log_execution } from "../ActionUtilities";
import { Database } from "../database";
-import rimraf = require("rimraf");
-import { mkdirSync, chmod, chmodSync } from "fs";
+import { Method } from "../RouteManager";
+import RouteSubscriber from "../RouteSubscriber";
+import { Search } from "../Search";
+import ApiManager, { Registration } from "./ApiManager";
+import { Directory, pathToDirectory } from "./UploadManager";
+const findInFiles = require('find-in-files');
export class SearchManager extends ApiManager {
@@ -48,8 +44,10 @@ export class SearchManager extends ApiManager {
res.send([]);
return;
}
- const results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, pathToDirectory(Directory.text), ".txt$");
const resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] };
+ let results: any;
+ const dir = pathToDirectory(Directory.text);
+ results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, dir, ".txt$");
for (const result in results) {
resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, ""));
resObj.lines.push(results[result].line);
diff --git a/src/server/ApiManagers/UtilManager.ts b/src/server/ApiManagers/UtilManager.ts
index ad8119bf4..aec523cd0 100644
--- a/src/server/ApiManagers/UtilManager.ts
+++ b/src/server/ApiManagers/UtilManager.ts
@@ -14,19 +14,6 @@ export default class UtilManager extends ApiManager {
protected initialize(register: Registration): void {
- register({
- method: Method.GET,
- subscription: new RouteSubscriber("environment").add("key"),
- secureHandler: ({ req, res }) => {
- const { key } = req.params;
- const value = process.env[key];
- if (!value) {
- console.log(red(`process.env.${key} is not defined.`));
- }
- return res.send(value);
- }
- });
-
// register({
// method: Method.POST,
// subscription: "/IBMAnalysis",
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index ab3564ebb..3f903a861 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,4 +1,4 @@
-import { unlinkSync, createWriteStream, readFileSync, rename, writeFile } from 'fs';
+import { unlinkSync, createWriteStream, readFileSync, rename, writeFile, existsSync } from 'fs';
import { Utils } from '../Utils';
import * as path from 'path';
import * as sharp from 'sharp';
@@ -6,7 +6,7 @@ import request = require('request-promise');
import { ExifImage } from 'exif';
import { Opt } from '../new_fields/Doc';
import { AcceptibleMedia, Upload } from './SharedMediaTypes';
-import { filesDirectory } from '.';
+import { filesDirectory, publicDirectory } from '.';
import { File } from 'formidable';
import { basename } from "path";
import { createIfNotExists } from './ActionUtilities';
@@ -100,7 +100,7 @@ export namespace DashUploadUtils {
const writeStream = createWriteStream(serverPathToFile(Directory.text, textFilename));
writeStream.write(result.text, error => error ? reject(error) : resolve());
});
- return MoveParsedFile(file, Directory.pdfs);
+ return MoveParsedFile(file, Directory.pdfs, undefined, result.text);
}
const manualSuffixes = [".webm"];
@@ -136,6 +136,16 @@ export namespace DashUploadUtils {
};
export async function buildFileDirectories() {
+ if (!existsSync(publicDirectory)) {
+ console.error("\nPlease ensure that the following directory exists...\n");
+ console.log(publicDirectory);
+ process.exit(0);
+ }
+ if (!existsSync(filesDirectory)) {
+ console.error("\nPlease ensure that the following directory exists...\n");
+ console.log(filesDirectory);
+ process.exit(0);
+ }
const pending = Object.keys(Directory).map(sub => createIfNotExists(`${filesDirectory}/${sub}`));
return Promise.all(pending);
}
@@ -227,7 +237,7 @@ export namespace DashUploadUtils {
* @param suffix If the file doesn't have a suffix and you want to provide it one
* to appear in the new location
*/
- export async function MoveParsedFile(file: File, destination: Directory, suffix: string | undefined = undefined): Promise<Upload.FileResponse> {
+ export async function MoveParsedFile(file: File, destination: Directory, suffix: string | undefined = undefined, text?: string): Promise<Upload.FileResponse> {
const { path: sourcePath } = file;
let name = path.basename(sourcePath);
suffix && (name += suffix);
@@ -239,7 +249,8 @@ export namespace DashUploadUtils {
result: error ? error : {
accessPaths: {
agnostic: getAccessPaths(destination, name)
- }
+ },
+ rawText: text
}
});
});
@@ -273,9 +284,22 @@ export namespace DashUploadUtils {
return information;
};
+ const bufferConverterRec = (layer: any) => {
+ for (const key of Object.keys(layer)) {
+ const val: any = layer[key];
+ if (val instanceof Buffer) {
+ layer[key] = val.toString();
+ } else if (Array.isArray(val) && typeof val[0] === "number") {
+ layer[key] = Buffer.from(val).toString();
+ } else if (typeof val === "object") {
+ bufferConverterRec(val);
+ }
+ }
+ };
+
const parseExifData = async (source: string): Promise<Upload.EnrichedExifData> => {
const image = await request.get(source, { encoding: null });
- return new Promise(resolve => {
+ const { data, error } = await new Promise(resolve => {
new ExifImage({ image }, (error, data) => {
let reason: Opt<string> = undefined;
if (error) {
@@ -284,6 +308,8 @@ export namespace DashUploadUtils {
resolve({ data, error: reason });
});
});
+ data && bufferConverterRec(data);
+ return { data, error };
};
const { pngs, jpgs, webps, tiffs } = AcceptibleMedia;
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 81f63656b..01aae5de7 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -19,7 +19,7 @@ export class Message<T> {
export enum Types {
Number, List, Key, Image, Web, Document, Text, Icon, RichText, DocumentReference,
- Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script, Templates
+ Html, Video, Audio, Ink, PDF, Tuple, Boolean, Script, Templates
}
export interface Transferable {
diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts
index a8680c0c9..80e4a6741 100644
--- a/src/server/RouteManager.ts
+++ b/src/server/RouteManager.ts
@@ -2,7 +2,6 @@ import RouteSubscriber from "./RouteSubscriber";
import { DashUserModel } from "./authentication/models/user_model";
import { Request, Response, Express } from 'express';
import { cyan, red, green } from 'colors';
-import { Utils } from "../client/northstar/utils/Utils";
export enum Method {
GET,
diff --git a/src/server/SharedMediaTypes.ts b/src/server/SharedMediaTypes.ts
index 2495123b7..0f788f6c5 100644
--- a/src/server/SharedMediaTypes.ts
+++ b/src/server/SharedMediaTypes.ts
@@ -21,6 +21,7 @@ export namespace Upload {
export interface FileInformation {
accessPaths: AccessPathInfo;
+ rawText?: string;
}
export type FileResponse<T extends FileInformation = FileInformation> = { source: File, result: T | Error };
diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts
index 9f9fc9619..947aa4289 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/Websocket/Websocket.ts
@@ -199,7 +199,7 @@ export namespace WebSocket {
function setField(socket: Socket, newValue: Transferable) {
Database.Instance.update(newValue.id, newValue, () =>
socket.broadcast.emit(MessageStore.SetField.Message, newValue));
- if (newValue.type === Types.Text) {
+ if (newValue.type === Types.Text) { // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR
Search.updateDocument({ id: newValue.id, data: (newValue as any).data });
}
}
@@ -221,6 +221,7 @@ export namespace WebSocket {
"pdf": ["_t", "url"],
"audio": ["_t", "url"],
"web": ["_t", "url"],
+ "script": ["_t", value => value.script.originalScript],
"RichTextField": ["_t", value => value.Text],
"date": ["_d", value => new Date(value.date).toISOString()],
"proxy": ["_i", "fieldId"],
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 529f8d56d..1d41c3570 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -2,10 +2,8 @@ import { action, computed, observable, reaction } from "mobx";
import * as rp from 'request-promise';
import { DocServer } from "../../../client/DocServer";
import { Docs, DocumentOptions } from "../../../client/documents/Documents";
-import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea";
-import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil";
import { UndoManager } from "../../../client/util/UndoManager";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
import { ScriptField, ComputedField } from "../../../new_fields/ScriptField";
@@ -20,6 +18,9 @@ import { makeTemplate } from "../../../client/util/DropConverter";
import { RichTextField } from "../../../new_fields/RichTextField";
import { PrefetchProxy } from "../../../new_fields/Proxy";
import { FormattedTextBox } from "../../../client/views/nodes/FormattedTextBox";
+import { MainView } from "../../../client/views/MainView";
+import { DocumentType } from "../../../client/documents/DocumentTypes";
+import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
export class CurrentUserUtils {
private static curr_id: string;
@@ -30,113 +31,301 @@ export class CurrentUserUtils {
public static get MainDocId() { return this.mainDocId; }
public static set MainDocId(id: string | undefined) { this.mainDocId = id; }
@computed public static get UserDocument() { return Doc.UserDoc(); }
- @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).pen as Doc; }
+ @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; }
@observable public static GuestTarget: Doc | undefined;
@observable public static GuestWorkspace: Doc | undefined;
@observable public static GuestMobile: Doc | undefined;
- static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) {
- const taskStatusValues = [{ title: "todo", _backgroundColor: "blue", color: "white" },
- { title: "in progress", _backgroundColor: "yellow", color: "black" },
- { title: "completed", _backgroundColor: "green", color: "white" }
- ];
- const noteTemplates = [
- Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }),
- Docs.Create.TextDocument("", { title: "text", style: "Idea", isTemplateDoc: true, backgroundColor: "pink" }),
- Docs.Create.TextDocument("", { title: "text", style: "Topic", isTemplateDoc: true, backgroundColor: "lightBlue" }),
- Docs.Create.TextDocument("", { title: "text", style: "Person", isTemplateDoc: true, backgroundColor: "lightGreen" }),
- Docs.Create.TextDocument("", {
- title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange", _autoHeight: false,
- layout: FormattedTextBox.LayoutString("Todo"), _height: 100, _showCaption: "caption", caption: RichTextField.DashField("taskStatus")
- })
- ];
- doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
- Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues);
- doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 }));
+ // sets up the default User Templates - slideView, queryView, descriptionView
+ static setupUserTemplateButtons(doc: Doc) {
+ if (doc["template-button-query"] === undefined) {
+ const queryTemplate = Docs.Create.MulticolumnDocument(
+ [
+ Docs.Create.QueryDocument({ title: "query", _height: 200 }),
+ Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true })
+ ],
+ { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
+ );
+ queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
+ doc["template-button-query"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
+ dragFactory: new PrefetchProxy(queryTemplate) as any as Doc,
+ removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "question-circle"
+ });
+ }
+
+ if (doc["template-button-slides"] === undefined) {
+ const slideTemplate = Docs.Create.MultirowDocument(
+ [
+ Docs.Create.MulticolumnDocument([], { title: "data", _height: 200 }),
+ Docs.Create.TextDocument("", { title: "text", _height: 100 })
+ ],
+ { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
+ );
+ slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
+ doc["template-button-slides"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
+ dragFactory: new PrefetchProxy(slideTemplate) as any as Doc,
+ removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "address-card"
+ });
+ }
+
+ if (doc["template-button-description"] === undefined) {
+ const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
+ Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
+ descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
+
+ doc["template-button-description"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
+ dragFactory: new PrefetchProxy(descriptionTemplate) as any as Doc,
+ removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "window-maximize"
+ });
+ }
+
+ if (doc["template-button-detail"] === undefined) {
+ const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create;
+
+ const carousel = CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" });
+
+ const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true });
+ const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 50, _autoHeight: true });
+ const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true });
+
+ const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"];
+ const detailedTemplate = {
+ doc: {
+ type: "doc", content: buxtonFieldKeys.map(fieldKey => ({
+ type: "paragraph",
+ content: [{ type: "dashField", attrs: { fieldKey } }]
+ }))
+ },
+ selection: { type: "text", anchor: 1, head: 1 },
+ storedMarks: []
+ };
+ details.text = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" "));
+
+ const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 };
+ const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: 12 };
+ const descriptionWrapperOpts = { title: "descriptions", _height: 300, columnWidth: -1, treeViewHideTitle: true, _pivotField: "title" };
+
+ const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts });
+ descriptionWrapper.sectionHeaders = new List<SchemaHeaderField>([
+ new SchemaHeaderField("[Long Description]", "LemonChiffon", undefined, undefined, undefined, true),
+ new SchemaHeaderField("[Details]", "lightBlue", undefined, undefined, undefined, true),
+ ]);
+ const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts });
+ detailView.isTemplateDoc = makeTemplate(detailView);
+
+ details.title = "Details";
+ short.title = "A Short Description";
+ long.title = "Long Description";
+
+ doc["template-button-detail"] = CurrentUserUtils.ficon({
+ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
+ dragFactory: new PrefetchProxy(detailView) as any as Doc,
+ removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "window-maximize"
+ });
+ }
+
+ if (doc["template-buttons"] === undefined) {
+ doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc,
+ doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc], {
+ title: "Compound Item Creators", _xMargin: 0, _showTitle: "title",
+ _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+ }));
+ } else {
+ DocListCast(Cast(doc["template-buttons"], Doc, null)?.data); // prefetch templates
+ }
+ return doc["template-buttons"] as Doc;
}
- static setupDefaultIconTypes(doc: Doc, buttons?: string[]) {
- doc.iconView = new PrefetchProxy(Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }));
- Doc.GetProto(doc.iconView as any as Doc).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', "");
- doc.isTemplateDoc = makeTemplate(doc.iconView as any as Doc);
- doc.iconImageView = new PrefetchProxy(Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { title: "data", _width: 50, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }));
- doc.isTemplateDoc = makeTemplate(doc.iconImageView as any as Doc, true, "image_icon");
- doc.iconColView = new PrefetchProxy(Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(this)") }));
- doc.isTemplateDoc = makeTemplate(doc.iconColView as any as Doc, true, "collection_icon");
- doc.iconViews = Docs.Create.TreeDocument([doc.iconView as any as Doc, doc.iconImageView as any as Doc, doc.iconColView as any as Doc], { title: "icon types", _height: 75 });
+
+ // setup the different note type skins
+ static setupNoteTemplates(doc: Doc) {
+ if (doc["template-note-Note"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Note");
+ doc["template-note-Note"] = new PrefetchProxy(noteView);
+ }
+ if (doc["template-note-Idea"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", { title: "text", style: "Idea", backgroundColor: "pink" });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea");
+ doc["template-note-Idea"] = new PrefetchProxy(noteView);
+ }
+ if (doc["template-note-Topic"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightBlue" });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic");
+ doc["template-note-Topic"] = new PrefetchProxy(noteView);
+ }
+ if (doc["template-note-Todo"] === undefined) {
+ const noteView = Docs.Create.TextDocument("", {
+ title: "text", style: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption",
+ layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus")
+ });
+ noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo");
+ doc["template-note-Todo"] = new PrefetchProxy(noteView);
+ }
+ const taskStatusValues = [
+ { title: "todo", _backgroundColor: "blue", color: "white" },
+ { title: "in progress", _backgroundColor: "yellow", color: "black" },
+ { title: "completed", _backgroundColor: "green", color: "white" }
+ ];
+ if (doc.fieldTypes === undefined) {
+ doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
+ Doc.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues);
+ }
+
+ if (doc["template-notes"] === undefined) {
+ doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc,
+ doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc],
+ { title: "Note Layouts", _height: 75 }));
+ } else {
+ const noteTypes = Cast(doc["template-notes"], Doc, null);
+ DocListCastAsync(noteTypes).then(list => noteTypes.data = new List<Doc>([doc["template-note-Note"] as any as Doc,
+ doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc]));
+ }
+
+ return doc["template-notes"] as Doc;
}
- // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
- static setupCreatorButtons(doc: Doc, alreadyCreatedButtons?: string[]) {
- const emptyPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" });
- const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" });
- doc.activePen = doc;
- const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
- { title: "collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection },
- { title: "preview", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' },
- { title: "web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", {_width: 300, _height: 300, title: "New Webpage" })' },
- { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' },
- { title: "buxton", icon: "cloud-upload-alt", ignoreClick: true, drag: "Docs.Create.Buxton()" },
- { title: "screenshot", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' },
- { title: "webcam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' },
- { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` },
- { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' },
- { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation },
- { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
- { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' },
- { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
- { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
- { title: "query", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
+ // creates Note templates, and initial "user" templates
+ static setupDocTemplates(doc: Doc) {
+ const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc);
+ const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
+ const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc);
+ if (doc.templateDocs === undefined) {
+ doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], {
+ title: "template layouts", _xPadding: 0,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
+ }));
+ }
+ }
+ // setup templates for different document types when they are iconified from Document Decorations
+ static setupDefaultIconTemplates(doc: Doc) {
+ if (doc["template-icon-view"] === undefined) {
+ const iconView = Docs.Create.TextDocument("", {
+ title: "icon", _width: 150, _height: 30, isTemplateDoc: true,
+ onClick: ScriptField.MakeScript("deiconifyView(self)")
+ });
+ Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', "");
+ iconView.isTemplateDoc = makeTemplate(iconView);
+ doc["template-icon-view"] = new PrefetchProxy(iconView);
+ }
+ if (doc["template-icon-view-rtf"] === undefined) {
+ const iconRtfView = Docs.Create.LabelDocument({ title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(self)") });
+ iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF);
+ doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView);
+ }
+ if (doc["template-icon-view-img"] === undefined) {
+ const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", {
+ title: "data", _width: 50, isTemplateDoc: true,
+ onClick: ScriptField.MakeScript("deiconifyView(self)")
+ });
+ iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG);
+ doc["template-icon-view-img"] = new PrefetchProxy(iconImageView);
+ }
+ if (doc["template-icon-view-col"] === undefined) {
+ const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onClick: ScriptField.MakeScript("deiconifyView(self)") });
+ iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL);
+ doc["template-icon-view-col"] = new PrefetchProxy(iconColView);
+ }
+ if (doc["template-icons"] === undefined) {
+ doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc,
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 }));
+ } else {
+ const templateIconsDoc = Cast(doc["template-icons"], Doc, null);
+ DocListCastAsync(templateIconsDoc).then(list => templateIconsDoc.data = new List<Doc>([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc,
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc]));
+ }
+ return doc["template-icons"] as Doc;
+ }
+ static creatorBtnDescriptors(doc: Doc): {
+ title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean,
+ click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc
+ }[] {
+ if (doc.emptyPresentation === undefined) {
+ doc.emptyPresentation = Docs.Create.PresDocument(new List<Doc>(),
+ { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" });
+ }
+ if (doc.emptyCollection === undefined) {
+ doc.emptyCollection = Docs.Create.FreeformDocument([],
+ { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" });
+ }
+ return [
+ { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc },
+ { title: "Drag a web page", label: "Web", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("", { title: "New Webpage" })' },
+ { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' },
+ { title: "Drag a screenshot", label: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' },
+ { title: "Drag a webcam", label: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' },
+ { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` },
+ { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding:10, _yPadding: 10, title: "Button" })' },
+ { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc },
+ { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' },
+ { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' },
+ { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
+ { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' },
+ { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' },
+ // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc },
+ // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc },
+ { title: "Drag a document previewer", label: "Prev", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' },
+ { title: "Drag a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
];
- return docProtoData.filter(d => !alreadyCreatedButtons?.includes(d.title)).map(data => Docs.Create.FontIconDocument({
- _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
- icon: data.icon,
- title: data.title,
- isButton: true,
- ignoreClick: data.ignoreClick,
- dropAction: data.click ? "copy" : undefined,
- onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
- onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
- ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined,
- activePen: data.activePen,
- backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]),
- dragFactory: data.dragFactory,
- }));
+
}
- static async updateCreatorButtons(doc: Doc) {
- const toolsBtn = await Cast(doc.ToolsBtn, Doc);
- if (toolsBtn) {
- const stackingDoc = await Cast(toolsBtn.sourcePanel, Doc);
- if (stackingDoc) {
- const stackdocs = await Cast(stackingDoc.data, listSpec(Doc));
- if (stackdocs) {
- const dragset = await Cast(stackdocs[0], Doc);
- if (dragset) {
- const dragdocs = await Cast(dragset.data, listSpec(Doc));
- if (dragdocs) {
- const dragDocs = await Promise.all(dragdocs);
- this.setupCreatorButtons(doc, dragDocs.map(d => StrCast(d.title))).map(nb => Doc.AddDocToList(dragset, "data", nb));
- }
- }
- }
+ // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
+ static async setupCreatorButtons(doc: Doc) {
+ let alreadyCreatedButtons: string[] = [];
+ const dragCreatorSet = await Cast(doc.myItemCreators, Doc, null);
+ if (dragCreatorSet) {
+ const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc));
+ if (dragCreators) {
+ const dragDocs = await Promise.all(dragCreators);
+ alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title));
}
}
+ const creatorBtns = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)).
+ map(data => Docs.Create.FontIconDocument({
+ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
+ icon: data.icon,
+ title: data.title,
+ label: data.label,
+ ignoreClick: data.ignoreClick,
+ dropAction: data.click ? "copy" : undefined,
+ onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
+ onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
+ ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined,
+ activePen: data.activePen,
+ backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]),
+ dragFactory: data.dragFactory,
+ }));
+
+ if (dragCreatorSet === undefined) {
+ doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, {
+ title: "Basic Item Creators", _showTitle: "title", _xMargin: 0,
+ _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+ }));
+ } else {
+ creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb));
+ }
+ return doc.myItemCreators as Doc;
}
static setupMobileButtons(doc: Doc, buttons?: string[]) {
const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
{ title: "record", icon: "microphone", ignoreClick: true, click: "FILL" },
- { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc },
- { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc },
- // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc },
+ { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc },
+ { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc },
+ // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "red", activePen: doc },
{ title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" },
// { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" },
];
@@ -150,11 +339,11 @@ export class CurrentUserUtils {
static setupThumbButtons(doc: Doc) {
const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
- { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
- { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc },
+ { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
+ { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc },
];
return docProtoData.map(data => Docs.Create.FontIconDocument({
_nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, title: data.title, icon: data.icon,
@@ -204,199 +393,244 @@ export class CurrentUserUtils {
});
}
- // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
- static setupToolsPanel(sidebarContainer: Doc, doc: Doc) {
+ // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
+ // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
+ static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) {
// setup a masonry view of all he creators
- const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), {
- _width: 500, _autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _yMargin: 5
- });
+ const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
+ const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc);
+
+ if (doc.myCreators === undefined) {
+ doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], {
+ title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0,
+ _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
+ }));
+ }
// setup a color picker
- const color = Docs.Create.ColorDocument({
- title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List<string>(["dropAction", "forceActive"])
- });
+ if (doc.myColorPicker === undefined) {
+ const color = Docs.Create.ColorDocument({
+ title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List<string>(["dropAction", "forceActive"])
+ });
+ doc.myColorPicker = new PrefetchProxy(color);
+ }
- return Docs.Create.ButtonDocument({
- _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer,
- letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
- _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
- }),
- isButton: true,
- onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
- });
+ if (doc["tabs-button-tools"] === undefined) {
+ doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({
+ _width: 35, _height: 25, title: "Tools", _fontSize: 10,
+ letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
+ sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
+ _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
+ })) as any as Doc,
+ targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
+ onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
+ }));
+ }
+ (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel
+ return doc["tabs-button-tools"] as Doc;
}
- // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views
- static setupLibraryPanel(sidebarContainer: Doc, doc: Doc) {
+ static setupWorkspaces(doc: Doc) {
// setup workspaces library item
- doc.workspaces = Docs.Create.TreeDocument([], {
- title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true,
- });
-
- doc.documents = Docs.Create.TreeDocument([], {
- title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
- });
+ if (doc.myWorkspaces === undefined) {
+ doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], {
+ title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true,
+ }));
+ }
+ const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`);
+ (doc.myWorkspaces as Doc).contextMenuScripts = new List<ScriptField>([newWorkspace!]);
+ (doc.myWorkspaces as Doc).contextMenuLabels = new List<string>(["Create New Workspace"]);
+ return doc.myWorkspaces as Doc;
+ }
+ static setupDocumentCollection(doc: Doc) {
+ if (doc.myDocuments === undefined) {
+ doc.myDocuments = new PrefetchProxy(Docs.Create.TreeDocument([], {
+ title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
+ }));
+ }
+ return doc.myDocuments as Doc;
+ }
+ static setupRecentlyClosed(doc: Doc) {
// setup Recently Closed library item
- doc.recentlyClosed = Docs.Create.TreeDocument([], {
- title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
- });
+ if (doc.myRecentlyClosed === undefined) {
+ doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], {
+ title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true,
+ }));
+ }
+ // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
+ PromiseValue(Cast(doc.myRecentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast));
+ const clearAll = ScriptField.MakeScript(`self.data = new List([])`);
+ (doc.myRecentlyClosed as Doc).contextMenuScripts = new List<ScriptField>([clearAll!]);
+ (doc.myRecentlyClosed as Doc).contextMenuLabels = new List<string>(["Clear All"]);
- return Docs.Create.ButtonDocument({
- _width: 50, _height: 25, title: "Library", fontSize: 10,
- letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
- title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
- }),
- isButton: true,
- targetContainer: sidebarContainer,
- onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
- });
+ return doc.myRecentlyClosed as Doc;
+ }
+ // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views
+ static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) {
+ const workspaces = CurrentUserUtils.setupWorkspaces(doc);
+ const documents = CurrentUserUtils.setupDocumentCollection(doc);
+ const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc);
+
+ if (doc["tabs-button-library"] === undefined) {
+ doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({
+ _width: 50, _height: 25, title: "Library", _fontSize: 10,
+ letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
+ sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], {
+ title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "move", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
+ })) as any as Doc,
+ targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
+ onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
+ }));
+ }
+ return doc["tabs-button-library"] as Doc;
}
// setup the Search button which will display the search panel.
- static setupSearchPanel(sidebarContainer: Doc) {
- return Docs.Create.ButtonDocument({
- _width: 50, _height: 25, title: "Search", fontSize: 10,
- letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
- sourcePanel: Docs.Create.QueryDocument({ title: "search stack", }),
- targetContainer: sidebarContainer,
- lockedPosition: true,
- isButton: true,
- onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
- });
+ static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) {
+ if (doc["tabs-button-search"] === undefined) {
+ doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({
+ _width: 50, _height: 25, title: "Search", _fontSize: 10,
+ letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
+ sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc,
+ searchFileTypes: new List<string>([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]),
+ targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc,
+ lockedPosition: true,
+ onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
+ }));
+ }
+ return doc["tabs-button-search"] as Doc;
}
- // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
- static setupSidebarButtons(doc: Doc) {
- const sidebarContainer = new Doc();
- doc.sidebarContainer = new PrefetchProxy(sidebarContainer);
- sidebarContainer._chromeStatus = "disabled";
- sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
+ static setupSidebarContainer(doc: Doc) {
+ if (doc["tabs-panelContainer"] === undefined) {
+ const sidebarContainer = new Doc();
+ sidebarContainer._chromeStatus = "disabled";
+ sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
+ doc["tabs-panelContainer"] = new PrefetchProxy(sidebarContainer);
+ }
+ return doc["tabs-panelContainer"] as Doc;
+ }
- doc.ToolsBtn = new PrefetchProxy(this.setupToolsPanel(sidebarContainer, doc));
- doc.LibraryBtn = new PrefetchProxy(this.setupLibraryPanel(sidebarContainer, doc));
- doc.SearchBtn = new PrefetchProxy(this.setupSearchPanel(sidebarContainer));
+ // setup the list of sidebar mode buttons which determine what is displayed in the sidebar
+ static async setupSidebarButtons(doc: Doc) {
+ const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc);
+ const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer);
+ const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer);
+ const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer);
// Finally, setup the list of buttons to display in the sidebar
- doc.sidebarButtons = new PrefetchProxy(Docs.Create.StackingDocument([doc.SearchBtn as any as Doc, doc.LibraryBtn as any as Doc, doc.ToolsBtn as any as Doc], {
- _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode",
- title: "sidebar btn row stack", backgroundColor: "dimGray",
- }));
+ if (doc["tabs-buttons"] === undefined) {
+ doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([searchBtn, libraryBtn, toolsBtn], {
+ _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode",
+ title: "sidebar btn row stack", backgroundColor: "dimGray",
+ }));
+ (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn });
+ }
}
+ static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
+ ...opts,
+ _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+ backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
+ })) as any as Doc
+
+ static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
+ ...opts,
+ dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
+ })) as any as Doc
+
/// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
- static setupExpandingButtons(doc: Doc) {
- const queryTemplate = Docs.Create.MulticolumnDocument(
- [
- Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }),
- Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true })
- ],
- { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
- queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
- const slideTemplate = Docs.Create.MultirowDocument(
- [
- Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }),
- Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true })
- ],
- { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
- slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
- const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
- Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
- descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
-
- const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
- ...opts, isButton: true,
- dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100
- })) as any as Doc;
- const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
- ...opts,
- _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", isButton: true, forceActive: true,
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
- backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
- })) as any as Doc;
-
- doc.undoBtn = ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" });
- doc.redoBtn = ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" });
- doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
- doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
- doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "sticky-note" });
- doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
- doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]);
- doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], {
- title: "template layouts", _xPadding: 0,
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
- }));
+ static setupDockedButtons(doc: Doc) {
+ if (doc["dockedBtn-pen"] === undefined) {
+ doc["dockedBtn-pen"] = CurrentUserUtils.ficon({
+ onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)"),
+ author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.inkPen, this)`), activePen: doc
+ });
+ }
+ if (doc["dockedBtn-undo"] === undefined) {
+ doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" });
+ }
+ if (doc["dockedBtn-redo"] === undefined) {
+ doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" });
+ }
+ if (doc.dockedBtns === undefined) {
+ doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc, doc["dockedBtn-pen"] as Doc]);
+ }
}
-
// sets up the default set of documents to be shown in the Overlay layer
static setupOverlays(doc: Doc) {
- doc.overlays = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "Overlays", backgroundColor: "#aca3a6" }));
+ if (doc.myOverlayDocuments === undefined) {
+ doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6" }));
+ }
}
// the initial presentation Doc to use
static setupDefaultPresentation(doc: Doc) {
- doc.presentationTemplate = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" }));
- doc.curPresentation = Docs.Create.PresDocument(new List<Doc>(), { title: "Presentation", _viewType: CollectionViewType.Stacking, _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" });
- }
-
- static setupMobileUploads(doc: Doc) {
- doc.optionalRightCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "New mobile uploads" }));
+ if (doc["template-presentation"] === undefined) {
+ doc["template-presentation"] = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
+ title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data"
+ }));
+ }
+ if (doc.activePresentation === undefined) {
+ doc.activePresentation = Docs.Create.PresDocument(new List<Doc>(), {
+ title: "Presentation", _viewType: CollectionViewType.Stacking,
+ _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0"
+ });
+ }
}
- static setupChildClicks(doc: Doc) {
- const openInTarget = Docs.Create.TextDocument("", { title: "On Child Clicked (open in target)" });
- const text = "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )";
- openInTarget.script = ScriptField.MakeScript(text, { thisContainer: Doc.name });
- doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" });
+ static setupRightSidebar(doc: Doc) {
+ if (doc.rightSidebarCollection === undefined) {
+ doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" }));
+ }
}
- static updateUserDocument(doc: Doc) {
- doc.title = Doc.CurrentUserEmail;
- new InkingControl();
- (doc.iconTypes === undefined) && CurrentUserUtils.setupDefaultIconTypes(doc);
- (doc.noteTypes === undefined) && CurrentUserUtils.setupDefaultDocTemplates(doc);
- (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc);
- (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc);
- (doc.expandingButtons === undefined) && CurrentUserUtils.setupExpandingButtons(doc);
- (doc.curPresentation === undefined) && CurrentUserUtils.setupDefaultPresentation(doc);
- (doc.sidebarButtons === undefined) && CurrentUserUtils.setupSidebarButtons(doc);
- (doc.childClickFuncs === undefined) && CurrentUserUtils.setupChildClicks(doc);
+ static setupClickEditorTemplates(doc: Doc) {
+ if (doc.childClickFuncs === undefined) {
+ const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
+ "docCast(thisContainer.target).then((target) => { target && docCast(this.source).then((source) => { target.proto.data = new List([source || this]); } ); } )",
+ { target: Doc.name }), { title: "On Child Clicked (open in target)", _width: 300, _height: 200 });
+ doc.childClickFuncs = Docs.Create.TreeDocument([openInTarget], { title: "on Child Click function templates" });
+ }
// this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved.
PromiseValue(Cast(doc.childClickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
- // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
- PromiseValue(Cast(doc.recentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast));
- // this is equivalent to using PrefetchProxies to make sure all the sidebarButtons and noteType internal Doc's have been retrieved.
- PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(DocListCast));
- PromiseValue(Cast(doc.sidebarButtons, Doc)).then(stackingDoc => {
- stackingDoc && PromiseValue(Cast(stackingDoc.data, listSpec(Doc))).then(sidebarButtons => {
- sidebarButtons && sidebarButtons.map((sidebarBtn, i) => {
- sidebarBtn && PromiseValue(Cast(sidebarBtn, Doc)).then(async btn => {
- btn && btn.sourcePanel && btn.targetContainer && i === 1 && (btn.onClick as ScriptField).script.run({ this: btn });
- });
- });
- });
- });
- // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
- doc.undoBtn && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc.undoBtn as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
- doc.redoBtn && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc.redoBtn as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
+ if (doc.clickFuncs === undefined) {
+ const onClick = Docs.Create.ScriptingDocument(undefined, {
+ title: "onClick", "onClick-rawScript": "console.log('click')",
+ isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200
+ }, "onClick");
+ const onCheckedClick = Docs.Create.ScriptingDocument(undefined, {
+ title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List<string>(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200
+ }, "onCheckedClick");
+ doc.clickFuncs = Docs.Create.TreeDocument([onClick, onCheckedClick], { title: "onClick funcs" });
+ }
+ PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
- this.updateCreatorButtons(doc);
- return doc;
+ return doc.clickFuncs as Doc;
}
- public static IsDocPinned(doc: Doc) {
- //add this new doc to props.Document
- const curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc;
- if (curPres) {
- return DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1;
- }
- return false;
- }
+ static async updateUserDocument(doc: Doc) {
+ new InkingControl();
+ doc.title = Doc.CurrentUserEmail;
+ doc.activePen = doc;
+ this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
+ this.setupDocTemplates(doc); // sets up the template menu of templates
+ this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
+ this.setupOverlays(doc); // documents in overlay layer
+ this.setupDockedButtons(doc); // the bottom bar of font icons
+ this.setupDefaultPresentation(doc); // presentation that's initially triggered
+ await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels
+ doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument();
+
+ // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
+ doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
+ doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
+ return doc;
+ }
public static async loadCurrentUser() {
return rp.get(Utils.prepend("/getCurrentUser")).then(response => {
if (response) {
@@ -419,79 +653,9 @@ export class CurrentUserUtils {
throw new Error("There should be a user id! Why does Dash think there isn't one?");
}
});
- // try {
- // const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" });
- // NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json());
- // await Gateway.Instance.ClearCatalog();
- // const extraSchemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []);
- // let extras = await Promise.all(extraSchemas.map(sc => Gateway.Instance.GetSchema("", sc)));
- // let catprom = CurrentUserUtils.SetNorthstarCatalog(await Gateway.Instance.GetCatalog(), extras);
- // // if (catprom) await Promise.all(catprom);
- // } catch (e) {
-
- // }
- }
-
- /* Northstar catalog ... really just for testing so this should eventually go away */
- // --------------- Northstar hooks ------------- /
- static _northstarSchemas: Doc[] = [];
- @observable private static _northstarCatalog?: Catalog;
- @computed public static get NorthstarDBCatalog() { return this._northstarCatalog; }
-
- @action static SetNorthstarCatalog(ctlog: Catalog, extras: Catalog[]) {
- CurrentUserUtils.NorthstarDBCatalog = ctlog;
- // if (ctlog && ctlog.schemas) {
- // extras.map(ex => ctlog.schemas!.push(ex));
- // return ctlog.schemas.map(async schema => {
- // let schemaDocuments: Doc[] = [];
- // let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema);
- // await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => {
- // promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt<Field>) => {
- // if (field instanceof Doc) {
- // schemaDocuments.push(field);
- // } else {
- // var atmod = new ColumnAttributeModel(attr);
- // let histoOp = new HistogramOperation(schema.displayName!,
- // new AttributeTransformationModel(atmod, AggregateFunction.None),
- // new AttributeTransformationModel(atmod, AggregateFunction.Count),
- // new AttributeTransformationModel(atmod, AggregateFunction.Count));
- // schemaDocuments.push(Docs.Create.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }));
- // }
- // })));
- // return promises;
- // }, [] as Promise<void>[]));
- // return CurrentUserUtils._northstarSchemas.push(Docs.Create.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }));
- // });
- // }
- }
- public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; }
-
- public static AddNorthstarSchema(schema: Schema, schemaDoc: Doc) {
- if (this._northstarCatalog && CurrentUserUtils._northstarSchemas) {
- this._northstarCatalog.schemas!.push(schema);
- CurrentUserUtils._northstarSchemas.push(schemaDoc);
- const schemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []);
- schemas.push(schema.displayName!);
- CurrentUserUtils.UserDocument.DBSchemas = new List<string>(schemas);
- }
- }
- public static GetNorthstarSchema(name: string): Schema | undefined {
- return !this._northstarCatalog || !this._northstarCatalog.schemas ? undefined :
- ArrayUtil.FirstOrDefault<Schema>(this._northstarCatalog.schemas, (s: Schema) => s.displayName === name);
- }
- public static GetAllNorthstarColumnAttributes(schema: Schema) {
- const recurs = (attrs: Attribute[], g?: AttributeGroup) => {
- if (g && g.attributes) {
- attrs.push.apply(attrs, g.attributes);
- if (g.attributeGroups) {
- g.attributeGroups.forEach(ng => recurs(attrs, ng));
- }
- }
- return attrs;
- };
- return recurs([] as Attribute[], schema ? schema.rootAttributeGroup : undefined);
}
}
Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); });
Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); });
+Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); \ No newline at end of file
diff --git a/src/server/database.ts b/src/server/database.ts
index fc91ff3a2..ad285765b 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -14,7 +14,7 @@ export namespace Database {
export let disconnect: Function;
const schema = 'Dash';
const port = 27017;
- export const url = `mongodb://localhost:${port}/${schema}`;
+ export const url = `mongodb://localhost:${port}/`;
enum ConnectionStates {
disconnected = 0,
@@ -35,7 +35,7 @@ export namespace Database {
console.log(`mongoose established default connection at ${url}`);
resolve();
});
- mongoose.connect(url, { useNewUrlParser: true });
+ mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true, dbName: schema });
});
}
} catch (e) {
@@ -46,17 +46,20 @@ export namespace Database {
}
}
- class Database implements IDatabase {
+ export class Database implements IDatabase {
public static DocumentsCollection = 'documents';
private MongoClient = mongodb.MongoClient;
private currentWrites: { [id: string]: Promise<void> } = {};
private db?: mongodb.Db;
private onConnect: (() => void)[] = [];
- constructor() {
- this.MongoClient.connect(url, (_err, client) => {
+ doConnect() {
+ console.error(`\nConnecting to Mongo with URL : ${url}\n`);
+ this.MongoClient.connect(url, { connectTimeoutMS: 30000, socketTimeoutMS: 30000, useUnifiedTopology: true }, (_err, client) => {
+ console.error("mongo connect response\n");
if (!client) {
- console.error("\nPlease start MongoDB by running 'mongod' in a terminal before continuing...\n");
+ console.error("\nMongo connect failed with the error:\n");
+ console.log(_err);
process.exit(0);
}
this.db = client.db();
@@ -65,6 +68,7 @@ export namespace Database {
}
public async update(id: string, value: any, callback: (err: mongodb.MongoError, res: mongodb.UpdateWriteOpResult) => void, upsert = true, collectionName = Database.DocumentsCollection) {
+
if (this.db) {
const collection = this.db.collection(collectionName);
const prom = this.currentWrites[id];
diff --git a/src/server/index.ts b/src/server/index.ts
index 97f70630b..f26c8a6ab 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -39,10 +39,10 @@ export const filesDirectory = path.resolve(publicDirectory, "files");
*/
async function preliminaryFunctions() {
// Utils.TraceConsoleLog();
+ await DashUploadUtils.buildFileDirectories();
await Logger.initialize();
await GoogleCredentialsLoader.loadCredentials();
GoogleApiServerUtils.processProjectCredentials();
- await DashUploadUtils.buildFileDirectories();
if (process.env.DB !== "MEM") {
await log_execution({
startMessage: "attempting to initialize mongodb connection",
@@ -106,12 +106,17 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }:
method: Method.GET,
subscription: ["/home", new RouteSubscriber("doc").add("docId")],
secureHandler: serve,
- publicHandler: ({ req, ...remaining }) => {
+ publicHandler: ({ req, res, ...remaining }) => {
const { originalUrl: target } = req;
const sharing = qs.parse(qs.extract(req.originalUrl), { sort: false }).sharing === "true";
const docAccess = target.startsWith("/doc/");
+ // since this is the public handler, there's no meaning of '/home' to speak of
+ // since there's no user logged in, so the only viable operation
+ // for a guest is to look at a shared document
if (sharing && docAccess) {
- serve({ req, ...remaining });
+ serve({ req, res, ...remaining });
+ } else {
+ res.redirect("/login");
}
}
});
@@ -148,5 +153,6 @@ export async function launchServer() {
if (process.env.RELEASE) {
(sessionAgent = new DashSessionAgent()).launch();
} else {
+ (Database.Instance as Database.Database).doConnect();
launchServer();
}
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 1150118f7..add607761 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -20,7 +20,6 @@ import * as request from 'request';
import RouteSubscriber from './RouteSubscriber';
import { publicDirectory } from '.';
import { logPort, } from './ActionUtilities';
-import { Utils } from '../Utils';
import { blue, yellow } from 'colors';
import * as cors from "cors";
diff --git a/src/server/updateProtos.ts b/src/server/updateProtos.ts
index 90490eb45..e9860bd61 100644
--- a/src/server/updateProtos.ts
+++ b/src/server/updateProtos.ts
@@ -1,8 +1,7 @@
import { Database } from "./database";
const protos =
- ["text", "histogram", "image", "web", "collection", "kvp",
- "video", "audio", "pdf", "icon", "import", "linkdoc"];
+ ["text", "image", "web", "collection", "kvp", "video", "audio", "pdf", "icon", "import", "linkdoc"];
(async function () {
await Promise.all(