diff options
author | mehekj <mehek.jethani@gmail.com> | 2021-10-21 16:46:49 -0400 |
---|---|---|
committer | mehekj <mehek.jethani@gmail.com> | 2021-10-21 16:46:49 -0400 |
commit | 353e72feb29d3549dcf7ec7875241ddb7a9a99d9 (patch) | |
tree | 743d8afe0700bff47c7ef5e141a606cbaba8c0e6 /src | |
parent | 6cec290f98103827727905874c5a9c5ced0bcca8 (diff) | |
parent | bdf0befa2b5eff79c2729254c2d053afe18b1646 (diff) |
Merge branch 'master' into temporalmedia-mehek
Diffstat (limited to 'src')
-rw-r--r-- | src/client/goldenLayout.js | 12 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 3 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 29 | ||||
-rw-r--r-- | src/client/views/MainView.scss | 17 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.scss | 23 | ||||
-rw-r--r-- | src/client/views/collections/TreeView.tsx | 12 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx | 86 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx | 18 | ||||
-rw-r--r-- | src/client/views/collections/collectionSchema/CollectionSchemaView.scss | 7 | ||||
-rw-r--r-- | src/client/views/linking/LinkEditor.tsx | 4 | ||||
-rw-r--r-- | src/fields/Doc.ts | 1 | ||||
-rw-r--r-- | src/server/server_Initialization.ts | 2 |
14 files changed, 179 insertions, 42 deletions
diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index 238f1ac0a..896237e1d 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -1583,7 +1583,7 @@ close: 'close', maximise: 'maximise', minimise: 'minimise', - popout: 'open in new window', + popout: 'new tab', popin: 'pop in', tabDropdown: 'additional tabs' } @@ -2355,6 +2355,7 @@ this.element.hide(); } }); + /** * This class represents a header above a Stack ContentItem. * @@ -2362,6 +2363,7 @@ * @param {lm.item.AbstractContentItem} parent */ lm.controls.Header = function (layoutManager, parent) { + lm.utils.EventEmitter.call(this); this.layoutManager = layoutManager; @@ -4449,7 +4451,11 @@ lm.items.Stack = function (layoutManager, config, parent) { lm.items.AbstractContentItem.call(this, layoutManager, config, parent); - this.element = $('<div class="lm_item lm_stack"></div>'); + this.element = $( + '<div class="lm_item lm_stack">' + + '<p class="empty-tabs-message">Click <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAUCAAAAABHICnvAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAHdElNRQfkCBsXMgbrEyzaAAAAT0lEQVQY02NgIAcIu8tgEW3/u4IDQ5B14/8LQlhFhckVFfCJjIyIOfP/QWpEZGSQJFS05s9fIPj3/z+YmseCTxS7CZS7DI+PsYcOjpAkDAA6H0KZxzDzlgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0wOC0yN1QyMzo1MDowNi0wNDowMDvgVpQAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjAtMDgtMjdUMjM6NTA6MDYtMDQ6MDBKve4oAAAAAElFTkSuQmCC"/> to create a new tab</p>' + + '</div>' + ); this._activeContentItem = null; var cfg = layoutManager.config; this._header = { // defaults' reconstruction from old configuration style @@ -5029,7 +5035,7 @@ 'close', 'maximise', 'minimise', - 'open in new window' + 'new tab' ]; }; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 3c32c2359..9d06ad8a3 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -810,7 +810,7 @@ export class CurrentUserUtils { const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`); const newDashboardButton: Doc = Docs.Create.FontIconDocument({ onClick: newDashboard, _forceActive: true, toolTip: "Create new dashboard", _stayInCollection: true, _hideContextMenu: true, title: "new dashboard", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true }); doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, + title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: "fileSystem", isFolder: true, system: true, @@ -1328,6 +1328,7 @@ export class CurrentUserUtils { Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); doc.savedFilters = new List<Doc>(); doc.filterDocCount = 0; + doc.freezeChildren = "remove|add"; 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.setupImportSidebar(doc); // sets up the import sidebar diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7f024a1da..ed6f39ffe 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -318,8 +318,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const doc = Document(docView.rootDoc); const nwidth = docView.nativeWidth; const nheight = docView.nativeHeight; - const width = (doc._width || 0); - let height = (doc._height || (nheight / nwidth * width)); + const docheight = doc._height || 0; + const docwidth = doc._width || 0; + const width = docwidth; + let height = (docheight || (nheight / nwidth * width)); height = !height || isNaN(height) ? 20 : height; const scale = docView.props.ScreenToLocalTransform().Scale; const modifyNativeDim = (e.ctrlKey || doc.forceReflow) && doc.nativeDimModifiable; @@ -332,17 +334,18 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P else dW = dH * nwidth / nheight; } } - const actualdW = Math.max(width + (dW * scale), 20); - const actualdH = Math.max(height + (dH * scale), 20); - doc.x = (doc.x || 0) + dX * (actualdW - width); - doc.y = (doc.y || 0) + dY * (actualdH - height); + let actualdW = Math.max(width + (dW * scale), 20); + let actualdH = Math.max(height + (dH * scale), 20); const fixedAspect = (nwidth && nheight); if (fixedAspect) { if ((Math.abs(dW) > Math.abs(dH) && (!dragBottom || !modifyNativeDim)) || dragRight) { if (dragRight && modifyNativeDim) { doc._nativeWidth = actualdW / (doc._width || 1) * Doc.NativeWidth(doc); } else { - if (!doc._fitWidth) doc._height = nheight / nwidth * actualdW; + if (!doc._fitWidth) { + actualdH = nheight / nwidth * actualdW; + doc._height = actualdH; + } else if (!modifyNativeDim || dragBotRight) doc._height = actualdH; } doc._width = actualdW; @@ -353,10 +356,16 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P doc._nativeHeight = actualdH / (doc._height || 1) * Doc.NativeHeight(doc); doc._autoHeight = false; } else { - if (!doc._fitWidth) doc._width = nwidth / nheight * actualdH; + if (!doc._fitWidth) { + actualdW = nwidth / nheight * actualdH; + doc._width = actualdW; + } else if (!modifyNativeDim || dragBotRight) doc._width = actualdW; } - if (!modifyNativeDim) doc._height = Math.min(nheight / nwidth * NumCast(doc._width), actualdH); + if (!modifyNativeDim) { + actualdH = Math.min(nheight / nwidth * NumCast(doc._width), actualdH); + doc._height = actualdH; + } else doc._height = actualdH; } } else { @@ -364,6 +373,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P dW && (doc._width = actualdW); dH && (doc._autoHeight = false); } + doc.x = (doc.x || 0) + dX * (actualdW - docwidth); + doc.y = (doc.y || 0) + dY * (actualdH - docheight); doc._lastModified = new DateField(); } const val = this._dragHeights.get(docView.layoutDoc); diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index c3cdb7dde..15cd2c144 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -59,6 +59,10 @@ .mainView-container { color: $dark-gray; + .lm_goldenlayout { + background: $medium-gray; + } + .lm_title { background: $light-gray; color: $dark-gray; @@ -166,12 +170,14 @@ position: absolute; z-index: 2; background-color: $light-gray; + .editable-title { background-color: $light-gray; } } } + .mainView-libraryHandle { background-color: $light-gray; } @@ -179,20 +185,24 @@ { .propertiesView { background-color: #252525; + input { background-color: $medium-gray; } - .propertiesView-sharingTable - { + + .propertiesView-sharingTable { background-color: $medium-gray; } + .editable-title { background-color: $medium-gray; } + .propertiesView-field { background-color: $medium-gray; } } + .mainView-propertiesDragger, .mainView-libraryHandle { background: #353535; @@ -202,8 +212,9 @@ .contextMenu-cont { background: $medium-gray; color: $white; + input::placeholder { - color:$white; + color: $white; } } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 6d0d5eb39..9a885fbf8 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -466,6 +466,7 @@ export class MainView extends React.Component { </div>; } + expandFlyout = action((button: Doc) => { // bcz: What's going on here!? // Chrome(not firefox) seems to have a bug when the flyout expands and there's a zoomed freeform tab. All of the div below the CollectionFreeFormView's main div diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 77e7b86ea..b2ee33807 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -65,6 +65,29 @@ display: inline; } +.empty-tabs-message { + position: absolute; + width: 100%; + z-index: 1; + top: 50%; + z-index: 1; + text-align: center; + font-size: 18; + color: $dark-gray; + + img { + position: relative; + top: -1px; + margin: 0 5px; + } +} + +.lm_header, +.lm_items { + z-index: 2; + position: relative; +} + .lm_drag_tab { padding: 0; width: 15px !important; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a3da0e0e4..7f2128230 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -820,7 +820,7 @@ export class TreeView extends React.Component<TreeViewProps> { childDocs: Doc[], treeView: CollectionTreeView, parentTreeView: CollectionTreeView | TreeView | undefined, - conainerCollection: Doc, + containerCollection: Doc, dataDoc: Doc | undefined, parentCollectionDoc: Doc | undefined, containerPrevSibling: Doc | undefined, @@ -846,16 +846,16 @@ export class TreeView extends React.Component<TreeViewProps> { unobserveHeight: (ref: any) => void, contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[]) ) { - const viewSpecScript = Cast(conainerCollection.viewSpecScript, ScriptField); + const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField); if (viewSpecScript) { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(conainerCollection.treeViewSortCriterion)); + const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion)); const rowWidth = () => panelWidth() - treeBulletWidth(); const treeViewRefs = new Map<Doc, TreeView | undefined>(); return docs.filter(child => child instanceof Doc).map((child, i) => { - const pair = Doc.GetLayoutDataDocPair(conainerCollection, dataDoc, child); + const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return (null); } @@ -883,7 +883,7 @@ export class TreeView extends React.Component<TreeViewProps> { return <TreeView key={child[Id]} ref={r => treeViewRefs.set(child, r ? r : undefined)} document={pair.layout} dataDoc={pair.data} - containerCollection={conainerCollection} + containerCollection={containerCollection} prevSibling={docs[i]} treeView={treeView} indentDocument={indent} @@ -891,7 +891,7 @@ export class TreeView extends React.Component<TreeViewProps> { onCheckedClick={onCheckedClick} onChildClick={onChildClick} renderDepth={renderDepth} - removeDoc={StrCast(conainerCollection.freezeChildren).includes("remove") ? undefined : remove} + removeDoc={StrCast(containerCollection.freezeChildren).includes("remove") ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} panelWidth={rowWidth} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index 0274cc49c..a439a7998 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -38,27 +38,35 @@ export interface CellProps { row: number; col: number; rowProps: CellInfo; + // currently unused CollectionView: Opt<CollectionView>; + // currently unused ContainingCollection: Opt<CollectionView>; Document: Doc; + // column name fieldKey: string; + // currently unused renderDepth: number; + // called when a button is pressed on the node itself addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; + // set whether the cell is in the isEditing mode setIsEditing: (isEditing: boolean) => void; isEditable: boolean; setPreviewDoc: (doc: Doc) => void; setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean; getField: (row: number, col?: number) => void; + // currnetly unused showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void; } @observer export class CollectionSchemaCell extends React.Component<CellProps> { + // return a field key that is corrected for whether it COMMENT public static resolvedFieldKey(column: string, rowDoc: Doc) { const fieldKey = column; if (fieldKey.startsWith("*")) { @@ -72,7 +80,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> { @observable protected _isEditing: boolean = false; protected _focusRef = React.createRef<HTMLDivElement>(); protected _rowDoc = this.props.rowProps.original; + // Gets the serialized data in proto form of the base proto that this document's proto inherits from protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original); + // methods for dragging and dropping protected _dropDisposer?: DragManager.DragDropDisposer; @observable contents: string = ""; @@ -81,6 +91,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> { @action onKeyDown = (e: KeyboardEvent): void => { + // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) { document.removeEventListener("keydown", this.onKeyDown); this._isEditing = true; @@ -90,7 +101,11 @@ export class CollectionSchemaCell extends React.Component<CellProps> { @action isEditingCallback = (isEditing: boolean): void => { + // a general method that takes a boolean that determines whether the cell should be in + // is-editing mode + // remove the event listener if it's there document.removeEventListener("keydown", this.onKeyDown); + // it's not already in is-editing mode, re-add the event listener isEditing && document.addEventListener("keydown", this.onKeyDown); this._isEditing = isEditing; this.props.setIsEditing(isEditing); @@ -99,12 +114,15 @@ export class CollectionSchemaCell extends React.Component<CellProps> { @action onPointerDown = async (e: React.PointerEvent): Promise<void> => { + // pan to the cell this.onItemDown(e); + // focus on it this.props.changeFocusedCellByIndex(this.props.row, this.props.col); this.props.setPreviewDoc(this.props.rowProps.original); let url: string; if (url = StrCast(this.props.rowProps.row.href)) { + // opens up the the doc in a new window, blurring the old one try { new URL(url); const temp = window.open(url)!; @@ -119,18 +137,25 @@ export class CollectionSchemaCell extends React.Component<CellProps> { @undoBatch applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => { + // apply a specified change to the cell const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) }); if (!res.success) return false; + // change what is rendered to this new changed cell content doc[this.renderFieldKey] = res.result; return true; + // return whether the change was successful } private drop = (e: Event, de: DragManager.DropEvent) => { + // if the drag has data at its completion if (de.complete.docDragData) { + // if only one doc was dragged if (de.complete.docDragData.draggedDocuments.length === 1) { + // update the renderFieldKey this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0]; } else { + // create schema document reflecting the new column arrangement const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {}); this._rowDataDoc[this.renderFieldKey] = coll; } @@ -139,7 +164,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> { } protected dropRef = (ele: HTMLElement | null) => { + // if the drop disposer is not undefined, run its function this._dropDisposer?.(); + // if ele is not null, give ele a non-undefined drop disposer ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); } @@ -163,33 +190,46 @@ export class CollectionSchemaCell extends React.Component<CellProps> { return <span style={{ color: contents ? "black" : "grey" }}>{contents ? contents?.valueOf() : "undefined"}</span>; } - @computed get renderFieldKey() { return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); } + @computed get renderFieldKey() { + // gets the resolved field key of this cell + return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); + } + onItemDown = async (e: React.PointerEvent) => { + // if the document is a document used to change UI for search results in schema view if (this.props.Document._searchDoc) { const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc); const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null); + // Jump to the this document DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext, undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); } } + renderCellWithType(type: string | undefined) { const dragRef: React.RefObject<HTMLDivElement> = React.createRef(); + // the column const fieldKey = this.renderFieldKey; + // the exact cell const field = this._rowDoc[fieldKey]; const onPointerEnter = (e: React.PointerEvent): void => { + // e.buttons === 1 means the left moue pointer is down if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) { dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; } }; const onPointerLeave = (e: React.PointerEvent): void => { + // change the class name to indicate that the cell is no longer being dragged dragRef.current!.className = "collectionSchemaView-cellContainer"; }; let contents = Field.toString(field as Field); + // display 2 hyphens instead of a blank box for empty cells contents = contents === "" ? "--" : contents; + // classname reflects the tatus of the cell let className = "collectionSchemaView-cellWrapper"; if (this._isEditing) className += " editing"; if (this.props.isFocused && this.props.isEditable) className += " focused"; @@ -197,19 +237,23 @@ export class CollectionSchemaCell extends React.Component<CellProps> { const positions = []; if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { + // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase(); const search = StrCast(this.props.Document._searchString).toLowerCase(); let start = term.indexOf(search); let tally = 0; + // if search is found in term if (start !== -1) { positions.push(start); } + // if search is found in term, continue finding all instances of search in term while (start < contents?.length && start !== -1) { term = term.slice(start + search.length + 1); tally += start + search.length + 1; start = term.indexOf(search); positions.push(tally + start); } + // remove the last position if (positions.length > 1) { positions.pop(); } @@ -279,6 +323,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> { //two options here: we can strip off outer quotes or we can figure out what's going on with the script const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length; + // change it if a change is made, otherwise, just compile using the old cell conetnts script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle numbers and expressions } else if (inputIsNum || value.startsWith("=")) { @@ -308,6 +353,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> { return retVal; })} OnFillDown={async (value: string) => { + // computes all of the value preceded by := const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); script.compiled && DocListCast(this.props.Document[this.props.fieldKey]). forEach((doc, i) => value.startsWith(":=") ? @@ -338,7 +384,10 @@ export class CollectionSchemaStringCell extends CollectionSchemaCell { render() @observer export class CollectionSchemaDateCell extends CollectionSchemaCell { - @computed get _date(): Opt<DateField> { return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; } + @computed get _date(): Opt<DateField> { + // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. + return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; + } @action handleChange = (date: any) => { @@ -377,8 +426,9 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { typecheck: true, transformer: DocumentIconContainer.getTransformer() }); - + // compile the script const results = script.compiled && script.run(); + // if the script was compiled and run if (results && results.success) { this._rowDoc[this.renderFieldKey] = results.result; return true; @@ -396,6 +446,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { @action isEditingCallback = (isEditing: boolean): void => { + // the isEditingCallback from a general CollectionSchemaCell document.removeEventListener("keydown", this.onKeyDown); isEditing && document.addEventListener("keydown", this.onKeyDown); this._isEditing = isEditing; @@ -404,6 +455,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { } render() { + // if there's a doc, render it return !this._doc ? this.renderCellWithType("document") : <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown} @@ -439,11 +491,11 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { export class CollectionSchemaImageCell extends CollectionSchemaCell { choosePath(url: URL) { - if (url.protocol === "data") return url.href; - if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); - if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here + if (url.protocol === "data") return url.href; // if the url ises the data protocol, just return the href + if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver + if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here — good question - const ext = path.extname(url.href); + const ext = path.extname(url.href); // the extension of the file return url.href.replace(ext, "_o" + path.extname(url.href)); } @@ -452,12 +504,13 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell { const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; + // If there is a path, follow it; otherwise, follow a link to a default image icon const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; - const aspect = Doc.NativeAspect(this._rowDoc); - let width = Math.min(75, this.props.rowProps.width); - const height = Math.min(75, width / aspect); - width = height * aspect; + const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio + let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px + const height = Math.min(75, width / aspect); // get a height either proportional to that or 75 px + width = height * aspect; // increase the width of the image if necessary to maintain proportionality const reference = React.createRef<HTMLDivElement>(); return <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}> @@ -477,13 +530,13 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { @computed get _field() { return this._rowDoc[this.renderFieldKey]; } @computed get _optionsList() { return this._field as List<any>; } - @observable private _opened = false; + @observable private _opened = false; // whether the list is opened @observable private _text = "select an item"; - @observable private _selectedNum = 0; + @observable private _selectedNum = 0; // the index of the list item selected @action onSetValue = (value: string) => { - // change if its a document + // change if it's a document this._optionsList[this._selectedNum] = this._text = value; (this._field as List<any>).splice(this._selectedNum, 1, value); @@ -491,6 +544,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { @action onSelected = (element: string, index: number) => { + // if an item is selected, the private variables should update to reflect this this._text = element; this._selectedNum = index; } @@ -504,6 +558,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { const link = false; const reference = React.createRef<HTMLDivElement>(); + // if the list is not opened, don't display it; otherwise, do. if (this._optionsList?.length) { const options = !this._opened ? (null) : <div> @@ -571,6 +626,7 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell { @observer export class CollectionSchemaButtons extends CollectionSchemaCell { + // the navigation buttons for schema view when it is used for search. render() { return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <></> : <div style={{ paddingTop: 8, paddingLeft: 3 }} > @@ -582,4 +638,4 @@ export class CollectionSchemaButtons extends CollectionSchemaCell { </button> </div>; } -}
\ No newline at end of file +} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index c659f749e..1306b79cb 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -24,6 +24,7 @@ export interface AddColumnHeaderProps { @observer export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHeaderProps> { + // the button that allows the user to add a column render() { return <button className="add-column" onClick={() => this.props.createColumn()}> <FontAwesomeIcon icon="plus" size="sm" /> @@ -31,7 +32,6 @@ export class CollectionSchemaAddColumnHeader extends React.Component<AddColumnHe } } - export interface ColumnMenuProps { columnField: SchemaHeaderField; // keyValue: string; @@ -395,8 +395,8 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> { this.closeResultsVisibility = "none"; } for (let i = 0; i < (filters?.length ?? 0) - 1; i++) { - if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i].split(":")[1]) === false) { - keyOptions.push(filters![i + 1]); + if (filters[i] === this.props.col.heading && keyOptions.includes(filters[i].split(":")[1]) === false) { + keyOptions.push(filters[i + 1]); } } const options = keyOptions.map(key => { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx index 456c38c68..2df95ffd8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx @@ -21,27 +21,38 @@ export interface MovableColumnProps { ScreenToLocalTransform: () => Transform; } export class MovableColumn extends React.Component<MovableColumnProps> { + // The header of the column private _header?: React.RefObject<HTMLDivElement> = React.createRef(); + // The container of the function that is responsible for moving the column over to a new plac private _colDropDisposer?: DragManager.DragDropDisposer; + // initial column position private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 }; + // sensitivity to being dragged, in pixels private _sensitivity: number = 16; + // Column reference ID private _dragRef: React.RefObject<HTMLDivElement> = React.createRef(); onPointerEnter = (e: React.PointerEvent): void => { + // if the column is left-clicked and it is being dragged if (e.buttons === 1 && SnappingManager.GetIsDragging()) { this._header!.current!.className = "collectionSchema-col-wrapper"; document.addEventListener("pointermove", this.onDragMove, true); } } + onPointerLeave = (e: React.PointerEvent): void => { this._header!.current!.className = "collectionSchema-col-wrapper"; document.removeEventListener("pointermove", this.onDragMove, true); !e.buttons && document.removeEventListener("pointermove", this.onPointerMove); } + onDragMove = (e: PointerEvent): void => { + // only take into account the horizonal direction when a column is dragged const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); const rect = this._header!.current!.getBoundingClientRect(); + // Now store the point at the top center of the column when it was in its original position const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top); + // to be compared with its new horizontal position const before = x[0] < bounds[0]; this._header!.current!.className = "collectionSchema-col-wrapper"; if (before) this._header!.current!.className += " col-before"; @@ -58,11 +69,15 @@ export class MovableColumn extends React.Component<MovableColumnProps> { colDrop = (e: Event, de: DragManager.DropEvent) => { document.removeEventListener("pointermove", this.onDragMove, true); + // we only care about whether the column is shifted to the side const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + // get the dimensions of the smallest rectangle that bounds the header const rect = this._header!.current!.getBoundingClientRect(); const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top); + // get whether the column was dragged before or after where it is now const before = x[0] < bounds[0]; const colDragData = de.complete.columnDragData; + // if there is colDragData, which happen when the drag is complete, reorder the columns according to the established variables if (colDragData) { e.stopPropagation(); this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns); @@ -85,8 +100,10 @@ export class MovableColumn extends React.Component<MovableColumnProps> { document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); }; + // if the left mouse button is the one being held if (e.buttons === 1) { const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y); + // If the movemnt of the drag exceeds the sensitivity value if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) { document.removeEventListener("pointermove", this.onPointerMove); e.stopPropagation(); @@ -105,6 +122,7 @@ export class MovableColumn extends React.Component<MovableColumnProps> { onPointerDown = (e: React.PointerEvent, ref: React.RefObject<HTMLDivElement>) => { this._dragRef = ref; const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY); + // If the cell thing dragged is not being edited if (!(e.target as any)?.tagName.includes("INPUT")) { this._startDragPosition = { x: dx, y: dy }; document.addEventListener("pointermove", this.onPointerMove); diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 9ebe14d6c..b64e9dac1 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -132,6 +132,13 @@ min-height: 30px; border: 0 !important; } + .rt-tr-group:nth-of-type(even) { + direction: ltr; + flex: 0 1 auto; + min-height: 30px; + border: 0 !important; + background-color: red; + } .rt-tr { width: 100%; min-height: 30px; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 5b5c3cd01..db331bb75 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -54,9 +54,9 @@ export class LinkEditor extends React.Component<LinkEditorProps> { linkRelationshipList.push(value); linkRelationshipSizes.push(1); const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")"; - linkColorList.push(randColor) + linkColorList.push(randColor); // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes - } else if (linkRelationshipList && value != prevRelationship) { + } else if (linkRelationshipList && value !== prevRelationship) { const index = linkRelationshipList.indexOf(value); //increment size of new relationship size if (index !== -1 && index < linkRelationshipSizes.length) { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 13f88e2fc..631bbabed 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1315,6 +1315,7 @@ export namespace Doc { if (typeof resolved === "object" && !(resolved instanceof Array)) { output = convertObject(resolved, excludeEmptyObjects, title, appendToExisting?.targetDoc); } else { + // give the proper types to the data extracted from the JSON const result = toField(resolved, excludeEmptyObjects); if (appendToExisting) { (output = appendToExisting.targetDoc)[appendToExisting.fieldKey || defaultKey] = result; diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 0f4a067fc..00a801e03 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -37,6 +37,8 @@ export let resolvedServerUrl: string; export default async function InitializeServer(routeSetter: RouteSetter) { const app = buildWithMiddleware(express()); + // Root route of express app + app.get("/", (req, res) => res.redirect("/home")); app.use(express.static(publicDirectory, { setHeaders: res => res.setHeader("Access-Control-Allow-Origin", "*") |