aboutsummaryrefslogtreecommitdiff
path: root/src/fields/Doc.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/fields/Doc.ts')
-rw-r--r--src/fields/Doc.ts157
1 files changed, 107 insertions, 50 deletions
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ceacb8a08..7170be6cc 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -7,9 +7,8 @@ import { DocServer } from '../client/DocServer';
import { DocumentType } from '../client/documents/DocumentTypes';
import { LinkManager } from '../client/util/LinkManager';
import { scriptingGlobal, ScriptingGlobals } from '../client/util/ScriptingGlobals';
-import { SelectionManager } from '../client/util/SelectionManager';
import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from '../client/util/SerializationHelper';
-import { undoable, UndoManager } from '../client/util/UndoManager';
+import { undoable } from '../client/util/UndoManager';
import { decycle } from '../decycler/decycler';
import * as JSZipUtils from '../JSZipUtils';
import { DashColor, incrementTitleCopy, intersectRect, Utils } from '../Utils';
@@ -21,6 +20,7 @@ import {
AclPrivate,
AclReadonly,
Animation,
+ AudioPlay,
CachedUpdates,
DirectLinks,
DocAcl,
@@ -48,9 +48,9 @@ import { FieldId, RefField } from './RefField';
import { RichTextField } from './RichTextField';
import { listSpec } from './Schema';
import { ComputedField, ScriptField } from './ScriptField';
-import { Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types';
+import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } from './Types';
import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField';
-import { deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions, containedFieldChangedHandler } from './util';
+import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, normalizeEmail, setter, SharingPermissions } from './util';
import JSZip = require('jszip');
export namespace Field {
export function toKeyValueString(doc: Doc, key: string): string {
@@ -157,7 +157,26 @@ export function updateCachedAcls(doc: Doc) {
@scriptingGlobal
@Deserializable('Doc', updateCachedAcls, ['id'])
export class Doc extends RefField {
- @observable public static CurrentlyLoading: Doc[];
+ @observable public static RecordingEvent = 0;
+
+ // this isn't really used at the moment, but is intended to indicate whether ink stroke are passed through a gesture recognizer
+ static GetRecognizeGestures() {
+ return BoolCast(Doc.UserDoc()._recognizeGestures);
+ }
+ static SetRecognizeGestures(show: boolean) {
+ Doc.UserDoc()._recognizeGestures = show;
+ }
+
+ //
+ // This controls whether fontIconButtons will display labels under their icons or not
+ //
+ static GetShowIconLabels() {
+ return BoolCast(Doc.UserDoc()._showLabel);
+ }
+ static SetShowIconLabels(show: boolean) {
+ Doc.UserDoc()._showLabel = show;
+ }
+ @observable public static CurrentlyLoading: Doc[] = []; // this assignment doesn't work. the actual assignment happens in DocumentManager's constructor
// removes from currently loading display
@action
public static removeCurrentlyLoading(doc: Doc) {
@@ -170,9 +189,6 @@ export class Doc extends RefField {
// adds doc to currently loading display
@action
public static addCurrentlyLoading(doc: Doc) {
- if (!Doc.CurrentlyLoading) {
- Doc.CurrentlyLoading = [];
- }
if (Doc.CurrentlyLoading.indexOf(doc) === -1) {
Doc.CurrentlyLoading.push(doc);
}
@@ -205,6 +221,9 @@ export class Doc extends RefField {
public static get MyContextMenuBtns() {
return DocCast(Doc.UserDoc().myContextMenuBtns);
}
+ public static get MyTopBarBtns() {
+ return DocCast(Doc.UserDoc().myTopBarBtns);
+ }
public static get MyRecentlyClosed() {
return DocCast(Doc.UserDoc().myRecentlyClosed);
}
@@ -331,6 +350,7 @@ export class Doc extends RefField {
@observable public [DocAcl]: { [key: string]: symbol } = {};
@observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout
@observable public [DirectLinks] = new ObservableSet<Doc>();
+ @observable public [AudioPlay]: any; // meant to store sound object from Howl
@observable public [Animation]: Opt<Doc>;
@observable public [Highlight]: boolean = false;
static __Anim(Doc: Doc) {
@@ -384,6 +404,12 @@ export class Doc extends RefField {
public static set noviceMode(val) {
Doc.UserDoc().noviceMode = val;
}
+ public static get IsSharingEnabled() {
+ return Doc.UserDoc().isSharingEnabled as boolean;
+ }
+ public static set IsSharingEnabled(val) {
+ Doc.UserDoc().isSharingEnabled = val;
+ }
public static get defaultAclPrivate() {
return Doc.UserDoc().defaultAclPrivate;
}
@@ -510,6 +536,13 @@ export namespace Doc {
export function IsDelegateField(doc: Doc, fieldKey: string) {
return doc && Get(doc, fieldKey, true) !== undefined;
}
+ //
+ // this will write the value to the key on either the data doc or the embedding doc. The choice
+ // of where to write it is based on:
+ // 1) if the embedding Doc already has this field defined on it, then it will be written to the embedding
+ // 2) if the data doc has the field, then it's written there.
+ // 3) if neither already has the field, then 'defaultProto' determines whether to write it to the data doc (or the embedding)
+ //
export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) {
if (key.startsWith('_')) key = key.substring(1);
const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined;
@@ -820,16 +853,24 @@ export namespace Doc {
export async function Zip(doc: Doc, zipFilename = 'dashExport.zip') {
const { clone, map, linkMap } = await Doc.MakeClone(doc);
const proms = new Set<string>();
- function replacer(key: any, value: any) {
+ function replacer(key: any, value: any) {
if (key && ['branchOf', 'cloneOf', 'cursors'].includes(key)) return undefined;
- if (value instanceof ImageField) {
- const extension = value.url.href.replace(/.*\./, '');
- proms.add(value.url.href.replace('.' + extension, '_o.' + extension));
- return SerializationHelper.Serialize(value);
+ if (value?.__type === 'image') {
+ const extension = value.url.replace(/.*\./, '');
+ proms.add(value.url.replace('.' + extension, '_o.' + extension));
+ return SerializationHelper.Serialize(new ImageField(value.url));
}
- if (value instanceof PdfField || value instanceof AudioField || value instanceof VideoField) {
- proms.add(value.url.href);
- return SerializationHelper.Serialize(value);
+ if (value?.__type === 'pdf') {
+ proms.add(value.url);
+ return SerializationHelper.Serialize(new PdfField(value.url));
+ }
+ if (value?.__type === 'audio') {
+ proms.add(value.url);
+ return SerializationHelper.Serialize(new AudioField(value.url));
+ }
+ if (value?.__type === 'video') {
+ proms.add(value.url);
+ return SerializationHelper.Serialize(new VideoField(value.url));
}
if (
value instanceof Doc ||
@@ -856,14 +897,15 @@ export namespace Doc {
const zip = new JSZip();
var count = 0;
- const promArr = Array.from(proms).filter(url => url.startsWith(window.location.origin));
+ const promArr = Array.from(proms).filter(url => url?.startsWith("/files")).map(url => url.replace("/",""))// window.location.origin));
+ console.log(promArr.length);
if (!promArr.length) {
zip.file('docs.json', jsonDocs);
zip.generateAsync({ type: 'blob' }).then(content => saveAs(content, zipFilename));
} else
promArr.forEach((url, i) => {
// loading a file and add it in a zip file
- JSZipUtils.getBinaryContent(url, (err: any, data: any) => {
+ JSZipUtils.getBinaryContent(window.location.origin+"/"+url, (err: any, data: any) => {
if (err) throw err; // or handle the error
// // Generate a directory within the Zip file structure
// const assets = zip.folder("assets");
@@ -979,7 +1021,7 @@ export namespace Doc {
references.add(doc);
return;
}
- const excludeLists = doc.title === 'My Recently Closed' || doc.title === 'My Header Bar' || doc.title === 'My Dashboards';
+ const excludeLists = ['My Recently Closed', 'My Header Bar', 'My Dashboards'].includes(StrCast(doc.title));
if (system !== undefined && ((system && !Doc.IsSystem(doc)) || (!system && Doc.IsSystem(doc)))) return;
references.add(doc);
Object.keys(doc).forEach(key => {
@@ -1430,18 +1472,36 @@ export namespace Doc {
const isTransparent = (color: string) => color !== '' && DashColor(color).alpha() !== 1;
return isTransparent(StrCast(doc[key]));
}
+ if (key === '-linkedTo') {
+ // links are not a field value, so handled here. value is an expression of form ([field=]idToDoc("..."))
+ const allLinks = LinkManager.Instance.getAllRelatedLinks(doc);
+ const matchLink = (value: string, anchor: Doc) => {
+ const linkedToExp = value?.split('=');
+ if (linkedToExp.length === 1) return Field.toScriptString(anchor) === value;
+ return Field.toScriptString(DocCast(anchor[linkedToExp[0]])) === linkedToExp[1];
+ };
+ // prettier-ignore
+ return (value === Doc.FilterNone && !allLinks.length) ||
+ (value === Doc.FilterAny && !!allLinks.length) ||
+ (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) ||
+ matchLink(value,DocCast(link.link_anchor_2)) ));
+ }
if (typeof value === 'string') {
value = value.replace(`,${Utils.noRecursionHack}`, '');
}
const fieldVal = doc[key];
+ // prettier-ignore
+ if ((value === Doc.FilterAny && fieldVal !== undefined) ||
+ (value === Doc.FilterNone && fieldVal === undefined)) {
+ return true;
+ }
if (Cast(fieldVal, listSpec('string'), []).length) {
- const vals = Cast(fieldVal, listSpec('string'), []);
+ const vals = StrListCast(fieldVal);
const docs = vals.some(v => (v as any) instanceof Doc);
if (docs) return value === Field.toString(fieldVal as Field);
return vals.some(v => v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
- const fieldStr = Field.toString(fieldVal as Field);
- return fieldStr.includes(value) || (value === String.fromCharCode(127) + '--undefined--' && fieldVal === undefined); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
+ return Field.toString(fieldVal as Field).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring
}
export function deiconifyView(doc: Doc) {
@@ -1454,24 +1514,40 @@ export namespace Doc {
prevLayout === 'icon' && (doc.deiconifyLayout = undefined);
doc.layout_fieldKey = deiconify || 'layout';
}
- export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: number[]) {
+ export function setDocRangeFilter(container: Opt<Doc>, key: string, range?: readonly number[], modifiers?: 'remove') {
+ //, modifiers: 'remove' | 'set'
if (!container) return;
+
const childFiltersByRanges = Cast(container._childFiltersByRanges, listSpec('string'), []);
+
for (let i = 0; i < childFiltersByRanges.length; i += 3) {
if (childFiltersByRanges[i] === key) {
+ console.log('this is key inside childfilters by range ' + key);
childFiltersByRanges.splice(i, 3);
+ console.log('this is child filters by range ' + childFiltersByRanges);
break;
}
}
if (range !== undefined) {
+ console.log('in doc.ts in set range filter');
childFiltersByRanges.push(key);
childFiltersByRanges.push(range[0].toString());
childFiltersByRanges.push(range[1].toString());
container._childFiltersByRanges = new List<string>(childFiltersByRanges);
+ console.log('this is child filters by range ' + childFiltersByRanges[0] + ',' + childFiltersByRanges[1] + ',' + childFiltersByRanges[2]);
+ console.log('this is new list ' + container._childFiltersByRange);
}
+
+ if (modifiers) {
+ childFiltersByRanges.splice(0, 3);
+ container._childFiltersByRanges = new List<string>(childFiltersByRanges);
+ }
+ console.log('this is child filters by range END' + childFiltersByRanges[0] + ',' + childFiltersByRanges[1] + ',' + childFiltersByRanges[2]);
}
export const FilterSep = '::';
+ export const FilterAny = '--any--';
+ export const FilterNone = '--undefined--';
// filters document in a container collection:
// all documents with the specified value for the specified key are included/excluded
@@ -1483,8 +1559,8 @@ export namespace Doc {
runInAction(() => {
for (let i = 0; i < childFilters.length; i++) {
const fields = childFilters[i].split(FilterSep); // split key:value:modifier
- if (fields[0] === key && (fields[1] === value || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
- if (fields[2] === modifiers && modifiers && fields[1] === value) {
+ if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
+ if (fields[2] === modifiers && modifiers && fields[1] === value.toString()) {
if (toggle) modifiers = 'remove';
else return;
}
@@ -1582,7 +1658,7 @@ export namespace Doc {
case DocumentType.COMPARISON: return 'columns';
case DocumentType.RTF: return 'sticky-note';
case DocumentType.COL:
- const folder: IconProp = isOpen === true ? 'folder-open' : isOpen === false ? 'folder' : 'question';
+ const folder: IconProp = isOpen === true ? 'folder-open' : isOpen === false ? 'folder' : doc?.title==='Untitled Collection'? 'object-group': 'chalkboard';
const chevron: IconProp = isOpen === true ? 'chevron-down' : isOpen === false ? 'chevron-right' : 'question';
return !doc?.isFolder ? folder : chevron;
case DocumentType.WEB: return 'globe-asia';
@@ -1598,6 +1674,10 @@ export namespace Doc {
case DocumentType.PDF: return 'file-pdf';
case DocumentType.LINK: return 'link';
case DocumentType.MAP: return 'map-marker-alt';
+ case DocumentType.DATAVIZ: return 'chart-bar';
+ case DocumentType.EQUATION: return 'calculator';
+ case DocumentType.SIMULATION: return 'rocket';
+ case DocumentType.CONFIG: return 'question-circle';
default: return 'question';
}
}
@@ -1805,24 +1885,6 @@ ScriptingGlobals.add(function setInPlace(doc: any, field: any, value: any) {
ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) {
return Doc.AreProtosEqual(doc1, doc2);
});
-ScriptingGlobals.add(function undo() {
- SelectionManager.DeselectAll();
- return UndoManager.Undo();
-});
-
-export function ShowUndoStack() {
- SelectionManager.DeselectAll();
- var buffer = '';
- UndoManager.undoStack.forEach((batch, i) => {
- buffer += 'Batch => ' + UndoManager.undoStackNames[i] + '\n';
- ///batch.forEach(undo => (buffer += ' ' + undo.prop + '\n'));
- });
- alert(buffer);
-}
-ScriptingGlobals.add(function redo() {
- SelectionManager.DeselectAll();
- return UndoManager.Redo();
-});
ScriptingGlobals.add(function DOC(id: string) {
console.log("Can't parse a document id in a script");
return 'invalid';
@@ -1837,12 +1899,7 @@ ScriptingGlobals.add(function activePresentationItem() {
const curPres = Doc.ActivePresentation;
return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)];
});
-ScriptingGlobals.add(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) {
- const docs = SelectionManager.Views()
- .map(dv => dv.props.Document)
- .filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.KVP && (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null)));
- return docs.length ? new List(docs) : prevValue;
-});
+
ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: any, modifiers: 'match' | 'check' | 'x' | 'remove') {
Doc.setDocFilter(container, key, value, modifiers);
});