aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLionel Han <47760119+IGoByJoe@users.noreply.github.com>2020-08-14 12:55:05 -0700
committerLionel Han <47760119+IGoByJoe@users.noreply.github.com>2020-08-14 12:55:05 -0700
commit4fd8f1533be68bdcd3a6b8a832a38655adde4d71 (patch)
treecd2110b252c6a73932dfae36ba3d535d5e40fff0 /src
parenta9161a668c96750d8bb50647c043a979058ef451 (diff)
parent36f7b54914b4d5fce98de3a6d83f1b186ebb17d1 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into new_audio
Diffstat (limited to 'src')
-rw-r--r--src/client/DocServer.ts123
-rw-r--r--src/client/documents/DocumentTypes.ts4
-rw-r--r--src/client/documents/Documents.ts14
-rw-r--r--src/client/util/CurrentUserUtils.ts274
-rw-r--r--src/client/util/DocumentManager.ts1
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/DropConverter.ts2
-rw-r--r--src/client/util/KeyCodes.ts2
-rw-r--r--src/client/util/SearchUtil.ts5
-rw-r--r--src/client/util/SelectionManager.ts9
-rw-r--r--src/client/util/SettingsManager.scss13
-rw-r--r--src/client/util/SettingsManager.tsx6
-rw-r--r--src/client/util/SharingManager.tsx4
-rw-r--r--src/client/views/.DS_Storebin10244 -> 10244 bytes
-rw-r--r--src/client/views/DocComponent.tsx28
-rw-r--r--src/client/views/DocumentDecorations.scss34
-rw-r--r--src/client/views/DocumentDecorations.tsx63
-rw-r--r--src/client/views/GestureOverlay.tsx14
-rw-r--r--src/client/views/GlobalKeyHandler.ts14
-rw-r--r--src/client/views/InkingStroke.tsx2
-rw-r--r--src/client/views/MainView.scss6
-rw-r--r--src/client/views/MainView.tsx130
-rw-r--r--src/client/views/MainViewNotifs.scss20
-rw-r--r--src/client/views/MainViewNotifs.tsx38
-rw-r--r--src/client/views/OverlayView.scss2
-rw-r--r--src/client/views/OverlayView.tsx2
-rw-r--r--src/client/views/PropertiesButtons.tsx30
-rw-r--r--src/client/views/ScriptingRepl.tsx2
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.scss76
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx89
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.scss1
-rw-r--r--src/client/views/collections/CollectionMenu.tsx25
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx260
-rw-r--r--src/client/views/collections/CollectionSchemaHeaders.tsx250
-rw-r--r--src/client/views/collections/CollectionSchemaView.scss93
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx52
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx7
-rw-r--r--src/client/views/collections/CollectionSubView.tsx51
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx25
-rw-r--r--src/client/views/collections/CollectionView.tsx120
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx14
-rw-r--r--src/client/views/collections/SchemaTable.tsx74
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx165
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx64
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx16
-rw-r--r--src/client/views/globalCssVariables.scss2
-rw-r--r--src/client/views/globalCssVariables.scss.d.ts1
-rw-r--r--src/client/views/linking/LinkEditor.tsx4
-rw-r--r--src/client/views/nodes/AudioBox.tsx1
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx23
-rw-r--r--src/client/views/nodes/DocHolderBox.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx36
-rw-r--r--src/client/views/nodes/FieldView.tsx10
-rw-r--r--src/client/views/nodes/FontIconBox.scss21
-rw-r--r--src/client/views/nodes/FontIconBox.tsx41
-rw-r--r--src/client/views/nodes/ImageBox.tsx4
-rw-r--r--src/client/views/nodes/LinkBox.tsx2
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx11
-rw-r--r--src/client/views/nodes/MenuIconBox.tsx6
-rw-r--r--src/client/views/nodes/PDFBox.tsx12
-rw-r--r--src/client/views/nodes/PresBox.scss226
-rw-r--r--src/client/views/nodes/PresBox.tsx866
-rw-r--r--src/client/views/nodes/WebBox.tsx10
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx45
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx5
-rw-r--r--src/client/views/pdf/PDFViewer.tsx11
-rw-r--r--src/client/views/presentationview/PresElementBox.scss4
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx145
-rw-r--r--src/client/views/search/SearchBox.tsx447
-rw-r--r--src/fields/Doc.ts4
-rw-r--r--src/fields/SchemaHeaderField.ts2
-rw-r--r--src/fields/ScriptField.ts4
-rw-r--r--src/fields/documentSchemas.ts2
-rw-r--r--src/fields/util.ts10
-rw-r--r--src/server/ApiManagers/SearchManager.ts8
-rw-r--r--src/server/ApiManagers/UploadManager.ts2
-rw-r--r--src/server/websocket.ts6
80 files changed, 2336 insertions, 1868 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 2fe3e9778..63e01bc5b 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -330,69 +330,76 @@ export namespace DocServer {
}
}
- // 2) synchronously, we emit a single callback to the server requesting the serialized (i.e. represented by a string)
- // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of
- // the fields have been returned from the server
- const getSerializedFields: Promise<any> = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds);
-
- // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects.
- // Here, once deserialized, we also invoke .proto to 'load' the documents' prototypes, which ensures that all
- // future .proto calls on the Doc won't have to go farther than the cache to get their actual value.
- const deserializeFields = getSerializedFields.then(async fields => {
- const fieldMap: { [id: string]: RefField } = {};
- const proms: Promise<void>[] = [];
- runInAction(() => {
- for (const field of fields) {
- if (field !== undefined && field !== null && !_cache[field.id]) {
- // deserialize
- const cached = _cache[field.id];
- if (!cached) {
- const prom = SerializationHelper.Deserialize(field).then(deserialized => {
- fieldMap[field.id] = deserialized;
-
- //overwrite or delete any promises (that we inserted as flags
- // to indicate that the field was in the process of being fetched). Now everything
- // should be an actual value within or entirely absent from the cache.
- if (deserialized !== undefined) {
- _cache[field.id] = deserialized;
- } else {
- delete _cache[field.id];
- }
- return deserialized;
- });
- // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
- // we set the value at the field's id to a promise that will resolve to the field.
- // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
- // The mapping in the .then call ensures that when other callers await these promises, they'll
- // get the resolved field
- _cache[field.id] = prom;
-
- // adds to a list of promises that will be awaited asynchronously
- proms.push(prom);
- } else if (cached instanceof Promise) {
- proms.push(cached as any);
+ if (requestedIds.length) {
+
+ // 2) synchronously, we emit a single callback to the server requesting the serialized (i.e. represented by a string)
+ // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of
+ // the fields have been returned from the server
+ const getSerializedFields: Promise<any> = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds);
+
+ // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects.
+ // Here, once deserialized, we also invoke .proto to 'load' the documents' prototypes, which ensures that all
+ // future .proto calls on the Doc won't have to go farther than the cache to get their actual value.
+ const deserializeFields = getSerializedFields.then(async fields => {
+ const fieldMap: { [id: string]: RefField } = {};
+ const proms: Promise<void>[] = [];
+ runInAction(() => {
+ for (const field of fields) {
+ if (field !== undefined && field !== null && !_cache[field.id]) {
+ // deserialize
+ const cached = _cache[field.id];
+ if (!cached) {
+ const prom = SerializationHelper.Deserialize(field).then(deserialized => {
+ fieldMap[field.id] = deserialized;
+
+ //overwrite or delete any promises (that we inserted as flags
+ // to indicate that the field was in the process of being fetched). Now everything
+ // should be an actual value within or entirely absent from the cache.
+ if (deserialized !== undefined) {
+ _cache[field.id] = deserialized;
+ } else {
+ delete _cache[field.id];
+ }
+ return deserialized;
+ });
+ // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
+ // we set the value at the field's id to a promise that will resolve to the field.
+ // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
+ // The mapping in the .then call ensures that when other callers await these promises, they'll
+ // get the resolved field
+ _cache[field.id] = prom;
+
+ // adds to a list of promises that will be awaited asynchronously
+ proms.push(prom);
+ } else if (cached instanceof Promise) {
+ proms.push(cached as any);
+ }
+ } else if (_cache[field.id] instanceof Promise) {
+ proms.push(_cache[field.id] as any);
+ (_cache[field.id] as any).then((f: any) => fieldMap[field.id] = f);
+ } else if (field) {
+ proms.push(_cache[field.id] as any);
+ fieldMap[field.id] = field;
}
- } else if (field) {
- proms.push(_cache[field.id] as any);
- fieldMap[field.id] = field;
}
- }
+ });
+ await Promise.all(proms);
+ return fieldMap;
});
- await Promise.all(proms);
- return fieldMap;
- });
- // 5) at this point, all fields have a) been returned from the server and b) been deserialized into actual Field objects whose
- // prototype documents, if any, have also been fetched and cached.
- const fields = await deserializeFields;
+ // 5) at this point, all fields have a) been returned from the server and b) been deserialized into actual Field objects whose
+ // prototype documents, if any, have also been fetched and cached.
+ const fields = await deserializeFields;
- // 6) with this confidence, we can now go through and update the cache at the ids of the fields that
- // we explicitly had to fetch. To finish it off, we add whatever value we've come up with for a given
- // id to the soon-to-be-returned field mapping.
- requestedIds.forEach(id => {
- const field = fields[id];
- map[id] = field;
- });
+ // 6) with this confidence, we can now go through and update the cache at the ids of the fields that
+ // we explicitly had to fetch. To finish it off, we add whatever value we've come up with for a given
+ // id to the soon-to-be-returned field mapping.
+ requestedIds.forEach(id => {
+ const field = fields[id];
+ map[id] = field;
+ });
+
+ }
// 7) those promises we encountered in the else if of 1), which represent
// other callers having already submitted a request to the server for (a) document(s)
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 71d6c2ccc..1bef6fa08 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -10,7 +10,7 @@ export enum DocumentType {
VID = "video", // video
AUDIO = "audio", // audio
PDF = "pdf", // pdf
- INK = "ink", // ink stroke
+ INK = "inks", // ink stroke
SCREENSHOT = "screenshot", // view of a desktop application
FONTICON = "fonticonbox", // font icon
SEARCH = "search", // search query
@@ -31,7 +31,7 @@ export enum DocumentType {
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)
- SEARCHITEM= "searchitem",
+ SEARCHITEM = "searchitem",
COMPARISON = "comparison", // before/after view with slider (view of 2 images)
GROUP = "group", // group of users
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a6a697574..42ba4d2c4 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -53,6 +53,7 @@ import { Upload } from "../../server/SharedMediaTypes";
const path = require('path');
export interface DocumentOptions {
+ system?: boolean;
_autoHeight?: boolean;
_panX?: number;
_panY?: number;
@@ -111,6 +112,7 @@ export interface DocumentOptions {
_columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
isTemplateForField?: string; // the field key for which the containing document is a rendering template
isTemplateDoc?: boolean;
+ watchedDocuments?: Doc; // list of documents to "watch" in an icon doc to display a badge
targetScriptKey?: string; // where to write a template script (used by collections with click templates which need to target onClick, onDoubleClick, etc)
templates?: List<string>;
hero?: ImageField; // primary image that best represents a compound document (e.g., for a buxton device document that has multiple images)
@@ -173,6 +175,7 @@ export interface DocumentOptions {
onPointerUp?: ScriptField;
dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
+ clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop
clipboard?: Doc;
UseCors?: boolean;
@@ -182,7 +185,7 @@ export interface DocumentOptions {
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;
- stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere
+ _stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere
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.
@@ -530,7 +533,7 @@ export namespace Docs {
Scripting.addGlobal(Buxton);
- const delegateKeys = ["x", "y", "layoutKey", "dropAction", "lockedPosiiton", "childDropAction", "isLinkButton", "isBackground", "removeDropProperties", "treeViewOpen"];
+ const delegateKeys = ["x", "y", "system", "layoutKey", "dropAction", "lockedPosiiton", "childDropAction", "isLinkButton", "isBackground", "removeDropProperties", "treeViewOpen"];
/**
* This function receives the relevant document prototype and uses
@@ -553,6 +556,8 @@ export namespace Docs {
export function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = "data") {
const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys, "^_");
+ protoProps.system = delegateProps.system;
+
if (!("author" in protoProps)) {
protoProps.author = Doc.CurrentUserEmail;
}
@@ -1159,7 +1164,7 @@ export namespace DocUtils {
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)) {
- optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey);
+ optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set`, system: true }, enumeratedFieldKey);
Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
}
const options = optionsCollection as Doc;
@@ -1208,5 +1213,4 @@ export namespace DocUtils {
}
Scripting.addGlobal("Docs", Docs);
-Scripting.addGlobal(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: "child of " + proto.title }); return d; });
-
+Scripting.addGlobal(function makeDelegate(proto: any) { const d = Docs.Create.DelegateDocument(proto, { title: "child of " + proto.title }); return d; }); \ No newline at end of file
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 4e75a51f6..153118083 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -23,6 +23,7 @@ import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView";
import { LabelBox } from "../views/nodes/LabelBox";
import { LinkManager } from "./LinkManager";
+import { Id } from "../../fields/FieldSymbols";
export class CurrentUserUtils {
private static curr_id: string;
@@ -45,10 +46,10 @@ export class CurrentUserUtils {
if (doc["template-button-query"] === undefined) {
const queryTemplate = Docs.Create.MulticolumnDocument(
[
- Docs.Create.SearchDocument({ _viewType: CollectionViewType.Schema, ignoreClick: true, forceActive: true, lockedPosition: true, title: "query", _height: 200 }),
- Docs.Create.FreeformDocument([], { title: "data", _height: 100 })
+ Docs.Create.SearchDocument({ _viewType: CollectionViewType.Schema, ignoreClick: true, forceActive: true, lockedPosition: true, title: "query", _height: 200, system: true }),
+ Docs.Create.FreeformDocument([], { title: "data", _height: 100, system: true })
],
- { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
+ { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true, system: true }
);
queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
doc["template-button-query"] = CurrentUserUtils.ficon({
@@ -80,10 +81,10 @@ export class CurrentUserUtils {
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 })
+ Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }),
+ Docs.Create.TextDocument("", { title: "text", _height: 100, system: true })
],
- { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true }
+ { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true, system: true }
);
slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
doc["template-button-slides"] = CurrentUserUtils.ficon({
@@ -94,7 +95,7 @@ export class CurrentUserUtils {
}
if (doc["template-button-description"] === undefined) {
- const descriptionTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header")); // text needs to be a space to allow templateText to be created
+ const descriptionTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _height: 100, system: true }, "header")); // text needs to be a space to allow templateText to be created
descriptionTemplate[DataSym].layout =
"<div>" +
" <FormattedTextBox {...props} height='{this._headerHeight||75}px' background='{this._headerColor||`orange`}' fieldKey={'header'}/>" +
@@ -110,7 +111,7 @@ export class CurrentUserUtils {
}
if (doc["template-button-link"] === undefined) { // set _backgroundColor to transparent to prevent link dot from obscuring document it's attached to.
- const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header")); // text needs to be a space to allow templateText to be created
+ const linkTemplate = Doc.MakeDelegate(Docs.Create.TextDocument(" ", { title: "header", _height: 100, system: true }, "header")); // text needs to be a space to allow templateText to be created
Doc.GetProto(linkTemplate).layout =
"<div>" +
" <FormattedTextBox {...props} height='{this._headerHeight||75}px' background='{this._headerColor||`lightGray`}' fieldKey={'header'}/>" +
@@ -158,9 +159,9 @@ export class CurrentUserUtils {
if (doc["template-button-switch"] === undefined) {
const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create;
- const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40 });
- const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1 });
- const no = FreeformDocument([], { title: "no", _height: 100, _width: 100 });
+ const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40, system: true });
+ const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1, system: true });
+ const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, system: true });
const labelTemplate = {
doc: {
type: "doc", content: [{
@@ -177,13 +178,13 @@ export class CurrentUserUtils {
// Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true");
Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]");
// Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false");
- const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, });
+ const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, system: true });
box.isTemplateDoc = makeTemplate(box, true, "switch");
doc["template-button-switch"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'),
dragFactory: new PrefetchProxy(box) as any as Doc,
- removeDropProperties: new List<string>(["dropAction"]), title: "data switch", icon: "toggle-on"
+ removeDropProperties: new List<string>(["dropAction"]), title: "data switch", icon: "toggle-on", system: true
});
}
@@ -193,12 +194,12 @@ export class CurrentUserUtils {
const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)");
const carousel = CarouselDocument([], {
title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10,
- onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F"
+ onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F", system: true
});
- const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true });
- const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true });
- const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true });
+ const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true, system: true });
+ const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true, system: true });
+ const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true, system: true });
const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"];
const detailedTemplate = {
@@ -215,7 +216,7 @@ export class CurrentUserUtils {
const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 };
const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: "12pt" };
- const descriptionWrapperOpts = { title: "descriptions", _height: 300, _columnWidth: -1, treeViewHideTitle: true, _pivotField: "title" };
+ const descriptionWrapperOpts = { title: "descriptions", _height: 300, _columnWidth: -1, treeViewHideTitle: true, _pivotField: "title", system: true };
const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts });
descriptionWrapper._columnHeaders = new List<SchemaHeaderField>([
@@ -223,7 +224,7 @@ export class CurrentUserUtils {
new SchemaHeaderField("[Long Description]", "dimGray", undefined, undefined, undefined, true),
new SchemaHeaderField("[Details]", "dimGray", undefined, undefined, undefined, true),
]);
- const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts });
+ const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts, system: true });
detailView.isTemplateDoc = makeTemplate(detailView);
details.title = "Details";
@@ -233,7 +234,7 @@ export class CurrentUserUtils {
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"
+ removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "window-maximize", system: true
});
}
@@ -251,7 +252,7 @@ export class CurrentUserUtils {
hidden: ComputedField.MakeFunction("self.userDoc.noviceMode") as any,
userDoc: doc,
_autoHeight: true, _width: 500, _columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
- dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
}));
} else {
const curButnTypes = Cast(doc["template-buttons"], Doc, null);
@@ -266,42 +267,42 @@ export class CurrentUserUtils {
// 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" });
+ const noteView = Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow", system: true });
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" });
+ const noteView = Docs.Create.TextDocument("", { title: "text", style: "Idea", backgroundColor: "pink", system: true });
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" });
+ const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightBlue", system: true });
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")
+ layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus"), system: true
});
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" }
+ { title: "todo", _backgroundColor: "blue", color: "white", system: true },
+ { title: "in progress", _backgroundColor: "yellow", color: "black", system: true },
+ { title: "completed", _backgroundColor: "green", color: "white", system: true }
];
if (doc.fieldTypes === undefined) {
- doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
+ doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations", system: true });
DocUtils.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 }));
+ { title: "Note Layouts", _height: 75, system: true }));
} else {
const curNoteTypes = Cast(doc["template-notes"], Doc, null);
const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc,
@@ -322,7 +323,7 @@ export class CurrentUserUtils {
const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc);
if (doc.templateDocs === undefined) {
doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], {
- title: "template layouts", _xPadding: 0,
+ title: "template layouts", _xPadding: 0, system: true,
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
}));
}
@@ -333,7 +334,7 @@ export class CurrentUserUtils {
if (doc["template-icon-view"] === undefined) {
const iconView = Docs.Create.LabelDocument({
title: "icon", textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("title"), _backgroundColor: "dimGray",
- _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
+ _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
});
// Docs.Create.TextDocument("", {
// title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
@@ -345,7 +346,7 @@ export class CurrentUserUtils {
if (doc["template-icon-view-rtf"] === undefined) {
const iconRtfView = Docs.Create.LabelDocument({
title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("text"),
- _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
+ _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
});
iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF);
doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView);
@@ -353,26 +354,26 @@ export class CurrentUserUtils {
if (doc["template-icon-view-button"] === undefined) {
const iconBtnView = Docs.Create.FontIconDocument({
title: "icon_" + DocumentType.BUTTON, _nativeHeight: 30, _nativeWidth: 30,
- _width: 30, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
+ _width: 30, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
});
iconBtnView.isTemplateDoc = makeTemplate(iconBtnView, true, "icon_" + DocumentType.BUTTON);
doc["template-icon-view-button"] = new PrefetchProxy(iconBtnView);
}
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, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)")
+ title: "data", _width: 50, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true
});
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, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") });
+ const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)"), system: true });
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-button"] as Doc,
- doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc, doc["template-icon-view-pdf"] as Doc], { title: "icon templates", _height: 75 }));
+ doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc, doc["template-icon-view-pdf"] as Doc], { title: "icon templates", _height: 75, system: true }));
} else {
const templateIconsDoc = Cast(doc["template-icons"], Doc, null);
const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, doc["template-icon-view-button"] as Doc,
@@ -387,73 +388,78 @@ export class CurrentUserUtils {
static creatorBtnDescriptors(doc: Doc): {
title: string, toolTip: string, icon: string, drag?: string, ignoreClick?: boolean,
- click?: string, ischecked?: string, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc, noviceMode?: boolean
+ click?: string, ischecked?: string, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc, noviceMode?: boolean, clickFactory?: Doc
}[] {
if (doc.emptyPresentation === undefined) {
doc.emptyPresentation = Docs.Create.PresDocument(new List<Doc>(),
- { title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" });
+ { title: "Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeStatus: "replaced", boxShadow: "0 0", system: true });
}
if (doc.emptyCollection === undefined) {
doc.emptyCollection = Docs.Create.FreeformDocument([],
- { _nativeWidth: undefined, _nativeHeight: undefined, _width: 150, _height: 100, title: "freeform" });
+ { _nativeWidth: undefined, _nativeHeight: undefined, _width: 150, _height: 100, title: "freeform", system: true });
+ }
+ if (doc.emptyPane === undefined) {
+ doc.emptyPane = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, title: "Untitled Collection", system: true });
}
if (doc.emptyComparison === undefined) {
- doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "compare", _width: 300, _height: 300 });
+ doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "compare", _width: 300, _height: 300, system: true });
}
if (doc.emptyScript === undefined) {
- doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250, title: "script" });
+ doc.emptyScript = Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250, title: "script", system: true });
}
if (doc.emptyScreenshot === undefined) {
- doc.emptyScreenshot = Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" });
+ doc.emptyScreenshot = Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot", system: true });
}
if (doc.emptyAudio === undefined) {
- doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "ready to record audio" });
+ doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "ready to record audio", system: true });
}
if (doc.emptyImage === undefined) {
- doc.emptyImage = 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" });
+ doc.emptyImage = 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", system: true });
}
if (doc.emptyButton === undefined) {
- doc.emptyButton = Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title: "Button" });
+ doc.emptyButton = Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title: "Button", system: true });
}
if (doc.emptyDocHolder === undefined) {
doc.emptyDocHolder = Docs.Create.DocumentDocument(
ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]") as any,
- { _width: 250, _height: 250, title: "container" });
+ { _width: 250, _height: 250, title: "container", system: true });
}
if (doc.emptyWebpage === undefined) {
- doc.emptyWebpage = Docs.Create.WebDocument("", { title: "webpage", _nativeWidth: 850, _nativeHeight: 962, _width: 400, UseCors: true });
+ doc.emptyWebpage = Docs.Create.WebDocument("", { title: "webpage", _nativeWidth: 850, _nativeHeight: 962, _width: 400, UseCors: true, system: true });
}
if (doc.activeMobileMenu === undefined) {
this.setupActiveMobileMenu(doc);
}
return [
- { toolTip: "Drag a collection", title: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc, noviceMode: true },
- { toolTip: "Drag a web page", title: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true },
- { toolTip: "Drag a cat image", title: "Image", icon: "cat", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyImage as Doc },
- { toolTip: "Drag a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyComparison as Doc, noviceMode: true },
- { toolTip: "Drag a screengrabber", title: "Grab", icon: "photo-video", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScreenshot as Doc },
+ { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(getCopy(this.clickFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, },
+ { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true },
+ { toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyImage as Doc },
+ { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyComparison as Doc, noviceMode: true },
+ { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScreenshot as Doc },
// { title: "Drag a webcam", title: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' },
- { toolTip: "Drag a audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyAudio as Doc, noviceMode: true },
- { toolTip: "Drag a button", title: "Button", icon: "bolt", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyButton as Doc, noviceMode: true },
+ { toolTip: "Tap to create an audio recorder in a new pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyAudio as Doc, noviceMode: true },
+ { toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyButton as Doc, noviceMode: true },
- { toolTip: "Drag a presentation view", title: "Present", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true },
- { toolTip: "Drag a search box", title: "Query", icon: "search", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptySearch as Doc },
- { toolTip: "Drag a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScript as Doc },
+ { toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Present", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true },
+ { toolTip: "Tap to create a search box in a new pane, drag for a search box", title: "Query", icon: "search", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptySearch as Doc },
+ { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyScript as Doc },
// { title: "Drag an import folder", title: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' },
- { toolTip: "Drag a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc },
+ { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc },
// { title: "Drag an instance of the device collection", title: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' },
// { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
// { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
// { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
// { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "pink", activeInkPen: doc },
// { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activeInkPen = this;', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "white", activeInkPen: doc },
- { toolTip: "Drag a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc },
+ { toolTip: "Tap to create a document previewer in a new pane, drag for a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc },
{ toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
{ toolTip: "Connect a Google Account", title: "Google Account", icon: "external-link-alt", click: 'GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' },
];
}
+
+
// setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
static async setupCreatorButtons(doc: Doc) {
let alreadyCreatedButtons: string[] = [];
@@ -466,13 +472,13 @@ export class CurrentUserUtils {
}
}
const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title));
- const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, ischecked, activeInkPen, backgroundColor, dragFactory, noviceMode }) => Docs.Create.FontIconDocument({
+ const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, ischecked, activeInkPen, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({
_nativeWidth: 50, _nativeHeight: 50, _width: 50, _height: 50,
icon,
title,
toolTip,
ignoreClick,
- dropAction: "copy",
+ dropAction: "alias",
onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined,
onClick: click ? ScriptField.MakeScript(click) : undefined,
ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined,
@@ -480,15 +486,16 @@ export class CurrentUserUtils {
backgroundColor,
removeDropProperties: new List<string>(["dropAction"]),
dragFactory,
+ clickFactory,
userDoc: noviceMode ? undefined as any : doc,
- hidden: noviceMode ? undefined as any : ComputedField.MakeFunction("self.userDoc.noviceMode")
+ hidden: noviceMode ? undefined as any : ComputedField.MakeFunction("self.userDoc.noviceMode"), system: true
}));
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 }),
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
}));
} else {
creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb));
@@ -496,19 +503,20 @@ export class CurrentUserUtils {
return doc.myItemCreators as Doc;
}
- static menuBtnDescriptions(): {
- title: string, icon: string, click: string,
+ static menuBtnDescriptions(doc: Doc): {
+ title: string, icon: string, click: string, watchedDocuments?: Doc
}[] {
+ this.setupSharingSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
return [
- { title: "Sharing", icon: "users", click: 'scriptContext.selectMenu(self, "Sharing")' },
- { title: "Workspace", icon: "desktop", click: 'scriptContext.selectMenu(self, "Workspace")' },
- { title: "Catalog", icon: "file", click: 'scriptContext.selectMenu(self, "Catalog")' },
- { title: "Archive", icon: "archive", click: 'scriptContext.selectMenu(self, "Archive")' },
- { title: "Import", icon: "upload", click: 'scriptContext.selectMenu(self, "Import")' },
- { title: "Tools", icon: "wrench", click: 'scriptContext.selectMenu(self, "Tools")' },
- { title: "Help", icon: "question-circle", click: 'scriptContext.selectMenu(self, "Help")' },
- { title: "Settings", icon: "cog", click: 'scriptContext.selectMenu(self, "Settings")' },
- { title: "User Doc", icon: "address-card", click: 'scriptContext.selectMenu(self, "UserDoc")' },
+ { title: "Sharing", icon: "users", click: 'selectMainMenu(self)', watchedDocuments: doc["sidebar-sharing"] as Doc },
+ { title: "Workspace", icon: "desktop", click: 'selectMainMenu(self)' },
+ { title: "Catalog", icon: "file", click: 'selectMainMenu(self)' },
+ { title: "Archive", icon: "archive", click: 'selectMainMenu(self)' },
+ { title: "Import", icon: "upload", click: 'selectMainMenu(self)' },
+ { title: "Tools", icon: "wrench", click: 'selectMainMenu(self)' },
+ { title: "Help", icon: "question-circle", click: 'selectMainMenu(self)' },
+ { title: "Settings", icon: "cog", click: 'selectMainMenu(self)' },
+ { title: "User Doc", icon: "address-card", click: 'selectMainMenu(self)' },
];
}
@@ -516,23 +524,24 @@ export class CurrentUserUtils {
if (doc["search-panel"] === undefined) {
doc["search-panel"] = new PrefetchProxy(Docs.Create.SearchDocument({
_width: 500, _height: 400, backgroundColor: "dimGray", ignoreClick: true,
- childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Schema, _chromeStatus: "disabled", title: "sidebar search stack",
+ childDropAction: "alias", lockedPosition: true, _viewType: CollectionViewType.Schema, _chromeStatus: "disabled", title: "sidebar search stack", system: true
})) as any as Doc;
}
}
static setupMenuPanel(doc: Doc) {
if (doc.menuStack === undefined) {
- const menuBtns = CurrentUserUtils.menuBtnDescriptions().map(({ title, icon, click }) =>
+ const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, icon, click, watchedDocuments }) =>
Docs.Create.FontIconDocument({
icon,
iconShape: "square",
title,
_backgroundColor: "black",
- stayInCollection: true,
+ _stayInCollection: true,
childDropAction: "same",
_width: 60,
_height: 60,
- onClick: ScriptField.MakeScript(click, { scriptContext: "any" }),
+ watchedDocuments,
+ onClick: ScriptField.MakeScript(click, { scriptContext: "any" }), system: true
}));
const userDoc = menuBtns[menuBtns.length - 1];
userDoc.userDoc = doc;
@@ -544,7 +553,7 @@ export class CurrentUserUtils {
_backgroundColor: "black",
_gridGap: 0,
_yMargin: 0,
- _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled",
+ _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, lockedPosition: true, _chromeStatus: "disabled", system: true
}));
}
// this resets all sidebar buttons to being deactivated
@@ -571,7 +580,7 @@ export class CurrentUserUtils {
// Sets up mobileMenu stacking document
static setupMobileMenu() {
const menu = new PrefetchProxy(Docs.Create.StackingDocument(this.setupMobileButtons(), {
- _width: 980, ignoreClick: true, lockedPosition: false, _chromeStatus: "disabled", title: "home", _yMargin: 100
+ _width: 980, ignoreClick: true, lockedPosition: false, _chromeStatus: "disabled", title: "home", _yMargin: 100, system: true
}));
return menu;
}
@@ -592,9 +601,9 @@ export class CurrentUserUtils {
title: data.title,
lockedPosition: true,
onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
- _backgroundColor: data.backgroundColor
+ _backgroundColor: data.backgroundColor, system: true
},
- [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)" }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
+ [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])
);
}
@@ -602,26 +611,26 @@ export class CurrentUserUtils {
static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, {
...opts,
dropAction: undefined, removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15,
- borderRounding: "5px", boxShadow: "0 0", _chromeStatus: "disabled"
+ borderRounding: "5px", boxShadow: "0 0", _chromeStatus: "disabled", system: true
}) as any as Doc
// sets up the text container for the information contained within the mobile button
static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, {
...opts,
dropAction: undefined, removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25,
- backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", _chromeStatus: "disabled", ignoreClick: true
+ backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", _chromeStatus: "disabled", ignoreClick: true, system: true
}) as any as Doc
// Sets up the title of the button
static mobileButtonText = (opts: DocumentOptions, buttonTitle: string) => Docs.Create.TextDocument(buttonTitle, {
...opts,
- dropAction: undefined, title: buttonTitle, _fontSize: "37pt", _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)"
+ dropAction: undefined, title: buttonTitle, _fontSize: "37pt", _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)", system: true
}) as any as Doc
// Sets up the description of the button
static mobileButtonInfo = (opts: DocumentOptions, buttonInfo: string) => Docs.Create.TextDocument(buttonInfo, {
...opts,
- dropAction: undefined, title: "info", _fontSize: "25pt", _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2,
+ dropAction: undefined, title: "info", _fontSize: "25pt", _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, system: true
}) as any as Doc
@@ -629,7 +638,7 @@ export class CurrentUserUtils {
const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [
{ title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
{ title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: 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.activeInkPen, this)`, activeInkPen: doc },
+ { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, system: true }), backgroundColor: "orange", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
{ title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
{ title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc },
];
@@ -640,7 +649,7 @@ export class CurrentUserUtils {
clipboard: data.clipboard,
onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined,
ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activeInkPen: data.activeInkPen, pointerHack: true,
- backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
+ backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory, system: true
}));
}
@@ -648,10 +657,10 @@ export class CurrentUserUtils {
if (!userDoc.thumbDoc) {
const thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
_width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
- _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
+ _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white", system: true
});
thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
- _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column"
+ _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column", system: true
});
userDoc.thumbDoc = thumbDoc;
}
@@ -687,20 +696,20 @@ export class CurrentUserUtils {
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",
+ _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", system: true
}));
}
// setup a color picker
if (doc.myColorPicker === undefined) {
const color = Docs.Create.ColorDocument({
- title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List<string>(["dropAction", "forceActive"])
+ title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List<string>(["dropAction", "forceActive"]), system: true
});
doc.myColorPicker = new PrefetchProxy(color);
}
if (doc["sidebar-tools"] === undefined) {
const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
- title: "sidebar-tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, forceActive: true
+ title: "sidebar-tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", hideFilterView: true, forceActive: true, system: true
})) as any as Doc;
doc["sidebar-tools"] = toolsStack;
@@ -712,7 +721,7 @@ export class CurrentUserUtils {
doc.myWorkspaces === undefined;
if (doc.myWorkspaces === undefined) {
doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true,
+ title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true, system: true
}));
}
if (doc["sidebar-workspaces"] === undefined) {
@@ -725,7 +734,7 @@ export class CurrentUserUtils {
doc["sidebar-workspaces"] = new PrefetchProxy(Docs.Create.TreeDocument([workspaces], {
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
- lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+ lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
})) as any as Doc;
}
}
@@ -735,7 +744,7 @@ export class CurrentUserUtils {
if (doc.myCatalog === undefined) {
doc.myCatalog = new PrefetchProxy(Docs.Create.SchemaDocument([], [], {
title: "CATALOG", _height: 1000, _fitWidth: true, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false,
- childDropAction: "alias", targetDropAction: "same", stayInCollection: true, treeViewOpen: true,
+ childDropAction: "alias", targetDropAction: "same", _stayInCollection: true, treeViewOpen: true, system: true
}));
}
@@ -746,7 +755,7 @@ export class CurrentUserUtils {
title: "sidebar-catalog",
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
- lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+ lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
})) as any as Doc;
}
}
@@ -755,7 +764,7 @@ export class CurrentUserUtils {
doc.myRecentlyClosed === undefined;
if (doc.myRecentlyClosed === undefined) {
doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], {
- title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, treeViewOpen: true, stayInCollection: true,
+ title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, treeViewOpen: true, _stayInCollection: true, system: true
}));
}
// this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready
@@ -771,7 +780,7 @@ export class CurrentUserUtils {
title: "sidebar-recentlyClosed",
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false, treeViewOpen: true,
- lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+ lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
})) as any as Doc;
}
}
@@ -784,7 +793,7 @@ export class CurrentUserUtils {
doc["sidebar-userDoc"] = new PrefetchProxy(Docs.Create.TreeDocument([doc], {
treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, title: "sidebar-userDoc",
treeViewTruncateTitleWidth: 150, hideFilterView: true, treeViewPreventOpen: false,
- lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same"
+ lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
})) as any as Doc;
}
}
@@ -795,6 +804,7 @@ export class CurrentUserUtils {
sidebarContainer._chromeStatus = "disabled";
sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()");
doc.sidebar = new PrefetchProxy(sidebarContainer);
+ doc.system = true;
}
return doc.sidebar as Doc;
}
@@ -812,20 +822,20 @@ export class CurrentUserUtils {
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
+ backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true, system: true
})) as any as Doc
static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
- ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40
+ ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true
})) 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 setupDockedButtons(doc: Doc) {
if (doc["dockedBtn-undo"] === undefined) {
- doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), toolTip: "click to undo", title: "undo", icon: "undo-alt" });
+ doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true });
}
if (doc["dockedBtn-redo"] === undefined) {
- doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), toolTip: "click to redo", title: "redo", icon: "redo-alt" });
+ doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true });
}
if (doc.dockedBtns === undefined) {
doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
@@ -834,7 +844,7 @@ export class CurrentUserUtils {
// sets up the default set of documents to be shown in the Overlay layer
static setupOverlays(doc: Doc) {
if (doc.myOverlayDocuments === undefined) {
- doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6" }));
+ doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6", system: true }));
}
}
@@ -842,21 +852,30 @@ export class CurrentUserUtils {
static setupDefaultPresentation(doc: Doc) {
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"
+ title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data", system: true
}));
}
if (doc.activePresentation === undefined) {
- doc.activePresentation = Docs.Create.PresDocument(new List<Doc>(), {
- title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias",
- _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0"
- });
+ doc.activePresentation = Doc.MakeCopy(doc.emptyPresentation as Doc, true);
}
}
- // Right sidebar is where mobile uploads are contained
+ // Sharing sidebar is where shared documents are contained
static setupSharingSidebar(doc: Doc) {
if (doc["sidebar-sharing"] === undefined) {
- doc["sidebar-sharing"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Shared Documents", childDropAction: "alias" }));
+ doc["sidebar-sharing"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Shared Documents", childDropAction: "alias", system: true }));
+ }
+ }
+
+ // Import sidebar is where shared documents are contained
+ static setupImportSidebar(doc: Doc) {
+ if (doc["sidebar-import-documents"] === undefined) {
+ doc["sidebar-import-documents"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Imported Documents", forceActive: true, _showTitle: "title", childDropAction: "alias", _autoHeight: true, _yMargin: 30, lockedPosition: true, _chromeStatus: "disabled" }));
+ }
+ if (doc["sidebar-import"] === undefined) {
+ const uploads = Cast(doc["sidebar-import-documents"], Doc, null);
+ const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _backgroundColor: "black", title: "Import", icon: "upload", system: true });
+ doc["sidebar-import"] = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "Imported Documents", _yMargin: 20, ignoreClick: true, lockedPosition: true }));
}
}
@@ -868,14 +887,14 @@ export class CurrentUserUtils {
"docCast(thisContainer.target).then((target) => target && (target.proto.data = new List([self]))) ",
{ thisContainer: Doc.name }), {
title: "Click to open in target", _width: 300, _height: 200,
- targetScriptKey: "onChildClick",
+ targetScriptKey: "onChildClick", system: true
});
const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript(
"openOnRight(self.doubleClickView)",
- {}), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" });
+ {}), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick", system: true });
- doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" });
+ doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates", system: true });
}
// this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved.
PromiseValue(Cast(doc["clickFuncs-child"], Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
@@ -883,24 +902,26 @@ export class CurrentUserUtils {
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
+ isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200, system: true
}, "onClick");
const onChildClick = Docs.Create.ScriptingDocument(undefined, {
title: "onChildClick", "onChildClick-rawScript": "console.log('child click')",
- isTemplateDoc: true, isTemplateForField: "onChildClick", _width: 300, _height: 200
+ isTemplateDoc: true, isTemplateForField: "onChildClick", _width: 300, _height: 200, system: true
}, "onChildClick");
const onDoubleClick = Docs.Create.ScriptingDocument(undefined, {
title: "onDoubleClick", "onDoubleClick-rawScript": "console.log('double click')",
- isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200
+ isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200, system: true
}, "onDoubleClick");
const onChildDoubleClick = Docs.Create.ScriptingDocument(undefined, {
title: "onChildDoubleClick", "onChildDoubleClick-rawScript": "console.log('child double click')",
- isTemplateDoc: true, isTemplateForField: "onChildDoubleClick", _width: 300, _height: 200
+ isTemplateDoc: true, isTemplateForField: "onChildDoubleClick", _width: 300, _height: 200, system: true
}, "onChildDoubleClick");
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
+ 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, system: true
}, "onCheckedClick");
- doc.clickFuncs = Docs.Create.TreeDocument([onClick, onChildClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" });
+ doc.clickFuncs = Docs.Create.TreeDocument([onClick, onChildClick, onDoubleClick, onCheckedClick], { title: "onClick funcs", system: true });
}
PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast));
@@ -922,25 +943,28 @@ export class CurrentUserUtils {
doc.fontFamily = StrCast(doc.fontFamily, "Arial");
doc.fontColor = StrCast(doc.fontColor, "black");
doc.fontHighlight = StrCast(doc.fontHighlight, "");
- doc.defaultColor = StrCast(doc.defaultColor, "white");
+ doc.defaultAclPrivate = BoolCast(doc.defaultAclPrivate, true);
+ doc.activeCollectionBackground = StrCast(doc.activeCollectionBackground, "white");
+ doc.activeCollectionNestedBackground = Cast(doc.activeCollectionNestedBackground, "string", null);
doc.noviceMode = BoolCast(doc.noviceMode, true);
doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); //
doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); //
Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]);
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.setupSharingSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing
+ this.setupImportSidebar(doc);
this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile
this.setupMenuPanel(doc);
this.setupSearchPanel(doc);
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();
doc.globalScriptDatabase = Docs.Prototypes.MainScriptDocument();
doc.globalGroupDatabase = Docs.Prototypes.MainGroupDocument();
+ setTimeout(() => this.setupDefaultPresentation(doc), 0); // presentation that's initially triggered
+
// 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 });
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index bd57e7f48..962294933 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -231,6 +231,7 @@ export class DocumentManager {
containerDoc.currentTimecode = targetTimecode;
const targetContext = await target?.context as Doc;
const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
+ console.log(targetNavContext);
DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished);
} else {
finished?.();
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 4b1860b5c..0cca61841 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -210,7 +210,7 @@ export namespace DragManager {
docDragData.droppedDocuments =
dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
docDragData.dropAction === "alias" ? Doc.MakeAlias(d) :
- docDragData.dropAction === "copy" ? Doc.MakeDelegate(d) : d);
+ docDragData.dropAction === "copy" ? Doc.MakeClone(d) : d);
docDragData.dropAction !== "same" && docDragData.droppedDocuments.forEach((drop: Doc, i: number) => {
const dragProps = Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []);
const remProps = (dragData?.removeDropProperties || []).concat(Array.from(dragProps));
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index d0acf14c3..f1848f7e5 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -58,7 +58,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
let dbox = doc;
// 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.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes("FontIconBox")) {
- dbox = Doc.MakeAlias(doc);
+ //dbox = Doc.MakeAlias(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
} else if (!doc.onDragStart && !doc.isButtonBar) {
const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
if (layoutDoc.type !== DocumentType.FONTICON) {
diff --git a/src/client/util/KeyCodes.ts b/src/client/util/KeyCodes.ts
index cacb72a57..de2457a5a 100644
--- a/src/client/util/KeyCodes.ts
+++ b/src/client/util/KeyCodes.ts
@@ -131,6 +131,6 @@ export class KeyCodes {
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 SUBTRACT: number = 189;
public static ADD: number = 187;
} \ No newline at end of file
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 7b2c601fe..b63fc8991 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -37,7 +37,8 @@ export namespace SearchUtil {
export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) {
query = query || "*"; //If we just have a filter query, search for * as the query
const rpquery = Utils.prepend("/dashsearch");
- const gotten = await rp.get(rpquery, { qs: { ...options, q: query } });
+ const replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}type_t:${arg}`);
+ const gotten = await rp.get(rpquery, { qs: { ...options, sort: "lastModified_d desc", q: replacedQuery } });
const result: IdSearchResult = gotten.startsWith("<") ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten);
if (!returnDocs) {
return result;
@@ -82,7 +83,7 @@ export namespace SearchUtil {
}
}
- return { docs: theDocs, numFound: theDocs.length, highlighting, lines: theLines };
+ return { docs: theDocs, numFound: result.numFound, highlighting, lines: theLines };
}
export async function GetAliasesOfDocument(doc: Doc): Promise<Doc[]>;
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 05ba00331..113278593 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -84,11 +84,4 @@ export namespace SelectionManager {
export function SelectedDocuments(): Array<DocumentView> {
return Array.from(manager.SelectedDocuments.keys());
}
-}
-
-
-Scripting.addGlobal(function selectDoc(doc: any) {
- const view = DocumentManager.Instance.getDocumentView(doc);
- view && SelectionManager.SelectDoc(view, false);
- //Doc.UserDoc().activeSelection = new List([doc]);
-}); \ No newline at end of file
+} \ No newline at end of file
diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss
index 01dda0aca..ec513e5d5 100644
--- a/src/client/util/SettingsManager.scss
+++ b/src/client/util/SettingsManager.scss
@@ -33,10 +33,10 @@
font-size: 12px;
padding-right: 15px;
color: black;
- margin-top: 4px;
+ margin-top: 10px;
/* right: 135; */
position: absolute;
- left: 235;
+ left: 243;
}
.settings-section {
@@ -97,6 +97,8 @@
.modes-content {
display: flex;
+ margin-left: 10px;
+ font-size: 12;
.modes-select {
// width: 170px;
@@ -112,6 +114,8 @@
.modes-playground,
.default-acl {
display: flex;
+ margin-left: 10px;
+ font-size: 12;
.playground-check,
.acl-check {
@@ -125,10 +129,12 @@
.playground-text {
color: black;
margin-right: 10px;
+ margin-top: 2;
}
.acl-text {
color: black;
+ margin-top: 2;
}
}
@@ -147,6 +153,7 @@
height: 20px;
border: 0.5px solid black;
border-radius: 5px;
+ padding-top: 3px;
}
}
@@ -229,7 +236,7 @@
}
.logout-button {
- right: 35;
+ right: 355;
position: absolute;
}
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index e3b91925a..b4778d3eb 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -56,7 +56,7 @@ export default class SettingsManager extends React.Component<{}> {
@undoBatch selectUserMode = action((e: React.ChangeEvent) => Doc.UserDoc().noviceMode = (e.currentTarget as any)?.value === "Novice");
@undoBatch changeFontFamily = action((e: React.ChangeEvent) => Doc.UserDoc().fontFamily = (e.currentTarget as any).value);
@undoBatch changeFontSize = action((e: React.ChangeEvent) => Doc.UserDoc().fontSize = (e.currentTarget as any).value);
- @undoBatch switchColor = action((color: ColorState) => Doc.UserDoc().defaultColor = String(color.hex));
+ @undoBatch switchColor = action((color: ColorState) => Doc.UserDoc().activeCollectionBackground = String(color.hex));
@undoBatch
playgroundModeToggle = action(() => {
this.playgroundMode = !this.playgroundMode;
@@ -91,10 +91,10 @@ export default class SettingsManager extends React.Component<{}> {
</div>
<div className="preferences-font">
<div className="preferences-font-text">Default Font</div>
- <select className="font-select" onChange={this.changeFontFamily}>
+ <select className="font-select" onChange={this.changeFontFamily} value={StrCast(Doc.UserDoc().fontFamily, "Times New Roman")} >
{fontFamilies.map(font => <option key={font} value={font} defaultValue={StrCast(Doc.UserDoc().fontFamily)}> {font} </option>)}
</select>
- <select className="size-select" onChange={this.changeFontSize}>
+ <select className="size-select" onChange={this.changeFontSize} value={StrCast(Doc.UserDoc().fontSize, "7pt")}>
{fontSizes.map(size => <option key={size} value={size} defaultValue={StrCast(Doc.UserDoc().fontSize)}> {size} </option>)}
</select>
</div>
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index d50a132f8..48a3c023f 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -179,6 +179,9 @@ export default class SharingManager extends React.Component<{}> {
if (group.docsShared) DocListCast(group.docsShared).forEach(doc => Doc.IndexOf(doc, DocListCast(user.notificationDoc[storage])) === -1 && Doc.AddDocToList(user.notificationDoc, storage, doc));
}
+ /**
+ * Called from the properties sidebar to change permissions of a user.
+ */
shareFromPropertiesSidebar = (shareWith: string, permission: SharingPermissions, target: Doc) => {
const user = this.users.find(({ user: { email } }) => email === (shareWith === "Me" ? Doc.CurrentUserEmail : shareWith));
if (user) this.setInternalSharing(user, permission, target);
@@ -228,7 +231,6 @@ export default class SharingManager extends React.Component<{}> {
const key = user.email.replace('.', '_');
const ACL = `ACL-${key}`;
-
target.author === Doc.CurrentUserEmail && distributeAcls(ACL, permission as SharingPermissions, target);
if (permission !== SharingPermissions.None) {
diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store
index c379549d0..c6f3afa14 100644
--- a/src/client/views/.DS_Store
+++ b/src/client/views/.DS_Store
Binary files differ
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index eea133ed9..8c8bb6fde 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -122,15 +122,23 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
@action.bound
removeDocument(doc: Doc | Doc[]): boolean {
- const docs = doc instanceof Doc ? [doc] : doc;
- docs.map(doc => doc.isPushpin = doc.annotationOn = undefined);
- const targetDataDoc = this.dataDoc;
- const value = DocListCast(targetDataDoc[this.annotationKey]);
- const toRemove = value.filter(v => docs.includes(v));
- // can't assign new List<Doc>(result) to this because you can't assign new values in addonly
- if (toRemove.length !== 0) {
- toRemove.forEach(doc => Doc.RemoveDocFromList(targetDataDoc, this.annotationKey, doc));
- return true;
+ const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+ if (effectiveAcl === AclAdmin || effectiveAcl === AclEdit) {
+ const docs = doc instanceof Doc ? [doc] : doc;
+ docs.map(doc => doc.isPushpin = doc.annotationOn = undefined);
+ const targetDataDoc = this.dataDoc;
+ const value = DocListCast(targetDataDoc[this.annotationKey]);
+ const toRemove = value.filter(v => docs.includes(v));
+
+ if (toRemove.length !== 0) {
+ const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
+ toRemove.forEach(doc => {
+ Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey + "-annotations", doc);
+ recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+ doc.deleted = true;
+ });
+ return true;
+ }
}
return false;
@@ -171,6 +179,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
added.map(doc => doc.context = this.props.Document);
(targetDataDoc[this.annotationKey] as List<Doc>).push(...added);
targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ const lastModified = "lastModified";
+ targetDataDoc[lastModified] = new DateField(new Date(Date.now()));
}
}
}
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 5401623e8..1e8cfdff4 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -21,14 +21,6 @@ $linkGap : 3px;
background: none;
}
-
- .documentDecorations-rotation {
- pointer-events: auto;
- cursor: alias;
- width: 10px;
- height: 10px;
- }
-
.documentDecorations-resizer {
pointer-events: auto;
background: $alt-accent;
@@ -76,11 +68,17 @@ $linkGap : 3px;
grid-column-end: 7;
}
+ #documentDecorations-rotation,
#documentDecorations-borderRadius {
- grid-column-start: 5;
- grid-column-end: 7;
+ grid-column: 5;
+ grid-row: 4;
border-radius: 100%;
background: dimgray;
+ height: 8;
+ right: -12;
+ top: 12;
+ position: relative;
+ pointer-events: all;
.borderRadiusTooltip {
width: 10px;
@@ -88,6 +86,11 @@ $linkGap : 3px;
position: absolute;
}
}
+ #documentDecorations-rotation {
+ background: transparent;
+ right: -15;
+ }
+
#documentDecorations-topLeftResizer,
#documentDecorations-bottomRightResizer {
@@ -193,11 +196,11 @@ $linkGap : 3px;
.documentDecorations-iconifyButton {
opacity: 1;
grid-column-start: 4;
- grid-column-end: 5;
+ grid-column-end: 4;
pointer-events: all;
text-align: center;
- left: -25px;
- top: -2px;
+ right: 0;
+ top: 0;
cursor: pointer;
position: absolute;
background: transparent;
@@ -206,14 +209,11 @@ $linkGap : 3px;
.documentDecorations-openInTab {
opacity: 1;
- grid-column-start: 4;
+ grid-column-start: 5;
grid-column-end: 5;
pointer-events: all;
text-align: center;
cursor: pointer;
- width: 15px;
- margin-left: -8px;
- margin-top: auto;
}
.documentDecorations-closeButton {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index f1169763e..03746a1d2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -197,17 +197,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@action
onCloseClick = async (e: React.MouseEvent | undefined) => {
if (!e?.button) {
- const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
SelectionManager.DeselectAll();
-
- selected.map(dv => {
- const effectiveAcl = GetEffectiveAcl(dv.props.Document);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
- recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
- dv.props.removeDocument?.(dv.props.Document);
- }
- });
+ selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
}
}
@action
@@ -418,6 +410,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
this._snapX = thisPt.thisX;
this._snapY = thisPt.thisY;
let dragBottom = false;
+ let dragRight = false;
let dX = 0, dY = 0, dW = 0, dH = 0;
const unfreeze = () =>
SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) =>
@@ -465,6 +458,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
case "documentDecorations-rightResizer":
unfreeze();
dW = move[0];
+ dragRight = true;
break;
}
@@ -482,7 +476,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (nwidth / nheight !== width / height) {
height = nheight / nwidth * width;
}
- if (!e.ctrlKey && (!dragBottom || !element.layoutDoc._fitWidth)) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
+ if (e.ctrlKey || (!dragBottom || !element.layoutDoc._fitWidth)) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
else dW = dH * nwidth / nheight;
}
@@ -492,33 +486,34 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
doc.x = (doc.x || 0) + dX * (actualdW - width);
doc.y = (doc.y || 0) + dY * (actualdH - height);
const fixedAspect = (nwidth && nheight);
+ const fieldKey = Doc.LayoutFieldKey(doc);
if (fixedAspect && (!nwidth || !nheight)) {
- doc._nativeWidth = nwidth = doc._width || 0;
- doc._nativeHeight = nheight = doc._height || 0;
+ doc[DataSym][fieldKey + "-nativeWidth"] = doc._nativeWidth = nwidth = doc._width || 0;
+ doc[DataSym][fieldKey + "-nativeHeight"] = doc._nativeHeight = nheight = doc._height || 0;
}
const anno = Cast(doc.annotationOn, Doc, null);
if (e.ctrlKey && anno) {
dW !== 0 && runInAction(() => {
const dataDoc = anno[DataSym];
- const fieldKey = Doc.LayoutFieldKey(anno);
- const nw = NumCast(dataDoc[fieldKey + "-nativeWidth"]);
- const nh = NumCast(dataDoc[fieldKey + "-nativeHeight"]);
- dataDoc[fieldKey + "-nativeWidth"] = nw + (dW > 0 ? 10 : -10);
- dataDoc[fieldKey + "-nativeHeight"] = nh + (dW > 0 ? 10 : -10) * nh / nw;
+ const annoFieldKey = Doc.LayoutFieldKey(anno);
+ const nw = NumCast(dataDoc[annoFieldKey + "-nativeWidth"]);
+ const nh = NumCast(dataDoc[annoFieldKey + "-nativeHeight"]);
+ dataDoc[annoFieldKey + "-nativeWidth"] = nw + (dW > 0 ? 10 : -10);
+ dataDoc[annoFieldKey + "-nativeHeight"] = nh + (dW > 0 ? 10 : -10) * nh / nw;
});
}
else if (nwidth > 0 && nheight > 0) {
- if (Math.abs(dW) > Math.abs(dH)) {
- if (!fixedAspect || e.ctrlKey) {
- doc._nativeWidth = actualdW / (doc._width || 1) * (doc._nativeWidth || 0);
+ if (Math.abs(dW) > Math.abs(dH) || dragRight) {
+ if (!fixedAspect || (dragRight && e.ctrlKey)) {
+ doc[DataSym][fieldKey + "-nativeWidth"] = doc._nativeWidth = actualdW / (doc._width || 1) * (doc._nativeWidth || 0);
}
doc._width = actualdW;
if (fixedAspect && !doc._fitWidth) doc._height = nheight / nwidth * doc._width;
else if (!fixedAspect || !e.ctrlKey) doc._height = actualdH;
}
else {
- if (!fixedAspect || e.ctrlKey || (dragBottom && element.layoutDoc._fitWidth)) {
- doc._nativeHeight = actualdH / (doc._height || 1) * (doc._nativeHeight || 0);
+ if (!fixedAspect || (dragBottom && (e.ctrlKey || element.layoutDoc._fitWidth))) {
+ doc[DataSym][fieldKey + "-nativeHeight"] = doc._nativeHeight = actualdH / (doc._height || 1) * (doc._nativeHeight || 0);
}
doc._height = actualdH;
if (fixedAspect && !doc._fitWidth) doc._width = nwidth / nheight * doc._height;
@@ -612,9 +607,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
return (null);
}
const canDelete = SelectionManager.SelectedDocuments().some(docView => {
- const docAcl = GetEffectiveAcl(docView.props.Document);
- const collectionAcl = GetEffectiveAcl(docView.props.ContainingCollectionDoc);
- return [docAcl, collectionAcl].some(acl => [AclAdmin, AclEdit].includes(acl));
+ const collectionAcl = GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]);
+ return collectionAcl === AclAdmin || collectionAcl === AclEdit;
});
const minimal = bounds.r - bounds.x < 100 ? true : false;
const maximizeIcon = minimal ? (
@@ -622,7 +616,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<div className="documentDecorations-contextMenu" onPointerDown={this.onSettingsDown}>
<FontAwesomeIcon size="lg" icon="cog" />
</div></Tooltip>) : canDelete ? (
- <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
+ <Tooltip title={<><div className="dash-tooltip">Close</div></>} placement="top">
<div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
{/* 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*/}
<FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
@@ -666,13 +660,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
bounds.y = bounds.b - (this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight);
}
var offset = 0;
- var rotButton = <></>;
- //make offset larger for ink to edit points
- if (seldoc.rootDoc.type === DocumentType.INK) {
- offset = 20;
- rotButton = <div id="documentDecorations-rotation" title="rotate" className="documentDecorations-rotation"
- onPointerDown={this.onRotateDown}> ⟲ </div>;
- }
+ let useRotation = seldoc.rootDoc.type === DocumentType.INK;
return (<div className="documentDecorations" style={{ background: darkScheme }} >
<div className="documentDecorations-background" style={{
@@ -696,12 +684,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) :
<Tooltip title={<><div className="dash-tooltip">{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}</div></>} placement="top">
<div className="documentDecorations-iconifyButton" onPointerDown={this.onIconifyDown}>
- {"_"}
+ <FontAwesomeIcon icon={seldoc.finalLayoutKey.includes("icon") ? "window-restore" : "window-minimize"} className="documentView-minimizedIcon" />
</div></Tooltip>}
- <Tooltip title={<><div className="dash-tooltip">Open Document In Tab</div></>} placement="top"><div className="documentDecorations-openInTab" onPointerDown={this.onMaximizeDown}>
+ <Tooltip title={<><div className="dash-tooltip">Open In a New Pane</div></>} placement="top"><div className="documentDecorations-openInTab" onPointerDown={this.onMaximizeDown}>
{SelectionManager.SelectedDocuments().length === 1 ? <FontAwesomeIcon icon="external-link-alt" className="documentView-minimizedIcon" /> : "..."}
</div></Tooltip>
- {rotButton}
<div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer"
onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-topResizer" className="documentDecorations-resizer"
@@ -725,8 +712,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
onPointerDown={this.onSelectorUp} onContextMenu={e => e.preventDefault()}>
<FontAwesomeIcon className="documentdecorations-times" icon={faArrowAltCircleUp} size="lg" />
</div></Tooltip>}
- <div id="documentDecorations-borderRadius" className="documentDecorations-radius"
- onPointerDown={this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}></div>
+ <div id={`documentDecorations-${useRotation ? "rotation" : "borderRadius"}`}
+ onPointerDown={useRotation ? this.onRotateDown : this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}>{useRotation && "⟲"}</div>
</div >
<div className="link-button-container" key="links" style={{ left: bounds.x - this._resizeBorderWidth / 2 + 10, top: bounds.b + this._resizeBorderWidth / 2 }}>
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 81bb542dd..76e786257 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -678,8 +678,8 @@ export default class GestureOverlay extends Touchable {
var top = Math.min(...ys);
const firstx = this._points[0].X;
const firsty = this._points[0].Y;
- const lastx = this._points[this._points.length - 2].X;
- const lasty = this._points[this._points.length - 2].Y;
+ var lastx = this._points[this._points.length - 2].X;
+ var lasty = this._points[this._points.length - 2].Y;
var fourth = (lastx - firstx) / 4;
if (isNaN(fourth) || fourth === 0) { fourth = 0.01; }
var m = (lasty - firsty) / (lastx - firstx);
@@ -771,11 +771,17 @@ export default class GestureOverlay extends Touchable {
break;
case "line":
+ if (Math.abs(firstx - lastx) < 20) {
+ lastx = firstx;
+ }
+ if (Math.abs(firsty - lasty) < 20) {
+ lasty = firsty;
+ }
this._points.push({ X: firstx, Y: firsty });
this._points.push({ X: firstx, Y: firsty });
- this._points.push({ X: firstx + 4 * fourth, Y: m * (firstx + 4 * fourth) + b });
- this._points.push({ X: firstx + 4 * fourth, Y: m * (firstx + 4 * fourth) + b });
+ this._points.push({ X: lastx, Y: lasty });
+ this._points.push({ X: lastx, Y: lasty });
break;
case "arrow":
const x1 = left;
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 182f6397c..be6aa6be2 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -1,6 +1,6 @@
import { action } from "mobx";
import { DateField } from "../../fields/DateField";
-import { Doc, DocListCast, AclEdit, AclAdmin } from "../../fields/Doc";
+import { Doc, DocListCast } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { InkTool } from "../../fields/InkField";
import { List } from "../../fields/List";
@@ -23,7 +23,6 @@ import PDFMenu from "./pdf/PDFMenu";
import { ContextMenu } from "./ContextMenu";
import GroupManager from "../util/GroupManager";
import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu";
-import { GetEffectiveAcl } from "../../fields/util";
const modifiers = ["control", "meta", "shift", "alt"];
type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise<KeyControlInfo>;
@@ -120,16 +119,9 @@ export default class KeyManager {
}
}
- const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
UndoManager.RunInBatch(() => {
- selected.map(dv => {
- const effectiveAcl = GetEffectiveAcl(dv.props.Document);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
- recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
- dv.props.removeDocument?.(dv.props.Document);
- }
- });
+ selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
}, "delete");
SelectionManager.DeselectAll();
break;
@@ -331,6 +323,8 @@ export default class KeyManager {
undoBatch(() => {
targetDataDoc[fieldKey] = new List<Doc>([...docList, ...added]);
targetDataDoc[fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ const lastModified = "lastModified";
+ targetDataDoc[lastModified] = new DateField(new Date(Date.now()));
})();
}
}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index e3390426b..41311ed86 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -43,7 +43,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
this.props.Document._backgroundColor = "rgba(0,0,0,0.7)";
this.props.Document.mixBlendMode = "hard-light";
this.props.Document.color = "#9b9b9bff";
- this.props.Document.stayInCollection = true;
+ this.props.Document._stayInCollection = true;
this.props.Document.isInkMask = true;
}
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index f3fba82bc..a05a2b858 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -4,6 +4,8 @@
.dash-tooltip {
font-size: 11px;
padding: 2px;
+ max-width: 150;
+ line-height: 150%;
}
.mainView-tabButtons {
@@ -157,7 +159,7 @@
width: 60px;
background-color: #121721;
- height: calc(100% - 32px);
+ height: calc(100% - $searchpanel-height);
//overflow-y: scroll;
//overflow-x: hidden;
@@ -215,7 +217,7 @@
.mainView-searchPanel {
width: 100%;
- height: 32px;
+ height: $searchpanel-height;
background-color: black;
color: white;
text-align: center;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4d5dfc99e..059e1f566 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -41,16 +41,14 @@ import { ContextMenu } from './ContextMenu';
import { DictationOverlay } from './DictationOverlay';
import { DocumentDecorations } from './DocumentDecorations';
import GestureOverlay from './GestureOverlay';
-import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
+import { ANTIMODEMENU_HEIGHT, SEARCH_PANEL_HEIGHT } from './globalCssVariables.scss';
import KeyManager from './GlobalKeyHandler';
import { LinkMenu } from './linking/LinkMenu';
import "./MainView.scss";
-import { MainViewNotifs } from './MainViewNotifs';
import { AudioBox } from './nodes/AudioBox';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
import { DocumentView } from './nodes/DocumentView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import RichTextMenu from './nodes/formattedText/RichTextMenu';
import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
import { LinkDocPreview } from './nodes/LinkDocPreview';
import { RadialMenu } from './nodes/RadialMenu';
@@ -59,10 +57,14 @@ import { OverlayView } from './OverlayView';
import PDFMenu from './pdf/PDFMenu';
import { PreviewCursor } from './PreviewCursor';
import { Hypothesis } from '../util/HypothesisUtils';
-import { undoBatch } from '../util/UndoManager';
import { WebBox } from './nodes/WebBox';
import * as ReactDOM from 'react-dom';
import { SearchBox } from './search/SearchBox';
+import { SearchUtil } from '../util/SearchUtil';
+import { Networking } from '../Network';
+import * as rp from 'request-promise';
+import { LinkManager } from '../util/LinkManager';
+import RichTextMenu from './nodes/formattedText/RichTextMenu';
@observer
export class MainView extends React.Component {
@@ -164,7 +166,7 @@ export class MainView extends React.Component {
}
}
- library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt,
+ library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock,
fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard,
fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight,
@@ -180,7 +182,8 @@ export class MainView extends React.Component {
fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper,
fa.faDesktop, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle,
fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp,
- fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, faBuffer);
+ fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, faBuffer, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl,
+ fa.faWindowMinimize, fa.faWindowRestore);
this.initEventListeners();
this.initAuthenticationRouters();
}
@@ -199,7 +202,7 @@ export class MainView extends React.Component {
let check = false;
const icon = "icon";
targets.forEach((thing) => {
- if (thing.className.toString() === "collectionSchemaView-table" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "beta" || thing.className.toString() === "collectionSchemaView-menuOptions-wrapper") {
+ if (thing.className.toString() === "collectionSchemaView-searchContainer" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "collectionSchema-header-menuOptions" || thing.className.toString() === "altcollectionTimeView-treeView") {
check = true;
}
});
@@ -258,7 +261,7 @@ export class MainView extends React.Component {
y: 400,
_width: this._panelWidth * .7 - this.propertiesWidth() * 0.7,
_height: this._panelHeight,
- title: "Collection " + workspaceCount,
+ title: "Untitled Collection",
};
const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
@@ -307,11 +310,7 @@ export class MainView extends React.Component {
DocServer.Control.makeEditable();
}
}
- // 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["sidebar-sharing"], Doc);
- col && Cast(col.data, listSpec(Doc)) && runInAction(() => MainViewNotifs.NotifsCol = col);
- }, 100);
+
return true;
}
@@ -332,7 +331,7 @@ export class MainView extends React.Component {
getPHeight = () => this._panelHeight;
getContentsHeight = () => this._panelHeight - this._buttonBarHeight;
- defaultBackgroundColors = (doc: Opt<Doc>) => {
+ defaultBackgroundColors = (doc: Opt<Doc>, renderDepth: number) => {
if (this.panelContent === doc?.title) return "lightgrey";
if (doc?.type === DocumentType.COL) {
@@ -342,7 +341,7 @@ export class MainView extends React.Component {
|| doc.title === "Advanced Item Prototypes" || doc.title === "all Creators") {
return "lightgrey";
}
- return StrCast(Doc.UserDoc().defaultColor);
+ return StrCast(renderDepth > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground);
}
if (this.darkScheme) {
switch (doc?.type) {
@@ -402,7 +401,7 @@ export class MainView extends React.Component {
TraceMobx();
const mainContainer = this.mainContainer;
const width = this.flyoutWidth + this.propertiesWidth();
- return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)`, height: `calc(100% - 32px)` }}>
+ return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)`, height: `calc(100% - ${SEARCH_PANEL_HEIGHT})` }}>
{!mainContainer ? (null) : this.mainDocView}
</div>;
}
@@ -439,15 +438,13 @@ export class MainView extends React.Component {
doc.dockingConfig ? this.openWorkspace(doc) :
CollectionDockingView.AddRightSplit(doc, libraryPath);
}
- sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
- //sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1);
- mainContainerXf = () => this.sidebarScreenToLocal().translate(-55, -this._buttonBarHeight);
+ sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0) - Number(SEARCH_PANEL_HEIGHT.replace("px", "")), 1);
+ mainContainerXf = () => this.sidebarScreenToLocal().translate(-58, 0);
- @computed get closePosition() { return 55 + this.flyoutWidth; }
@computed get flyout() {
if (!this.sidebarContent) return null;
return <div className="mainView-libraryFlyout">
- <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - 32px)`, width: "100%", overflow: "visible" }}>
+ <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - ${SEARCH_PANEL_HEIGHT})`, width: "100%", overflow: "visible" }}>
{/* {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close"
onPointerDown={this.closeFlyout}>
<FontAwesomeIcon icon="times" color="black" size="lg" />
@@ -531,22 +528,24 @@ export class MainView extends React.Component {
_lastButton: Doc | undefined;
@action
- selectMenu = (button: Doc, str: string) => {
+ selectMenu = (button: Doc) => {
+ const title = StrCast(Doc.GetProto(button).title);
this._lastButton && (this._lastButton.color = "white");
this._lastButton && (this._lastButton._backgroundColor = "");
- if (this.panelContent === str && this.flyoutWidth !== 0) {
+ if (this.panelContent === title && this.flyoutWidth !== 0) {
this.panelContent = "none";
this.flyoutWidth = 0;
} else {
let panelDoc: Doc | undefined;
- switch (this.panelContent = str) {
+ switch (this.panelContent = title) {
case "Tools": panelDoc = Doc.UserDoc()["sidebar-tools"] as Doc ?? undefined; break;
case "Workspace": panelDoc = Doc.UserDoc()["sidebar-workspaces"] as Doc ?? undefined; break;
case "Catalog": panelDoc = Doc.UserDoc()["sidebar-catalog"] as Doc ?? undefined; break;
case "Archive": panelDoc = Doc.UserDoc()["sidebar-recentlyClosed"] as Doc ?? undefined; break;
case "Settings": SettingsManager.Instance.open(); break;
+ case "Import": panelDoc = Doc.UserDoc()["sidebar-import"] as Doc ?? undefined; break;
case "Sharing": panelDoc = Doc.UserDoc()["sidebar-sharing"] as Doc ?? undefined; break;
- case "UserDoc": panelDoc = Doc.UserDoc()["sidebar-userDoc"] as Doc ?? undefined; break;
+ case "User Doc": panelDoc = Doc.UserDoc()["sidebar-userDoc"] as Doc ?? undefined; break;
}
this.sidebarContent.proto = panelDoc;
if (panelDoc) {
@@ -610,7 +609,6 @@ export class MainView extends React.Component {
</div>
</div>
{this.dockingContent}
- <MainViewNotifs />
{this.showProperties ? (null) :
<div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onPropertiesPointerDown}
style={{ right: rightFlyout, top: "50%" }}>
@@ -819,8 +817,8 @@ export class MainView extends React.Component {
<DocumentDecorations />
{this.search}
<CollectionMenu />
- <FormatShapePane />
<div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
+ <FormatShapePane />
{LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
{DocumentLinksButton.EditLink ? <LinkMenu docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)}
{LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors}
@@ -895,7 +893,83 @@ export class MainView extends React.Component {
document.addEventListener("editSuccess", onSuccess);
});
}
+
+ importDocument = () => {
+ const sidebar = Cast(Doc.UserDoc()["sidebar-import-documents"], Doc, null);
+ const sidebarDocView = DocumentManager.Instance.getDocumentView(sidebar);
+ const input = document.createElement("input");
+ input.type = "file";
+ input.multiple = true;
+ input.accept = ".zip, application/pdf, video/*, image/*, audio/*";
+ input.onchange = async _e => {
+ const upload = Utils.prepend("/uploadDoc");
+ const formData = new FormData();
+ const file = input.files && input.files[0];
+ if (file && file.type === 'application/zip') {
+ formData.append('file', file);
+ formData.append('remap', "true");
+ const response = await fetch(upload, { method: "POST", body: formData });
+ const json = await response.json();
+ if (json !== "error") {
+ const doc = await DocServer.GetRefField(json);
+ if (doc instanceof Doc && sidebarDocView) {
+ sidebarDocView.props.addDocument?.(doc);
+ setTimeout(() => {
+ SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => {
+ docs.docs.forEach(d => LinkManager.Instance.addLink(d));
+ });
+ }, 2000); // need to give solr some time to update so that this query will find any link docs we've added.
+
+ }
+ }
+ } else if (input.files && input.files.length !== 0) {
+ const files = input.files || [];
+ Array.from(files).forEach(async file => {
+ const res = await Networking.UploadFilesToServer(file);
+ res.map(async ({ result }) => {
+ const name = file.name;
+ if (result instanceof Error) {
+ return;
+ }
+ const path = Utils.prepend(result.accessPaths.agnostic.client);
+ let doc: Doc;
+ // Case 1: File is a video
+ if (file.type.includes("video")) {
+ doc = Docs.Create.VideoDocument(path, { _height: 100, title: name });
+ // Case 2: File is a PDF document
+ } else if (file.type === "application/pdf") {
+ doc = Docs.Create.PdfDocument(path, { _height: 100, _fitWidth: true, title: name });
+ // Case 3: File is an image
+ } else if (file.type.includes("image")) {
+ doc = Docs.Create.ImageDocument(path, { _height: 100, title: name });
+ // Case 4: File is an audio document
+ } else {
+ doc = Docs.Create.AudioDocument(path, { title: name });
+ }
+ const res = await rp.get(Utils.prepend("/getUserDocumentId"));
+ if (!res) {
+ throw new Error("No user id returned");
+ }
+ const field = await DocServer.GetRefField(res);
+ let pending: Opt<Doc>;
+ if (field instanceof Doc) {
+ pending = sidebar;
+ }
+ if (pending) {
+ const data = await Cast(pending.data, listSpec(Doc));
+ if (data) data.push(doc);
+ else pending.data = new List([doc]);
+ }
+ });
+ });
+ } else {
+ console.log("No file selected");
+ }
+ };
+ input.click();
+ }
}
+Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); });
Scripting.addGlobal(function freezeSidebar() { MainView.expandFlyout(); });
Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; });
Scripting.addGlobal(function copyWorkspace() {
@@ -905,3 +979,5 @@ Scripting.addGlobal(function copyWorkspace() {
// bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
setTimeout(() => MainView.Instance.openWorkspace(copiedWorkspace), 0);
});
+Scripting.addGlobal(function importDocument() { return MainView.Instance.importDocument(); },
+ "imports files from device directly into the import sidebar");
diff --git a/src/client/views/MainViewNotifs.scss b/src/client/views/MainViewNotifs.scss
deleted file mode 100644
index 92d7d6ee3..000000000
--- a/src/client/views/MainViewNotifs.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-.mainNotifs-container {
- position:absolute;
- z-index: 1000;
- top: 12px;
-
- .mainNotifs-badge {
- position: absolute;
- top: -10px;
- right: -10px;
- color: white;
- background: #f44b42;
- font-weight: 300;
- border-radius: 100%;
- width: 25px;
- height: 25px;
- text-align: center;
- padding-top: 4px;
- font-size: 12px;
- }
-} \ No newline at end of file
diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx
deleted file mode 100644
index 89006ebc8..000000000
--- a/src/client/views/MainViewNotifs.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { observable } from 'mobx';
-import { observer } from 'mobx-react';
-import "normalize.css";
-import * as React from 'react';
-import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { returnFalse, setupMoveUpEvents } from '../../Utils';
-import { DragManager } from '../util/DragManager';
-import "./MainViewNotifs.scss";
-import { MainView } from './MainView';
-import { NumCast } from '../../fields/Types';
-
-
-@observer
-export class MainViewNotifs extends React.Component {
- @observable static NotifsCol: Opt<Doc>;
- _notifsRef = React.createRef<HTMLDivElement>();
-
- onPointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e,
- (e: PointerEvent) => {
- const dragData = new DragManager.DocumentDragData([MainViewNotifs.NotifsCol!]);
- DragManager.StartDocumentDrag([this._notifsRef.current!], dragData, e.x, e.y);
- return true;
- },
- returnFalse,
- () => MainViewNotifs.NotifsCol && MainView.Instance.selectMenu(MainViewNotifs.NotifsCol, "Sharing"));
- }
-
- render() {
- const length = MainViewNotifs.NotifsCol ? DocListCast(MainViewNotifs.NotifsCol.data).length : 0;
- return <div className="mainNotifs-container" style={{ width: 15, height: 15, top: 12 + NumCast(MainViewNotifs.NotifsCol?.position) * 60 }} ref={this._notifsRef}>
- <button className="mainNotifs-badge" style={length > 0 ? { "display": "initial" } : { "display": "none" }}
- onPointerDown={this.onPointerDown} >
- {length}
- </button>
- </div>;
- }
-}
diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss
index 09a349012..555f4298d 100644
--- a/src/client/views/OverlayView.scss
+++ b/src/client/views/OverlayView.scss
@@ -44,6 +44,6 @@
}
.overlayView-doc {
- z-index: 1;
+ z-index: 9002; //so that it appears above chroma
position: absolute;
} \ No newline at end of file
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 5c3a8185c..49580cde4 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -182,7 +182,7 @@ export class OverlayView extends React.Component {
offsetx = NumCast(d.x) - e.clientX;
offsety = NumCast(d.y) - e.clientY;
};
- return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
+ return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ top: d.type === 'presentation' ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
<DocumentView
Document={d}
LibraryPath={emptyPath}
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 5e25ead87..35d4f7f6e 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -3,7 +3,7 @@ import { faArrowAltCircleDown, faArrowAltCircleRight, faArrowAltCircleUp, faChec
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, AclEdit, AclAdmin } from "../../fields/Doc";
+import { Doc } from "../../fields/Doc";
import { RichTextField } from '../../fields/RichTextField';
import { Cast, NumCast, BoolCast } from "../../fields/Types";
import { emptyFunction, setupMoveUpEvents, Utils } from "../../Utils";
@@ -30,7 +30,6 @@ import { undoBatch, UndoManager } from '../util/UndoManager';
import { DocumentType } from '../documents/DocumentTypes';
import { InkField } from '../../fields/InkField';
import { PresBox } from './nodes/PresBox';
-import { GetEffectiveAcl } from "../../fields/util";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -417,14 +416,14 @@ export class PropertiesButtons extends React.Component<{}, {}> {
get deleteButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip
- title={<><div className="dash-tooltip">{"Delete Document"}</div></>} placement="top">
+ title={<><div className="dash-tooltip">Close Document</div></>} placement="top">
<div>
<div className={"propertiesButtons-linkButton-empty"}
onPointerDown={this.deleteDocument}>
{<FontAwesomeIcon className="propertiesButtons-icon"
- icon="trash-alt" size="lg" />}
+ icon="times" size="lg" />}
</div>
- <div className="propertiesButtons-title"> delete </div>
+ <div className="propertiesButtons-title"> close </div>
</div>
</Tooltip>;
}
@@ -432,16 +431,8 @@ export class PropertiesButtons extends React.Component<{}, {}> {
@undoBatch
@action
deleteDocument = () => {
- const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
-
- selected.map(dv => {
- const effectiveAcl = GetEffectiveAcl(dv.props.Document);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
- recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
- dv.props.removeDocument?.(dv.props.Document);
- }
- });
+ selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
this.selectedDoc && (this.selectedDoc.deleted = true);
this.selectedDocumentView?.props.ContainingCollectionView?.removeDocument(this.selectedDocumentView?.props.Document);
SelectionManager.DeselectAll();
@@ -648,7 +639,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
this.selectedDoc._backgroundColor = "rgba(0,0,0,0.7)";
this.selectedDoc.mixBlendMode = "hard-light";
this.selectedDoc.color = "#9b9b9bff";
- this.selectedDoc.stayInCollection = true;
+ this.selectedDoc._stayInCollection = true;
this.selectedDoc.isInkMask = true;
}
}
@@ -718,6 +709,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const isInk = this.selectedDoc[Doc.LayoutFieldKey(this.selectedDoc)] instanceof InkField;
const isCollection = this.selectedDoc.type === DocumentType.COL ? true : false;
const isFreeForm = this.selectedDoc._viewType === "freeform" ? true : false;
+ const hasContext = this.selectedDoc.context ? true : false;
return <div><div className="propertiesButtons" style={{ paddingBottom: "5.5px" }}>
<div className="propertiesButtons-button">
@@ -732,7 +724,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-button">
{this.pinWithViewButton}
</div>
- <div className="propertiesButtons-button">
+ <div className="propertiesButtons-button" style={{ display: hasContext ? "" : "none" }}>
{this.copyButton}
</div>
<div className="propertiesButtons-button">
@@ -750,6 +742,9 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-button">
{this.sharingButton}
</div>
+ <div className="propertiesButtons-button">
+ {this.contextButton}
+ </div>
<div className="propertiesButtons-button" style={{ display: !considerPush ? "none" : "" }}>
{this.considerGoogleDocsPush}
</div>
@@ -774,9 +769,6 @@ export class PropertiesButtons extends React.Component<{}, {}> {
<div className="propertiesButtons-button" style={{ display: !isInk ? "none" : "" }}>
{this.maskButton}
</div>
- <div className="propertiesButtons-button">
- {this.contextButton}
- </div>
</div>
</div>;
}
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index 1eb380e0b..db087fb23 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -104,7 +104,7 @@ export class ScriptingRepl extends React.Component {
if (ts.isParameter(node.parent)) {
// delete knownVars[node.text];
} else if (isntPropAccess && isntPropAssign && !(node.text in knownVars) && !(node.text in globalThis)) {
- const match = node.text.match(/\d([0-9]+)/);
+ const match = node.text.match(/d([0-9]+)/);
if (match) {
const m = parseInt(match[1]);
usedDocuments.push(m);
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 27aea4b99..8a27f8102 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -64,7 +64,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
</div>
<div className="collectionCarouselView-caption" key="caption"
style={{
- background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.backgroundColor?.(this.props.Document)),
+ background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.backgroundColor?.(this.props.Document, this.props.renderDepth)),
color: StrCast(this.layoutDoc._captionColor, StrCast(this.layoutDoc.color)),
borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
}}>
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 4204ef5bb..6ebd5103b 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -20,82 +20,6 @@
}
}
-.miniPres:hover {
- opacity: 1;
-}
-
-.miniPres {
- position: absolute;
- overflow: hidden;
- right: 10;
- top: 10;
- opacity: 0.1;
- transition: all 0.4s;
- /* border: solid 1px; */
- color: white;
- /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
-
- .miniPresOverlay {
- display: grid;
- grid-template-columns: auto auto auto auto auto auto auto auto;
- grid-template-rows: 100%;
- height: 100%;
- justify-items: center;
- align-items: center;
-
- .miniPres-button-text {
- display: flex;
- height: 20;
- font-weight: 400;
- min-width: 100%;
- border-radius: 5px;
- align-items: center;
- justify-content: center;
- transition: all 0.3s;
- }
-
- .miniPres-button-frame {
- justify-self: center;
- align-self: center;
- align-items: center;
- display: grid;
- grid-template-columns: auto auto auto;
- justify-content: space-around;
- font-size: 11;
- margin-left: 7;
- width: 30;
- height: 85%;
- background-color: rgba(91, 157, 221, 0.4);
- border-radius: 5px;
- }
-
- .miniPres-divider {
- width: 0.5px;
- height: 80%;
- border-right: solid 2px #5a5a5a;
- }
-
- .miniPres-button {
- display: flex;
- height: 20;
- min-width: 20;
- border-radius: 100%;
- align-items: center;
- justify-content: center;
- transition: all 0.3s;
- }
-
- .miniPres-button:hover {
- background-color: #5a5a5a;
- }
-
- .miniPres-button-text:hover {
- background-color: #5a5a5a;
- }
- }
-}
-
-
.lm_title {
margin-top: 3px;
border-radius: 5px;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 3691e844f..43da0d3cf 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -191,31 +191,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
return retVal;
}
- @undoBatch
- @action
- public static ReplaceTab(document: Doc, stack: any): Opt<Doc> {
- if (!CollectionDockingView.Instance) return undefined;
- const instance = CollectionDockingView.Instance;
- const replaceTab = (doc: Doc, child: any): Opt<Doc> => {
- for (const contentItem of child.contentItems) {
- const { config, isStack, isRow, isColumn } = contentItem;
- if (isRow || isColumn || isStack) {
- const val = replaceTab(doc, contentItem);
- if (val) return val;
- } else if (config.component === "DocumentFrameRenderer" &&
- config.props.documentId === doc[Id]) {
- const alias = Doc.MakeAlias(doc);
- config.props.documentId = alias[Id];
- config.title = alias.title;
- instance.stateChanged();
- return alias;
- }
- }
- return undefined;
- };
- return replaceTab(document, instance._goldenLayout.root);
- }
-
//
// Creates a vertical split on the right side of the docking view, and then adds the Document to the right of that split
//
@@ -358,6 +333,32 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
return true;
}
+ @undoBatch
+ @action
+ public ReplaceTab = (stack: any, document: Doc, libraryPath?: Doc[]) => {
+ Doc.GetProto(document).lastOpened = new DateField;
+ const docContentConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
+ if (stack === undefined) {
+ let stack: any = this._goldenLayout.root;
+ while (!stack.isStack) {
+ if (stack.contentItems.length) {
+ stack = stack.contentItems[0];
+ } else {
+ stack.addChild({ type: 'stack', content: [docContentConfig] });
+ stack = undefined;
+ break;
+ }
+ }
+ if (stack) {
+ stack.addChild(docContentConfig);
+ }
+ } else {
+ stack.addChild(docContentConfig, undefined);
+ }
+ this.layoutChanged();
+ return true;
+ }
+
setupGoldenLayout() {
const config = StrCast(this.props.Document.dockingConfig);
if (config) {
@@ -727,9 +728,11 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
pinDoc.presZoomButton = true;
pinDoc.context = curPres;
Doc.AddDocToList(curPres, "data", pinDoc);
+ if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
if (!DocumentManager.Instance.getDocumentView(curPres)) {
CollectionDockingView.AddRightSplit(curPres);
}
+ DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
}
}
}
@@ -758,7 +761,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
this.props.glContainer.on("tab", this.onActiveContentItemChanged);
this.onActiveContentItemChanged();
- this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, "white") }),
+ this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white") }),
(data) => {
const selected = data.views.some(v => Doc.AreProtosEqual(v.props.Document, this._document));
this._tab && (this._tab.style.backgroundColor = selected ? data.color : "");
@@ -821,7 +824,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
if (this._mainCont && this._mainCont.children) {
const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement);
const scale = Utils.GetScreenTransform(this._mainCont).scale;
- return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale);
+ return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale);
}
return Transform.Identity();
}
@@ -837,12 +840,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
} else if (location === "close") {
return CollectionDockingView.CloseRightSplit(doc);
} else if (location === "replace") {
- const alias = CollectionDockingView.ReplaceTab(doc, this._stack);
- if (alias) {
- runInAction(() => this._document = alias);
- return true;
- }
- return false;
+ CollectionDockingView.UseRightSplit(doc);
+ return true;
} else {// if (location === "inPlace") {
return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath);
}
@@ -873,30 +872,11 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
const currentFrame = Cast(presTargetDoc.currentFrame, "number", null);
return currentFrame;
}
- renderMiniPres() {
- return (
- <div className="miniPres"
- style={{ width: 250, height: 30, background: '#323232' }}
- >
- {<div className="miniPresOverlay">
- <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
- <div className="miniPres-button" onClick={() => PresBox.Instance.startAutoPres(PresBox.Instance.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
- <div className="miniPres-button" onClick={PresBox.Instance.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
- <div className="miniPres-divider"></div>
- <div className="miniPres-button-text">
- Slide {PresBox.Instance.itemIndex + 1} / {PresBox.Instance.childDocs.length}
- {PresBox.Instance.playButtonFrames}
- </div>
- <div className="miniPres-divider"></div>
- <div className="miniPres-button-text" onClick={PresBox.Instance.updateMinimize}>EXIT</div>
- </div>}
- </div>
- );
- }
+
renderMiniMap() {
return <div className="miniMap" style={{
width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor,
- StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!))),
+ StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))),
}}>
<CollectionFreeFormView
Document={this._document!}
@@ -975,7 +955,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
{document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
- {document._viewType === CollectionViewType.Freeform && this._document?.miniPres ? this.renderMiniPres() : (null)}
</>;
}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 3cf46dbed..e1b07077e 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -119,7 +119,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
// transform: this.props.Document.linearViewIsExpanded ? "" : "rotate(45deg)"
}}
onPointerDown={e => e.stopPropagation()} >
- <p>+</p>
+ <p>{BoolCast(this.props.Document.linearViewIsExpanded) ? "–" : "+"}</p>
</label>;
return <div className="collectionLinearView-outer">
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index b41cbe92d..8658212b7 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -315,6 +315,7 @@
display: inline-flex;
position: relative;
align-items: center;
+ margin-left: 10px;
.antimodeMenu-button {
text-align: center;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 53d2a136e..5119ff6c9 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -85,7 +85,8 @@ export default class CollectionMenu extends AntimodeMenu {
const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Properties Panel" : "Open Properties Panel";
const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="properties" placement="bottom">
- <button className="antimodeMenu-button" key="properties" onPointerDown={this.toggleProperties}>
+ <button className="antimodeMenu-button" key="properties" style={{ backgroundColor: "#424242" }}
+ onPointerDown={this.toggleProperties}>
<FontAwesomeIcon icon={propIcon} size="lg" />
</button>
</Tooltip>;
@@ -580,9 +581,9 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
onPointerDown={action(() => { this.changeColor(color, "color"); this._colorBtn = false; this.editProperties(color, "color"); })}
style={{ backgroundColor: this._colorBtn ? "121212" : "", zIndex: 1001 }}>
{/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */}
- <div className="color-previewII" style={{ backgroundColor: color }} />
- {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
-
+ <div className="color-previewII" style={{ backgroundColor: color }}>
+ {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
+ </div>
</button>)}
</div>;
}
@@ -622,7 +623,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
</div>
</Tooltip> : null}
{!this.isText && !this.props.isDoc ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
- <div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
+ <div className="numKeyframe" style={{ color: this.document.editing ? "white" : "black", backgroundColor: this.document.editing ? "#5B9FDD" : "#AEDDF8" }}
onClick={action(() => this.document.editing = !this.document.editing)} >
{NumCast(this.document.currentFrame)}
</div>
@@ -669,7 +670,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
@computed get pivotField() { return StrCast(this.document._pivotField); }
getKeySuggestions = async (value: string): Promise<string[]> => {
- value = value.toLowerCase();
+ const val = value.toLowerCase();
const docs = DocListCast(this.document[this.props.fieldKey]);
if (Doc.UserDoc().noviceMode) {
@@ -677,7 +678,7 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
(key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
- return keys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
} else {
const keys = new Set<string>();
docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
@@ -685,16 +686,16 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 ||
key.indexOf("lastModified") >= 0 || (key[0].toUpperCase() === key[0] &&
key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
- return noviceKeys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
}
}
if (docs instanceof Doc) {
- return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value));
+ return Object.keys(docs).filter(key => key.toLowerCase().indexOf(val) > -1);
} else {
const keys = new Set<string>();
docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
- return Array.from(keys).filter(key => key.toLowerCase().startsWith(value));
+ return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1);
}
}
@@ -735,8 +736,10 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
@action resetValue = () => { this._currentKey = this.pivotField; };
render() {
+ const doctype = this.props.docView.Document.type;
+ const isPres: boolean = (doctype === DocumentType.PRES);
return (
- <div className="collectionStackingViewChrome-cont">
+ isPres ? (null) : <div className="collectionStackingViewChrome-cont">
<div className="collectionStackingViewChrome-pivotField-cont">
<div className="collectionStackingViewChrome-pivotField-label">
GROUP BY:
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 8a1dd8472..20ce6b76d 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -1,5 +1,5 @@
import React = require("react");
-import { action, observable, trace, computed } from "mobx";
+import { action, observable, trace, computed, runInAction } from "mobx";
import { observer } from "mobx-react";
import { CellInfo } from "react-table";
import "react-table/react-table.css";
@@ -33,6 +33,8 @@ import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { DateField } from "../../../fields/DateField";
import { RichTextField } from "../../../fields/RichTextField";
+import { DocumentManager } from "../../util/DocumentManager";
+import { SearchUtil } from "../../util/SearchUtil";
const path = require('path');
library.add(faExpand);
@@ -67,10 +69,29 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
protected _document = this.props.rowProps.original;
protected _dropDisposer?: DragManager.DragDropDisposer;
- componentDidMount() {
+ async componentWillMount() {
+
+ }
+
+ async componentDidMount() {
document.addEventListener("keydown", this.onKeyDown);
+ console.log("mounted");
+ console.log(this.type);
+ if (this.type === "context") {
+ console.log("mounted2");
+ const doc = Doc.GetProto(this.props.rowProps.original);
+ const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
+ if (aliasdoc.length > 0) {
+ const targetContext = Cast(aliasdoc[0].context, Doc) as Doc;
+ console.log(StrCast(targetContext.title));
+ runInAction(() => this.contents = StrCast(targetContext.title));
+ }
+ }
+
}
+ @observable contents: string = "";
+
componentWillUnmount() {
document.removeEventListener("keydown", this.onKeyDown);
}
@@ -159,6 +180,31 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
// e.stopPropagation();
// }
+ returnHighlights(bing: (() => string), positions?: number[]) {
+ const results = [];
+ const contents = bing();
+
+ if (positions !== undefined) {
+ StrCast(this.props.Document._searchString);
+ const length = StrCast(this.props.Document._searchString).length;
+ const color = contents ? "black" : "grey";
+
+ results.push(<span key="-1" style={{ color }}>{contents?.slice(0, positions[0])}</span>);
+ positions.forEach((num, cur) => {
+ results.push(<span key={"start" + cur} style={{ backgroundColor: "#FFFF00", color }}>{contents?.slice(num, num + length)}</span>);
+ let end = 0;
+ cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1];
+ results.push(<span key={"end" + cur} style={{ color }}>{contents?.slice(num + length, end)}</span>);
+ }
+ );
+ return results;
+ }
+ else {
+ return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>;
+ }
+ }
+ type: string = "";
+
renderCellWithType(type: string | undefined) {
const dragRef: React.RefObject<HTMLDivElement> = React.createRef();
@@ -200,12 +246,23 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
const doc = FieldValue(Cast(field, Doc));
const fieldIsDoc = (type === "document" && typeof field === "object") || (typeof field === "object" && doc);
- const onItemDown = (e: React.PointerEvent) => {
- //fieldIsDoc &&
- SetupDrag(this._focusRef,
- () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document,
- this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument,
- this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
+ const onItemDown = async (e: React.PointerEvent) => {
+ if (this.props.Document._searchDoc !== undefined) {
+ const doc = Doc.GetProto(this.props.rowProps.original);
+ const aliasdoc = await SearchUtil.GetAliasesOfDocument(doc);
+ let targetContext = undefined;
+ if (aliasdoc.length > 0) {
+ targetContext = Cast(aliasdoc[0].context, Doc) as Doc;
+ }
+ DocumentManager.Instance.jumpToDocument(this.props.rowProps.original, false, undefined, targetContext);
+ }
+ else {
+ fieldIsDoc &&
+ SetupDrag(this._focusRef,
+ () => this._document[props.fieldKey] instanceof Doc ? this._document[props.fieldKey] : this._document,
+ this._document[props.fieldKey] instanceof Doc ? (doc: Doc | Doc[], target: Doc | undefined, addDoc: (newDoc: Doc | Doc[]) => any) => addDoc(doc) : this.props.moveDocument,
+ this._document[props.fieldKey] instanceof Doc ? "alias" : this.props.Document.schemaDoc ? "copy" : undefined)(e);
+ }
};
const onPointerEnter = (e: React.PointerEvent): void => {
if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) {
@@ -250,20 +307,10 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
// </div>
// );
const positions = [];
+ let cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
+ this.type = props.fieldKey;
if (StrCast(this.props.Document._searchString).toLowerCase() !== "") {
- const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
- let term = "";
- if (cfield !== undefined) {
- if (cfield.Text !== undefined) {
- term = cfield.Text;
- }
- else if (StrCast(cfield)) {
- term = StrCast(cfield);
- }
- else {
- term = String(NumCast(cfield));
- }
- }
+ let term = Field.toString(cfield as Field);
term = term.toLowerCase();
const search = StrCast(this.props.Document._searchString).toLowerCase();
let start = term.indexOf(search);
@@ -281,89 +328,123 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
positions.pop();
}
}
+ let search = false;
+ if (this.props.Document._searchDoc !== undefined) {
+ search = true;
+ }
+
return (
<div className="collectionSchemaView-cellContainer" style={{ cursor: fieldIsDoc ? "grab" : "auto" }}
ref={dragRef} onPointerDown={this.onPointerDown} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}>
<div className={className} ref={this._focusRef} onPointerDown={onItemDown} tabIndex={-1}>
- <div className="collectionSchemaView-cellContents" ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}>
- <EditableView
- positions={positions.length > 0 ? positions : undefined}
- search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined}
- editing={this._isEditing}
- isEditingCallback={this.isEditingCallback}
- display={"inline"}
- contents={contents ? contents : type === "number" ? "0" : "undefined"}
- highlight={positions.length > 0 ? true : undefined}
- //contents={StrCast(contents)}
- height={"auto"}
- maxHeight={Number(MAX_ROW_HEIGHT)}
- placeholder={"enter value"}
- bing={() => {
- const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
- if (cfield !== undefined) {
- console.log(typeof (cfield));
- // if (typeof(cfield)===RichTextField)
- const a = cfield as RichTextField;
- if (a.Text !== undefined) {
- return (a.Text);
- }
- else if (StrCast(cfield)) {
- return StrCast(cfield);
- }
- else {
- return String(NumCast(cfield));
- }
- }
- }}
- GetValue={() => {
- if (type === "number" && (contents === 0 || contents === "0")) {
- return "0";
- } else {
+ <div className="collectionSchemaView-cellContents"
+ ref={type === undefined || type === "document" ? this.dropRef : null} key={props.Document[Id]}>
+ {!search ?
+ <EditableView
+ positions={positions.length > 0 ? positions : undefined}
+ search={StrCast(this.props.Document._searchString) ? StrCast(this.props.Document._searchString) : undefined}
+ editing={this._isEditing}
+ isEditingCallback={this.isEditingCallback}
+ display={"inline"}
+ contents={contents ? contents : type === "number" ? "0" : "undefined"}
+ highlight={positions.length > 0 ? true : undefined}
+ //contents={StrCast(contents)}
+ height={"auto"}
+ maxHeight={Number(MAX_ROW_HEIGHT)}
+ placeholder={"undefined"}
+ bing={() => {
const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
- if (type === "number") {
- return StrCast(cfield);
+ if (cfield !== undefined) {
+ // if (typeof(cfield)===RichTextField)
+ const a = cfield as RichTextField;
+ const b = cfield as DateField;
+ console.log(b);
+ if (a.Text !== undefined) {
+ return (a.Text);
+ }
+ else if (b.toString() !== undefined) {
+ return b.toString();
+ }
+ else if (StrCast(cfield)) {
+ return StrCast(cfield);
+ }
+ else {
+ return String(NumCast(cfield));
+ }
}
- const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
- const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
- const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
- Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
- return val;
+ }}
+ GetValue={() => {
+ if (type === "number" && (contents === 0 || contents === "0")) {
+ return "0";
+ } else {
+ const cfield = ComputedField.WithoutComputed(() => FieldValue(props.Document[props.fieldKey]));
+ if (type === "number") {
+ return StrCast(cfield);
+ }
+ const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined;
+ const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1];
+ const val = cscript !== undefined ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) :
+ Field.IsField(cfield) ? Field.toScriptString(cfield) : "";
+ return val;
- }
+ }
- }}
- SetValue={action((value: string) => {
- let retVal = false;
+ }}
+ SetValue={action((value: string) => {
+ let retVal = false;
+
+ if (value.startsWith(":=")) {
+ retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
+ } else {
+ const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
+ if (script.compiled) {
+ retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run);
+ }
- if (value.startsWith(":=")) {
- retVal = this.props.setComputed(value.substring(2), props.Document, this.props.rowProps.column.id!, this.props.row, this.props.col);
- } else {
+ }
+ if (retVal) {
+ this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
+ this.props.setIsEditing(false);
+ }
+ return retVal;
+
+ //return true;
+ })}
+ OnFillDown={async (value: string) => {
const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
if (script.compiled) {
- retVal = this.applyToDoc(props.Document, this.props.row, this.props.col, script.run);
+ DocListCast(this.props.Document[this.props.fieldKey]).
+ forEach((doc, i) => value.startsWith(":=") ?
+ this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) :
+ this.applyToDoc(doc, i, this.props.col, script.run));
}
-
+ }}
+ />
+ :
+ this.returnHighlights(() => {
+ console.log(props.fieldKey);
+ const dateCheck: Date | undefined = this.props.rowProps.original[this.props.rowProps.column.id as string] instanceof DateField ? DateCast(this.props.rowProps.original[this.props.rowProps.column.id as string]).date : undefined;
+ if (dateCheck !== undefined) {
+ cfield = dateCheck.toLocaleString();
}
- if (retVal) {
- this._isEditing = false; // need to set this here. otherwise, the assignment of the field will invalidate & cause render() to be called with the wrong value for 'editing'
- this.props.setIsEditing(false);
+ if (props.fieldKey === "context") {
+ cfield = this.contents;
+ console.log("this should work");
}
- return retVal;
+ if (props.fieldKey === "*lastModified") {
+ if (FieldValue(props.Document["data-lastModified"]) !== undefined) {
+ const d = ComputedField.WithoutComputed(() => FieldValue(props.Document["data-lastModified"])) as DateField;
+ cfield = d.date.toLocaleString();
+ }
- //return true;
- })}
- OnFillDown={async (value: string) => {
- const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
- if (script.compiled) {
- DocListCast(this.props.Document[this.props.fieldKey]).
- forEach((doc, i) => value.startsWith(":=") ?
- this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) :
- this.applyToDoc(doc, i, this.props.col, script.run));
+ else if (FieldValue(props.Document["text-lastModified"]) !== undefined) {
+ const d = ComputedField.WithoutComputed(() => FieldValue(props.Document["text-lastModified"])) as DateField;
+ cfield = d.date.toLocaleString();
+ }
}
- }}
- />
-
-
+ return Field.toString(cfield as Field);
+ }, positions)
+ }
</div >
{/* {fieldIsDoc ? docExpander : null} */}
</div>
@@ -903,7 +984,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
}}><button onClick={() => {
doc.searchMatch = false;
setTimeout(() => doc.searchMatch = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
}} style={{ padding: 2, left: 77 }}>
<FontAwesomeIcon icon="arrow-up" size="sm" />
</button>
@@ -911,7 +991,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
{
doc.searchMatchAlt = false;
setTimeout(() => doc.searchMatchAlt = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
}
}} style={{ padding: 2 }}>
<FontAwesomeIcon icon="arrow-down" size="sm" />
@@ -929,7 +1008,6 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
onClick={() => {
doc.searchMatch = false;
setTimeout(() => doc.searchMatch = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
}}>
<FontAwesomeIcon icon="arrow-down" size="sm" />
</button></div >;
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index e65adcf76..5c0e6581b 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -1,22 +1,24 @@
import React = require("react");
-import { action, observable } from "mobx";
-import { observer } from "mobx-react";
-import "./CollectionSchemaView.scss";
-import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl, faCalendar } from '@fortawesome/free-solid-svg-icons';
-import { library, IconProp } from "@fortawesome/fontawesome-svg-core";
+import { IconProp, library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { ColumnType } from "./CollectionSchemaView";
-import { faFile } from "@fortawesome/free-regular-svg-icons";
-import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { listSpec } from "../../../fields/Schema";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
+import { ScriptField } from "../../../fields/ScriptField";
+import { Cast, StrCast } from "../../../fields/Types";
import { undoBatch } from "../../util/UndoManager";
-import { Doc } from "../../../fields/Doc";
-import { StrCast } from "../../../fields/Types";
+import { SearchBox } from "../search/SearchBox";
+import { ColumnType } from "./CollectionSchemaView";
+import "./CollectionSchemaView.scss";
+import { CollectionView } from "./CollectionView";
+import * as fa from '@fortawesome/free-solid-svg-icons';
+
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
-library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes, faImage, faListUl, faCalendar);
-
export interface HeaderProps {
keyValue: SchemaHeaderField;
possibleKeys: string[];
@@ -35,7 +37,7 @@ export interface HeaderProps {
export class CollectionSchemaHeader extends React.Component<HeaderProps> {
render() {
const icon: IconProp = this.props.keyType === ColumnType.Number ? "hashtag" : this.props.keyType === ColumnType.String ? "font" :
- this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "file" :
+ this.props.keyType === ColumnType.Boolean ? "check-square" : this.props.keyType === ColumnType.Doc ? "sort-amount-down" :
this.props.keyType === ColumnType.Image ? "image" : this.props.keyType === ColumnType.List ? "list-ul" : this.props.keyType === ColumnType.Date ? "calendar" :
"align-justify";
return (
@@ -238,18 +240,6 @@ export class CollectionSchemaColumnMenu extends React.Component<ColumnMenuProps>
renderContent = () => {
return (
<div className="collectionSchema-header-menuOptions">
- <div className="collectionSchema-headerMenu-group">
- <label>Key:</label>
- <KeysDropdown
- keyValue={this.props.columnField.heading}
- possibleKeys={this.props.possibleKeys}
- existingKeys={this.props.existingKeys}
- canAddNew={true}
- addNew={this.props.addNew}
- onSelect={this.props.onSelect}
- setIsEditing={this.props.setIsEditing}
- />
- </div>
{this.props.onlyShowOptions ? <></> :
<>
{this.renderTypes()}
@@ -286,6 +276,15 @@ export interface KeysDropdownProps {
setIsEditing: (isEditing: boolean) => void;
width?: string;
docs?: Doc[];
+ Document: Doc;
+ dataDoc: Doc | undefined;
+ fieldKey: string;
+ ContainingCollectionDoc: Doc | undefined;
+ ContainingCollectionView: Opt<CollectionView>;
+ active?: (outsideReaction?: boolean) => boolean;
+ openHeader: (column: any, screenx: number, screeny: number) => void;
+ col: SchemaHeaderField;
+ icon: IconProp;
}
@observer
export class KeysDropdown extends React.Component<KeysDropdownProps> {
@@ -301,34 +300,38 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
@action
onSelect = (key: string): void => {
- if (key.slice(0, this._key.length) === this._key && this._key !== key) {
- const filter = key.slice(this._key.length - key.length);
- this.props.onSelect(this._key, this._key, this.props.addNew, filter);
- }
- else {
- this.props.onSelect(this._key, key, this.props.addNew);
- this.setKey(key);
- this._isOpen = false;
- this.props.setIsEditing(false);
- }
- }
-
- @action
- onSelect2 = (key: string): void => {
- this._searchTerm = this._searchTerm.slice(0, this._key.length) + key;
+ this.props.onSelect(this._key, key, this.props.addNew);
+ this.setKey(key);
this._isOpen = false;
-
+ this.props.setIsEditing(false);
}
@undoBatch
onKeyDown = (e: React.KeyboardEvent): void => {
if (e.key === "Enter") {
- const keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
- if (keyOptions.length) {
- this.onSelect(keyOptions[0]);
- } else if (this._searchTerm !== "" && this.props.canAddNew) {
- this.setSearchTerm(this._searchTerm || this._key);
- this.onSelect(this._searchTerm);
+ if (this._searchTerm.includes(":")) {
+ const colpos = this._searchTerm.indexOf(":");
+ const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
+ if (temp === "") {
+ Doc.setDocFilter(this.props.Document, this._key, temp, undefined);
+ }
+ else {
+ Doc.setDocFilter(this.props.Document, this._key, temp, "match");
+ this.props.col.setColor("green");
+ }
+ }
+ else {
+ let keyOptions = this._searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ const blockedkeys = ["_scrollTop", "customTitle", "limitHeight", "proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
+ keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
+ if (keyOptions.length) {
+ this.onSelect(keyOptions[0]);
+ console.log("case1");
+ } else if (this._searchTerm !== "" && this.props.canAddNew) {
+ this.setSearchTerm(this._searchTerm || this._key);
+ console.log("case2");
+ this.onSelect(this._searchTerm);
+ }
}
}
}
@@ -360,87 +363,172 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
onPointerOut = (e: React.PointerEvent): void => {
this._canClose = true;
}
-
+ @action
renderOptions = (): JSX.Element[] | JSX.Element => {
- if (!this._isOpen) return <></>;
-
+ if (!this._isOpen) {
+ this.defaultMenuHeight = 0;
+ return <></>;
+ }
const searchTerm = this._searchTerm.trim() === "New field" ? "" : this._searchTerm;
- const keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
+ let keyOptions = searchTerm === "" ? this.props.possibleKeys : this.props.possibleKeys.filter(key => key.toUpperCase().indexOf(this._searchTerm.toUpperCase()) > -1);
const exactFound = keyOptions.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1 ||
this.props.existingKeys.findIndex(key => key.toUpperCase() === this._searchTerm.toUpperCase()) > -1;
+ const blockedkeys = ["proto", "x", "y", "_width", "_height", "_autoHeight", "_fontSize", "_fontFamily", "context", "zIndex", "_timeStampOnEnter", "lines", "highlighting", "searchMatch", "creationDate", "isPrototype", "text-annotations", "aliases", "text-lastModified", "text-noTemplate", "layoutKey", "baseProto", "_xMargin", "_yMargin", "layout", "layout_keyValue", "links"];
+ keyOptions = keyOptions.filter(n => !blockedkeys.includes(n));
+
const options = keyOptions.map(key => {
return <div key={key} className="key-option" style={{
border: "1px solid lightgray",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
}}
onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect(key); this.setSearchTerm(""); }}>{key}</div>;
});
// if search term does not already exist as a group type, give option to create new group type
+
if (this._key !== this._searchTerm.slice(0, this._key.length)) {
+ console.log("little further");
if (!exactFound && this._searchTerm !== "" && this.props.canAddNew) {
options.push(<div key={""} className="key-option" style={{
- border: "1px solid lightgray",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ border: "1px solid lightgray", width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white",
}}
onClick={() => { this.onSelect(this._searchTerm); this.setSearchTerm(""); }}>
Create "{this._searchTerm}" key</div>);
}
}
+ if (options.length === 0) {
+ this.defaultMenuHeight = 0;
+ }
+ else {
+ if (this.props.docs) {
+ const panesize = this.props.docs.length * 30;
+ options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ else {
+ options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ }
return options;
}
+ docSafe: Doc[] = [];
+
+ @action
renderFilterOptions = (): JSX.Element[] | JSX.Element => {
- if (!this._isOpen) return <></>;
+ if (!this._isOpen) {
+ this.defaultMenuHeight = 0;
+ return <></>;
+ }
+
const keyOptions: string[] = [];
- const temp = this._searchTerm.slice(this._key.length);
- this.props.docs?.forEach((doc) => {
+ const colpos = this._searchTerm.indexOf(":");
+ const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
+ if (this.docSafe.length === 0) {
+ this.docSafe = DocListCast(this.props.dataDoc![this.props.fieldKey]);
+ }
+ const docs = this.docSafe;
+ docs.forEach((doc) => {
const key = StrCast(doc[this._key]);
if (keyOptions.includes(key) === false && key.includes(temp)) {
keyOptions.push(key);
}
});
+ const filters = Cast(this.props.Document._docFilters, listSpec("string"));
+ for (let i = 0; i < (filters?.length ?? 0) - 1; i += 3) {
+ if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i + 1]) === false) {
+ keyOptions.push(filters![i + 1]);
+ }
+ }
+
+ if (filters === undefined || filters.length === 0 || filters.includes(this._key) === false) {
+ this.props.col.setColor("rgb(241, 239, 235)");
+ }
const options = keyOptions.map(key => {
+ //Doc.setDocFilter(this.props.Document!, this._key, key, undefined);
+ let bool = false;
+ console.log(filters);
+ if (filters !== undefined) {
+ bool = filters.includes(key) && filters[filters.indexOf(key) + 1] === "check";
+ console.log(filters.includes(key));
+ }
return <div key={key} className="key-option" style={{
- border: "1px solid lightgray",
- width: this.props.width, maxWidth: this.props.width, overflowX: "hidden"
+ border: "1px solid lightgray", paddingLeft: 5, textAlign: "left",
+ width: this.props.width, maxWidth: this.props.width, overflowX: "hidden", background: "white", backgroundColor: "white",
}}
- onPointerDown={e => e.stopPropagation()} onClick={() => { this.onSelect2(key); }}>{key}</div>;
+ >
+ <input type="checkbox" onChange={(e) => {
+ e.target.checked === true ? Doc.setDocFilter(this.props.Document, this._key, key, "check") : Doc.setDocFilter(this.props.Document, this._key, key, undefined);
+ e.target.checked === true ? this.props.col.setColor("green") : "";
+ e.target.checked === true && SearchBox.Instance.filter === true ? Doc.setDocFilter(docs[0], this._key, key, "check") : Doc.setDocFilter(docs[0], this._key, key, undefined);
+ }}
+ checked={bool} ></input>
+ <span style={{ paddingLeft: 4 }}>
+ {key}
+ </span>
+
+ </div>;
});
+ if (options.length === 0) {
+ this.defaultMenuHeight = 0;
+ }
+ else {
+ if (this.props.docs) {
+ const panesize = this.props.docs.length * 30;
+ options.length * 20 + 8 - 10 > panesize ? this.defaultMenuHeight = panesize : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ else {
+ options.length > 5 ? this.defaultMenuHeight = 108 : this.defaultMenuHeight = options.length * 20 + 8;
+ }
+ }
return options;
}
+ @observable defaultMenuHeight = 0;
+
+
+ get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; }
+
+ @computed get scriptField() {
+ console.log("we kinda made it");
+ const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)";
+ const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name });
+ return script ? () => script : undefined;
+ }
+ filterBackground = () => "rgba(105, 105, 105, 0.432)";
+
+ @observable filterOpen: boolean | undefined = undefined;
render() {
return (
- <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}>
- {this._key === this._searchTerm.slice(0, this._key.length) ?
- <div style={{ position: "absolute", marginLeft: "4px", marginTop: "3", color: "grey", pointerEvents: "none", lineHeight: 1.15 }}>
- {this._key}
+ <div style={{ display: "flex" }}>
+ <FontAwesomeIcon onClick={e => { this.props.openHeader(this.props.col, e.clientX, e.clientY); }} icon={this.props.icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} />
+
+ {/* <FontAwesomeIcon icon={fa.faSearchMinus} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} onClick={e => {
+ runInAction(() => { this._isOpen === undefined ? this._isOpen = true : this._isOpen = !this._isOpen })
+ }} /> */}
+
+ <div className="keys-dropdown" style={{ zIndex: 10, width: this.props.width, maxWidth: this.props.width }}>
+ <input className="keys-search" style={{ width: "100%" }}
+ ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
+ onChange={e => this.onChange(e.target.value)}
+ onClick={(e) => {
+ //this._inputRef.current!.select();
+ e.stopPropagation();
+ }} onFocus={this.onFocus} onBlur={this.onBlur}></input>
+ <div className="keys-options-wrapper" style={{
+ width: this.props.width, maxWidth: this.props.width, height: "auto",
+ }}
+ onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}>
+ {this._searchTerm.includes(":") ? this.renderFilterOptions() : this.renderOptions()}
</div>
- : undefined}
- <input className="keys-search" style={{ width: "100%" }}
- ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
- onChange={e => this.onChange(e.target.value)}
- onClick={(e) => {
- //this._inputRef.current!.select();
- e.stopPropagation();
- }} onFocus={this.onFocus} onBlur={this.onBlur}></input>
- <div className="keys-options-wrapper" style={{
- backgroundColor: "white",
- width: this.props.width, maxWidth: this.props.width,
- }}
- onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerOut}>
- {this._key === this._searchTerm.slice(0, this._key.length) ?
- this.renderFilterOptions() : this.renderOptions()}
- </div>
- </div >
+ </div >
+ </div>
);
}
}
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index ba0a259c5..5c2931a8b 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -43,6 +43,49 @@
// }
}
+.collectionSchemaView-searchContainer {
+ border-width: $COLLECTION_BORDER_WIDTH;
+ border-color: $intermediate-color;
+ border-style: solid;
+ border-radius: $border-radius;
+ box-sizing: border-box;
+ position: relative;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ margin-top: 0;
+ transition: top 0.5s;
+ display: flex;
+ justify-content: space-between;
+ flex-wrap: nowrap;
+ touch-action: none;
+
+ div {
+ touch-action: none;
+ }
+
+
+ .collectionSchemaView-tableContainer {
+ width: 100%;
+ height: 100%;
+ }
+
+ .collectionSchemaView-dividerDragger {
+ position: relative;
+ height: 100%;
+ width: 20px;
+ z-index: 20;
+ right: 0;
+ top: 0;
+ background: gray;
+ cursor: col-resize;
+ }
+
+ // .documentView-node:first-child {
+ // background: $light-color;
+ // }
+}
+
.ReactTable {
width: 100%;
background: white;
@@ -165,7 +208,7 @@
.collectionSchema-header-menu {
- height: 100%;
+ height: auto;
z-index: 100;
position: absolute;
background:white;
@@ -280,11 +323,9 @@ button.add-column {
background-color: white;
.key-option {
- //background-color: $light-color;
background-color: white;
border: 1px solid lightgray;
padding: 2px 3px;
-
&:not(:first-child) {
border-top: 0;
}
@@ -315,12 +356,53 @@ button.add-column {
}
}
+.altcollectionTimeView-treeView {
+ display: flex;
+ flex-direction: column;
+ width: 175px;
+ height: auto;
+ position: fixed;
+ border-left: solid 1px;
+ z-index: 1;
+
+ .collectionTimeView-addfacet {
+ display: inline-block;
+ width: 200px;
+ height: 30px;
+ background: darkGray;
+ text-align: left;
+
+ .collectionTimeView-button {
+ align-items: center;
+ display: flex;
+ width: 100%;
+ height: 100%;
+
+ .collectionTimeView-span {
+ margin: auto;
+ }
+ }
+
+ >div,
+ >div>div {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .altcollectionTimeView-tree {
+ display: inline-block;
+ width: 100%;
+ height: calc(100% - 30px);
+ }
+}
+
.collectionSchema-row {
height: 100%;
background-color: white;
&.row-focused .rt-td {
- background-color: rgb(255, 246, 246); //$light-color-secondary;
+ background-color: #bfffc0; //$light-color-secondary;
}
&.row-wrapped {
@@ -383,6 +465,9 @@ button.add-column {
.collectionSchemaView-cellWrapper {
height: 100%;
padding: 4px;
+ text-align:left;
+ padding-left:19px;
+
position: relative;
&:focus {
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a003de0d3..f1de3cee7 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -11,7 +11,7 @@ import { Doc } from "../../../fields/Doc";
import { List } from "../../../fields/List";
import { listSpec } from "../../../fields/Schema";
import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
-import { Cast, NumCast } from "../../../fields/Types";
+import { Cast, NumCast, BoolCast } from "../../../fields/Types";
import { TraceMobx } from "../../../fields/util";
import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents } from "../../../Utils";
import { SnappingManager } from "../../util/SnappingManager";
@@ -71,8 +71,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@observable _pointerY = 0;
@observable _openTypes: boolean = false;
@computed get menuCoordinates() {
- const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX));
- const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY));
+ let searchx = 0;
+ let searchy = 0;
+ if (this.props.Document._searchDoc !== undefined) {
+ const el = document.getElementsByClassName("collectionSchemaView-searchContainer")[0];
+ if (el !== undefined) {
+ const rect = el.getBoundingClientRect();
+ searchx = rect.x;
+ searchy = rect.y;
+ }
+ }
+ const x = Math.max(0, Math.min(document.body.clientWidth - this._menuWidth, this._pointerX)) - searchx;
+ const y = Math.max(0, Math.min(document.body.clientHeight - this._menuHeight, this._pointerY)) - searchy;
return this.props.ScreenToLocalTransform().transformPoint(x, y);
}
@@ -110,7 +120,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
document.removeEventListener("pointerdown", this.detectClick);
}
- @action setHeaderIsEditing = (isEditing: boolean) => this._headerIsEditing = isEditing;
+ @action setHeaderIsEditing = (isEditing: boolean) => {
+ this._headerIsEditing = isEditing;
+ }
detectClick = (e: PointerEvent): void => {
if (this._node && this._node.contains(e.target as Node)) {
@@ -356,17 +368,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@action
closeHeader = () => { this._headerOpen = false; }
- renderKeysDropDown = (col: any) => {
- return <KeysDropdown
- keyValue={col.heading}
- possibleKeys={this.possibleKeys}
- existingKeys={this.columns.map(c => c.heading)}
- canAddNew={true}
- addNew={false}
- onSelect={this.changeColumns}
- setIsEditing={this.setHeaderIsEditing}
- />;
- }
+
@undoBatch
@action
@@ -405,10 +407,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
@computed get renderMenuContent() {
TraceMobx();
return <div className="collectionSchema-header-menuOptions">
- <div className="collectionSchema-headerMenu-group">
- <label>Key:</label>
- {this.renderKeysDropDown(this._col)}
- </div>
{this.renderTypes(this._col)}
{this.renderSorting(this._col)}
{this.renderColors(this._col)}
@@ -424,7 +422,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
super.CreateDropTarget(ele);
}
- isFocused = (doc: Doc): boolean => this.props.isSelected() && doc === this._focusedTable;
+ isFocused = (doc: Doc, outsideReaction: boolean): boolean => this.props.isSelected(outsideReaction) && doc === this._focusedTable;
@action setFocused = (doc: Doc) => this._focusedTable = doc;
@@ -611,14 +609,18 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
}
render() {
+ let name = "collectionSchemaView-container";
+ if (this.props.Document._searchDoc !== undefined) {
+ name = "collectionSchemaView-searchContainer";
+ }
TraceMobx();
const menuContent = this.renderMenuContent;
const menu = <div className="collectionSchema-header-menu" ref={this.setNode}
onWheel={e => this.onZoomMenu(e)}
onPointerDown={e => this.onHeaderClick(e)}
style={{
- position: "fixed", background: "white",
- transform: `translate(${this.menuCoordinates[0] / this.scale}px, ${this.menuCoordinates[1] / this.scale}px)`
+ position: "fixed", background: "white", border: "black 1px solid",
+ transform: `translate(${(this.menuCoordinates[0] / this.scale)}px, ${(this.menuCoordinates[1] / this.scale)}px)`
}}>
<Measure offset onResize={action((r: any) => {
const dim = this.props.ScreenToLocalTransform().inverse().transformDirection(r.offset.width, r.offset.height);
@@ -627,11 +629,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
{({ measureRef }) => <div ref={measureRef}> {menuContent} </div>}
</Measure>
</div>;
- return <div className="collectionSchemaView-container"
+ return <div className={name}
style={{
- overflow: this.props.overflow === true ? "auto" : undefined,
+ overflow: this.props.overflow === true ? "scroll" : undefined,
pointerEvents: !this.props.active() && !SnappingManager.GetIsDragging() ? "none" : undefined,
- width: this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
+ width: name === "collectionSchemaView-searchContainer" ? "auto" : this.props.PanelWidth() || "100%", height: this.props.PanelHeight() || "100%", position: "relative",
}} >
<div className="collectionSchemaView-tableContainer"
style={{ backgroundColor: "white", width: `calc(100% - ${this.previewWidth()}px)` }}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b27af66ba..fe3d57bdb 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,7 +4,7 @@ import { CursorProperty } from "csstype";
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import Switch from 'rc-switch';
-import { DataSym, Doc, HeightSym, WidthSym, DocListCastAsync } from "../../../fields/Doc";
+import { DataSym, Doc, HeightSym, WidthSym } from "../../../fields/Doc";
import { collectionSchema, documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
@@ -28,7 +28,6 @@ import { CollectionViewType } from "./CollectionView";
import { SnappingManager } from "../../util/SnappingManager";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { DocUtils } from "../../documents/Documents";
-import { MainViewNotifs } from "../MainViewNotifs";
const _global = (window /* browser */ || global /* node */) as any;
type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
@@ -299,10 +298,6 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
const srcInd = docs.indexOf(doc);
docs.splice(srcInd, 1);
docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
- DocListCastAsync(docs).then(resolvedDocs => {
- const pos = resolvedDocs?.findIndex(shareDoc => shareDoc.icon === "users") || 0; // hopefully find out if the sharing doc has been moved
- if (MainViewNotifs.NotifsCol && pos !== -1) MainViewNotifs.NotifsCol.position = pos;
- });
} else if (i < (newDocs.length / 2)) { //glr: for some reason dragged documents are duplicated
if (targInd === -1) targInd = docs.length;
else targInd = docs.indexOf(newDocs[0]) + 1;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1aeb1b65..3f2ad47a5 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -112,10 +112,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
[...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
}
@computed get childDocs() {
- let rawdocs: (Doc | Promise<Doc>)[] = DocListCast(this.props.Document._searchDocs);
-
- if (rawdocs.length !== 0) {
- } else if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
+ let rawdocs: (Doc | Promise<Doc>)[] = [];
+ if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
rawdocs = [this.dataField];
} else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it.
rawdocs = Cast(this.dataField, listSpec(Doc), null);
@@ -128,30 +126,25 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
- let childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
+ const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
+
+ let searchDocs = DocListCast(this.props.Document._searchDocs);
- const searchDocs = DocListCast(this.props.Document._searchDocs);
- // if (searchDocs !== undefined && searchDocs.length > 0) {
- // let newdocs: Doc[] = [];
- // childDocs.forEach((el) => {
- // searchDocs.includes(el) ? newdocs.push(el) : undefined;
- // });
- // childDocs = newdocs;
- // }
let docsforFilter: Doc[] = childDocs;
+
if (searchDocs !== undefined && searchDocs.length > 0) {
docsforFilter = [];
- // let newdocs: Doc[] = [];
- // let newarray: Doc[] = [];
- //while (childDocs.length > 0) {
- //newarray = [];
+ const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ console.log(searchDocs);
+ searchDocs = DocUtils.FilterDocs(searchDocs, this.docFilters(), docRangeFilters, viewSpecScript);
+ console.log(this.docFilters());
+ console.log(searchDocs);
childDocs.forEach((d) => {
if (d.data !== undefined) {
- console.log(d);
let newdocs = DocListCast(d.data);
if (newdocs.length > 0) {
- let vibecheck: boolean | undefined = undefined;
+ let displaycheck: boolean | undefined = undefined;
let newarray: Doc[] = [];
while (newdocs.length > 0) {
newarray = [];
@@ -163,12 +156,12 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
});
}
if (searchDocs.includes(t)) {
- vibecheck = true;
+ displaycheck = true;
}
});
newdocs = newarray;
}
- if (vibecheck === true) {
+ if (displaycheck === true) {
docsforFilter.push(d);
}
}
@@ -177,14 +170,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
docsforFilter.push(d);
}
});
- //childDocs = newarray;
- //}
+ return docsforFilter;
}
- childDocs = docsforFilter;
-
const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
-
- return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, this.docFilters(), docRangeFilters, viewSpecScript);
+ return this.props.Document.dontRegisterView ? childDocs : DocUtils.FilterDocs(childDocs, this.docFilters(), docRangeFilters, viewSpecScript);
}
@action
@@ -251,6 +240,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
} else added = res;
+ !added && alert("You don't have permission to perform this move");
+ e.stopPropagation();
} else {
ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
added = this.addDocument(docDragData.droppedDocuments);
@@ -343,7 +334,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
let srcWeb: Doc | undefined;
if (SelectionManager.SelectedDocuments().length) {
srcWeb = SelectionManager.SelectedDocuments()[0].props.Document;
- srcUrl = (srcWeb.data as WebField).url.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
+ srcUrl = (srcWeb.data as WebField).url?.href?.match(/http[s]?:\/\/[^/]*/)?.[0];
}
const reg = new RegExp(Utils.prepend(""), "g");
const modHtml = srcUrl ? html.replace(reg, srcUrl) : html;
@@ -351,7 +342,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
this.props.addDocument(htmlDoc);
if (srcWeb) {
- const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any);
+ const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0].contentDocument?.getSelection()?.focusNode as any);
if (focusNode) {
const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
const x = (rect?.x || 0);
@@ -481,7 +472,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
completed?.();
} else {
if (text && !text.includes("https://")) {
- this.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
+ UndoManager.RunInBatch(() => this.addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 })), "drop");
}
}
disposer();
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3c7471d7c..d096e7d66 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -53,7 +53,7 @@ export interface TreeViewProps {
indentDocument?: () => void;
outdentDocument?: () => void;
ScreenToLocalTransform: () => Transform;
- backgroundColor?: (doc: Doc) => string | undefined;
+ backgroundColor?: (doc: Doc, renderDepth: number) => string | undefined;
outerXf: () => { translateX: number, translateY: number };
treeViewDoc: Doc;
parentKey: string;
@@ -88,7 +88,7 @@ class TreeView extends React.Component<TreeViewProps> {
get doc() { return this.props.document; }
get noviceMode() { return BoolCast(Doc.UserDoc().noviceMode, false); }
get displayName() { return "TreeView(" + this.doc.title + ")"; } // this makes mobx trace() statements more descriptive
- get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); }
+ get defaultExpandedView() { return this.childDocs.length ? this.fieldKey : StrCast(this.doc.defaultExpandedView, this.noviceMode ? "layout" : "fields"); }
@observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
set treeViewOpen(c: boolean) {
if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c;
@@ -108,6 +108,7 @@ class TreeView extends React.Component<TreeViewProps> {
}
@computed get childDocs() { return this.childDocList(this.fieldKey); }
@computed get childLinks() { return this.childDocList("links"); }
+ @computed get childAnnos() { return this.childDocList(this.fieldKey + "-annotations"); }
@computed get boundsOfCollectionDocument() {
return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 || !DocListCast(this.props.document[this.fieldKey]).length ? undefined :
Doc.ComputeContentBounds(DocListCast(this.props.document[this.fieldKey]));
@@ -127,7 +128,7 @@ class TreeView extends React.Component<TreeViewProps> {
constructor(props: any) {
super(props);
- const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); selectDoc(self);} `);
+ const script = ScriptField.MakeScript(`{setInPlace(self, 'editTitle', '${this._uniqueId}'); documentView.select();} `, { documentView: "any" });
this._editTitleScript = script && (() => script);
if (Doc.GetT(this.doc, "editTitle", "string", true) === "*") Doc.SetInPlace(this.doc, "editTitle", this._uniqueId, false);
}
@@ -313,11 +314,11 @@ class TreeView extends React.Component<TreeViewProps> {
@computed get renderContent() {
TraceMobx();
const expandKey = this.treeViewExpandedView;
- if (["links", this.fieldKey].includes(expandKey)) {
+ if (["links", "annotations", this.fieldKey].includes(expandKey)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey);
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) =>
(doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true), true);
- const docs = expandKey === "links" ? this.childLinks : this.childDocs;
+ const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
const sortKey = `${this.fieldKey}-sortAscending`;
return <ul key={expandKey + "more"} onClick={(e) => {
this.doc[sortKey] = (this.doc[sortKey] ? false : (this.doc[sortKey] === false ? undefined : true));
@@ -397,7 +398,7 @@ class TreeView extends React.Component<TreeViewProps> {
title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
onClick={this.bulletClick}
style={{ color: StrCast(this.doc.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"))} />}
+ {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs?.length ? "caret-square-right" : "caret-right") : (this.childDocs?.length ? "caret-square-down" : "caret-down"))} />}
</div>;
}
@@ -424,7 +425,8 @@ class TreeView extends React.Component<TreeViewProps> {
this.doc.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? (Doc.UserDoc().noviceMode ? "layout" : "fields") :
this.treeViewExpandedView === "fields" && this.layoutDoc ? "layout" :
this.treeViewExpandedView === "layout" && DocListCast(this.doc.links).length ? "links" :
- this.childDocs ? this.fieldKey : (Doc.UserDoc().noviceMode ? "layout" : "fields");
+ (this.treeViewExpandedView === "links" || this.treeViewExpandedView === "layout") && DocListCast(this.doc[this.fieldKey + "-annotations"]).length ? "annotations" :
+ this.childDocs.length ? this.fieldKey : (Doc.UserDoc().noviceMode ? "layout" : "fields");
}
this.treeViewOpen = true;
})}>
@@ -453,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
NativeHeight={returnZero}
NativeWidth={returnZero}
contextMenuItems={this.contextMenuItems}
+ opacity={returnOne}
renderDepth={1}
focus={returnTrue}
parentActive={returnTrue}
@@ -475,7 +478,7 @@ class TreeView extends React.Component<TreeViewProps> {
</div >
{headerElements}
<div className="treeViewItem-openRight" onClick={this.openRight}>
- <FontAwesomeIcon title="open in pane on right" icon="external-link-alt" size="sm" />
+ <FontAwesomeIcon title="open in a new pane" icon="external-link-alt" size="sm" />
</div>
</>;
}
@@ -494,7 +497,7 @@ class TreeView extends React.Component<TreeViewProps> {
}
}
} else this._editMaxWidth = "";
- return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onPointerDown={e => this.props.active() && SelectionManager.DeselectAll()}>
+ return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onPointerDown={e => this.props.active(true) && SelectionManager.DeselectAll()}>
<li className="collection-child">
<div className={`treeViewItem-header` + (this._editMaxWidth ? "-editing" : "")} ref={this._header} style={{ maxWidth: this._editMaxWidth }} onClick={e => {
if (this.props.active(true)) {
@@ -533,7 +536,7 @@ class TreeView extends React.Component<TreeViewProps> {
dropAction: dropActionType,
addDocTab: (doc: Doc, where: string) => boolean,
pinToPres: (document: Doc) => void,
- backgroundColor: undefined | ((document: Doc) => string | undefined),
+ backgroundColor: undefined | ((document: Doc, renderDepth: number) => string | undefined),
screenToLocalXf: () => Transform,
outerXf: () => { translateX: number, translateY: number },
active: (outsideReaction?: boolean) => boolean,
@@ -813,7 +816,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
<div className="collectionTreeView-container" onContextMenu={this.onContextMenu}>
<div className="collectionTreeView-dropTarget" id="body"
style={{
- background: this.props.backgroundColor?.(this.doc),
+ background: this.props.backgroundColor?.(this.doc, this.props.renderDepth),
paddingLeft: `${NumCast(this.doc._xPadding, 10)}px`,
paddingRight: `${NumCast(this.doc._xPadding, 10)}px`,
paddingTop: `${NumCast(this.doc._yPadding, 20)}px`,
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0feec3fbd..6dd21ef7f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -46,6 +46,7 @@ import { CollectionTimeView } from './CollectionTimeView';
import { CollectionTreeView } from "./CollectionTreeView";
import './CollectionView.scss';
import { ContextMenuProps } from '../ContextMenuItem';
+import { table } from 'console';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -141,7 +142,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
const targetDataDoc = this.props.Document[DataSym];
const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
const added = docs.filter(d => !docList.includes(d));
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
if (added.length) {
if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
@@ -182,6 +183,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
// targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
(targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+ const lastModified = "lastModified";
+ targetDataDoc[lastModified] = new DateField(new Date(Date.now()));
}
}
}
@@ -190,16 +193,19 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
@action.bound
removeDocument = (doc: any): boolean => {
- const collectionEffectiveAcl = GetEffectiveAcl(this.props.Document);
- const docEffectiveAcl = GetEffectiveAcl(doc);
- // you can remove the document if you either have Admin/Edit access to the collection or to the specific document
- if (collectionEffectiveAcl === AclEdit || collectionEffectiveAcl === AclAdmin || docEffectiveAcl === AclAdmin || docEffectiveAcl === AclEdit) {
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
const docs = doc instanceof Doc ? [doc] : doc as Doc[];
const targetDataDoc = this.props.Document[DataSym];
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
const toRemove = value.filter(v => docs.includes(v));
if (toRemove.length !== 0) {
- toRemove.forEach(doc => Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc));
+ const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
+ toRemove.forEach(doc => {
+ Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc);
+ recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+ doc.deleted = true;
+ });
return true;
}
}
@@ -216,7 +222,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return true;
}
const first = doc instanceof Doc ? doc : doc[0];
- if (!first?.stayInCollection && addDocument !== returnFalse) {
+ if (!first?._stayInCollection && addDocument !== returnFalse) {
if (UndoManager.RunInTempBatch(() => this.removeDocument(doc))) {
const added = addDocument(doc);
if (!added) UndoManager.UndoTempBatch();
@@ -510,56 +516,56 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
</label>)}
</div>
);
- return !this._facetWidth || this.props.dontRegisterView ? (null) :
- <div className="collectionTimeView-treeView" style={{ width: `${this.facetWidth()}px`, overflow: this.facetWidth() < 15 ? "hidden" : undefined }}>
- <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
- <div className="collectionTimeView-button">
- <FontAwesomeIcon icon={faEdit} size={"lg"} />
- <span className="collectionTimeView-span">Facet Filters</span>
- </div>
- </Flyout>
- </div>
- <div className="collectionTimeView-tree" key="tree">
- <CollectionTreeView
- PanelPosition={""}
- Document={facetCollection}
- DataDoc={facetCollection}
- fieldKey={`${this.props.fieldKey}-filter`}
- CollectionView={this}
- docFilters={returnEmptyFilter}
- 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.ignoreFields}
- annotationsKey={""}
- dontRegisterView={true}
- backgroundColor={this.filterBackground}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- addDocument={returnFalse} />
- </div>
- </div>;
+
+ return !this._facetWidth || this.props.dontRegisterView ? (null) : <div className="collectionTimeView-treeView" style={{ width: `${this.facetWidth()}px`, overflow: this.facetWidth() < 15 ? "hidden" : undefined }}>
+ <div className="collectionTimeView-addFacet" style={{ width: `${this.facetWidth()}px` }} onPointerDown={e => e.stopPropagation()}>
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout}>
+ <div className="collectionTimeView-button">
+ <FontAwesomeIcon icon={faEdit} size={"lg"} />
+ <span className="collectionTimeView-span">Facet Filters</span>
+ </div>
+ </Flyout>
+ </div>
+ <div className="collectionTimeView-tree" key="tree">
+ <CollectionTreeView
+ PanelPosition={""}
+ Document={facetCollection}
+ DataDoc={facetCollection}
+ fieldKey={`${this.props.fieldKey}-filter`}
+ CollectionView={this}
+ docFilters={returnEmptyFilter}
+ 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.ignoreFields}
+ annotationsKey={""}
+ dontRegisterView={true}
+ backgroundColor={this.filterBackground}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ addDocument={returnFalse} />
+ </div>
+ </div>;
}
childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 4c8cac3ed..149d4927b 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -15,6 +15,7 @@ import { faCog, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
import { DocumentView } from "../nodes/DocumentView";
import { SelectionManager } from "../../util/SelectionManager";
+import { Tooltip } from "@material-ui/core";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -121,16 +122,17 @@ export class DockingViewButtonSelector extends React.Component<{ views: () => Do
}
render() {
- return <span title="Tap for menu, drag tab as document"
- onPointerDown={e => {
+ return <Tooltip title={<><div className="dash-tooltip">Tap for toolbar, drag to create alias in another pane</div></>} placement="bottom">
+ <span 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={"arrows-alt"} size={"sm"} />
- </Flyout>
- </span>;
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
+ <FontAwesomeIcon icon={"arrows-alt"} size={"sm"} />
+ </Flyout>
+ </span>
+ </Tooltip>;
}
}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index a974c5496..a2c529a21 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -63,12 +63,12 @@ export interface SchemaTableProps {
addDocument: (document: Doc | Doc[]) => boolean;
moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
ScreenToLocalTransform: () => Transform;
- active: (outsideReaction: boolean) => boolean;
+ active: (outsideReaction: boolean | undefined) => boolean;
onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
addDocTab: (document: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
isSelected: (outsideReaction?: boolean) => boolean;
- isFocused: (document: Doc) => boolean;
+ isFocused: (document: Doc, outsideReaction: boolean) => boolean;
setFocused: (document: Doc) => void;
setPreviewDoc: (document: Doc) => void;
columns: SchemaHeaderField[];
@@ -155,7 +155,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const possibleKeys = this.props.documentKeys.filter(key => this.props.columns.findIndex(existingKey => existingKey.heading.toUpperCase() === key.toUpperCase()) === -1);
const columns: Column<Doc>[] = [];
- const tableIsFocused = this.props.isFocused(this.props.Document);
+ const tableIsFocused = this.props.isFocused(this.props.Document, false);
const focusedRow = this._focusedCell.row;
const focusedCol = this._focusedCell.col;
const isEditable = !this.props.headerIsEditing;
@@ -177,8 +177,13 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
);
}
+ this.props.active;
const cols = this.props.columns.map(col => {
+ const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
+ this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
+ this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
+ this.getColumnType(col) === ColumnType.Date ? "calendar" : "align-justify";
const keysDropdown = <KeysDropdown
keyValue={col.heading}
@@ -189,24 +194,20 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
onSelect={this.props.changeColumns}
setIsEditing={this.props.setHeaderIsEditing}
docs={this.props.childDocs}
+ Document={this.props.Document}
+ dataDoc={this.props.dataDoc}
+ fieldKey={this.props.fieldKey}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+ ContainingCollectionView={this.props.ContainingCollectionView}
+ active={this.props.active}
+ openHeader={this.props.openHeader}
+ icon={icon}
+ col={col}
// try commenting this out
width={"100%"}
/>;
- const icon: IconProp = this.getColumnType(col) === ColumnType.Number ? "hashtag" : this.getColumnType(col) === ColumnType.String ? "font" :
- this.getColumnType(col) === ColumnType.Boolean ? "check-square" : this.getColumnType(col) === ColumnType.Doc ? "file" :
- this.getColumnType(col) === ColumnType.Image ? "image" : this.getColumnType(col) === ColumnType.List ? "list-ul" :
- this.getColumnType(col) === ColumnType.Date ? "calendar" : "align-justify";
- const headerText = this._showTitleDropdown ? keysDropdown : <div
- onClick={this.changeTitleMode}
- style={{
- background: col.color, padding: "2px",
- letterSpacing: "2px",
- textTransform: "uppercase",
- display: "flex"
- }}>
- {col.heading}</div>;
const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up";
@@ -218,19 +219,12 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
background: col.color, padding: "2px",
display: "flex", cursor: "default", height: "100%",
}}>
- <FontAwesomeIcon icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px" }} />
- {/* <div className="keys-dropdown"
- style={{ display: "inline", zIndex: 1000 }}> */}
+ {/* <FontAwesomeIcon onClick={e => this.props.openHeader(col, e.clientX, e.clientY)} icon={icon} size="lg" style={{ display: "inline", paddingBottom: "1px", paddingTop: "4px", cursor: "hand" }} /> */}
{keysDropdown}
- {/* </div> */}
<div onClick={e => this.changeSorting(col)}
- style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit" }}>
+ style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "hand" }}>
<FontAwesomeIcon icon={sortIcon} size="lg" />
</div>
- {/* <div onClick={e => this.props.openHeader(col, e.clientX, e.clientY)}
- style={{ float: "right", paddingRight: "6px", zIndex: 1, background: "inherit" }}>
- <FontAwesomeIcon icon={"compass"} size="sm" />
- </div> */}
</div>;
return {
@@ -318,27 +312,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
}
-
- @action
- nextHighlight = (e: React.MouseEvent, doc: Doc) => {
- e.preventDefault();
- e.stopPropagation();
- doc.searchMatch = false;
- console.log(doc.searchMatch);
- setTimeout(() => doc.searchMatch = true, 0);
- console.log(doc.searchMatch);
-
- doc.searchIndex = NumCast(doc.searchIndex);
- }
-
- @action
- nextHighlight2 = (doc: Doc) => {
-
- doc.searchMatchAlt = false;
- setTimeout(() => doc.searchMatchAlt = true, 0);
- doc.searchIndex = NumCast(doc.searchIndex);
- }
-
constructor(props: SchemaTableProps) {
super(props);
// convert old schema columns (list of strings) into new schema columns (list of schema header fields)
@@ -347,7 +320,8 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
} else if (this.props.Document._schemaHeaders === undefined) {
- this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb")]);
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb"), new SchemaHeaderField("author", "#f1efeb"), new SchemaHeaderField("*lastModified", "#f1efeb"),
+ new SchemaHeaderField("text", "#f1efeb"), new SchemaHeaderField("type", "#f1efeb"), new SchemaHeaderField("context", "#f1efeb")]);
}
}
@@ -369,7 +343,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
addDoc: this.tableAddDoc,
removeDoc: this.props.deleteDocument,
rowInfo,
- rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document),
+ rowFocused: !this.props.headerIsEditing && rowInfo.index === this._focusedCell.row && this.props.isFocused(this.props.Document, true),
textWrapRow: this.toggleTextWrapRow,
rowWrapped: this.textWrappedRows.findIndex(id => rowInfo.original[Id] === id) > -1,
dropAction: StrCast(this.props.Document.childDropAction),
@@ -383,7 +357,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
const row = rowInfo.index;
//@ts-ignore
const col = this.columns.map(c => c.heading).indexOf(column!.id);
- const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document);
+ const isFocused = this._focusedCell.row === row && this._focusedCell.col === col && this.props.isFocused(this.props.Document, true);
// TODO: editing border doesn't work :(
return {
style: {
@@ -403,7 +377,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
@action
onKeyDown = (e: KeyboardEvent): void => {
- if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document)) {// && this.props.isSelected(true)) {
+ if (!this._cellIsEditing && !this.props.headerIsEditing && this.props.isFocused(this.props.Document, true)) {// && this.props.isSelected(true)) {
const direction = e.key === "Tab" ? "tab" : e.which === 39 ? "right" : e.which === 37 ? "left" : e.which === 38 ? "up" : e.which === 40 ? "down" : "";
this._focusedCell = this.changeFocusedCellByDirection(direction, this._focusedCell.row, this._focusedCell.col);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 163554db9..46e30f616 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -15,7 +15,7 @@ import { ScriptField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
import { TraceMobx } from "../../../../fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils, setupMoveUpEvents } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
@@ -378,7 +378,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
getClusterColor = (doc: Doc) => {
- let clusterColor = this.props.backgroundColor?.(doc);
+ let clusterColor = this.props.backgroundColor?.(doc, this.props.renderDepth + 1);
const cluster = NumCast(doc.cluster);
if (this.Document.useClusters) {
if (this._clusterSets.length <= cluster) {
@@ -1200,27 +1200,29 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.addDocTab(childDocs as any as Doc, "inParent");
this.props.ContainingCollectionView?.removeDocument(this.props.Document);
}));
- layoutDocsInGrid = () => {
- UndoManager.RunInBatch(() => {
- const docs = this.childLayoutPairs;
- const startX = this.Document._panX || 0;
- let x = startX;
- let y = this.Document._panY || 0;
- let i = 0;
- const width = Math.max(...docs.map(doc => NumCast(doc.layout._width)));
- const height = Math.max(...docs.map(doc => NumCast(doc.layout._height)));
- docs.forEach(pair => {
- pair.layout.x = x;
- pair.layout.y = y;
- x += width + 20;
- if (++i === 6) {
- i = 0;
- x = startX;
- y += height + 20;
- }
- });
- }, "arrange contents");
- }
+
+
+ @undoBatch
+ layoutDocsInGrid = action(() => {
+ const docs = this.childLayoutPairs;
+ const startX = this.Document._panX || 0;
+ let x = startX;
+ let y = this.Document._panY || 0;
+ let i = 0;
+ const width = Math.max(...docs.map(doc => NumCast(doc.layout._width)));
+ const height = Math.max(...docs.map(doc => NumCast(doc.layout._height)));
+ docs.forEach(pair => {
+ pair.layout.x = x;
+ pair.layout.y = y;
+ x += width + 20;
+ if (++i === 6) {
+ i = 0;
+ x = startX;
+ y += height + 20;
+ }
+ });
+ });
+
@undoBatch
@action
toggleNativeDimensions = () => {
@@ -1495,8 +1497,123 @@ interface CollectionFreeFormViewPannableContentsProps {
@observer
class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+ @observable private _drag: string = '';
+
+ //Adds event listener so knows pointer is down and moving
+ onPointerDown = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ const corner = e.target as any;
+ console.log(corner.id);
+ if (corner) this._drag = corner.id;
+ const rect = document.getElementById(this._drag);
+ if (rect) {
+ console.log(this._drag);
+ setupMoveUpEvents(e.target, e, this.onPointerMove, (e) => { }, (e) => { });
+ }
+ }
+
+ //Removes all event listeners
+ onPointerUp = (e: PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._drag = "";
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ //Adjusts the value in NodeStore
+ @action
+ onPointerMove = (e: PointerEvent) => {
+ const doc = document.getElementById('resizable');
+ const rect = doc!.getBoundingClientRect();
+ const toNumber = (original: number, delta: number): number => {
+ return original + (delta * this.props.zoomScaling());
+ };
+ if (doc) {
+ const height = doc.offsetHeight;
+ const width = doc.offsetWidth;
+ const top = doc.offsetTop;
+ const left = doc.offsetLeft;
+ switch (this._drag) {
+ case "": break;
+ case "resizer-br":
+ doc.style.width = toNumber(width, e.movementX) + 'px';
+ doc.style.height = toNumber(height, e.movementY) + 'px';
+ break;
+ case "resizer-bl":
+ doc.style.width = toNumber(width, -e.movementX) + 'px';
+ doc.style.height = toNumber(height, e.movementY) + 'px';
+ doc.style.left = toNumber(left, e.movementX) + 'px';
+ break;
+ case "resizer-tr":
+ doc.style.width = toNumber(width, -e.movementX) + 'px';
+ doc.style.height = toNumber(height, -e.movementY) + 'px';
+ doc.style.top = toNumber(top, e.movementY) + 'px';
+ case "resizer-tl":
+ doc.style.width = toNumber(width, -e.movementX) + 'px';
+ doc.style.height = toNumber(height, -e.movementY) + 'px';
+ doc.style.top = toNumber(top, e.movementY) + 'px';
+ doc.style.left = toNumber(left, e.movementX) + 'px';
+ case "resizable":
+ doc.style.top = toNumber(top, e.movementY) + 'px';
+ doc.style.left = toNumber(left, e.movementX) + 'px';
+ }
+ this.updateAll(height, width, top, left);
+ return false;
+ }
+ return true;
+ }
+
+ @action
+ updateAll = (width: number, height: number, top: number, left: number) => {
+ const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ this.updateList(targetDoc, activeItem["viewfinder-width-indexed"], width);
+ this.updateList(targetDoc, activeItem["viewfinder-height-indexed"], height);
+ this.updateList(targetDoc, activeItem["viewfinder-top-indexed"], top);
+ this.updateList(targetDoc, activeItem["viewfinder-left-indexed"], left);
+ }
+
+ @action
+ updateList = (doc: Doc, list: any, val: number) => {
+ const x: List<number> = list;
+ if (x && x.length >= NumCast(doc.currentFrame) + 1) {
+ x[NumCast(doc.currentFrame)] = val;
+ list = x;
+ } else if (doc && x) {
+ x.length = NumCast(doc.currentFrame) + 1;
+ x[NumCast(doc.currentFrame)] = val;
+ list = x;
+ }
+ }
+
+ // scale: NumCast(targetDoc._viewScale),
+ @computed get zoomProgressivizeContainer() {
+ const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ if (activeItem && activeItem.zoomProgressivize) {
+ const vfLeft: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-left-indexed"]);
+ const vfWidth: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-width-indexed"]);
+ const vfTop: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-top-indexed"]);
+ const vfHeight: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-height-indexed"]);
+ return (
+ <>
+ {!activeItem.editZoomProgressivize ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}>
+ <div className='resizers'>
+ <div id="resizer-tl" className='resizer top-left' onPointerDown={this.onPointerDown}></div>
+ <div id="resizer-tr" className='resizer top-right' onPointerDown={this.onPointerDown}></div>
+ <div id="resizer-bl" className='resizer bottom-left' onPointerDown={this.onPointerDown}></div>
+ <div id="resizer-br" className='resizer bottom-right' onPointerDown={this.onPointerDown}></div>
+ </div>
+ </div>}
+ </>
+ );
+ }
+ }
+
@computed get zoomProgressivize() {
- return PresBox.Instance && this.props.zoomProgressivize ? PresBox.Instance.zoomProgressivizeContainer : (null);
+ return PresBox.Instance && this.props.zoomProgressivize ? this.zoomProgressivizeContainer : (null);
}
@computed get progressivize() {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1a708d67d..c0b19fcd2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -21,6 +21,7 @@ import { CollectionView } from "../CollectionView";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import "./MarqueeView.scss";
import React = require("react");
+import { ContextMenuItem } from "../../ContextMenuItem";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -70,23 +71,19 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
onKeyPress = (e: KeyboardEvent) => {
//make textbox and add it to this collection
// tslint:disable-next-line:prefer-const
- let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
+ const cm = ContextMenu.Instance;
+ const [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
if (e.key === "?") {
- ContextMenu.Instance.setDefaultItem("?", (str: string) => {
- const textDoc = Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, {
- _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false,
- title: "bing", UseCors: true
- });
- this.props.addDocTab(textDoc, "onRight");
- });
+ cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
+ Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false, title: "bing", UseCors: true }), "onRight"));
- ContextMenu.Instance.displayMenu(this._downX, this._downY);
+ cm.displayMenu(this._downX, this._downY);
e.stopPropagation();
} else
if (e.key === ":") {
DocUtils.addDocumentCreatorMenuItems(this.props.addLiveTextDocument, this.props.addDocument, x, y);
- ContextMenu.Instance.displayMenu(this._downX, this._downY);
+ cm.displayMenu(this._downX, this._downY);
e.stopPropagation();
} else if (e.key === "a" && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
@@ -108,11 +105,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (br) break;
}
}
+ let ypos = y;
ns.map(line => {
const indent = line.search(/\S|$/);
- const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, title: line });
+ const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: ypos, title: line });
this.props.addDocument(newBox);
- y += 40 * this.props.getTransform().Scale;
+ ypos += 40 * this.props.getTransform().Scale;
});
})();
e.stopPropagation();
@@ -280,7 +278,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else {
this._downX = x;
this._downY = y;
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl)) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
this.clearSelection();
}
@@ -342,41 +340,33 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@undoBatch
@action
delete = () => {
- const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = this.marqueeSelect(false);
SelectionManager.DeselectAll();
-
- selected.map(doc => {
- const effectiveAcl = GetEffectiveAcl(doc);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
- recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
- this.props.removeDocument(doc);
- }
- });
+ selected.forEach(doc => this.props.removeDocument(doc));
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
}
- 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 newCollection = (creator || Docs.Create.FreeformDocument)(selected, {
- x: bounds.left,
- y: bounds.top,
- _panX: 0,
- _panY: 0,
- isBackground,
- backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : isBackground ? "cyan" : undefined,
- _width: bounds.width,
- _height: bounds.height,
- title: "a nested collection",
- });
+ getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => {
+ const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
+ Doc.GetProto(doc).data = new List<Doc>(selected);
+ Doc.GetProto(doc).title = "nested freeform";
+ doc._panX = doc._panY = 0;
+ return doc;
+ })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
+ newCollection.system = undefined;
+ newCollection.isBackground = isBackground;
+ newCollection.backgroundColor = this.props.isAnnotationOverlay ? "#00000015" : isBackground ? "cyan" : undefined;
+ newCollection._width = this.Bounds.width;
+ newCollection._height = this.Bounds.height;
+ newCollection.x = this.Bounds.left;
+ newCollection.y = this.Bounds.top;
selected.forEach(d => d.context = newCollection);
this.hideMarquee();
return newCollection;
- }
+ });
@action
pileup = (e: KeyboardEvent | React.PointerEvent | undefined) => {
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index e0f3eca44..57e968aa7 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -316,7 +316,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
getPermissionsSelect(user: string, permission: string) {
return <select className="permissions-select"
- defaultValue={permission}
+ value={permission}
onChange={e => this.changePermissions(e, user)}>
{Object.values(SharingPermissions).map(permission => {
return (
@@ -963,22 +963,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
if (this.isPres) {
const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0;
- return <div className="propertiesView">
- <div className="propertiesView-title">
+ return <div className="propertiesView" style={{ width: this.props.width }}>
+ <div className="propertiesView-title" style={{ width: this.props.width }}>
Presentation
</div>
<div className="propertiesView-name">
{this.editableTitle}
<div className="propertiesView-presSelected">
- {PresBox.Instance._selectedArray.length} selected
+ {PresBox.Instance?._selectedArray.length} selected
<div className="propertiesView-selectedList">
- {PresBox.Instance.listOfSelected}
+ {PresBox.Instance?.listOfSelected}
</div>
</div>
</div>
{!selectedItem ? (null) : <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
- onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })}
+ onPointerDown={action(() => { this.openPresTransitions = !this.openPresTransitions; })}
style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
&nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
<div className="propertiesView-presTrails-title-icon">
@@ -1028,7 +1028,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{PresBox.Instance.newDocumentDropdown}
</div> : null}
</div>
- <div className="propertiesView-sharing">
+ {/* <div className="propertiesView-sharing">
<div className="propertiesView-sharing-title"
onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
style={{ backgroundColor: this.openSharing ? "black" : "" }}>
@@ -1040,7 +1040,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openSharing ? <div className="propertiesView-sharing-content">
{this.sharingTable}
</div> : null}
- </div>
+ </div> */}
</div>;
}
}
diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss
index 4c79a7c2f..7eb07ff55 100644
--- a/src/client/views/globalCssVariables.scss
+++ b/src/client/views/globalCssVariables.scss
@@ -29,6 +29,7 @@ $search-thumnail-size: 130;
$contextMenu-zindex: 100000; // context menu shows up over everything
$radialMenu-zindex: 100000; // context menu shows up over everything
+$searchpanel-height: 32px;
$mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc
$docDecorations-zindex: 998; // then doc decorations appear over everything else
$remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right?
@@ -43,4 +44,5 @@ $MAX_ROW_HEIGHT: 44px;
MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT;
SEARCH_THUMBNAIL_SIZE: $search-thumnail-size;
ANTIMODEMENU_HEIGHT: $antimodemenu-height;
+ SEARCH_PANEL_HEIGHT: $searchpanel-height;
} \ No newline at end of file
diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts
index a7ca4b300..fd1f60f13 100644
--- a/src/client/views/globalCssVariables.scss.d.ts
+++ b/src/client/views/globalCssVariables.scss.d.ts
@@ -6,6 +6,7 @@ interface IGlobalScss {
MAX_ROW_HEIGHT: string;
SEARCH_THUMBNAIL_SIZE: string;
ANTIMODEMENU_HEIGHT: string;
+ SEARCH_PANEL_HEIGHT: string;
}
declare const globalCssVariables: IGlobalScss;
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index c9e39cf7b..ed64bde32 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -382,11 +382,11 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
</div>
<div className="linkEditor-followingDropdown-option"
onPointerDown={() => this.changeFollowBehavior("onRight")}>
- Always open in new pane on right
+ Always open in a new pane
</div>
<div className="linkEditor-followingDropdown-option"
onPointerDown={() => this.changeFollowBehavior("inTab")}>
- Always open in new tab
+ Always open in a new tab
</div>
{this.props.linkDoc.linksToAnnotation ?
<div className="linkEditor-followingDropdown-option"
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 289388320..900963eb0 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -85,6 +85,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
constructor(props: Readonly<FieldViewProps>) {
super(props);
+ AudioBox.Instance = this;
// onClick play scripts
AudioBox.RangeScript = AudioBox.RangeScript || ScriptField.MakeScript(`scriptContext.playFrom((this.audioStart), (this.audioEnd))`, { scriptContext: "any" })!;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 42a42ddf1..52f6a66c8 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -132,7 +132,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
}
- public static updateKeyframe(docs: Doc[], time: number) {
+ public static updateKeyframe(docs: Doc[], time: number, targetDoc?: Doc) {
const timecode = Math.round(time);
docs.forEach(doc => {
const xindexed = Cast(doc['x-indexed'], listSpec("number"), null);
@@ -145,11 +145,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
xindexed?.length <= timecode + 1 && xindexed.push(undefined as any as number);
yindexed?.length <= timecode + 1 && yindexed.push(undefined as any as number);
opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number);
- if (doc.appearFrame) {
+ if (doc.appearFrame && targetDoc) {
if (doc.appearFrame === timecode + 1) {
- doc["text-color"] = "red";
+ doc["text-color"] = StrCast(targetDoc["pres-text-color"]);
} else if (doc.appearFrame < timecode + 1) {
- doc["text-color"] = "grey";
+ doc["text-color"] = StrCast(targetDoc["pres-text-viewed-color"]);
} else { doc["text-color"] = "black"; }
} else if (doc.appearFrame === 0) {
doc["text-color"] = "black";
@@ -164,15 +164,16 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
}
- public static setupZoom(doc: Doc, zoomProgressivize: boolean = false) {
+
+ public static setupZoom(doc: Doc, targDoc: Doc, zoomProgressivize: boolean = false) {
const width = new List<number>();
const height = new List<number>();
const top = new List<number>();
const left = new List<number>();
- width.push(NumCast(doc.width));
- height.push(NumCast(doc.height));
- top.push(NumCast(doc.height) / -2);
- left.push(NumCast(doc.width) / -2);
+ width.push(NumCast(targDoc._width));
+ height.push(NumCast(targDoc._height));
+ top.push(NumCast(targDoc._height) / -2);
+ left.push(NumCast(targDoc._width) / -2);
doc["viewfinder-width-indexed"] = width;
doc["viewfinder-height-indexed"] = height;
doc["viewfinder-top-indexed"] = top;
@@ -267,13 +268,13 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
NativeHeight = () => this.nativeHeight;
render() {
TraceMobx();
- const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document);
+ const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document, this.props.renderDepth);
return <div className="collectionFreeFormDocumentView-container"
style={{
boxShadow:
this.Opacity === 0 ? undefined : // if it's not visible, then no shadow
this.layoutDoc.z ? `#9c9396 ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow
- this.props.backgroundHalo?.() && this.props.Document.type !== DocumentType.INK ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ this.props.backgroundHalo?.() && this.props.Document.type !== DocumentType.INK ? (`${this.props.backgroundColor?.(this.props.Document, this.props.renderDepth)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
this.layoutDoc.isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big
StrCast(this.layoutDoc.boxShadow, ""),
borderRadius: StrCast(Doc.Layout(this.layoutDoc).borderRounding),
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index 0c4242172..88eb48f51 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -184,7 +184,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
onContextMenu={this.specificContextMenu}
onPointerDown={this.onPointerDown} onClick={this.onClick}
style={{
- background: this.props.backgroundColor?.(containedDoc),
+ background: this.props.backgroundColor?.(containedDoc, this.props.renderDepth),
border: `#00000021 solid ${this.xPad}px`,
borderTop: `#0000005e solid ${this.yPad}px`,
borderBottom: `#0000005e solid ${this.yPad}px`,
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 31dd33fc1..cf8645e4c 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -241,6 +241,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
style={{
width: this.props.InMenu ? "20px" : "30px", height: this.props.InMenu ? "20px" : "30px",
backgroundColor: DocumentLinksButton.StartLink ? "" : "grey",
+ opacity: DocumentLinksButton.StartLink ? "" : "50%",
border: DocumentLinksButton.StartLink ? "" : "none"
}}
onPointerDown={DocumentLinksButton.StartLink ? this.completeLink : emptyFunction}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 47e1b2715..d92dc0ec2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -6,15 +6,13 @@ import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { listSpec } from "../../../fields/Schema";
-import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
-import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
+import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, emptyPath, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
-import { ClientRecommender } from '../../ClientRecommender';
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from "../../util/DocumentManager";
@@ -22,7 +20,6 @@ import { DragManager, dropActionType } from "../../util/DragManager";
import { InteractionUtils } from '../../util/InteractionUtils';
import { LinkManager } from '../../util/LinkManager';
import { Scripting } from '../../util/Scripting';
-import { SearchUtil } from '../../util/SearchUtil';
import { SelectionManager } from "../../util/SelectionManager";
import SharingManager from '../../util/SharingManager';
import { SnappingManager } from '../../util/SnappingManager';
@@ -33,7 +30,6 @@ import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from "../DocComponent";
import { EditableView } from '../EditableView';
-import { KeyphraseQueryView } from '../KeyphraseQueryView';
import { DocumentContentsView } from "./DocumentContentsView";
import { DocumentLinksButton } from './DocumentLinksButton';
import "./DocumentView.scss";
@@ -86,7 +82,7 @@ export interface DocumentViewProps {
addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
pinToPres: (document: Doc) => void;
backgroundHalo?: () => boolean;
- backgroundColor?: (doc: Doc) => string | undefined;
+ backgroundColor?: (doc: Doc, renderDepth: number) => string | undefined;
forcedBackgroundColor?: (doc: Doc) => string | undefined;
opacity?: () => number | undefined;
ChromeHeight?: () => number;
@@ -179,7 +175,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
RadialMenu.Instance.openMenu(pt.pageX - 15, pt.pageY - 15);
// RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "map-pin", selected: -1 });
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
(effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && RadialMenu.Instance.addItem({ description: "Delete", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "external-link-square-alt", selected: -1 });
// RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "trash", selected: -1 });
RadialMenu.Instance.addItem({ description: "Pin", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
@@ -324,6 +320,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
self: this.rootDoc,
scriptContext: this.props.scriptContext,
thisContainer: this.props.ContainingCollectionDoc,
+ documentView: this,
shiftKey: e.shiftKey
}, console.log);
if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) && !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc)) {
@@ -570,19 +567,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (Doc.UserDoc().activeWorkspace === this.props.Document) {
alert("Can't delete the active workspace");
} else {
- const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
const selected = SelectionManager.SelectedDocuments().slice();
SelectionManager.DeselectAll();
-
- selected.map(dv => {
- const effectiveAcl = GetEffectiveAcl(dv.props.Document);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
- recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
- dv.props.removeDocument?.(dv.props.Document);
- }
- });
-
- this.props.Document.deleted = true;
+ selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
this.props.removeDocument?.(this.props.Document);
}
}
@@ -776,8 +763,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()) && moreItems.push({ description: "Toggle Always Show Link End", event: () => Doc.UserDoc()["documentLinksButton-hideEnd"] = !Doc.UserDoc()["documentLinksButton-hideEnd"], icon: "eye" });
}
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
- (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && moreItems.push({ description: "Delete", event: this.deleteClicked, icon: "trash" });
+ moreItems.push({ description: "Close", event: this.deleteClicked, icon: "times" });
!more && cm.addItem({ description: "More...", subitems: moreItems, icon: "hand-point-right" });
cm.moveAfter(cm.findByDescription("More...")!, cm.findByDescription("OnClick...")!);
@@ -829,7 +815,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
@computed get contents() {
const pos = this.props.relative ? "relative " : "absolute";
TraceMobx();
- return (<div style={{ width: "100%", height: "100%" }}>
+ return (<div className="documentView-contentsView" style={{ borderRadius: "inherit", width: "100%", height: "100%" }}>
<DocumentContentsView key={1}
docFilters={this.props.docFilters}
ContainingCollectionView={this.props.ContainingCollectionView}
@@ -935,7 +921,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const showTitle = StrCast(this.layoutDoc._showTitle);
const showTitleHover = StrCast(this.layoutDoc._showTitleHover);
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 showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined;
const captionView = (!showCaption ? (null) :
<div className="documentView-captionWrapper" style={{ backgroundColor: StrCast(this.layoutDoc["caption-backgroundColor"]), color: StrCast(this.layoutDoc["caption-color"]) }}>
<DocumentContentsView {...OmitKeys(this.props, ['children']).omit}
@@ -1002,9 +988,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
render() {
if (!(this.props.Document instanceof Doc)) return (null);
- if (GetEffectiveAcl(this.props.Document) === AclPrivate) return (null);
+ if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null);
if (this.props.Document.hidden) return (null);
- const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : this.props.forcedBackgroundColor?.(this.Document) || StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document);
+ const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : this.props.forcedBackgroundColor?.(this.Document) || StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document, this.props.renderDepth);
const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null)));
const finalOpacity = this.props.opacity ? this.props.opacity() : opacity;
const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index dd70fb1db..9d61ec6d1 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -5,7 +5,7 @@ import { DateField } from "../../../fields/DateField";
import { Doc, FieldResult, Opt, Field } from "../../../fields/Doc";
import { List } from "../../../fields/List";
import { ScriptField } from "../../../fields/ScriptField";
-import { AudioField, VideoField } from "../../../fields/URLField";
+import { AudioField, VideoField, WebField } from "../../../fields/URLField";
import { Transform } from "../../util/Transform";
import { CollectionView } from "../collections/CollectionView";
import { AudioBox } from "./AudioBox";
@@ -38,7 +38,7 @@ export interface FieldViewProps {
pinToPres: (document: Doc) => void;
removeDocument?: (document: Doc | Doc[]) => boolean;
moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
- backgroundColor?: (document: Doc) => string | undefined;
+ backgroundColor?: (document: Doc, renderDepth: number) => string | undefined;
ScreenToLocalTransform: () => Transform;
bringToFront: (doc: Doc, sendToBack?: boolean) => void;
active: (outsideReaction?: boolean) => boolean;
@@ -136,9 +136,9 @@ export class FieldView extends React.Component<FieldViewProps> {
return <div> {field.map(f => Field.toString(f)).join(", ")} </div>;
}
// bcz: this belongs here, but it doesn't render well so taking it out for now
- // else if (field instanceof HtmlField) {
- // return <WebBox {...this.props} />
- // }
+ else if (field instanceof WebField) {
+ return <p>{Field.toString(field.url.href)}</p>;
+ }
else if (!(field instanceof Promise)) {
return <p>{Field.toString(field)}</p>;
}
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 6a540269e..75bc90d7a 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -13,6 +13,27 @@
width: 100%;
}
+.fontIconBadge-container {
+ position:absolute;
+ z-index: 1000;
+ top: 12px;
+
+ .fontIconBadge {
+ position: absolute;
+ top: -10px;
+ right: -10px;
+ color: white;
+ background: #f44b42;
+ font-weight: 300;
+ border-radius: 100%;
+ width: 25px;
+ height: 25px;
+ text-align: center;
+ padding-top: 4px;
+ font-size: 12px;
+ }
+}
+
.menuButton-round {
border-radius: 100%;
background-color: black;
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index a6b1678b5..fd71876b0 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -5,13 +5,14 @@ import { createSchema, makeInterface } from '../../../fields/Schema';
import { DocComponent } from '../DocComponent';
import './FontIconBox.scss';
import { FieldView, FieldViewProps } from './FieldView';
-import { StrCast, Cast, NumCast } from '../../../fields/Types';
-import { Utils, emptyFunction } from "../../../Utils";
+import { StrCast, Cast, ScriptCast } from '../../../fields/Types';
+import { Utils, setupMoveUpEvents, returnFalse, emptyFunction } from "../../../Utils";
import { runInAction, observable, reaction, IReactionDisposer } from 'mobx';
-import { Doc } from '../../../fields/Doc';
+import { Doc, DocListCast } from '../../../fields/Doc';
import { ContextMenu } from '../ContextMenu';
import { ScriptField } from '../../../fields/ScriptField';
import { Tooltip } from '@material-ui/core';
+import { DragManager } from '../../util/DragManager';
const FontIconSchema = createSchema({
icon: "string",
});
@@ -61,8 +62,9 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
render() {
const label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title));
const color = StrCast(this.layoutDoc.color, this._foregroundColor);
- const backgroundColor = StrCast(this.layoutDoc._backgroundColor, StrCast(this.rootDoc.backgroundColor, this.props.backgroundColor?.(this.rootDoc)));
+ const backgroundColor = StrCast(this.layoutDoc._backgroundColor, StrCast(this.rootDoc.backgroundColor, this.props.backgroundColor?.(this.rootDoc, this.props.renderDepth)));
const shape = StrCast(this.layoutDoc.iconShape, "round");
+
const button = <button className={`menuButton-${shape}`} ref={this._ref} onContextMenu={this.specificContextMenu}
style={{
boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined,
@@ -72,6 +74,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
{<FontAwesomeIcon className={`menuButton-icon-${shape}`} icon={StrCast(this.dataDoc.icon, "user") as any} color={color}
size={this.layoutDoc.iconShape === "square" ? "sm" : "lg"} />}
{!label ? (null) : <div className="fontIconBox-label" style={{ color, backgroundColor }}> {label} </div>}
+ {this.props.Document.watchedDocuments ? <FontIconBadge collection={Cast(this.props.Document.watchedDocuments, Doc, null)} /> : (null)}
</div>
</button>;
return !this.layoutDoc.toolTip ? button :
@@ -79,4 +82,34 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
{button}
</Tooltip>;
}
+}
+
+interface FontIconBadgeProps {
+ collection: Doc;
+}
+
+@observer
+export class FontIconBadge extends React.Component<FontIconBadgeProps> {
+ _notifsRef = React.createRef<HTMLDivElement>();
+
+ onPointerDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e,
+ (e: PointerEvent) => {
+ const dragData = new DragManager.DocumentDragData([this.props.collection]);
+ DragManager.StartDocumentDrag([this._notifsRef.current!], dragData, e.x, e.y);
+ return true;
+ },
+ returnFalse, emptyFunction, false);
+ }
+
+ render() {
+ if (!(this.props.collection instanceof Doc)) return (null);
+ const length = DocListCast(this.props.collection.data).length;
+ return <div className="fontIconBadge-container" style={{ width: 15, height: 15, top: 12 }} ref={this._notifsRef}>
+ <div className="fontIconBadge" style={length > 0 ? { "display": "initial" } : { "display": "none" }}
+ onPointerDown={this.onPointerDown} >
+ {length}
+ </div>
+ </div>;
+ }
} \ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index d668d332b..216c5f39e 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
if (field) {
const funcs: ContextMenuProps[] = [];
funcs.push({ description: "Rotate Clockwise 90", event: this.rotate, icon: "expand-arrows-alt" });
- funcs.push({ description: "Make Background", event: () => this.layoutDoc.isBackground = true, icon: "expand-arrows-alt" });
+ funcs.push({ description: "Make Background", event: () => { this.layoutDoc.isBackground = true; this.props.bringToFront?.(this.rootDoc); }, icon: "expand-arrows-alt" });
if (!Doc.UserDoc().noviceMode) {
funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" });
funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
@@ -466,7 +466,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
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`
+ borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
}} >
<CollectionFreeFormView {...this.props}
forceScaling={true}
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 3f942e87b..532e7dc15 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -17,7 +17,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); }
render() {
return <div className={`linkBox-container${this.active() ? "-interactive" : ""}`}
- style={{ background: this.props.backgroundColor?.(this.props.Document) }} >
+ style={{ background: this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) }} >
<CollectionTreeView {...this.props}
ChromeHeight={returnZero}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index ebb916307..c4481b213 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -7,21 +7,16 @@ import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, re
import { Docs } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { Transform } from "../../util/Transform";
+import { ContextMenu } from '../ContextMenu';
import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
-import React = require("react");
-import { DocumentView } from './DocumentView';
-import { sortAndDeduplicateDiagnostics } from 'typescript';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { LinkManager } from '../../util/LinkManager';
import { DocumentLinksButton } from './DocumentLinksButton';
-import { ContextMenu } from '../ContextMenu';
-import { undoBatch } from '../../util/UndoManager';
+import React = require("react");
interface Props {
linkDoc?: Doc;
linkSrc?: Doc;
href?: string;
- backgroundColor: (doc: Doc) => string;
+ backgroundColor: (doc: Doc, renderDepth: number) => string;
addDocTab: (document: Doc, where: string) => boolean;
location: number[];
}
diff --git a/src/client/views/nodes/MenuIconBox.tsx b/src/client/views/nodes/MenuIconBox.tsx
index 0aa7b327e..5ed8a9b78 100644
--- a/src/client/views/nodes/MenuIconBox.tsx
+++ b/src/client/views/nodes/MenuIconBox.tsx
@@ -19,10 +19,10 @@ export class MenuIconBox extends DocComponent<FieldViewProps, MenuIconDocument>(
render() {
- const color = this.props.backgroundColor?.(this.props.Document) === "lightgrey" ? "black" : "white";
- const menuBTN = <div className="menuButton" style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }}>
+ const color = this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) === "lightgrey" ? "black" : "white";
+ const menuBTN = <div className="menuButton" style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) }}>
<div className="menuButton-wrap"
- style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document) }} >
+ style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) }} >
<FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" />
<div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div>
</div>
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 323da1233..255a1b2d0 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -60,19 +60,19 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
if (href) {
const pathCorrectionTest = /upload\_[a-z0-9]{32}.(.*)/g;
const matches = pathCorrectionTest.exec(href);
- console.log("\nHere's the { url } being fed into the outer regex:");
- console.log(href);
- console.log("And here's the 'properPath' build from the captured filename:\n");
+ // console.log("\nHere's the { url } being fed into the outer regex:");
+ // console.log(href);
+ // console.log("And here's the 'properPath' build from the captured filename:\n");
if (matches !== null && href.startsWith(window.location.origin)) {
const properPath = Utils.prepend(`/files/pdfs/${matches[0]}`);
- console.log(properPath);
+ //console.log(properPath);
if (!properPath.includes(href)) {
console.log(`The two (url and proper path) were not equal`);
const proto = Doc.GetProto(Document);
proto[this.props.fieldKey] = new PdfField(properPath);
proto[backup] = href;
} else {
- console.log(`The two (url and proper path) were equal`);
+ //console.log(`The two (url and proper path) were equal`);
}
} else {
console.log("Outer matches was null!");
@@ -91,7 +91,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
loaded = (nw: number, nh: number, np: number) => {
this.dataDoc[this.props.fieldKey + "-numPages"] = np;
- this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = nw * 96 / 72;
+ this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = Math.max(NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]), nw * 96 / 72);
this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = nh * 96 / 72;
!this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw));
}
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index a87b0e466..c4d8f1a4f 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -3,6 +3,7 @@ $dark-blue: #5B9FDD;
$light-background: #ececec;
.presBox-cont {
+ cursor: auto;
position: absolute;
display: block;
pointer-events: inherit;
@@ -12,14 +13,14 @@ $light-background: #ececec;
width: 100%;
min-width: 20px;
height: 100%;
- min-height: 41px;
+ min-height: 35px;
letter-spacing: 2px;
overflow: hidden;
transition: 0.7s opacity ease;
.presBox-listCont {
position: relative;
- height: calc(100% - 25px);
+ height: calc(100% - 67px);
width: 100%;
margin-top: 3px;
}
@@ -50,6 +51,7 @@ $light-background: #ececec;
background-color: #323232;
.toolbar-button {
+ cursor: pointer;
margin-left: 10px;
margin-right: 10px;
letter-spacing: 0;
@@ -153,7 +155,6 @@ $light-background: #ececec;
margin-left: 5px;
margin-top: 5px;
margin-bottom: 5px;
- margin-right: 5px;
width: max-content;
justify-content: center;
align-items: center;
@@ -161,6 +162,30 @@ $light-background: #ececec;
padding-left: 10px;
}
+ .ribbon-propertyUpDown {
+ height: 20;
+ width: 20;
+ margin-top: 5px;
+ display: grid;
+ grid-template-rows: 10px 10px;
+
+ .ribbon-propertyUpDownItem {
+ cursor: pointer;
+ color: white;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ width: 100%;
+ background: black;
+ }
+
+ .ribbon-propertyUpDownItem:hover {
+ background: darkgrey;
+ transform: scale(1.05);
+ }
+ }
+
.presBox-subheading {
font-size: 11;
font-weight: 400;
@@ -254,6 +279,18 @@ $light-background: #ececec;
width: 100%;
}
+ .presBox-input {
+ width: 30;
+ height: 100%;
+ background: none;
+ border: none;
+ text-align: right;
+ }
+
+ .presBox-input:focus {
+ outline: none;
+ }
+
.ribbon-frameSelector {
border: black solid 1px;
width: 60px;
@@ -281,6 +318,7 @@ $light-background: #ececec;
}
.numKeyframe {
+ cursor: pointer;
font-size: 10;
font-weight: 600;
position: relative;
@@ -311,6 +349,7 @@ $light-background: #ececec;
.ribbon-final-button {
+ cursor: pointer;
position: relative;
font-size: 11;
font-weight: normal;
@@ -329,7 +368,13 @@ $light-background: #ececec;
background-color: #979797;
}
+ .ribbon-final-button:hover {
+ transform: scale(1.05);
+ transition: all 0.4s;
+ }
+
.ribbon-final-button-hidden {
+ cursor: pointer;
position: relative;
font-size: 11;
font-weight: normal;
@@ -347,6 +392,11 @@ $light-background: #ececec;
border-radius: 10px;
background-color: black;
}
+
+ .ribbon-final-button-hidden:hover {
+ transform: scale(1.05);
+ transition: all 0.4s;
+ }
}
.selectedList {
@@ -363,6 +413,7 @@ $light-background: #ececec;
}
.ribbon-button {
+ cursor: pointer;
font-size: 10.5;
font-weight: 200;
height: 20;
@@ -399,11 +450,9 @@ $light-background: #ececec;
grid-template-rows: max-content auto;
justify-self: center;
margin-top: 10px;
- /* padding-left: 10px; */
padding-right: 10px;
letter-spacing: normal;
width: 100%;
- /* max-width: 100%; */
height: max-content;
font-weight: 500;
position: relative;
@@ -412,10 +461,36 @@ $light-background: #ececec;
border-bottom: solid 1px darkgrey;
.presBox-dropdown:hover {
- border: solid 1px #378AD8;
- border-bottom-left-radius: 0px;
+ border: solid 1px $dark-blue;
+
+ .presBox-dropdownIcon {
+ color: $dark-blue;
+ }
+ }
+
+ .presBox-dropdown {
+ cursor: pointer;
+ display: grid;
+ grid-template-columns: auto 20%;
+ position: relative;
+ border: solid 1px black;
+ background-color: $light-background;
+ border-radius: 5px;
+ font-size: 10;
+ height: 25;
+ padding-left: 5px;
+ align-items: center;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-weight: 200;
+ width: 100%;
+ min-width: max-content;
+ max-width: 200px;
+ overflow: visible;
+
.presBox-dropdownOption {
+ cursor: pointer;
font-size: 11;
display: block;
padding-left: 10px;
@@ -431,13 +506,13 @@ $light-background: #ececec;
.presBox-dropdownOption.active {
position: relative;
- background-color: #aedef8;
+ background-color: $light-blue;
}
.presBox-dropdownOptions {
position: absolute;
- top: 24px;
- left: -1px;
+ top: 23px;
+ left: -2px;
z-index: 200;
width: 85%;
min-width: max-content;
@@ -449,34 +524,6 @@ $light-background: #ececec;
}
.presBox-dropdownIcon {
- color: #378AD8;
- }
- }
-
- .presBox-dropdown {
- display: grid;
- grid-template-columns: auto 20%;
- position: relative;
- border: solid 1px black;
- background-color: $light-background;
- border-radius: 5px;
- font-size: 10;
- height: 25;
- padding-left: 5px;
- align-items: center;
- margin-top: 5px;
- margin-bottom: 5px;
- font-weight: 200;
- width: 100%;
- min-width: max-content;
- max-width: 200px;
- overflow: visible;
-
- .presBox-dropdownOptions {
- display: none;
- }
-
- .presBox-dropdownIcon {
position: relative;
color: black;
align-self: center;
@@ -509,6 +556,7 @@ $light-background: #ececec;
}
.dropdown-play-button {
+ cursor: pointer;
font-size: 12;
padding-left: 5px;
padding-right: 5px;
@@ -523,6 +571,7 @@ $light-background: #ececec;
}
.presBox-button-left {
+ cursor: pointer;
position: relative;
align-self: flex-start;
justify-self: flex-start;
@@ -539,6 +588,7 @@ $light-background: #ececec;
}
.presBox-button-right {
+ cursor: pointer;
position: relative;
text-align: center;
border-left: solid 1px darkgrey;
@@ -561,6 +611,7 @@ $light-background: #ececec;
}
.dropdown-play {
+ cursor: pointer;
right: 0px;
top: calc(100% + 2px);
display: none;
@@ -581,6 +632,7 @@ $light-background: #ececec;
}
.open-layout {
+ cursor: pointer;
position: relative;
display: flex;
align-items: center;
@@ -612,6 +664,7 @@ $light-background: #ececec;
}
.layout {
+ cursor: pointer;
align-self: center;
justify-self: center;
margin-top: 5;
@@ -682,6 +735,7 @@ $light-background: #ececec;
grid-template-columns: auto auto;
.presBox-viewPicker {
+ cursor: pointer;
height: 25;
position: relative;
display: inline-block;
@@ -708,6 +762,7 @@ $light-background: #ececec;
}
.presBox-button {
+ cursor: pointer;
height: 25px;
border-radius: 5px;
display: none;
@@ -746,7 +801,7 @@ $light-background: #ececec;
}
- .miniPresOverlay {
+ .presPanelOverlay {
background-color: #323232;
color: white;
border-radius: 5px;
@@ -761,7 +816,7 @@ $light-background: #ececec;
right: 10px;
transition: all 0.2s;
- .miniPres-button-text {
+ .presPanel-button-text {
display: flex;
height: 20;
width: max-content;
@@ -778,13 +833,13 @@ $light-background: #ececec;
transition: all 0.3s;
}
- .miniPres-divider {
+ .presPanel-divider {
width: 0.5px;
height: 80%;
border-right: solid 1px #5a5a5a;
}
- .miniPres-button-frame {
+ .presPanel-button-frame {
justify-self: center;
align-self: center;
align-items: center;
@@ -799,7 +854,8 @@ $light-background: #ececec;
border-radius: 5px;
}
- .miniPres-button {
+ .presPanel-button {
+ cursor: pointer;
display: flex;
height: 20;
min-width: 20;
@@ -811,11 +867,11 @@ $light-background: #ececec;
transition: all 0.3s;
}
- .miniPres-button:hover {
+ .presPanel-button:hover {
background-color: #5a5a5a;
}
- .miniPres-button-text:hover {
+ .presPanel-button-text:hover {
background-color: #5a5a5a;
}
}
@@ -894,4 +950,82 @@ $light-background: #ececec;
.select {
font-size: 100%;
}
-} \ No newline at end of file
+}
+
+.miniPres:hover {
+ opacity: 1;
+}
+
+.miniPres {
+ cursor: grab;
+ position: absolute;
+ overflow: hidden;
+ right: 10;
+ top: 10;
+ opacity: 0.1;
+ transition: all 0.4s;
+ /* border: solid 1px; */
+ color: white;
+ /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
+
+ .miniPresOverlay {
+ display: grid;
+ grid-template-columns: auto auto auto auto auto auto auto auto;
+ grid-template-rows: 100%;
+ height: 100%;
+ justify-items: center;
+ align-items: center;
+
+ .miniPres-button-text {
+ cursor: pointer;
+ display: flex;
+ height: 20;
+ font-weight: 400;
+ min-width: 100%;
+ border-radius: 5px;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ }
+
+ .miniPres-button-frame {
+ justify-self: center;
+ align-self: center;
+ align-items: center;
+ display: grid;
+ grid-template-columns: auto auto auto;
+ justify-content: space-around;
+ font-size: 11;
+ margin-left: 7;
+ width: 30;
+ height: 85%;
+ background-color: rgba(91, 157, 221, 0.4);
+ border-radius: 5px;
+ }
+
+ .miniPres-divider {
+ width: 0.5px;
+ height: 80%;
+ border-right: solid 2px #5a5a5a;
+ }
+
+ .miniPres-button {
+ cursor: pointer;
+ display: flex;
+ height: 20;
+ min-width: 20;
+ border-radius: 100%;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ }
+
+ .miniPres-button:hover {
+ background-color: #5a5a5a;
+ }
+
+ .miniPres-button-text:hover {
+ background-color: #5a5a5a;
+ }
+ }
+}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 849fc4076..5fc76223d 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -23,10 +23,12 @@ import { Scripting } from "../../util/Scripting";
import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
import { List } from "../../../fields/List";
import { Tooltip } from "@material-ui/core";
-import { CollectionFreeFormViewChrome } from "../collections/CollectionMenu";
import { actionAsync } from "mobx-utils";
import { SelectionManager } from "../../util/SelectionManager";
import { AudioBox } from "./AudioBox";
+import { DocumentView } from "./DocumentView";
+import { SketchPicker, ColorState } from "react-color";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
type PresBoxSchema = makeInterface<[typeof documentSchema]>;
const PresBoxDocument = makeInterface(documentSchema);
@@ -54,13 +56,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@observable private presentTools: boolean = false;
@observable private pathBoolean: boolean = false;
@observable private expandBoolean: boolean = false;
+ @observable private openMovementDropdown: boolean = false;
+ @observable private openEffectDropdown: boolean = false;
@computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
@computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); }
@computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); }
constructor(props: any) {
super(props);
- PresBox.Instance = this;
+ if (Doc.UserDoc().activePresentation = this.rootDoc) PresBox.Instance = this;
if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations.
Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({
title: "pres element template", backgroundColor: "transparent", _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
@@ -92,8 +96,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
}
@computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+
componentWillUnmount() {
document.removeEventListener("keydown", this.keyEvents, true);
+ this.turnOffEdit();
}
componentDidMount() {
@@ -106,6 +112,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
updateCurrentPresentation = () => {
Doc.UserDoc().activePresentation = this.rootDoc;
+ PresBox.Instance = this;
}
/**
@@ -123,25 +130,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const lastFrame = Cast(presTargetDoc.lastFrame, "number", null);
const curFrame = NumCast(presTargetDoc.currentFrame);
let internalFrames: boolean = false;
- if (presTargetDoc.presProgressivize || presTargetDoc.zoomProgressivize || presTargetDoc.scrollProgressivize) internalFrames = true;
+ if (presTargetDoc.presProgressivize || activeItem.zoomProgressivize || presTargetDoc.scrollProgressivize) internalFrames = true;
// Case 1: There are still other frames and should go through all frames before going to next slide
if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
presTargetDoc._viewTransition = "all 1s";
setTimeout(() => presTargetDoc._viewTransition = undefined, 1010);
presTargetDoc.currentFrame = curFrame + 1;
if (presTargetDoc.scrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(presTargetDoc, currentFrame);
- if (presTargetDoc.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
- if (presTargetDoc.zoomProgressivize) this.zoomProgressivizeNext(presTargetDoc);
+ if (presTargetDoc.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, presTargetDoc);
+ else presTargetDoc.editing = true;
+ if (activeItem.zoomProgressivize) this.zoomProgressivizeNext(presTargetDoc);
// Case 2: Audio or video therefore wait to play the audio or video before moving on
- } else if ((presTargetDoc.type === DocumentType.AUDIO) && !this._moveOnFromAudio) {
+ } else if ((presTargetDoc.type === DocumentType.AUDIO) && !this._moveOnFromAudio && this.layoutDoc.presStatus !== 'auto') {
AudioBox.Instance.playFrom(0);
this._moveOnFromAudio = true;
// Case 3: No more frames in current doc and next slide is defined, therefore move to next slide
} else if (this.childDocs[this.itemIndex + 1] !== undefined) {
const nextSelected = this.itemIndex + 1;
+ if (presTargetDoc.type === DocumentType.AUDIO) AudioBox.Instance.pause();
this.gotoDocument(nextSelected, this.itemIndex);
const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
if (activeNext && targetNext.type === DocumentType.AUDIO && activeNext.playAuto) {
+ AudioBox.Instance.playFrom(0);
+ this._moveOnFromAudio = true;
} else this._moveOnFromAudio = false;
}
}
@@ -156,10 +167,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
back = () => {
this.updateCurrentPresentation();
const docAtCurrent = this.childDocs[this.itemIndex];
- if (docAtCurrent) {
+ const targetDoc = Cast(docAtCurrent.presentationTargetDoc, Doc, null);
+ const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null);
+ const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
+ const lastFrame = Cast(targetDoc.lastFrame, "number", null);
+ const curFrame = NumCast(targetDoc.currentFrame);
+ if (lastFrame !== undefined && curFrame >= 1) {
+ this.prevKeyframe(targetDoc, docAtCurrent);
+ } else if (docAtCurrent) {
let prevSelected = this.itemIndex;
prevSelected = Math.max(0, prevSelected - 1);
this.gotoDocument(prevSelected, this.itemIndex);
+ if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc.currentFrame = NumCast(prevTargetDoc.lastFrame);
}
}
@@ -174,8 +193,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
if (presTargetDoc?.lastFrame !== undefined) {
presTargetDoc.currentFrame = 0;
}
- this.navigateToElement(this.childDocs[index]); //Handles movement to element
this._selectedArray = [this.childDocs[index]]; //Update selected array
+ //Handles movement to element
+ if (this.layoutDoc._viewType === "stacking") this.navigateToElement(this.childDocs[index]);
this.onHideDocument(); //Handles hide after/before
}
});
@@ -197,8 +217,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.turnOffEdit();
if (this.itemIndex >= 0) {
- if (targetDoc) {
- if (srcContext) this.layoutDoc.presCollection = srcContext;
+ if (srcContext && targetDoc) {
+ this.layoutDoc.presCollection = srcContext;
} else if (targetDoc) this.layoutDoc.presCollection = targetDoc;
}
if (collectionDocView) {
@@ -211,21 +231,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const docToJump = curDoc;
const willZoom = false;
- //docToJump stayed same meaning, it was not in the group or was the last element in the group
- if (targetDoc.zoomProgressivize && this.rootDoc.presStatus !== 'edit') {
- this.zoomProgressivizeNext(targetDoc);
- } else if (docToJump === curDoc) {
- //checking if curDoc has navigation open
- if (curDoc.presNavButton && targetDoc) {
- await DocumentManager.Instance.jumpToDocument(targetDoc, false, undefined, srcContext);
- } else if (curDoc.presZoomButton && targetDoc) {
+ // If openDocument is selected then it should open the document for the user
+ if (activeItem.openDocument) {
+ this.props.addDocTab(activeItem, "replace");
+ } else
+ //docToJump stayed same meaning, it was not in the group or was the last element in the group
+ if (activeItem.zoomProgressivize && this.rootDoc.presStatus !== 'edit') {
+ this.zoomProgressivizeNext(targetDoc);
+ } else if (docToJump === curDoc) {
+ //checking if curDoc has navigation open
+ if (curDoc.presNavButton && targetDoc) {
+ await DocumentManager.Instance.jumpToDocument(targetDoc, false, undefined, srcContext);
+ } else if (curDoc.presZoomButton && targetDoc) {
+ //awaiting jump so that new scale can be found, since jumping is async
+ await DocumentManager.Instance.jumpToDocument(targetDoc, true, undefined, srcContext);
+ }
+ } else {
//awaiting jump so that new scale can be found, since jumping is async
- await DocumentManager.Instance.jumpToDocument(targetDoc, true, undefined, srcContext);
+ targetDoc && await DocumentManager.Instance.jumpToDocument(targetDoc, willZoom, undefined, srcContext);
}
- } else {
- //awaiting jump so that new scale can be found, since jumping is async
- targetDoc && await DocumentManager.Instance.jumpToDocument(targetDoc, willZoom, undefined, srcContext);
- }
// After navigating to the document, if it is added as a presPinView then it will
// adjust the pan and scale to that of the pinView when it was added.
// TODO: Add option to remove presPinView
@@ -234,10 +258,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
targetDoc._panY = activeItem.presPinViewY;
targetDoc._viewScale = activeItem.presPinViewScale;
}
- // If openDocument is selected then it should open the document for the user
- if (collectionDocView && activeItem.openDocument) {
- collectionDocView.props.addDocTab(activeItem, "inPlace");
- }
// If website and has presWebsite data associated then on click it should
// go back to that specific website
// TODO: Add progressivize for navigating web (storing websites for given frames)
@@ -250,22 +270,23 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
* Uses the viewfinder to progressivize through the different views of a single collection.
* @param presTargetDoc: document for which internal zoom is used
*/
- zoomProgressivizeNext = (presTargetDoc: Doc) => {
- const srcContext = Cast(presTargetDoc.context, Doc, null);
- const docView = DocumentManager.Instance.getDocumentView(presTargetDoc);
- const vfLeft: number = this.checkList(presTargetDoc, presTargetDoc["viewfinder-left-indexed"]);
- const vfWidth: number = this.checkList(presTargetDoc, presTargetDoc["viewfinder-width-indexed"]);
- const vfTop: number = this.checkList(presTargetDoc, presTargetDoc["viewfinder-top-indexed"]);
- const vfHeight: number = this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]);
+ zoomProgressivizeNext = (activeItem: Doc) => {
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ const srcContext = Cast(targetDoc?.context, Doc, null);
+ const docView = DocumentManager.Instance.getDocumentView(targetDoc);
+ const vfLeft = this.checkList(targetDoc, activeItem["viewfinder-left-indexed"]);
+ const vfWidth = this.checkList(targetDoc, activeItem["viewfinder-width-indexed"]);
+ const vfTop = this.checkList(targetDoc, activeItem["viewfinder-top-indexed"]);
+ const vfHeight = this.checkList(targetDoc, activeItem["viewfinder-height-indexed"]);
// Case 1: document that is not a Golden Layout tab
if (srcContext) {
const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
if (srcDocView) {
- const layoutdoc = Doc.Layout(presTargetDoc);
+ const layoutdoc = Doc.Layout(targetDoc);
const panelWidth: number = srcDocView.props.PanelWidth();
const panelHeight: number = srcDocView.props.PanelHeight();
- const newPanX = NumCast(presTargetDoc.x) + NumCast(layoutdoc._width) / 2;
- const newPanY = NumCast(presTargetDoc.y) + NumCast(layoutdoc._height) / 2;
+ const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2;
+ const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2;
const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
srcContext._panX = newPanX + (vfLeft + (vfWidth / 2));
srcContext._panY = newPanY + (vfTop + (vfHeight / 2));
@@ -277,9 +298,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const panelWidth: number = docView.props.PanelWidth();
const panelHeight: number = docView.props.PanelHeight();
const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
- presTargetDoc._panX = vfLeft + (vfWidth / 2);
- presTargetDoc._panY = vfTop + (vfWidth / 2);
- presTargetDoc._viewScale = newScale;
+ targetDoc._panX = vfLeft + (vfWidth / 2);
+ targetDoc._panY = vfTop + (vfWidth / 2);
+ targetDoc._viewScale = newScale;
}
const resize = document.getElementById('resizable');
if (resize) {
@@ -299,7 +320,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
onHideDocument = () => {
this.childDocs.forEach((doc, index) => {
const curDoc = Cast(doc, Doc, null);
- const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+ const tagDoc = Cast(curDoc.presentationTargetDoc!, Doc, null);
if (tagDoc) tagDoc.opacity = 1;
if (curDoc.presHideTillShownButton) {
if (index > this.itemIndex) {
@@ -319,40 +340,58 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
+
//The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc
@undoBatch
@action
startAutoPres = (startSlide: number) => {
this.updateCurrentPresentation();
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ let activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ let targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ let duration = NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition);
+ const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
+ const load = async () => { // Wrap the loop into an async function for this to work
+ for (var i = startSlide; i < this.childDocs.length; i++) {
+ activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ duration = NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition);
+ if (duration <= 100) { duration = 2500; }
+ if (NumCast(targetDoc.lastFrame) > 0) {
+ for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) {
+ await timer(duration / NumCast(targetDoc.lastFrame));
+ this.next();
+ }
+ }
+ await timer(duration); this.next(); // then the created Promise can be awaited
+ if (i === this.childDocs.length - 1) setTimeout(() => { clearTimeout(this._presTimer); if (this.layoutDoc.presStatus === 'auto') this.layoutDoc.presStatus = "manual"; }, duration);
+ }
+ };
if (this.layoutDoc.presStatus === "auto") {
- if (this._presTimer) clearInterval(this._presTimer);
+ if (this._presTimer) clearTimeout(this._presTimer);
this.layoutDoc.presStatus = "manual";
} else {
this.layoutDoc.presStatus = "auto";
this.startPresentation(startSlide);
this.gotoDocument(startSlide, this.itemIndex);
- this._presTimer = setInterval(() => {
- if (this.itemIndex + 1 < this.childDocs.length) this.next();
- else {
- clearInterval(this._presTimer);
- this.layoutDoc.presStatus = "manual";
- }
- }, targetDoc.presDuration ? NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition) : 2000);
+ load();
}
}
//The function that resets the presentation by removing every action done by it. It also
//stops the presentaton.
- // TODO: Ensure resetPresentation is called when the presentation is closed
resetPresentation = () => {
this.updateCurrentPresentation();
this.rootDoc._itemIndex = 0;
}
@action togglePath = () => this.pathBoolean = !this.pathBoolean;
- @action toggleExpand = () => this.expandBoolean = !this.expandBoolean;
+ @action toggleExpandMode = () => {
+ this.rootDoc.expandBoolean = !this.rootDoc.expandBoolean;
+ this.childDocs.forEach((doc) => {
+ if (this.rootDoc.expandBoolean) doc.presExpandInlineButton = true;
+ else if (!this.rootDoc.expandBoolean) doc.presExpandInlineButton = false;
+ });
+ }
/**
* The function that starts the presentation at the given index, also checking if actions should be applied
@@ -376,17 +415,23 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
* The method called to open the presentation as a minimized view
* TODO: Look at old updateMinimize and compare...
*/
+ @undoBatch
+ @action
updateMinimize = () => {
- const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
- this.turnOffEdit();
- if (srcContext) {
- if (srcContext.miniPres) {
- srcContext.miniPres = false;
- CollectionDockingView.AddRightSplit(this.rootDoc);
- } else {
- srcContext.miniPres = true;
- this.props.addDocTab?.(this.rootDoc, "close");
- }
+ if (this.layoutDoc.inOverlay) {
+ this.layoutDoc.presStatus = 'edit';
+ Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
+ CollectionDockingView.AddRightSplit(this.rootDoc);
+ this.layoutDoc.inOverlay = false;
+ } else {
+ this.layoutDoc.presStatus = 'manual';
+ const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
+ this.rootDoc.y = pt[1] + 10;
+ this.rootDoc._height = 35;
+ this.rootDoc._width = 250;
+ this.props.addDocTab?.(this.rootDoc, "close");
+ Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
}
}
@@ -426,6 +471,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
break;
case 'jump': //Jump Cut
targetDoc.presTransition = 0;
+ activeItem.presZoomButton = true;
activeItem.presSwitchButton = !activeItem.presSwitchButton;
if (activeItem.presSwitchButton) activeItem.presMovement = 'Jump cut';
else activeItem.presMovement = 'None';
@@ -449,6 +495,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
} else {
doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
!this.childDocs.includes(doc) && (doc.presZoomButton = true);
+ if (this.rootDoc.expandBoolean) doc.presExpandInlineButton = true;
}
});
return true;
@@ -488,20 +535,28 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
return list;
}
+ @action
+ selectPres = () => {
+ const presDocView = DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc)!;
+ SelectionManager.SelectDoc(presDocView, false);
+ }
+
//Regular click
@action
selectElement = (doc: Doc) => {
this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex));
+ this.selectPres();
}
//Command click
@action
multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
if (!this._selectedArray.includes(doc)) {
- this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
+ this._selectedArray.push(doc);
this._eleArray.push(ref);
this._dragArray.push(drag);
}
+ this.selectPres();
}
//Shift click
@@ -516,17 +571,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this._dragArray.push(drag);
}
}
+ this.selectPres();
}
- // Key for when the presentaiton is active (according to Selection Manager)
+ // Key for when the presentaiton is active
@action
keyEvents = (e: KeyboardEvent) => {
let handled = false;
const anchorNode = document.activeElement as HTMLDivElement;
if (anchorNode && anchorNode.className?.includes("lm_title")) return;
if (e.keyCode === 27) { // Escape key
- if (this.layoutDoc.presStatus === "edit") this._selectedArray = [];
+ if (this.layoutDoc.inOverlay) { this.updateMinimize(); }
+ else if (this.layoutDoc.presStatus === "edit") { this._selectedArray = []; this._eleArray = []; this._dragArray = []; }
else this.layoutDoc.presStatus = "edit";
+ if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
} if ((e.metaKey || e.altKey) && e.keyCode === 65) { // Ctrl-A to select all
if (this.layoutDoc.presStatus === "edit") {
@@ -534,14 +592,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
handled = true;
}
} if (e.keyCode === 37 || e.keyCode === 38) { // left(37) / a(65) / up(38) to go back
- this.back();
+ this.back(); if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
} if (e.keyCode === 39 || e.keyCode === 40) { // right (39) / d(68) / down(40) to go to next
- this.next();
+ this.next(); if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
} if (e.keyCode === 32) { // spacebar to 'present' or autoplay
if (this.layoutDoc.presStatus !== "edit") this.startAutoPres(0);
- else this.layoutDoc.presStatus = "manual";
+ else this.layoutDoc.presStatus = "manual"; if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
}
if (e.keyCode === 8) { // delete selected items
@@ -565,23 +623,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@action
viewPaths = async () => {
const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
- if (this.pathBoolean) {
- if (srcContext) {
- this.togglePath();
- srcContext._fitToBox = false;
- srcContext._viewType = "freeform";
- srcContext.presPathView = false;
- }
- } else {
- if (srcContext) {
- this.togglePath();
- srcContext._fitToBox = true;
- srcContext._viewType = "freeform";
- srcContext.presPathView = true;
- }
+ if (this.pathBoolean && srcContext) {
+ this.togglePath();
+ srcContext.presPathView = false;
+ } else if (srcContext) {
+ this.togglePath();
+ srcContext.presPathView = true;
}
- const viewType = srcContext?._viewType;
- const fit = srcContext?._fitToBox;
}
// Adds the index in the pres path graphically
@@ -589,7 +637,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const order: JSX.Element[] = [];
this.childDocs.forEach((doc, index) => {
const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
- const srcContext = Cast(targetDoc.context, Doc, null);
+ const srcContext = Cast(targetDoc?.context, Doc, null);
// Case A: Document is contained within the colleciton
if (this.rootDoc.presCollection === srcContext) {
order.push(
@@ -619,7 +667,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
let pathPoints = "";
this.childDocs.forEach((doc, index) => {
const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
- const srcContext = Cast(targetDoc.context, Doc, null);
+ const srcContext = Cast(targetDoc?.context, Doc, null);
if (targetDoc && this.rootDoc.presCollection === srcContext) {
const n1x = NumCast(targetDoc.x) + (NumCast(targetDoc._width) / 2);
const n1y = NumCast(targetDoc.y) + (NumCast(targetDoc._height) / 2);
@@ -669,16 +717,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
// Converts seconds to ms and updates presTransition
- setTransitionTime = (number: String) => {
- const timeInMS = Number(number) * 1000;
+ setTransitionTime = (number: String, change?: number) => {
+ let timeInMS = Number(number) * 1000;
+ if (change) timeInMS += change;
+ if (timeInMS < 100) timeInMS = 100;
+ if (timeInMS > 10000) timeInMS = 10000;
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
if (targetDoc) targetDoc.presTransition = timeInMS;
}
// Converts seconds to ms and updates presDuration
- setDurationTime = (number: String) => {
- const timeInMS = Number(number) * 1000;
+ setDurationTime = (number: String, change?: number) => {
+ let timeInMS = Number(number) * 1000;
+ if (change) timeInMS += change;
+ if (timeInMS < 100) timeInMS = 100;
+ if (timeInMS > 20000) timeInMS = 20000;
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
if (targetDoc) targetDoc.presDuration = timeInMS;
@@ -689,19 +743,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
if (activeItem && targetDoc) {
- const transitionSpeed = targetDoc.presTransition ? String(Number(targetDoc.presTransition) / 1000) : 0.5;
- let duration = targetDoc.presDuration ? String(Number(targetDoc.presDuration) / 1000) : 2;
+ const transitionSpeed = targetDoc.presTransition ? NumCast(targetDoc.presTransition) / 1000 : 0.5;
+ let duration = targetDoc.presDuration ? NumCast(targetDoc.presDuration) / 1000 : 2;
if (targetDoc.type === DocumentType.AUDIO) duration = NumCast(targetDoc.duration);
const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
return (
- <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
<div className="ribbon-box">
Movement
- <div className="presBox-dropdown" onPointerDown={e => e.stopPropagation()}>
+ <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? 'solid 2px #5B9FDD' : 'solid 1px black' }}>
{activeItem.presMovement}
- <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} />
- <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onClick={e => e.stopPropagation()}>
+ <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
<div className={`presBox-dropdownOption ${activeItem.presMovement === 'None' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('none')}>None</div>
<div className={`presBox-dropdownOption ${activeItem.presMovement === 'Zoom' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('zoom')}>Pan and Zoom</div>
<div className={`presBox-dropdownOption ${activeItem.presMovement === 'Pan' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('pan')}>Pan</div>
@@ -709,8 +763,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
</div>
</div>
<div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === 'Pan' || activeItem.presMovement === 'Zoom' ? "inline-flex" : "none" }}>
- <div className="presBox-subheading" >Transition Speed</div>
- <div className="ribbon-property"> {transitionSpeed} s </div>
+ <div className="presBox-subheading">Transition Speed</div>
+ <div className="ribbon-property">
+ <input className="presBox-input"
+ type="number" value={transitionSpeed}
+ onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+ onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
+ </div>
+ <div className="ribbon-propertyUpDown">
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(transitionSpeed), 1000)}>
+ <FontAwesomeIcon icon={"caret-up"} />
+ </div>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(transitionSpeed), -1000)}>
+ <FontAwesomeIcon icon={"caret-down"} />
+ </div>
+ </div>
</div>
<input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed} className={`toolbar-slider ${activeItem.presMovement === 'Pan' || activeItem.presMovement === 'Zoom' ? "" : "none"}`} id="toolbar-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setTransitionTime(e.target.value); }} />
<div className={`slider-headers ${activeItem.presMovement === 'Pan' || activeItem.presMovement === 'Zoom' ? "" : "none"}`}>
@@ -727,9 +794,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
</div>
<div className="ribbon-doubleButton" >
<div className="presBox-subheading">Slide Duration</div>
- <div className="ribbon-property"> {duration} s </div>
+ <div className="ribbon-property">
+ <input className="presBox-input"
+ type="number" value={duration}
+ onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+ onChange={action((e) => this.setDurationTime(e.target.value))} /> s
+ </div>
+ <div className="ribbon-propertyUpDown">
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.setDurationTime(String(duration), 1000)}>
+ <FontAwesomeIcon icon={"caret-up"} />
+ </div>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.setDurationTime(String(duration), -1000)}>
+ <FontAwesomeIcon icon={"caret-down"} />
+ </div>
+ </div>
</div>
- <input type="range" step="0.1" min="0.1" max="10" value={duration} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }} className={"toolbar-slider"} id="duration-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }} />
+ <input type="range" step="0.1" min="0.1" max="20" value={duration} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "block" }} className={"toolbar-slider"} id="duration-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }} />
<div className={"slider-headers"} style={{ display: targetDoc.type === DocumentType.AUDIO ? "none" : "grid" }}>
<div className="slider-text">Short</div>
<div className="slider-text">Medium</div>
@@ -738,12 +818,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
</div>
<div className="ribbon-box">
Effects
- <div className="presBox-dropdown"
- onPointerDown={e => e.stopPropagation()}
- >
+ <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown; })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? 'solid 2px #5B9FDD' : 'solid 1px black' }}>
{effect}
- <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} />
- <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onClick={e => e.stopPropagation()}>
+ <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openEffectDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? "grid" : "none" }} onPointerDown={e => e.stopPropagation()}>
<div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'None'}>None</div>
<div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Fade'}>Fade In</div>
<div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Flip'}>Flip</div>
@@ -774,7 +852,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
Apply to all
</div>
</div>
- </div>
+ </div >
);
}
}
@@ -793,6 +871,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
return effect;
}
+ @undoBatch
+ @action
applyTo = (array: Doc[]) => {
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
@@ -803,12 +883,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
tagDoc.presTransition = targetDoc.presTransition;
tagDoc.presDuration = targetDoc.presDuration;
tagDoc.presEffect = targetDoc.presEffect;
+ tagDoc.presEffectDirection = targetDoc.presEffectDirection;
+ curDoc.presMovement = activeItem.presMovement;
+ curDoc.presHideTillShownButton = activeItem.presHideTillShownButton;
+ curDoc.presHideAfterButton = activeItem.presHideAfterButton;
}
});
}
-
- private inputRef = React.createRef<HTMLInputElement>();
-
@computed get optionsDropdown() {
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
@@ -838,9 +919,41 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
}}>Presentation pin view</div>
</div>
- <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}>
- <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div>
+ <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
+ <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+ <div className="presBox-subheading">Pan X</div>
+ <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+ <input className="presBox-input"
+ style={{ textAlign: 'left', width: 50 }}
+ type="number" value={NumCast(activeItem.presPinViewX)}
+ onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+ onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
+ </div>
+ </div>
+ <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+ <div className="presBox-subheading">Pan Y</div>
+ <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+ <input className="presBox-input"
+ style={{ textAlign: 'left', width: 50 }}
+ type="number" value={NumCast(activeItem.presPinViewY)}
+ onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+ onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
+ </div>
+ </div>
+ <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+ <div className="presBox-subheading">Scale</div>
+ <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+ <input className="presBox-input"
+ style={{ textAlign: 'left', width: 50 }}
+ type="number" value={NumCast(activeItem.presPinViewScale)}
+ onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }}
+ onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
+ </div>
+ </div>
</div>
+ {/* <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}>
+ <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div>
+ </div> */}
</div>
</div>
</div >
@@ -865,11 +978,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
<div className="title" style={{ alignSelf: 'center' }}>Title</div>
<div className="content">Text goes here</div>
</div>
- {/* <div className="layout" style={{ border: this.layout === 'twoColumns' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'twoColumns'; this.createNewSlide(this.layout); })}>
- <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>Title</div>
- <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>Column one text</div>
- <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>Column two text</div>
- </div> */}
</div>
</div>
</div >
@@ -884,13 +992,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@computed get newDocumentDropdown() {
return (
<div>
- <div className={"presBox-ribbon"} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className={"presBox-ribbon"} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div className="ribbon-box">
Slide Title: <br></br>
- <input className="ribbon-textInput" placeholder="..." type="text" name="fname" ref={this.inputRef} onChange={(e) => {
- e.stopPropagation();
- runInAction(() => this.title = e.target.value);
- }}></input>
+ <input className="ribbon-textInput" placeholder="..." type="text" name="fname"
+ onFocus={() => {
+ document.removeEventListener("keydown", this.keyEvents, true);
+ }}
+ onChange={(e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ runInAction(() => this.title = e.target.value);
+ }}></input>
</div>
<div className="ribbon-box">
Choose type:
@@ -1007,7 +1120,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
// Case in which the document has keyframes to navigate to next key frame
@undoBatch
@action
- nextKeyframe = (tagDoc: Doc): void => {
+ nextKeyframe = (tagDoc: Doc, activeItem: Doc): void => {
const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
const currentFrame = Cast(tagDoc.currentFrame, "number", null);
if (currentFrame === undefined) {
@@ -1016,23 +1129,23 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
}
CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
- CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
+ CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc);
tagDoc.currentFrame = Math.max(0, (currentFrame || 0) + 1);
tagDoc.lastFrame = Math.max(NumCast(tagDoc.currentFrame), NumCast(tagDoc.lastFrame));
- if (tagDoc.zoomProgressivize) {
+ if (activeItem.zoomProgressivize) {
const resize = document.getElementById('resizable');
if (resize) {
- resize.style.width = this.checkList(tagDoc, tagDoc["viewfinder-width-indexed"]) + 'px';
- resize.style.height = this.checkList(tagDoc, tagDoc["viewfinder-height-indexed"]) + 'px';
- resize.style.top = this.checkList(tagDoc, tagDoc["viewfinder-top-indexed"]) + 'px';
- resize.style.left = this.checkList(tagDoc, tagDoc["viewfinder-left-indexed"]) + 'px';
+ resize.style.width = this.checkList(tagDoc, activeItem["viewfinder-width-indexed"]) + 'px';
+ resize.style.height = this.checkList(tagDoc, activeItem["viewfinder-height-indexed"]) + 'px';
+ resize.style.top = this.checkList(tagDoc, activeItem["viewfinder-top-indexed"]) + 'px';
+ resize.style.left = this.checkList(tagDoc, activeItem["viewfinder-left-indexed"]) + 'px';
}
}
}
@undoBatch
@action
- prevKeyframe = (tagDoc: Doc): void => {
+ prevKeyframe = (tagDoc: Doc, activeItem: Doc): void => {
const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
const currentFrame = Cast(tagDoc.currentFrame, "number", null);
if (currentFrame === undefined) {
@@ -1041,13 +1154,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
tagDoc.currentFrame = Math.max(0, (currentFrame || 0) - 1);
- if (tagDoc.zoomProgressivize) {
+ if (activeItem.zoomProgressivize) {
const resize = document.getElementById('resizable');
if (resize) {
- resize.style.width = this.checkList(tagDoc, tagDoc["viewfinder-width-indexed"]) + 'px';
- resize.style.height = this.checkList(tagDoc, tagDoc["viewfinder-height-indexed"]) + 'px';
- resize.style.top = this.checkList(tagDoc, tagDoc["viewfinder-top-indexed"]) + 'px';
- resize.style.left = this.checkList(tagDoc, tagDoc["viewfinder-left-indexed"]) + 'px';
+ resize.style.width = this.checkList(tagDoc, activeItem["viewfinder-width-indexed"]) + 'px';
+ resize.style.height = this.checkList(tagDoc, activeItem["viewfinder-height-indexed"]) + 'px';
+ resize.style.top = this.checkList(tagDoc, activeItem["viewfinder-top-indexed"]) + 'px';
+ resize.style.left = this.checkList(tagDoc, activeItem["viewfinder-left-indexed"]) + 'px';
}
}
}
@@ -1067,58 +1180,72 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
case DocumentType.AUDIO: type = "Audio"; break;
case DocumentType.VID: type = "Video"; break;
case DocumentType.IMG: type = "Image"; break;
+ case DocumentType.WEB: type = "Web page"; break;
default: type = "Other node"; break;
}
}
return type;
}
+ @observable private openActiveColorPicker: boolean = false;
+ @observable private openViewedColorPicker: boolean = false;
+
+
+
@computed get progressivizeDropdown() {
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
-
+ const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black";
+ const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black";
if (activeItem && targetDoc) {
return (
<div>
<div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div className="ribbon-box">
{this.stringType} selected
- <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}>
- <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Child documents</div>
- <div className="ribbon-button" style={{ display: activeItem.presProgressivize ? "flex" : "none", backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div>
+ <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}>
+ <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Contents</div>
+ <div className="ribbon-button" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div>
</div>
- <div className="ribbon-doubleButton" style={{ display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
- <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Internal zoom</div>
- <div className="ribbon-button" style={{ display: activeItem.zoomProgressivize ? "flex" : "none", backgroundColor: targetDoc.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Viewfinder</div>
- {/* <div className="ribbon-button" style={{ display: activeItem.zoomProgressivize ? "flex" : "none", backgroundColor: targetDoc.editSnapZoomProgressivize ? "#aedef8" : "" }} onClick={this.editSnapZoomProgressivize}>Snapshot</div> */}
+ <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
+ <div className="presBox-subheading">Active text color</div>
+ <div className="ribbon-property" style={{ backgroundColor: activeFontColor }} onClick={action(() => { console.log("hi"); this.openActiveColorPicker = !this.openActiveColorPicker; })}>
+ </div>
+ </div>
+ {this.activeColorPicker}
+ <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
+ <div className="presBox-subheading">Viewed font color</div>
+ <div className="ribbon-property" style={{ backgroundColor: viewedFontColor }} onClick={action(() => this.openViewedColorPicker = !this.openViewedColorPicker)}>
+ </div>
</div>
- {/* <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}>
- <div className="ribbon-button" onClick={this.progressivizeText}>Text progressivize</div>
- <div className="ribbon-button" style={{ display: activeItem.textProgressivize ? "flex" : "none", backgroundColor: targetDoc.editTextProgressivize ? "#aedef8" : "" }} onClick={this.editTextProgressivize}>Edit</div>
+ {this.viewedColorPicker}
+ {/* <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
+ <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Zoom</div>
+ <div className="ribbon-button" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Edit</div>
</div> */}
- <div className="ribbon-doubleButton" style={{ display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
- <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll progressivize</div>
- <div className="ribbon-button" style={{ display: activeItem.scrollProgressivize ? "flex" : "none", backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div>
+ <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
+ <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll</div>
+ <div className="ribbon-button" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div>
</div>
</div>
<div className="ribbon-final-box" style={{ display: activeItem.zoomProgressivize || activeItem.scrollProgressivize || activeItem.presProgressivize || activeItem.textProgressivize ? "grid" : "none" }}>
Frames
<div className="ribbon-doubleButton">
<div className="ribbon-frameSelector">
- <div key="back" title="back frame" className="backKeyframe" onClick={e => { e.stopPropagation(); this.prevKeyframe(targetDoc); }}>
+ <div key="back" title="back frame" className="backKeyframe" onClick={e => { e.stopPropagation(); this.prevKeyframe(targetDoc, activeItem); }}>
<FontAwesomeIcon icon={"caret-left"} size={"lg"} />
</div>
- <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: targetDoc.editing ? "#5a9edd" : "#5a9edd" }}
+ <div key="num" title="toggle view all" className="numKeyframe" style={{ color: targetDoc.editing ? "white" : "black", backgroundColor: targetDoc.editing ? "#5B9FDD" : "#AEDDF8" }}
onClick={action(() => targetDoc.editing = !targetDoc.editing)} >
{NumCast(targetDoc.currentFrame)}
</div>
- <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={e => { e.stopPropagation(); this.nextKeyframe(targetDoc); }}>
+ <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={e => { e.stopPropagation(); this.nextKeyframe(targetDoc, activeItem); }}>
<FontAwesomeIcon icon={"caret-right"} size={"lg"} />
</div>
</div>
<Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div></Tooltip>
</div>
- <div className="ribbon-button" style={{ height: 20, backgroundColor: "#5a9edd" }} onClick={() => console.log(" TODO: play frames")}>Play</div>
+ <div className="ribbon-button" style={{ height: 20, backgroundColor: "#AEDDF8" }} onClick={() => console.log(" TODO: play frames")}>Play</div>
</div>
</div>
</div>
@@ -1126,43 +1253,70 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
}
+ @undoBatch
+ @action
+ switchActive = (color: ColorState) => {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ const val = String(color.hex);
+ targetDoc["pres-text-color"] = val;
+ return true;
+ }
+ @undoBatch
+ @action
+ switchPresented = (color: ColorState) => {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ const val = String(color.hex);
+ targetDoc["pres-text-viewed-color"] = val;
+ return true;
+ }
+
+ @computed get activeColorPicker() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ return !this.openActiveColorPicker ? (null) : <SketchPicker onChange={this.switchActive}
+ presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+ '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+ '#FFFFFF', '#f1efeb', 'transparent']}
+ color={StrCast(targetDoc["pres-text-color"])} />;
+ }
+
+ @computed get viewedColorPicker() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ return !this.openViewedColorPicker ? (null) : <SketchPicker onChange={this.switchPresented}
+ presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
+ '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
+ '#FFFFFF', '#f1efeb', 'transparent']}
+ color={StrCast(targetDoc["pres-text-viewed-color"])} />;
+ }
+
turnOffEdit = () => {
this.childDocs.forEach((doc) => {
doc.editSnapZoomProgressivize = false;
doc.editZoomProgressivize = false;
doc.editScrollProgressivize = false;
const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
- targetDoc.editSnapZoomProgressivize = false;
- targetDoc.editZoomProgressivize = false;
- targetDoc.editScrollProgressivize = false;
- if (doc.type === DocumentType.WEB) {
- doc.presWebsite = doc.data;
+ if (targetDoc) {
+ targetDoc.editZoomProgressivize = false;
+ targetDoc.editScrollProgressivize = false;
}
});
}
//Toggle whether the user edits or not
@action
- editSnapZoomProgressivize = (e: React.MouseEvent) => {
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
- if (!targetDoc.editSnapZoomProgressivize) {
- targetDoc.editSnapZoomProgressivize = true;
- } else {
- targetDoc.editSnapZoomProgressivize = false;
- }
-
- }
-
- //Toggle whether the user edits or not
- @action
editZoomProgressivize = (e: React.MouseEvent) => {
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
if (!targetDoc.editZoomProgressivize) {
+ if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; targetDoc.zoomProgressivize = true;
targetDoc.editZoomProgressivize = true;
+ activeItem.editZoomProgressivize = true;
} else {
targetDoc.editZoomProgressivize = false;
+ activeItem.editZoomProgressivize = false;
}
}
@@ -1172,6 +1326,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
if (!targetDoc.editScrollProgressivize) {
+ if (!targetDoc.scrollProgressivize) { targetDoc.scrollProgressivize = true; activeItem.scrollProgressivize = true; }
targetDoc.editScrollProgressivize = true;
} else {
targetDoc.editScrollProgressivize = false;
@@ -1185,7 +1340,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
activeItem.scrollProgressivize = !activeItem.scrollProgressivize;
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
- targetDoc.scrollProgressivize = !targetDoc.zoomProgressivize;
+ targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize;
CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc.currentFrame), true);
if (targetDoc.editScrollProgressivize) {
targetDoc.editScrollProgressivize = false;
@@ -1202,52 +1357,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
activeItem.zoomProgressivize = !activeItem.zoomProgressivize;
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize;
- CollectionFreeFormDocumentView.setupZoom(targetDoc, true);
- if (targetDoc.editZoomProgressivize) {
- targetDoc.editZoomProgressivize = false;
+ CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc, true);
+ if (activeItem.editZoomProgressivize) {
+ activeItem.editZoomProgressivize = false;
targetDoc.currentFrame = 0;
targetDoc.lastFrame = 0;
}
}
- //Progressivize Text nodes
- @action
- editTextProgressivize = (e: React.MouseEvent) => {
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
- targetDoc.currentFrame = targetDoc.lastFrame;
- if (targetDoc?.editTextProgressivize) {
- targetDoc.editTextProgressivize = false;
- } else {
- targetDoc.editTextProgressivize = true;
- }
- }
-
- @action
- progressivizeText = (e: React.MouseEvent) => {
- e.stopPropagation();
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- activeItem.presProgressivize = !activeItem.presProgressivize;
- const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
- const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
- targetDoc.presProgressivize = !targetDoc.presProgressivize;
- if (activeItem.presProgressivize) {
- targetDoc.currentFrame = 0;
- CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true);
- targetDoc.lastFrame = docs.length - 1;
- }
- }
-
//Progressivize Child Docs
@action
editProgressivize = (e: React.MouseEvent) => {
const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
targetDoc.currentFrame = targetDoc.lastFrame;
- if (targetDoc?.editProgressivize) {
- targetDoc.editProgressivize = false;
- } else {
+ if (!targetDoc.editProgressivize) {
+ if (!activeItem.presProgressivize) { activeItem.presProgressivize = true; targetDoc.presProgressivize = true; }
targetDoc.editProgressivize = true;
+ } else {
+ targetDoc.editProgressivize = false;
}
}
@@ -1258,6 +1386,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
if (!activeItem.presProgressivize) {
+ targetDoc.editing = false;
activeItem.presProgressivize = true;
targetDoc.presProgressivize = true;
targetDoc.currentFrame = 0;
@@ -1267,11 +1396,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
targetDoc.editProgressivize = false;
activeItem.presProgressivize = false;
targetDoc.presProgressivize = false;
- // docs.forEach((doc, index) => {
- // doc.appearFrame = 0;
- // });
targetDoc.currentFrame = 0;
targetDoc.lastFrame = 0;
+ targetDoc.editing = true;
}
}
@@ -1308,236 +1435,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
else doc.displayMovement = true;
}
- private _isDraggingTL = false;
- private _isDraggingTR = false;
- private _isDraggingBR = false;
- private _isDraggingBL = false;
- private _isDragging = false;
- // private _drag = "";
-
- // onPointerDown = (e: React.PointerEvent): void => {
- // e.stopPropagation();
- // e.preventDefault();
- // if (e.button === 0) {
- // this._drag = e.currentTarget.id;
- // console.log(this._drag);
- // }
- // document.removeEventListener("pointermove", this.onPointerMove);
- // document.addEventListener("pointermove", this.onPointerMove);
- // document.removeEventListener("pointerup", this.onPointerUp);
- // document.addEventListener("pointerup", this.onPointerUp);
- // }
-
-
- //Adds event listener so knows pointer is down and moving
- onPointerMid = (e: React.PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isDragging = true;
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- //Adds event listener so knows pointer is down and moving
- onPointerBR = (e: React.PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isDraggingBR = true;
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- //Adds event listener so knows pointer is down and moving
- onPointerBL = (e: React.PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isDraggingBL = true;
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- //Adds event listener so knows pointer is down and moving
- onPointerTR = (e: React.PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isDraggingTR = true;
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- //Adds event listener so knows pointer is down and moving
- onPointerTL = (e: React.PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isDraggingTL = true;
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- //Removes all event listeners
- onPointerUp = (e: PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isDraggingTL = false;
- this._isDraggingTR = false;
- this._isDraggingBL = false;
- this._isDraggingBR = false;
- this._isDragging = false;
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
-
- //Adjusts the value in NodeStore
- onPointerMove = (e: PointerEvent): void => {
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- const tagDocView = DocumentManager.Instance.getDocumentView(targetDoc);
- e.stopPropagation();
- e.preventDefault();
- const doc = document.getElementById('resizable');
- if (doc && tagDocView) {
-
- const scale2 = tagDocView.childScaling();
- const scale3 = tagDocView.props.ScreenToLocalTransform().Scale;
- const scale = NumCast(targetDoc._viewScale);
- console.log("scale: " + NumCast(targetDoc._viewScale));
- let height = doc.offsetHeight;
- let width = doc.offsetWidth;
- let top = doc.offsetTop;
- let left = doc.offsetLeft;
- // const newHeightB = height += (e.movementY * NumCast(targetDoc._viewScale));
- // const newHeightT = height -= (e.movementY * NumCast(targetDoc._viewScale));
- // const newWidthR = width += (e.movementX * NumCast(targetDoc._viewScale));
- // const newWidthL = width -= (e.movementX * NumCast(targetDoc._viewScale));
- // const newLeft = left += (e.movementX * NumCast(targetDoc._viewScale));
- // const newTop = top += (e.movementY * NumCast(targetDoc._viewScale));
- // switch (this._drag) {
- // case "": break;
- // case "resizer-br":
- // doc.style.height = newHeightB + 'px';
- // doc.style.width = newWidthR + 'px';
- // break;
- // case "resizer-bl":
- // doc.style.height = newHeightB + 'px';
- // doc.style.width = newWidthL + 'px';
- // doc.style.left = newLeft + 'px';
- // break;
- // case "resizer-tr":
- // doc.style.width = newWidthR + 'px';
- // doc.style.height = newHeightT + 'px';
- // doc.style.top = newTop + 'px';
- // case "resizer-tl":
- // doc.style.width = newWidthL + 'px';
- // doc.style.height = newHeightT + 'px';
- // doc.style.top = newTop + 'px';
- // doc.style.left = newLeft + 'px';
- // case "resizable":
- // doc.style.top = newTop + 'px';
- // doc.style.left = newLeft + 'px';
- // }
- //Bottom right
- if (this._isDraggingBR) {
- const newHeight = height += (e.movementY * scale);
- doc.style.height = newHeight + 'px';
- const newWidth = width += (e.movementX * scale);
- doc.style.width = newWidth + 'px';
- // Bottom left
- } else if (this._isDraggingBL) {
- const newHeight = height += (e.movementY * scale);
- doc.style.height = newHeight + 'px';
- const newWidth = width -= (e.movementX * scale);
- doc.style.width = newWidth + 'px';
- const newLeft = left += (e.movementX * scale);
- doc.style.left = newLeft + 'px';
- // Top right
- } else if (this._isDraggingTR) {
- const newWidth = width += (e.movementX * scale);
- doc.style.width = newWidth + 'px';
- const newHeight = height -= (e.movementY * scale);
- doc.style.height = newHeight + 'px';
- const newTop = top += (e.movementY * scale);
- doc.style.top = newTop + 'px';
- // Top left
- } else if (this._isDraggingTL) {
- const newWidth = width -= (e.movementX * scale);
- doc.style.width = newWidth + 'px';
- const newHeight = height -= (e.movementY * scale);
- doc.style.height = newHeight + 'px';
- const newTop = top += (e.movementY * scale);
- doc.style.top = newTop + 'px';
- const newLeft = left += (e.movementX * scale);
- doc.style.left = newLeft + 'px';
- } else if (this._isDragging) {
- const newTop = top += (e.movementY * scale);
- doc.style.top = newTop + 'px';
- const newLeft = left += (e.movementX * scale);
- doc.style.left = newLeft + 'px';
- }
- this.updateList(targetDoc, targetDoc["viewfinder-width-indexed"], width);
- this.updateList(targetDoc, targetDoc["viewfinder-height-indexed"], height);
- this.updateList(targetDoc, targetDoc["viewfinder-top-indexed"], top);
- this.updateList(targetDoc, targetDoc["viewfinder-left-indexed"], left);
- }
- }
-
@action
checkList = (doc: Doc, list: any): number => {
const x: List<number> = list;
if (x && x.length >= NumCast(doc.currentFrame) + 1) {
return x[NumCast(doc.currentFrame)];
- } else {
+ } else if (x) {
x.length = NumCast(doc.currentFrame) + 1;
x[NumCast(doc.currentFrame)] = x[NumCast(doc.currentFrame) - 1];
return x[NumCast(doc.currentFrame)];
- }
-
- }
-
- @action
- updateList = (doc: Doc, list: any, val: number) => {
- const x: List<number> = list;
- if (x && x.length >= NumCast(doc.currentFrame) + 1) {
- x[NumCast(doc.currentFrame)] = val;
- list = x;
- } else {
- x.length = NumCast(doc.currentFrame) + 1;
- x[NumCast(doc.currentFrame)] = val;
- list = x;
- }
- }
-
- // scale: NumCast(targetDoc._viewScale),
- @computed get zoomProgressivizeContainer() {
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- if (targetDoc) {
- const vfLeft: number = this.checkList(targetDoc, targetDoc["viewfinder-left-indexed"]);
- const vfWidth: number = this.checkList(targetDoc, targetDoc["viewfinder-width-indexed"]);
- const vfTop: number = this.checkList(targetDoc, targetDoc["viewfinder-top-indexed"]);
- const vfHeight: number = this.checkList(targetDoc, targetDoc["viewfinder-height-indexed"]);
- return (
- <>
- {!targetDoc.editZoomProgressivize ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerMid} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}>
- <div className='resizers'>
- <div id="resizer-tl" className='resizer top-left' onPointerDown={this.onPointerTL}></div>
- <div id="resizer-tr" className='resizer top-right' onPointerDown={this.onPointerTR}></div>
- <div id="resizer-bl" className='resizer bottom-left' onPointerDown={this.onPointerBL}></div>
- <div id="resizer-br" className='resizer bottom-right' onPointerDown={this.onPointerBR}></div>
- </div>
- </div>}
- </>
- );
- }
+ } else return 100;
}
@computed get progressivizeChildDocs() {
@@ -1620,8 +1527,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
return width;
}
+ @action
+ toggleProperties = () => {
+ if (CurrentUserUtils.propertiesWidth > 0) {
+ CurrentUserUtils.propertiesWidth = 0;
+ } else {
+ CurrentUserUtils.propertiesWidth = 250;
+ }
+ }
+
@computed get toolbar() {
- const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left";
+ const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel";
return (
<div id="toolbarContainer" className={'presBox-toolbar'} style={{ display: this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }}>
<Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
@@ -1634,12 +1551,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
<FontAwesomeIcon icon={"exchange-alt"} />
</div>
</Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{this.expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
- <div style={{ opacity: this.childDocs.length > 0 ? 1 : 0.3 }} className={`toolbar-button ${this.expandBoolean ? "active" : ""}`} onClick={() => { if (this.childDocs.length > 0) this.toggleExpand(); this.childDocs.forEach((doc, ind) => { if (this.expandBoolean) doc.presExpandInlineButton = true; else doc.presExpandInlineButton = false; }); }}>
+ <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
+ <div className={`toolbar-button ${this.rootDoc.expandBoolean ? "active" : ""}`} onClick={this.toggleExpandMode}>
<FontAwesomeIcon icon={"eye"} />
</div>
</Tooltip>
<div className="toolbar-divider" />
+ <Tooltip title={<><div className="dash-tooltip">{propTitle}</div></>}>
+ <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
+ <FontAwesomeIcon className={"toolbar-thumbtack"} icon={propIcon} style={{ color: CurrentUserUtils.propertiesWidth > 0 ? '#AEDDF8' : 'white' }} />
+ </div>
+ </Tooltip>
</div>
);
}
@@ -1697,18 +1619,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@computed get playButtons() {
// Case 1: There are still other frames and should go through all frames before going to next slide
- return (<div className="miniPresOverlay" style={{ display: this.layoutDoc.presStatus !== "edit" ? "inline-flex" : "none" }}>
- <div className="miniPres-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
- <div className="miniPres-button" onClick={() => this.startAutoPres(this.itemIndex)}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
- <div className="miniPres-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
- <div className="miniPres-divider"></div>
- <div className="miniPres-button-text" style={{ display: this.props.PanelWidth() > 250 ? "inline-flex" : "none" }}>
+ return (<div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== "edit" ? "inline-flex" : "none" }}>
+ <div className="presPanel-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
+ <div className="presPanel-button" onClick={() => this.startAutoPres(this.itemIndex)}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
+ <div className="presPanel-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
+ <div className="presPanel-divider"></div>
+ <div className="presPanel-button-text" style={{ display: this.props.PanelWidth() > 250 ? "inline-flex" : "none" }}>
Slide {this.itemIndex + 1} / {this.childDocs.length}
{this.playButtonFrames}
</div>
- <div className="miniPres-divider"></div>
- {this.props.PanelWidth() > 250 ? <div className="miniPres-button-text" onClick={() => this.layoutDoc.presStatus = "edit"}>EXIT</div>
- : <div className="miniPres-button" onClick={() => this.layoutDoc.presStatus = "edit"}>
+ <div className="presPanel-divider"></div>
+ {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={() => this.layoutDoc.presStatus = "edit"}>EXIT</div>
+ : <div className="presPanel-button" onClick={() => this.layoutDoc.presStatus = "edit"}>
<FontAwesomeIcon icon={"times"} />
</div>}
</div>);
@@ -1720,28 +1642,44 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
// needed to ensure that the childDocs are loaded for looking up fields
this.childDocs.slice();
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
- return <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} >
- {this.topPanel}
- {this.toolbar}
- {this.newDocumentToolbarDropdown}
- <div className="presBox-listCont">
- {mode !== CollectionViewType.Invalid ?
- <CollectionView {...this.props}
- ContainingCollectionDoc={this.props.Document}
- PanelWidth={this.props.PanelWidth}
- PanelHeight={this.panelHeight}
- moveDocument={returnFalse}
- childOpacity={returnOne}
- childLayoutTemplate={this.childLayoutTemplate}
- filterAddDocument={this.addDocumentFilter}
- removeDocument={returnFalse}
- dontRegisterView={true}
- focus={this.selectElement}
- ScreenToLocalTransform={this.getTransform} />
- : (null)
- }
+ return this.layoutDoc.inOverlay ?
+ <div className="miniPres" style={{ width: 250, height: 35, background: '#323232', top: 0, zIndex: 3000000 }}>
+ {<div className="miniPresOverlay">
+ <div className="miniPres-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
+ <div className="miniPres-button" onClick={() => this.startAutoPres(this.itemIndex)}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
+ <div className="miniPres-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
+ <div className="miniPres-divider"></div>
+ <div className="miniPres-button-text">
+ Slide {this.itemIndex + 1} / {this.childDocs.length}
+ {this.playButtonFrames}
+ </div>
+ <div className="miniPres-divider"></div>
+ <div className="miniPres-button-text" onClick={this.updateMinimize}>EXIT</div>
+ </div>}
</div>
- </div>;
+ :
+ <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} >
+ {this.topPanel}
+ {this.toolbar}
+ {this.newDocumentToolbarDropdown}
+ <div className="presBox-listCont">
+ {mode !== CollectionViewType.Invalid ?
+ <CollectionView {...this.props}
+ ContainingCollectionDoc={this.props.Document}
+ PanelWidth={this.props.PanelWidth}
+ PanelHeight={this.panelHeight}
+ moveDocument={returnFalse}
+ childOpacity={returnOne}
+ childLayoutTemplate={this.childLayoutTemplate}
+ filterAddDocument={this.addDocumentFilter}
+ removeDocument={returnFalse}
+ dontRegisterView={true}
+ focus={this.selectElement}
+ ScreenToLocalTransform={this.getTransform} />
+ : (null)
+ }
+ </div>
+ </div>;
}
}
Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 3283f568a..1393e7868 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
import { observer } from "mobx-react";
import { Dictionary } from "typescript-collections";
import * as WebRequest from 'web-request';
-import { Doc, DocListCast, Opt, AclAddonly, AclEdit, AclAdmin } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt, AclAddonly, AclEdit, AclAdmin, DataSym } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { HtmlField } from "../../../fields/HtmlField";
@@ -454,9 +454,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
view = <span className="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />;
} else if (field instanceof WebField) {
const url = this.layoutDoc.UseCors ? Utils.CorsProxy(field.url.href) : field.url.href;
- view = <iframe className="webBox-iframe" enable-annotation={true} ref={this._iframeRef} src={url} onLoad={this.iframeLoaded} />;
+ view = <iframe className="webBox-iframe" enable-annotation={"true"} ref={this._iframeRef} src={url} onLoad={this.iframeLoaded}
+ // the 'allow-top-navigation' and 'allow-top-navigation-by-user-activation' attributes are left out to prevent iframes from redirecting the top-level Dash page
+ sandbox={"allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts"} />;
} else {
- view = <iframe className="webBox-iframe" enable-annotation={true} ref={this._iframeRef} src={"https://crossorigin.me/https://cs.brown.edu"} />;
+ view = <iframe className="webBox-iframe" enable-annotation={"true"} ref={this._iframeRef} src={"https://crossorigin.me/https://cs.brown.edu"} />;
}
return view;
}
@@ -535,7 +537,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
@action
highlight = (color: string) => {
// creates annotation documents for current highlights
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) ? this.makeAnnotationDocument(color) : undefined;
annotationDoc && this.addDocument?.(annotationDoc);
return annotationDoc ?? undefined;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 20d9a4fe5..2ded33346 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -23,7 +23,7 @@ import { PrefetchProxy } from '../../../../fields/Proxy';
import { RichTextField } from "../../../../fields/RichTextField";
import { RichTextUtils } from '../../../../fields/RichTextUtils';
import { createSchema, makeInterface } from "../../../../fields/Schema";
-import { Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../fields/Types";
+import { Cast, DateCast, NumCast, StrCast, ScriptCast, BoolCast } from "../../../../fields/Types";
import { TraceMobx, OVERRIDE_ACL, GetEffectiveAcl } from '../../../../fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils';
import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
@@ -377,6 +377,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
public highlightSearchTerms = (terms: string[], alt: boolean) => {
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);
const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
@@ -384,30 +385,31 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
let 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);
- flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
- this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
- this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
- if (alt === true) {
- if (this._searchIndex > 1) {
- this._searchIndex += -2;
- }
- else if (this._searchIndex === 1) {
- this._searchIndex = length - 1;
- }
- else if (this._searchIndex === 0 && length !== 1) {
- this._searchIndex = length - 2;
- }
-
+ if (BoolCast(Doc.GetProto(this.dataDoc).resetSearch) === true) {
+ this._searchIndex = 0;
+ Doc.GetProto(this.dataDoc).resetSearch = undefined;
}
else {
+ this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+ if (alt === true) {
+ if (this._searchIndex > 1) {
+ this._searchIndex += -2;
+ }
+ else if (this._searchIndex === 1) {
+ this._searchIndex = length - 1;
+ }
+ else if (this._searchIndex === 0 && length !== 1) {
+ this._searchIndex = length - 2;
+ }
+ }
}
- const index = this._searchIndex;
- Doc.GetProto(this.dataDoc).searchIndex = index;
+ const lastSel = Math.min(flattened.length - 1, this._searchIndex);
+ flattened.forEach((h: TextSelection, ind: number) => tr = tr.addMark(h.from, h.to, ind === lastSel ? activeMark : mark));
+ flattened[lastSel] && this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(flattened[lastSel].from), tr.doc.resolve(flattened[lastSel].to))).scrollIntoView());
+
+ console.log(this._searchIndex);
}
}
@@ -647,7 +649,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const options = cm.findByDescription("Options...");
const optionItems = options && "subitems" in options ? options.subitems : [];
- !Doc.UserDoc().noviceMode && optionItems.push({ description: this.Document._singleLine ? "Make Single Line" : "Make Multi Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
+ !Doc.UserDoc().noviceMode && optionItems.push({ description: !this.Document._singleLine ? "Make Single Line" : "Make Multi Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
optionItems.push({ description: `${this.Document._autoHeight ? "Lock" : "Auto"} Height`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
optionItems.push({ description: `${!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Lock" : "Unlock"} Aspect`, event: this.toggleNativeDimensions, icon: "snowflake" });
!options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
@@ -1579,6 +1581,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
onScroll={this.onscrolled} onDrop={this.ondrop} >
<div className={`formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
style={{
+ overflow: this.layoutDoc._singleLine ? "hidden" : undefined,
padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) : `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
pointerEvents: !this.props.active() ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : undefined) : undefined
}}
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 459632ec8..b683fb25d 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -163,11 +163,14 @@ export default class RichTextMenu extends AntimodeMenu {
}
update(view: EditorView, lastState: EditorState | undefined) {
- this.updateFromDash(view, lastState, this.editorProps);
+ RichTextMenu.Instance.updateFromDash(view, lastState, this.editorProps);
}
@action
public async updateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) {
+ RichTextMenu.Instance.finalUpdateFromDash(view, lastState, props);
+ }
+ public async finalUpdateFromDash(view: EditorView, lastState: EditorState | undefined, props: any) {
if (!view || !(view as any).TextView?.props.isSelected(true)) {
return;
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index cfa9a1844..f9ae78778 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -4,7 +4,7 @@ const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
import * as Pdfjs from "pdfjs-dist";
import "pdfjs-dist/web/pdf_viewer.css";
import { Dictionary } from "typescript-collections";
-import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym, AclAddonly, AclEdit, AclAdmin } from "../../../fields/Doc";
+import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym, AclAddonly, AclEdit, AclAdmin, DataSym } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { InkTool } from "../../../fields/InkField";
@@ -337,7 +337,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
nextAnnotation = () => {
this.Index = Math.min(this.Index + 1, this.allAnnotations.length - 1);
this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
- this.Document.searchIndex = this.Index;
}
@@ -400,10 +399,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@action
search = (searchString: string, fwd: boolean, clear: boolean = false) => {
if (clear) {
- this._pdfViewer.findController.executeCommand('reset', { query: "" });
+ this._pdfViewer?.findController.executeCommand('reset', { query: "" });
} else if (!searchString) {
fwd ? this.nextAnnotation() : this.prevAnnotation();
- } else if (this._pdfViewer.pageViewsReady) {
+ } else if (this._pdfViewer?.pageViewsReady) {
this._pdfViewer.findController.executeCommand('findagain', {
caseSensitive: false,
findPrevious: !fwd,
@@ -411,7 +410,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
phraseSearch: true,
query: searchString
});
- this.Document.searchIndex = this.Index;
}
else if (this._mainCont.current) {
const executeFind = () => {
@@ -425,7 +423,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
};
this._mainCont.current.addEventListener("pagesloaded", executeFind);
this._mainCont.current.addEventListener("pagerendered", executeFind);
- this.Document.searchIndex = this.Index;
}
}
@@ -576,7 +573,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@action
highlight = (color: string) => {
// creates annotation documents for current highlights
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color);
annotationDoc && this.addDocument?.(annotationDoc);
return annotationDoc as Doc ?? undefined;
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index 1e776384a..6ee190b82 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -3,6 +3,7 @@ $dark-blue: #5B9FDD;
$light-background: #ececec;
.presElementBox-item {
+ cursor: grab;
display: grid;
grid-template-columns: max-content max-content max-content max-content;
background-color: #d5dce2;
@@ -161,6 +162,7 @@ $light-background: #ececec;
}
.presElementBox-closeIcon {
+ cursor: pointer;
position: absolute;
border-radius: 100%;
z-index: 300;
@@ -177,6 +179,7 @@ $light-background: #ececec;
}
.presElementBox-expand {
+ cursor: pointer;
position: absolute;
border-radius: 100%;
z-index: 300;
@@ -193,6 +196,7 @@ $light-background: #ececec;
}
.presElementBox-expand-selected {
+ cursor: pointer;
position: absolute;
border-radius: 100%;
right: 3px;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index a6dbb76ef..a25a8ee33 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -19,6 +19,7 @@ import { PresBox } from "../nodes/PresBox";
import { DocumentType } from "../../documents/DocumentTypes";
import { Tooltip } from "@material-ui/core";
import { DragManager } from "../../util/DragManager";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
export const presSchema = createSchema({
presentationTargetDoc: Doc,
@@ -59,111 +60,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
}
/**
- * The function that is called on click to turn Hiding document till press option on/off.
- * It also sets the beginning and end opacitys.
- */
- @action
- onHideDocumentUntilPressClick = (e: React.MouseEvent) => {
- e.stopPropagation();
- this.rootDoc.presHideTillShownButton = !this.rootDoc.presHideTillShownButton;
- if (!this.rootDoc.presHideTillShownButton) {
- if (this.indexInPres >= this.itemIndex && this.targetDoc) {
- this.targetDoc.opacity = 1;
- }
- } else {
- if (this.presStatus !== "edit" && this.indexInPres > this.itemIndex && this.targetDoc) {
- this.targetDoc.opacity = 0;
- }
- }
- }
-
- /**
- * The function that is called on click to turn Hiding document after presented option on/off.
- * It also makes sure that the option swithches from fade-after to this one, since both
- * can't coexist.
- */
- @action
- onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => {
- e.stopPropagation();
- this.rootDoc.presHideAfterButton = !this.rootDoc.presHideAfterButton;
- if (!this.rootDoc.presHideAfterButton) {
- if (this.indexInPres <= this.itemIndex && this.targetDoc) {
- this.targetDoc.opacity = 1;
- }
- } else {
- if (this.rootDoc.presFadeButton) this.rootDoc.presFadeButton = false;
- if (this.presStatus !== "edit" && this.indexInPres < this.itemIndex && this.targetDoc) {
- this.targetDoc.opacity = 0;
- }
- }
- }
-
- @action
- progressivize = (e: React.MouseEvent) => {
- e.stopPropagation();
- this.rootDoc.presProgressivize = !this.rootDoc.presProgressivize;
- const rootTarget = Cast(this.rootDoc.presentationTargetDoc, Doc, null);
- const docs = rootTarget.type === DocumentType.COL ? DocListCast(rootTarget[Doc.LayoutFieldKey(rootTarget)]) :
- DocListCast(rootTarget[Doc.LayoutFieldKey(rootTarget) + "-annotations"]);
- if (this.rootDoc.presProgressivize) {
- rootTarget.currentFrame = 0;
- CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true);
- rootTarget.lastFrame = docs.length - 1;
- }
- }
-
- /**
- * The function that is called on click to turn fading document after presented option on/off.
- * It also makes sure that the option swithches from hide-after to this one, since both
- * can't coexist.
- */
- @action
- onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => {
- e.stopPropagation();
- this.rootDoc.presFadeButton = !this.rootDoc.presFadeButton;
- if (!this.rootDoc.presFadeButton) {
- if (this.indexInPres <= this.itemIndex && this.targetDoc) {
- this.targetDoc.opacity = 1;
- }
- } else {
- this.rootDoc.presHideAfterButton = false;
- if (this.presStatus !== "edit" && (this.indexInPres < this.itemIndex) && this.targetDoc) {
- this.targetDoc.opacity = 0.5;
- }
- }
- }
-
- /**
- * The function that is called on click to turn navigation option of docs on/off.
- */
- @action
- onNavigateDocumentClick = (e: React.MouseEvent) => {
- e.stopPropagation();
- this.rootDoc.presNavButton = !this.rootDoc.presNavButton;
- if (this.rootDoc.presNavButton) {
- this.rootDoc.presZoomButton = false;
- if (this.itemIndex === this.indexInPres) {
- this.props.focus(this.rootDoc);
- }
- }
- }
-
- /**
- * The function that is called on click to turn zoom option of docs on/off.
- */
- @action
- onZoomDocumentClick = (e: React.MouseEvent) => {
- e.stopPropagation();
-
- this.rootDoc.presZoomButton = !this.rootDoc.presZoomButton;
- if (this.rootDoc.presZoomButton) {
- this.rootDoc.presNavButton = false;
- if (this.itemIndex === this.indexInPres) {
- this.props.focus(this.rootDoc);
- }
- }
- }
- /**
* Returns a local transformed coordinate array for given coordinates.
*/
ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
@@ -233,12 +129,21 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+ @action
headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
- const element = document.elementFromPoint(e.clientX, e.clientY)?.parentElement;
+ const element = e.target as any;
e.stopPropagation();
e.preventDefault();
- if (element) {
- if (PresBox.Instance._eleArray.includes(element)) {
+ if (element && !(e.ctrlKey || e.metaKey)) {
+ if (PresBox.Instance._eleArray.includes(this._itemRef.current!)) {
+ setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+ } else {
+ PresBox.Instance._selectedArray = [];
+ PresBox.Instance._selectedArray.push(this.rootDoc);
+ PresBox.Instance._eleArray = [];
+ PresBox.Instance._eleArray.push(this._itemRef.current!);
+ PresBox.Instance._dragArray = [];
+ PresBox.Instance._dragArray.push(this._dragRef.current!);
setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
}
}
@@ -293,8 +198,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
}
}
+ @action
+ toggleProperties = () => {
+ if (CurrentUserUtils.propertiesWidth === 0) {
+ CurrentUserUtils.propertiesWidth = 250;
+ }
+ }
+
render() {
- const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree;
const className = "presElementBox-item" + (PresBox.Instance._selectedArray.includes(this.rootDoc) ? " presElementBox-active" : "");
const pbi = "presElementBox-interaction";
return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : (
@@ -319,6 +230,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
PresBox.Instance._dragArray.push(this._dragRef.current!);
}
}}
+ onDoubleClick={e => {
+ this.toggleProperties();
+ this.props.focus(this.rootDoc);
+ PresBox.Instance._eleArray = [];
+ PresBox.Instance._eleArray.push(this._itemRef.current!);
+ PresBox.Instance._dragArray = [];
+ PresBox.Instance._dragArray.push(this._dragRef.current!);
+ }}
onPointerDown={this.headerDown}
onPointerUp={this.headerUp}
>
@@ -347,14 +266,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
<div ref={this._highlightTopRef} onPointerOver={this.onPointerTop} onPointerLeave={this.onPointerLeave} className="presElementBox-highlightTop" style={{ zIndex: 299, backgroundColor: "rgba(0,0,0,0)" }} />
<div ref={this._highlightBottomRef} onPointerOver={this.onPointerBottom} onPointerLeave={this.onPointerLeave} className="presElementBox-highlightBottom" style={{ zIndex: 299, backgroundColor: "rgba(0,0,0,0)" }} />
<div className="presElementBox-highlight" style={{ backgroundColor: PresBox.Instance._selectedArray.includes(this.rootDoc) ? "#AEDDF8" : "rgba(0,0,0,0)" }} />
- <div className="presElementBox-buttons" style={{ display: this.rootDoc.presExpandInlineButton ? "grid" : "none" }}>
- <button title="Zoom" className={pbi + (this.rootDoc.presZoomButton ? "-selected" : "")} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Navigate" className={pbi + (this.rootDoc.presNavButton ? "-selected" : "")} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Hide Before" className={pbi + (this.rootDoc.presHideTillShownButton ? "-selected" : "")} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={"file"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Hide After" className={pbi + (this.rootDoc.presHideAfterButton ? "-selected" : "")} onClick={this.onHideDocumentAfterPresentedClick}><FontAwesomeIcon icon={"file-download"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Progressivize" className={pbi + (this.rootDoc.presProgressivize ? "-selected" : "")} onClick={this.progressivize}><FontAwesomeIcon icon={"tasks"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Effect" className={pbi + (this.rootDoc.presEffect ? "-selected" : "")}>E</button>
- </div>
{this.renderEmbeddedInline}
</div>
);
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 25fc8ff0b..770a03cb1 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from '@material-ui/core';
-import { action, computed, observable, runInAction } from 'mobx';
+import { action, computed, observable, runInAction, reaction, IReactionDisposer } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import * as rp from 'request-promise';
@@ -54,6 +54,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@observable private _visibleElements: JSX.Element[] = [];
@observable private _visibleDocuments: Doc[] = [];
+ static NUM_SEARCH_RESULTS_PER_PAGE = 25;
+
private _resultsSet = new Map<Doc, number>();
private _resultsRef = React.createRef<HTMLDivElement>();
public inputRef = React.createRef<HTMLInputElement>();
@@ -86,7 +88,19 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
@observable setupButtons = false;
+ private _disposers: { [name: string]: IReactionDisposer } = {};
+
componentDidMount = () => {
+ this._disposers.filters = reaction(() => Cast(this.props.Document._docFilters, listSpec("string")), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks
+ newFilters => {
+ if (this.searchFullDB) {
+ runInAction(() => this._pageStart = 0);
+ this.submitSearch();
+ // newFilters?.forEach(f => {
+ // console.log(f);
+ // })
+ }
+ });
if (this.setupButtons === false) {
runInAction(() => this.setupButtons = true);
@@ -113,6 +127,10 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
}
+ componentWillUnmount() {
+ Object.values(this._disposers).forEach(disposer => disposer?.());
+ }
+
@action
getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc)
@@ -123,15 +141,35 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
onChange(e: React.ChangeEvent<HTMLInputElement>) {
this.layoutDoc._searchString = e.target.value;
this.newsearchstring = e.target.value;
-
-
if (e.target.value === "") {
+ if (this.currentSelectedCollection !== undefined) {
+ let newarray: Doc[] = [];
+ let docs: Doc[] = [];
+ docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+ while (docs.length > 0) {
+ newarray = [];
+ docs.forEach((d) => {
+ if (d.data !== undefined) {
+ d._searchDocs = new List<Doc>();
+ d._docFilters = new List();
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ });
+ docs = newarray;
+ }
+
+ this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
+ this.currentSelectedCollection.props.Document._docFilters = new List();
+ this.props.Document.selectedDoc = undefined;
+ }
this._results.forEach(result => {
Doc.UnBrushDoc(result[0]);
result[0].searchMatch = undefined;
});
- this.props.Document._schemaHeaders = new List<SchemaHeaderField>([]);
if (this.currentSelectedCollection !== undefined) {
this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
this.currentSelectedCollection = undefined;
@@ -153,6 +191,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
enter = (e: React.KeyboardEvent) => {
if (e.key === "Enter") {
this.layoutDoc._searchString = this.newsearchstring;
+ runInAction(() => this._pageStart = 0);
if (StrCast(this.layoutDoc._searchString) !== "" || !this.searchFullDB) {
runInAction(() => this.open = true);
@@ -185,7 +224,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
}
- public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB];
+ public _allIcons: string[] = [DocumentType.INK, 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;
@@ -205,26 +244,100 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
getFinalQuery(query: string): string {
//alters the query so it looks in the correct fields
- //if this is true, then not all of the field boxes are checked
+ //if this is true, th`en not all of the field boxes are checked
//TODO: data
- if (this.fieldFiltersApplied) {
- query = this.applyBasicFieldFilters(query);
- query = query.replace(/\s+/g, ' ').trim();
+ const initialfilters = Cast(this.props.Document._docFilters, listSpec("string"), []);
+
+ const type: string[] = [];
+
+ const filters: string[] = [];
+
+ for (let i = 0; i < initialfilters.length; i = i + 3) {
+ if (initialfilters[i + 2] !== undefined) {
+ filters.push(initialfilters[i]);
+ filters.push(initialfilters[i + 1]);
+ filters.push(initialfilters[i + 2]);
+ }
}
- //alters the query based on if all words or any words are required
- //if this._wordstatus is false, all words are required and a + is added before each
- if (!this._basicWordStatus) {
- query = this.basicRequireWords(query);
- query = query.replace(/\s+/g, ' ').trim();
+ const finalfilters: { [key: string]: string[] } = {};
+
+ for (let i = 0; i < filters.length; i = i + 3) {
+ if (finalfilters[filters[i]] !== undefined) {
+ finalfilters[filters[i]].push(filters[i + 1]);
+ }
+ else {
+ finalfilters[filters[i]] = [filters[i + 1]];
+ }
}
- // if should be searched in a specific collection
- if (this._collectionStatus) {
- query = this.addCollectionFilter(query);
- query = query.replace(/\s+/g, ' ').trim();
+ for (const key in finalfilters) {
+ const values = finalfilters[key];
+ if (values.length === 1) {
+ const mod = "_t:";
+ const newWords: string[] = [];
+ const oldWords = values[0].split(" ");
+ oldWords.forEach((word, i) => {
+ i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"");
+ });
+ query = `(${query}) AND (${newWords.join(" ")})`;
+ }
+ else {
+ for (let i = 0; i < values.length; i++) {
+ const mod = "_t:";
+ const newWords: string[] = [];
+ const oldWords = values[i].split(" ");
+ oldWords.forEach((word, i) => {
+ i === 0 ? newWords.push(key + mod + "\"" + word + "\"") : newWords.push("AND " + key + mod + "\"" + word + "\"");
+ });
+ const v = "(" + newWords.join(" ") + ")";
+ if (i === 0) {
+ query = `(${query}) AND (${v}`;
+ if (values.length === 1) {
+ query = query + ")";
+ }
+ }
+ else if (i === values.length - 1) {
+ query = query + " OR " + v + ")";
+ }
+ else {
+ query = query + " OR " + v;
+ }
+ }
+ }
}
+
+
+ // let limit = typepos.length
+ // typepos.forEach(i => {
+ // if (i === 0) {
+ // if (i + 1 === limit) {
+ // query = query + " && " + filters[i] + "_t:" + filters;
+ // }
+ // else if (filters[i] === filters[i + 3]) {
+ // query = query + " && (" + filters[i] + "_t:" + filters;
+ // }
+ // else {
+ // query = query + " && " + filters[i] + "_t:" + filters;
+ // }
+
+ // }
+ // else if (i + 3 > filters.length) {
+
+ // }
+ // else {
+
+ // }
+
+ // });
+
+ // query = this.applyBasicFieldFilters(query);
+
+
+
+ query = query.replace(/-\s+/g, '');
+ query = query.replace(/-/g, "");
return query;
}
@@ -235,7 +348,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@action
filterDocsByType(docs: Doc[]) {
const finalDocs: Doc[] = [];
- const blockedTypes: string[] = ["preselement", "docholder", "collection", "search", "searchitem", "script", "fonticonbox", "button", "label"];
+ const blockedTypes: string[] = [DocumentType.PRESELEMENT, DocumentType.DOCHOLDER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING];
docs.forEach(doc => {
const layoutresult = Cast(doc.type, "string");
if (layoutresult && !blockedTypes.includes(layoutresult)) {
@@ -299,6 +412,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
searchCollection(query: string) {
const selectedCollection: DocumentView = SelectionManager.SelectedDocuments()[0];
query = query.toLowerCase();
+
if (selectedCollection !== undefined) {
this.currentSelectedCollection = selectedCollection;
if (this.filter === true) {
@@ -312,6 +426,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
while (docs.length > 0) {
newarray = [];
docs.forEach((d) => {
+ d ? console.log(Cast(d.context, Doc)) : null;
if (d.data !== undefined) {
newarray.push(...DocListCast(d.data));
}
@@ -375,15 +490,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
applyBasicFieldFilters(query: string) {
let finalQuery = "";
- if (this._titleFieldStatus) {
- finalQuery = finalQuery + this.basicFieldFilters(query, Keys.TITLE);
- }
- if (this._authorFieldStatus) {
- finalQuery = finalQuery + this.basicFieldFilters(query, Keys.AUTHOR);
- }
- if (this._deletedDocsStatus) {
- finalQuery = finalQuery + this.basicFieldFilters(query, Keys.DATA);
- }
+ finalQuery = finalQuery + this.basicFieldFilters(query, Keys.TITLE);
+ finalQuery = finalQuery + this.basicFieldFilters(query, Keys.AUTHOR);
+
if (this._deletedDocsStatus) {
finalQuery = finalQuery + this.basicFieldFilters(query, Keys.TEXT);
}
@@ -394,8 +503,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
let mod = "";
switch (type) {
case Keys.AUTHOR: mod = " author_t:"; break;
- case Keys.DATA: break; // TODO
- case Keys.TITLE: mod = " _title_t:"; break;
+ case Keys.TITLE: mod = " title_t:"; break;
case Keys.TEXT: mod = " text_t:"; break;
}
@@ -412,10 +520,33 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@action
submitSearch = async (reset?: boolean) => {
+ if (this.currentSelectedCollection !== undefined) {
+ let newarray: Doc[] = [];
+ let docs: Doc[] = [];
+ docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+ while (docs.length > 0) {
+ newarray = [];
+ docs.forEach((d) => {
+ if (d.data !== undefined) {
+ d._searchDocs = new List<Doc>();
+ //d._docFilters = new List();
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ });
+ docs = newarray;
+ }
+
+ this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
+ this.currentSelectedCollection.props.Document._docFilters = new List();
+ this.props.Document.selectedDoc = undefined;
+ }
if (reset) {
this.layoutDoc._searchString = "";
}
- this.props.Document._docFilters = undefined;
+ //this.props.Document._docFilters = new List();
this.noresults = "";
this.dataDoc[this.fieldKey] = new List<Doc>([]);
@@ -423,9 +554,9 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
this.children = 0;
this.buckets = [];
this.new_buckets = {};
- const query = StrCast(this.layoutDoc._searchString);
+ let query = StrCast(this.layoutDoc._searchString);
Doc.SetSearchQuery(query);
- this.getFinalQuery(query);
+ this.searchFullDB ? query = this.getFinalQuery(query) : console.log("local");
this._results.forEach(result => {
Doc.UnBrushDoc(result[0]);
result[0].searchMatch = undefined;
@@ -473,22 +604,21 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
}
private get filterQuery() {
- const types = this.filterTypes;
- const baseExpr = "NOT baseProto_b:true";
+ const types = ["preselement", "docholder", "search", "searchitem", "script", "fonticonbox", "button", "label"]; // this.filterTypes;
+ const baseExpr = "NOT baseProto_b:true AND NOT system_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(" ")})`;
+ const typeExpr = !types ? "" : ` ${types.map(type => `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`;
// fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello
- const query = [baseExpr, includeDeleted, includeIcons].join(" AND ").replace(/AND $/, "");
+ const query = [baseExpr, includeDeleted, includeIcons, typeExpr].join(" AND ").replace(/AND $/, "");
return query;
}
getDataStatus() { return this._deletedDocsStatus; }
- private NumResults = 25;
+ private NumResults = 50;
private lockPromise?: Promise<void>;
getResults = async (query: string) => {
- console.log("Get");
if (this.lockPromise) {
await this.lockPromise;
}
@@ -496,6 +626,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) {
this._curRequest = SearchUtil.Search(query, true, { fq: this.filterQuery, start: this._maxSearchIndex, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => {
// happens at the beginning
+ this.realTotalResults = res.numFound;
if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) {
this._numTotalResults = res.numFound;
}
@@ -513,28 +644,17 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
const index = this._resultsSet.get(doc);
const highlight = highlights[doc[Id]];
const line = lines.get(doc[Id]) || [];
- const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : [];
- doc ? console.log(Cast(doc.context, Doc)) : null;
- if (this.findCommonElements(hlights)) {
- }
- else {
- const layoutresult = Cast(doc.type, "string");
- if (layoutresult) {
- if (this.new_buckets[layoutresult] === undefined) {
- this.new_buckets[layoutresult] = 1;
- }
- else {
- this.new_buckets[layoutresult] = this.new_buckets[layoutresult] + 1;
- }
- }
- if (index === undefined) {
- this._resultsSet.set(doc, this._results.length);
- this._results.push([doc, hlights, line]);
- } else {
- this._results[index][1].push(...hlights);
- this._results[index][2].push(...line);
- }
+ const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)).filter(k => k) : [];
+ // if (this.findCommonElements(hlights)) {
+ // }
+ if (index === undefined) {
+ this._resultsSet.set(doc, this._results.length);
+ this._results.push([doc, hlights, line]);
+ } else {
+ this._results[index][1].push(...hlights);
+ this._results[index][2].push(...line);
}
+
});
});
@@ -586,7 +706,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
y += 300;
}
}
- return Docs.Create.SearchDocument({ _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString), searchQuery: StrCast(this.layoutDoc._searchString) });
+ return Docs.Create.SchemaDocument(Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []), DocListCast(this.dataDoc[this.fieldKey]), { _autoHeight: true, _viewType: CollectionViewType.Schema, title: StrCast(this.layoutDoc._searchString) });
}
@action.bound
@@ -597,6 +717,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
this._searchbarOpen = true;
}
+ realTotalResults: number = 0;
+
@action.bound
closeSearch = () => {
//this.closeResults();
@@ -615,26 +737,21 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
this._curRequest = undefined;
}
+ @observable _pageStart: number = 0;
+ @observable _pageCount: number = SearchBox.NUM_SEARCH_RESULTS_PER_PAGE;
+
@observable children: number = 0;
@action
resultsScrolled = (e?: React.UIEvent<HTMLDivElement>) => {
if (!this._resultsRef.current) return;
- this.props.Document._schemaHeaders = new List<SchemaHeaderField>([]);
-
- const scrollY = e ? e.currentTarget.scrollTop : this._resultsRef.current ? this._resultsRef.current.scrollTop : 0;
- const itemHght = 53;
- const startIndex = Math.floor(Math.max(0, scrollY / itemHght));
- //const endIndex = Math.ceil(Math.min(this._numTotalResults - 1, startIndex + (this._resultsRef.current.getBoundingClientRect().height / itemHght)));
- const endIndex = 30;
- //this._endIndex = endIndex === -1 ? 12 : endIndex;
this._endIndex = 30;
- const headers = new Set<string>(["title", "author", "*lastModified", "text"]);
- if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
- if (this.noresults === "") {
- this.noresults = "No search results :(";
- }
- return;
- }
+ const headers = new Set<string>(["title", "author", "text", "type", "data", "*lastModified", "context"]);
+ // if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) {
+ // if (this.noresults === "") {
+ // this.noresults = "No search results :(";
+ // }
+ // return;
+ // }
if (this._numTotalResults <= this._maxSearchIndex) {
this._numTotalResults = this._results.length;
@@ -642,7 +759,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
// only hit right at the beginning
// visibleElements is all of the elements (even the ones you can't see)
- else if (this._visibleElements.length !== this._numTotalResults) {
+ if (this._visibleElements.length !== this._numTotalResults) {
// undefined until a searchitem is put in there
this._visibleElements = Array<JSX.Element>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
this._visibleDocuments = Array<Doc>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
@@ -651,62 +768,51 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
this._isSorted = Array<undefined>(this._numTotalResults === -1 ? 0 : this._numTotalResults);
}
- for (let i = 0; i < this._numTotalResults; i++) {
+ let max = this.NumResults;
+ max > this._results.length ? max = this._results.length : console.log("");
+ for (let i = this._pageStart; i < max; i++) {
//if the index is out of the window then put a placeholder in
//should ones that have already been found get set to placeholders?
- if (i < startIndex || i > endIndex) {
- if (this._isSearch[i] !== "placeholder") {
- this._isSearch[i] = "placeholder";
- this._isSorted[i] = "placeholder";
- this._visibleElements[i] = <div className="searchBox-placeholder" key={`searchBox-placeholder-${i}`}>Loading...</div>;
- }
- }
- else {
- if (this._isSearch[i] !== "search") {
- let result: [Doc, string[], string[]] | undefined = undefined;
- if (i >= this._results.length) {
- this.getResults(StrCast(this.layoutDoc._searchString));
- if (i < this._results.length) result = this._results[i];
- if (result) {
- const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
- const lines = new List<string>(result[2]);
- result[0].lines = lines;
- result[0].highlighting = highlights.join(", ");
- highlights.forEach((item) => headers.add(item));
- this._visibleDocuments[i] = result[0];
- this._isSearch[i] = "search";
- Doc.BrushDoc(result[0]);
- result[0].searchMatch = true;
- Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
- this.children++;
- }
- }
- else {
- result = this._results[i];
- if (result) {
- const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
- const lines = new List<string>(result[2]);
- highlights.forEach((item) => headers.add(item));
- result[0].lines = lines;
- result[0].highlighting = highlights.join(", ");
- result[0].searchMatch = true;
- if (i < this._visibleDocuments.length) {
- this._visibleDocuments[i] = result[0];
- this._isSearch[i] = "search";
- Doc.BrushDoc(result[0]);
- Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
- this.children++;
- }
- }
+
+ if (this._isSearch[i] !== "search") {
+ let result: [Doc, string[], string[]] | undefined = undefined;
+
+ result = this._results[i];
+ if (result) {
+ const highlights = Array.from([...Array.from(new Set(result[1]).values())]);
+ const lines = new List<string>(result[2]);
+ highlights.forEach((item) => headers.add(item));
+ result[0].lines = lines;
+ result[0].highlighting = highlights.join(", ");
+ result[0].searchMatch = true;
+ if (i < this._visibleDocuments.length) {
+ this._visibleDocuments[i] = result[0];
+ this._isSearch[i] = "search";
+ Doc.BrushDoc(result[0]);
+ Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]);
+ this.children++;
}
+
}
+
}
}
- const schemaheaders: SchemaHeaderField[] = [];
this.headerscale = headers.size;
- headers.forEach((item) => schemaheaders.push(new SchemaHeaderField(item, "#f1efeb")));
- this.headercount = schemaheaders.length;
- this.props.Document._schemaHeaders = new List<SchemaHeaderField>(schemaheaders);
+ if (Cast(this.props.Document._docFilters, listSpec("string"), []).length === 0) {
+ const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []);
+ if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") {
+ const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i);
+ headers.forEach(header => {
+ if (oldSchemaHeaders.includes(header) === false) {
+ newSchemaHeaders.push(new SchemaHeaderField(header, "#f1efeb"));
+ }
+ });
+ this.headercount = newSchemaHeaders.length;
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>(newSchemaHeaders);
+ } else if (this.props.Document._schemaHeaders === undefined) {
+ this.props.Document._schemaHeaders = new List<SchemaHeaderField>([new SchemaHeaderField("title", "#f1efeb")]);
+ }
+ }
if (this._maxSearchIndex >= this._numTotalResults) {
this._visibleElements.length = this._results.length;
this._visibleDocuments.length = this._results.length;
@@ -733,6 +839,8 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); }
+ @computed get viewspec() { return Cast(this.props.Document._docFilters, listSpec("string"), []); }
+
getTransform = () => {
return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
}
@@ -749,56 +857,87 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
@observable filter = false;
- //Make id layour document
+ @action newpage() {
+ this._pageStart += SearchBox.NUM_SEARCH_RESULTS_PER_PAGE;
+ this.dataDoc[this.fieldKey] = new List<Doc>([]);
+ this.resultsScrolled();
+ }
render() {
this.props.Document._chromeStatus === "disabled";
this.props.Document._searchDoc = true;
const cols = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length;
let length = 0;
- cols > 5 ? length = 1076 : length = cols * 205 + 51;
+ length = cols * 205 + 51;
let height = 0;
const rows = this.children;
- rows > 8 ? height = 31 + 31 * 8 : height = 31 * rows + 31;
+ height = 31 + 31 * 6;
return (
<div style={{ pointerEvents: "all" }} className="searchBox-container">
<div className="searchBox-bar">
<div style={{ position: "absolute", left: 15 }}>{Doc.CurrentUserEmail}</div>
<div style={{ display: "flex", alignItems: "center" }}>
- <FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg"
- style={{ color: "black", padding: 1, left: 35, position: "relative" }} />
-
+ <Tooltip title={<div className="dash-tooltip" >drag search results as collection</div>} ><div>
+ <FontAwesomeIcon onPointerDown={SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined)} icon={"search"} size="lg"
+ style={{ cursor: "hand", color: "black", padding: 1, left: 35, position: "relative" }} />
+ </div></Tooltip>
+ <div style={{
+ position: "relative",
+ left: 245,
+ zIndex: 9000,
+ color: "grey",
+ background: "white",
+ }}> {`${this._results.length}` + " of " + `${this.realTotalResults}`}</div>
<div style={{ cursor: "default", left: 250, position: "relative", }}>
<Tooltip title={<div className="dash-tooltip" >only display documents matching search</div>} ><div>
<FontAwesomeIcon icon={"filter"} size="lg"
- style={{ padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }}
+ style={{ cursor: "hand", padding: 1, backgroundColor: this.filter ? "white" : "lightgray", color: this.filter ? "black" : "white" }}
onPointerDown={e => { e.stopPropagation(); SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined); }}
onClick={action(() => {
- const dofilter = (currentSelectedCollection: DocumentView) => {
- let docs = DocListCast(currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(currentSelectedCollection.dataDoc)]);
+ ///DONT Change without emailing andy r first.
+ this.filter = !this.filter && !this.searchFullDB;
+ if (this.filter === true && this.currentSelectedCollection !== undefined) {
+ this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>(this.docsforfilter);
+ let newarray: Doc[] = [];
+ let docs: Doc[] = [];
+ docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
while (docs.length > 0) {
- const newarray: Doc[] = [];
- docs.filter(d => d.data !== undefined).forEach((d) => {
- d._searchDocs = new List<Doc>(this.docsforfilter);
- newarray.push(...DocListCast(d.data));
+ newarray = [];
+ docs.forEach((d) => {
+ if (d.data !== undefined) {
+ d._searchDocs = new List<Doc>(this.docsforfilter);
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
});
docs = newarray;
}
- };
- this.filter = !this.filter && !this.searchFullDB;
- if (this.filter === true && this.currentSelectedCollection !== undefined) {
- this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>(this.docsforfilter);
-
- dofilter(this.currentSelectedCollection);
- this.currentSelectedCollection.props.Document._docFilters = new List<string>(Cast(this.props.Document._docFilters, listSpec("string"), []));
+ this.currentSelectedCollection.props.Document._docFilters = new List<string>(this.viewspec);
this.props.Document.selectedDoc = this.currentSelectedCollection.props.Document;
}
else if (this.filter === false && this.currentSelectedCollection !== undefined) {
-
- dofilter(this.currentSelectedCollection);
+ let newarray: Doc[] = [];
+ let docs: Doc[] = [];
+ docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]);
+ while (docs.length > 0) {
+ newarray = [];
+ docs.forEach((d) => {
+ if (d.data !== undefined) {
+ d._searchDocs = new List<Doc>();
+ d._docFilters = new List();
+ const newdocs = DocListCast(d.data);
+ newdocs.forEach((newdoc) => {
+ newarray.push(newdoc);
+ });
+ }
+ });
+ docs = newarray;
+ }
this.currentSelectedCollection.props.Document._searchDocs = new List<Doc>([]);
- this.currentSelectedCollection.props.Document._docFilters = undefined;
+ this.currentSelectedCollection.props.Document._docFilters = new List();
this.props.Document.selectedDoc = undefined;
}
}
@@ -832,6 +971,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
docs.forEach((d) => {
if (d.data !== undefined) {
d._searchDocs = new List<Doc>();
+ d._docFilters = new List();
const newdocs = DocListCast(d.data);
newdocs.forEach((newdoc) => {
newarray.push(newdoc);
@@ -840,7 +980,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
});
docs = newarray;
}
- this.currentSelectedCollection.props.Document._docFilters = undefined;
+ this.currentSelectedCollection.props.Document._docFilters = new List();
this.currentSelectedCollection.props.Document._searchDocs = undefined;
this.currentSelectedCollection = undefined;
}
@@ -866,6 +1006,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
docs.forEach((d) => {
if (d.data !== undefined) {
d._searchDocs = new List<Doc>();
+ d._docFilters = new List();
const newdocs = DocListCast(d.data);
newdocs.forEach((newdoc) => {
newarray.push(newdoc);
@@ -874,7 +1015,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
});
docs = newarray;
}
- this.currentSelectedCollection.props.Document._docFilters = undefined;
+ this.currentSelectedCollection.props.Document._docFilters = new List();
this.currentSelectedCollection.props.Document._searchDocs = undefined;
this.currentSelectedCollection = undefined;
}
@@ -900,7 +1041,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
removeDocument={returnFalse}
PanelHeight={this.open === true ? () => height : () => 0}
PanelWidth={this.open === true ? () => length : () => 0}
- overflow={cols > 5 || rows > 8 ? true : false}
+ overflow={length > window.innerWidth || rows > 6 ? true : false}
focus={this.selectElement}
ScreenToLocalTransform={Transform.Identity}
/>
@@ -920,4 +1061,4 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
</div >
);
}
-}
+} \ No newline at end of file
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b535fea5a..ea53bc9a2 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -806,7 +806,8 @@ export namespace Doc {
target[targetKey] = new PrefetchProxy(templateDoc);
} else {
titleTarget && (Doc.GetProto(target).title = titleTarget);
- Doc.GetProto(target)[targetKey] = new PrefetchProxy(templateDoc);
+ const setDoc = [AclAdmin, AclEdit].includes(GetEffectiveAcl(Doc.GetProto(target))) ? Doc.GetProto(target) : target;
+ setDoc[targetKey] = new PrefetchProxy(templateDoc);
}
}
return target;
@@ -1044,6 +1045,7 @@ export namespace Doc {
if (docFilters[i] === key && (docFilters[i + 1] === value || modifiers === "match")) {
if (docFilters[i + 2] === modifiers && modifiers && docFilters[i + 1] === value) return;
docFilters.splice(i, 3);
+ container._docFilters = new List<string>(docFilters);
break;
}
}
diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts
index 07c90f5a2..22ae454f8 100644
--- a/src/fields/SchemaHeaderField.ts
+++ b/src/fields/SchemaHeaderField.ts
@@ -114,7 +114,7 @@ export class SchemaHeaderField extends ObjectField {
}
[ToScriptString]() {
- return `invalid`;
+ return `header(${this.heading},${this.type}})`;
}
[ToString]() {
return `SchemaHeaderField`;
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index 4cc3a7cc7..9391f56ac 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -56,6 +56,9 @@ async function deserializeScript(script: ScriptField) {
if (script.script.originalScript === 'self.userDoc.noviceMode') {
return (script as any).script = (ScriptField.NoviceMode ?? (ScriptField.NoviceMode = ComputedField.MakeFunction('self.userDoc.noviceMode')))?.script;
}
+ if (script.script.originalScript === `selectMainMenu(self)`) {
+ return (script as any).script = (ScriptField.SelectMenu ?? (ScriptField.SelectMenu = ComputedField.MakeFunction('selectMainMenu(self)')))?.script;
+ }
const captures: ProxyField<Doc> = (script as any).captures;
if (captures) {
const doc = (await captures.value())!;
@@ -89,6 +92,7 @@ export class ScriptField extends ObjectField {
public static DeiconifyView: Opt<ScriptField>;
public static ConvertToButtons: Opt<ScriptField>;
public static NoviceMode: Opt<ScriptField>;
+ public static SelectMenu: Opt<ScriptField>;
constructor(script: CompiledScript, setterscript?: CompiledScript) {
super();
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index ada13226e..848a648e1 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -102,7 +102,7 @@ export const documentSchema = createSchema({
_lockedTransform: "boolean",// whether a freeformview can pan/zoom
// drag drop properties
- stayInCollection: "boolean",// whether document can be dropped into a different collection
+ _stayInCollection: "boolean",// whether document can be dropped into a different collection
dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document.
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") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move'
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 4c71572db..3d832636f 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -161,8 +161,7 @@ export function GetEffectiveAcl(target: any, in_prop?: string | symbol | number)
if (target[AclSym] && Object.keys(target[AclSym]).length) {
// if the current user is the author of the document / the current user is a member of the admin group
- // but not if the doc in question is an alias - the current user will be the author of their alias rather than the original author
- if ((Doc.CurrentUserEmail === (target.__fields?.author || target.author) && !(target.aliasOf || target.__fields?.aliasOf)) || currentUserGroups.includes("admin")) return AclAdmin;
+ if (Doc.CurrentUserEmail === (target.__fields?.author || target.author) || currentUserGroups.includes("admin")) return AclAdmin;
// if the ACL is being overriden or the property being modified is one of the playground fields (which can be freely modified)
if (_overrideAcl || (in_prop && DocServer.PlaygroundFields?.includes(in_prop.toString()))) return AclEdit;
@@ -218,9 +217,10 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc
changed = true;
// maps over the aliases of the document
- if (target.aliases) {
- DocListCast(target.aliases).map(alias => {
- distributeAcls(key, acl, alias, inheritingFromCollection);
+ const aliases = DocListCast(target.aliases);
+ if (aliases.length) {
+ aliases.map(alias => {
+ alias !== target && distributeAcls(key, acl, alias, inheritingFromCollection);
});
}
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
index 7251e07a1..a5aaab63e 100644
--- a/src/server/ApiManagers/SearchManager.ts
+++ b/src/server/ApiManagers/SearchManager.ts
@@ -62,7 +62,7 @@ export class SearchManager extends ApiManager {
subscription: "/dashsearch",
secureHandler: async ({ req, res }) => {
const solrQuery: any = {};
- ["q", "fq", "start", "rows", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]);
+ ["q", "fq", "start", "rows", "sort", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]);
if (solrQuery.q === undefined) {
res.send([]);
return;
@@ -136,6 +136,9 @@ export namespace SolrManager {
const term = ToSearchTerm(value);
if (term !== undefined) {
const { suffix, value } = term;
+ if (key.endsWith('lastModified')) {
+ update["lastModified" + suffix] = value;
+ }
update[key + suffix] = value;
dynfield = true;
}
@@ -176,7 +179,8 @@ export namespace SolrManager {
"audio": ["_t", "url"],
"web": ["_t", "url"],
"date": ["_d", value => new Date(value.date).toISOString()],
- // "proxy": ["_i", "fieldId"],
+ "proxy": ["_i", "fieldId"],
+ "prefetch_proxy": ["_i", "fieldId"],
"list": ["_l", list => {
const results = [];
for (const value of list.fields) {
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index bd8fe97eb..e088cd2c4 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -279,7 +279,7 @@ function delay(ms: number) {
*
* On failure, returns undefined.
*/
-async function captureYoutubeScreenshot(targetUrl: string){
+async function captureYoutubeScreenshot(targetUrl: string) {
// const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
// const page = await browser.newPage();
// // await page.setViewport({ width: 1920, height: 1080 });
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 63cfa41f0..ec351c283 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -39,7 +39,6 @@ export namespace WebSocket {
io = sio().listen(resolvedPorts.socket);
}
logPort("websocket", resolvedPorts.socket);
- console.log();
io.on("connection", function (socket: Socket) {
_socket = socket;
@@ -204,7 +203,7 @@ export namespace WebSocket {
Database.Instance.update(newValue.id, newValue, () =>
socket.broadcast.emit(MessageStore.SetField.Message, newValue));
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 });
+ Search.updateDocument({ id: newValue.id, data: { set: (newValue as any).data } });
}
}
@@ -230,8 +229,7 @@ export namespace WebSocket {
"script": ["_t", value => value.script.originalScript],
"RichTextField": ["_t", value => value.Text],
"date": ["_d", value => new Date(value.date).toISOString()],
- // "proxy": ["_i", "fieldId"],
- // "proxy": ["", "fieldId"],
+ "proxy": ["_i", "fieldId"],
"list": ["_l", list => {
const results = [];
for (const value of list.fields) {