aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/DocumentManager.ts16
-rw-r--r--src/client/util/DragManager.ts44
-rw-r--r--src/client/util/History.ts136
-rw-r--r--src/client/util/Import & Export/DirectoryImportBox.tsx18
-rw-r--r--src/client/util/LinkManager.ts11
-rw-r--r--src/client/util/RichTextSchema.tsx17
-rw-r--r--src/client/util/Scripting.ts72
-rw-r--r--src/client/util/SearchUtil.ts41
-rw-r--r--src/client/util/SerializationHelper.ts10
-rw-r--r--src/client/util/TooltipTextMenu.tsx32
-rw-r--r--src/client/util/type_decls.d2
11 files changed, 302 insertions, 97 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index acd8dcef7..262194a40 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -3,7 +3,7 @@ import { DocumentView } from '../views/nodes/DocumentView';
import { Doc, DocListCast, Opt } from '../../new_fields/Doc';
import { FieldValue, Cast, NumCast, BoolCast, StrCast } from '../../new_fields/Types';
import { listSpec } from '../../new_fields/Schema';
-import { undoBatch } from './UndoManager';
+import { undoBatch, UndoManager } from './UndoManager';
import { CollectionDockingView } from '../views/collections/CollectionDockingView';
import { CollectionView } from '../views/collections/CollectionView';
import { CollectionPDFView } from '../views/collections/CollectionPDFView';
@@ -106,14 +106,16 @@ export class DocumentManager {
@computed
public get LinkedDocumentViews() {
- let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush, false)).reduce((pairs, dv) => {
+ let pairs = DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush)).reduce((pairs, dv) => {
let linksList = LinkManager.Instance.getAllRelatedLinks(dv.props.Document);
pairs.push(...linksList.reduce((pairs, link) => {
if (link) {
let linkToDoc = LinkManager.Instance.getOppositeAnchor(link, dv.props.Document);
- DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => {
- pairs.push({ a: dv, b: docView1, l: link });
- });
+ if (linkToDoc) {
+ DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => {
+ pairs.push({ a: dv, b: docView1, l: link });
+ });
+ }
}
return pairs;
}, [] as { a: DocumentView, b: DocumentView, l: Doc }[]));
@@ -140,7 +142,9 @@ export class DocumentManager {
if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) {
docView.props.Document.libraryBrush = true;
if (linkPage !== undefined) docView.props.Document.curPage = linkPage;
- docView.props.focus(docView.props.Document, willZoom);
+ UndoManager.RunInBatch(() => {
+ docView!.props.focus(docView!.props.Document, willZoom);
+ }, "focus");
} else {
if (!contextDoc) {
if (docContext) {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index cb71db2c5..323908302 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -58,19 +58,27 @@ export function SetupDrag(
return onItemDown;
}
+function moveLinkedDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean {
+ const document = SelectionManager.SelectedDocuments()[0];
+ document.props.removeDocument && document.props.removeDocument(doc);
+ addDocument(doc);
+ return true;
+}
+
export async function DragLinkAsDocument(dragEle: HTMLElement, x: number, y: number, linkDoc: Doc, sourceDoc: Doc) {
let draggeddoc = LinkManager.Instance.getOppositeAnchor(linkDoc, sourceDoc);
-
- let moddrag = await Cast(draggeddoc.annotationOn, Doc);
- let dragdocs = moddrag ? [moddrag] : [draggeddoc];
- let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs);
- dragData.dropAction = "alias" as dropActionType;
- DragManager.StartLinkedDocumentDrag([dragEle], sourceDoc, dragData, x, y, {
- handlers: {
- dragComplete: action(emptyFunction),
- },
- hideSource: false
- });
+ if (draggeddoc) {
+ let moddrag = await Cast(draggeddoc.annotationOn, Doc);
+ let dragdocs = moddrag ? [moddrag] : [draggeddoc];
+ let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs);
+ dragData.moveDocument = moveLinkedDocument;
+ DragManager.StartLinkedDocumentDrag([dragEle], dragData, x, y, {
+ handlers: {
+ dragComplete: action(emptyFunction),
+ },
+ hideSource: false
+ });
+ }
}
export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) {
@@ -81,8 +89,9 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n
let linkDocs = LinkManager.Instance.getAllRelatedLinks(srcTarg);
if (linkDocs) {
draggedDocs = linkDocs.map(link => {
- return LinkManager.Instance.getOppositeAnchor(link, sourceDoc);
- });
+ let opp = LinkManager.Instance.getOppositeAnchor(link, sourceDoc);
+ if (opp) return opp;
+ }) as Doc[];
}
}
if (draggedDocs.length) {
@@ -93,7 +102,8 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n
}
let dragdocs = moddrag.length ? moddrag : draggedDocs;
let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs);
- DragManager.StartLinkedDocumentDrag([dragEle], sourceDoc, dragData, x, y, {
+ dragData.moveDocument = moveLinkedDocument;
+ DragManager.StartLinkedDocumentDrag([dragEle], dragData, x, y, {
handlers: {
dragComplete: action(emptyFunction),
},
@@ -102,6 +112,7 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n
}
}
+
export namespace DragManager {
export function Root() {
const root = document.getElementById("root");
@@ -227,15 +238,14 @@ export namespace DragManager {
});
}
- export function StartLinkedDocumentDrag(eles: HTMLElement[], sourceDoc: Doc, dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) {
+ export function StartLinkedDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) {
+ dragData.moveDocument = moveLinkedDocument;
runInAction(() => StartDragFunctions.map(func => func()));
StartDrag(eles, dragData, downX, downY, options,
(dropData: { [id: string]: any }) => {
- // dropData.droppedDocuments =
let droppedDocuments: Doc[] = dragData.draggedDocuments.reduce((droppedDocs: Doc[], d) => {
let dvs = DocumentManager.Instance.getDocumentViews(d);
-
if (dvs.length) {
let inContext = dvs.filter(dv => dv.props.ContainingCollectionView === SelectionManager.SelectedDocuments()[0].props.ContainingCollectionView);
if (inContext.length) {
diff --git a/src/client/util/History.ts b/src/client/util/History.ts
index 545ea8629..e9ff21b22 100644
--- a/src/client/util/History.ts
+++ b/src/client/util/History.ts
@@ -2,6 +2,8 @@ import { Doc, Opt, Field } from "../../new_fields/Doc";
import { DocServer } from "../DocServer";
import { RouteStore } from "../../server/RouteStore";
import { MainView } from "../views/MainView";
+import * as qs from 'query-string';
+import { Utils, OmitKeys } from "../../Utils";
export namespace HistoryUtil {
export interface DocInitializerList {
@@ -11,9 +13,11 @@ export namespace HistoryUtil {
export interface DocUrl {
type: "doc";
docId: string;
- initializers: {
+ initializers?: {
[docId: string]: DocInitializerList;
};
+ readonly?: boolean;
+ nro?: boolean;
}
export type ParsedUrl = DocUrl;
@@ -21,7 +25,7 @@ export namespace HistoryUtil {
// const handlers: ((state: ParsedUrl | null) => void)[] = [];
function onHistory(e: PopStateEvent) {
if (window.location.pathname !== RouteStore.home) {
- const url = e.state as ParsedUrl || parseUrl(window.location.pathname);
+ const url = e.state as ParsedUrl || parseUrl(window.location);
if (url) {
switch (url.type) {
case "doc":
@@ -62,42 +66,111 @@ export namespace HistoryUtil {
// }
// }
- export function parseUrl(pathname: string): ParsedUrl | undefined {
- let pathnameSplit = pathname.split("/");
- if (pathnameSplit.length !== 2) {
- return undefined;
+ const parsers: { [type: string]: (pathname: string[], opts: qs.ParsedQuery) => ParsedUrl | undefined } = {};
+ const stringifiers: { [type: string]: (state: ParsedUrl) => string } = {};
+
+ type ParserValue = true | "none" | "json" | ((value: string) => any);
+
+ type Parser = {
+ [key: string]: ParserValue
+ };
+
+ function addParser(type: string, requiredFields: Parser, optionalFields: Parser, customParser?: (pathname: string[], opts: qs.ParsedQuery, current: ParsedUrl) => ParsedUrl | null | undefined) {
+ function parse(parser: ParserValue, value: string | string[] | null | undefined) {
+ if (value === undefined || value === null) {
+ return value;
+ }
+ if (Array.isArray(value)) {
+ } else if (parser === true || parser === "json") {
+ value = JSON.parse(value);
+ } else if (parser === "none") {
+ } else {
+ value = parser(value);
+ }
+ return value;
}
- const type = pathnameSplit[0];
- const data = pathnameSplit[1];
+ parsers[type] = (pathname, opts) => {
+ const current: any = { type };
+ for (const required in requiredFields) {
+ if (!(required in opts)) {
+ return undefined;
+ }
+ const parser = requiredFields[required];
+ let value = opts[required];
+ value = parse(parser, value);
+ if (value !== null && value !== undefined) {
+ current[required] = value;
+ }
+ }
+ for (const opt in optionalFields) {
+ if (!(opt in opts)) {
+ continue;
+ }
+ const parser = optionalFields[opt];
+ let value = opts[opt];
+ value = parse(parser, value);
+ if (value !== undefined) {
+ current[opt] = value;
+ }
+ }
+ if (customParser) {
+ const val = customParser(pathname, opts, current);
+ if (val === null) {
+ return undefined;
+ } else if (val === undefined) {
+ return current;
+ } else {
+ return val;
+ }
+ }
+ return current;
+ };
+ }
- if (type === "doc") {
- const s = data.split("?");
- if (s.length < 1 || s.length > 2) {
- return undefined;
+ function addStringifier(type: string, keys: string[], customStringifier?: (state: ParsedUrl, current: string) => string) {
+ stringifiers[type] = state => {
+ let path = Utils.prepend(`/${type}`);
+ if (customStringifier) {
+ path = customStringifier(state, path);
}
- const docId = s[0];
- const initializers = s.length === 2 ? JSON.parse(decodeURIComponent(s[1])) : {};
- return {
- type: "doc",
- docId,
- initializers
- };
+ const queryObj = OmitKeys(state, keys).extract;
+ const query: any = {};
+ Object.keys(queryObj).forEach(key => query[key] = queryObj[key] === null ? null : JSON.stringify(queryObj[key]));
+ const queryString = qs.stringify(query);
+ return path + (queryString ? `?${queryString}` : "");
+ };
+ }
+
+ addParser("doc", {}, { readonly: true, initializers: true, nro: true }, (pathname, opts, current) => {
+ if (pathname.length !== 2) return undefined;
+
+ current.initializers = current.initializers || {};
+ const docId = pathname[1];
+ current.docId = docId;
+ });
+ addStringifier("doc", ["initializers", "readonly", "nro"], (state, current) => {
+ return `${current}/${state.docId}`;
+ });
+
+
+ export function parseUrl(location: Location | URL): ParsedUrl | undefined {
+ const pathname = location.pathname.substring(1);
+ const search = location.search;
+ const opts = qs.parse(search, { sort: false });
+ let pathnameSplit = pathname.split("/");
+
+ const type = pathnameSplit[0];
+
+ if (type in parsers) {
+ return parsers[type](pathnameSplit, opts);
}
return undefined;
}
export function createUrl(params: ParsedUrl): string {
- let baseUrl = DocServer.prepend(`/${params.type}`);
- switch (params.type) {
- case "doc":
- const initializers = encodeURIComponent(JSON.stringify(params.initializers));
- const id = params.docId;
- let url = baseUrl + `/${id}`;
- if (Object.keys(params.initializers).length) {
- url += `?${initializers}`;
- }
- return url;
+ if (params.type in stringifiers) {
+ return stringifiers[params.type](params);
}
return "";
}
@@ -112,7 +185,10 @@ export namespace HistoryUtil {
async function onDocUrl(url: DocUrl) {
const field = await DocServer.GetRefField(url.docId);
- await Promise.all(Object.keys(url.initializers).map(id => initDoc(id, url.initializers[id])));
+ const init = url.initializers;
+ if (init) {
+ await Promise.all(Object.keys(init).map(id => initDoc(id, init[id])));
+ }
if (field instanceof Doc) {
MainView.Instance.openWorkspace(field, true);
}
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index ce95ba90e..75b0b52a7 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx
@@ -8,7 +8,7 @@ import { FieldViewProps, FieldView } from "../../views/nodes/FieldView";
import Measure, { ContentRect } from "react-measure";
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faArrowUp, faTag, faPlus } from '@fortawesome/free-solid-svg-icons';
+import { faTag, faPlus, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons';
import { Docs, DocumentOptions } from "../../documents/Documents";
import { observer } from "mobx-react";
import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from "./ImportMetadataEntry";
@@ -40,7 +40,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
constructor(props: FieldViewProps) {
super(props);
- library.add(faArrowUp, faTag, faPlus);
+ library.add(faTag, faPlus);
let doc = this.props.Document;
this.editingMetadata = this.editingMetadata || false;
this.persistent = this.persistent || false;
@@ -98,12 +98,12 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
runInAction(() => this.remaining++);
- let prom = fetch(DocServer.prepend(RouteStore.upload), {
+ let prom = fetch(Utils.prepend(RouteStore.upload), {
method: 'POST',
body: formData
}).then(async (res: Response) => {
(await res.json()).map(action((file: any) => {
- let docPromise = Docs.getDocumentFromType(type, DocServer.prepend(file), { nativeWidth: 300, width: 300, title: dropFileName });
+ let docPromise = Docs.Get.DocumentFromType(type, Utils.prepend(file), { nativeWidth: 300, width: 300, title: dropFileName });
docPromise.then(doc => {
doc && docs.push(doc) && runInAction(() => this.remaining--);
});
@@ -136,7 +136,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
};
let parent = this.props.ContainingCollectionView;
if (parent) {
- let importContainer = Docs.StackingDocument(docs, options);
+ let importContainer = Docs.Create.StackingDocument(docs, options);
importContainer.singleColumn = false;
Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer);
!this.persistent && this.props.removeDocument && this.props.removeDocument(doc);
@@ -237,12 +237,12 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
}} />
<div style={{
position: "absolute",
- left: this.left + 12.6,
- top: this.top + 11,
+ left: this.left + 8,
+ top: this.top + 10,
opacity: uploading ? 0 : 1,
transition: "0.4s opacity ease"
}}>
- <FontAwesomeIcon icon={faArrowUp} color="#FFFFFF" size={"2x"} />
+ <FontAwesomeIcon icon={faCloudUploadAlt} color="#FFFFFF" size={"2x"} />
</div>
<img
style={{
@@ -318,7 +318,7 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
opacity: uploading ? 0 : 1,
transition: "0.4s opacity ease"
}}
- icon={isEditing ? faArrowUp : faTag}
+ icon={isEditing ? faCloudUploadAlt : faTag}
color="#FFFFFF"
size={"1x"}
/>
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 944bc532f..a647f22c1 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -5,6 +5,7 @@ import { listSpec } from "../../new_fields/Schema";
import { List } from "../../new_fields/List";
import { Id } from "../../new_fields/FieldSymbols";
import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { Docs } from "../documents/Documents";
/*
@@ -35,7 +36,9 @@ export class LinkManager {
// the linkmanagerdoc stores a list of docs representing all linkdocs in 'allLinks' and a list of strings representing all group types in 'allGroupTypes'
// lists of strings representing the metadata keys for each group type is stored under a key that is the same as the group type
public get LinkManagerDoc(): Doc | undefined {
- return FieldValue(Cast(CurrentUserUtils.UserDocument.linkManagerDoc, Doc));
+ // return FieldValue(Cast(CurrentUserUtils.UserDocument.linkManagerDoc, Doc));
+
+ return Docs.Prototypes.MainLinkDocument();
}
public getAllLinks(): Doc[] {
@@ -232,11 +235,11 @@ export class LinkManager {
// finds the opposite anchor of a given anchor in a link
//TODO This should probably return undefined if there isn't an opposite anchor
//TODO This should also await the return value of the anchor so we don't filter out promises
- public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc {
+ public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) {
- return Cast(linkDoc.anchor2, Doc, null)!;
+ return Cast(linkDoc.anchor2, Doc, null);
} else {
- return Cast(linkDoc.anchor1, Doc, null)!;
+ return Cast(linkDoc.anchor1, Doc, null);
}
}
} \ No newline at end of file
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index a2842ca42..ce9e29b26 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -215,12 +215,13 @@ export const marks: { [index: string]: MarkSpec } = {
link: {
attrs: {
href: {},
+ location: { default: null },
title: { default: null }
},
inclusive: false,
parseDOM: [{
tag: "a[href]", getAttrs(dom: any) {
- return { href: dom.getAttribute("href"), title: dom.getAttribute("title") };
+ return { href: dom.getAttribute("href"), location: dom.getAttribute("location"), title: dom.getAttribute("title") };
}
}],
toDOM(node: any) { return ["a", node.attrs, 0]; }
@@ -409,6 +410,20 @@ export const marks: { [index: string]: MarkSpec } = {
}]
},
+ p18: {
+ parseDOM: [{ style: 'font-size: 18px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 18px;'
+ }]
+ },
+
+ p20: {
+ parseDOM: [{ style: 'font-size: 20px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 20px;'
+ }]
+ },
+
p24: {
parseDOM: [{ style: 'font-size: 24px;' }],
toDOM: () => ['span', {
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 3156c4f43..46dc320b0 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -1,5 +1,7 @@
-// import * as ts from "typescript"
-let ts = (window as any).ts;
+import * as ts from "typescript";
+export { ts };
+// export const ts = (window as any).ts;
+
// // @ts-ignore
// import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts'
// // @ts-ignore
@@ -33,6 +35,8 @@ export interface CompileError {
errors: any[];
}
+export type CompileResult = CompiledScript | CompileError;
+
export namespace Scripting {
export function addGlobal(global: { name: string }): void;
export function addGlobal(name: string, global: any): void;
@@ -53,15 +57,36 @@ export namespace Scripting {
}
scriptingGlobals[n] = obj;
}
+
+ export function makeMutableGlobalsCopy(globals?: { [name: string]: any }) {
+ return { ..._scriptingGlobals, ...(globals || {}) };
+ }
+
+ export function setScriptingGlobals(globals: { [key: string]: any }) {
+ scriptingGlobals = globals;
+ }
+
+ export function resetScriptingGlobals() {
+ scriptingGlobals = _scriptingGlobals;
+ }
+
+ // const types = Object.keys(ts.SyntaxKind).map(kind => ts.SyntaxKind[kind]);
+ export function printNodeType(node: any, indentation = "") {
+ console.log(indentation + ts.SyntaxKind[node.kind]);
+ }
+
+ export function getGlobals() {
+ return Object.keys(scriptingGlobals);
+ }
}
export function scriptingGlobal(constructor: { new(...args: any[]): any }) {
Scripting.addGlobal(constructor);
}
-const scriptingGlobals: { [name: string]: any } = {};
+const _scriptingGlobals: { [name: string]: any } = {};
+let scriptingGlobals: { [name: string]: any } = _scriptingGlobals;
-export type CompileResult = CompiledScript | CompileError;
function Run(script: string | undefined, customParams: string[], diagnostics: any[], originalScript: string, options: ScriptOptions): CompileResult {
const errors = diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error);
if ((options.typecheck !== false && errors) || !script) {
@@ -161,6 +186,8 @@ class ScriptingCompilerHost {
}
}
+export type Traverser = (node: ts.Node, indentation: string) => boolean | void;
+export type TraverserParam = Traverser | { onEnter: Traverser, onLeave: Traverser };
export interface ScriptOptions {
requiredType?: string;
addReturn?: boolean;
@@ -168,10 +195,23 @@ export interface ScriptOptions {
capturedVariables?: { [name: string]: Field };
typecheck?: boolean;
editable?: boolean;
+ traverser?: TraverserParam;
+ transformer?: ts.TransformerFactory<ts.SourceFile>;
+ globals?: { [name: string]: any };
+}
+
+// function forEachNode(node:ts.Node, fn:(node:any) => void);
+function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, indentation = "") {
+ return onEnter(node, indentation) || ts.forEachChild(node, (n: any) => {
+ forEachNode(n, onEnter, onExit, indentation + " ");
+ }) || (onExit && onExit(node, indentation));
}
export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult {
const { requiredType = "", addReturn = false, params = {}, capturedVariables = {}, typecheck = true } = options;
+ if (options.globals) {
+ Scripting.setScriptingGlobals(options.globals);
+ }
let host = new ScriptingCompilerHost;
let paramNames: string[] = [];
if ("this" in params || "this" in capturedVariables) {
@@ -191,10 +231,27 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
paramList.push(`${key}: ${capturedVariables[key].constructor.name}`);
}
let paramString = paramList.join(", ");
+ if (options.traverser) {
+ const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true);
+ const onEnter = typeof options.traverser === "object" ? options.traverser.onEnter : options.traverser;
+ const onLeave = typeof options.traverser === "object" ? options.traverser.onLeave : undefined;
+ forEachNode(sourceFile, onEnter, onLeave);
+ }
+ if (options.transformer) {
+ const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true);
+ const result = ts.transform(sourceFile, [options.transformer]);
+ const transformed = result.transformed;
+ const printer = ts.createPrinter({
+ newLine: ts.NewLineKind.LineFeed
+ });
+ script = printer.printFile(transformed[0]);
+ result.dispose();
+ }
let funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} {
${addReturn ? `return ${script};` : script}
})`;
host.writeFile("file.ts", funcScript);
+
if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib);
let program = ts.createProgram(["file.ts"], {}, host);
let testResult = program.emit();
@@ -202,7 +259,12 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics);
- return Run(outputText, paramNames, diagnostics, script, options);
+ const result = Run(outputText, paramNames, diagnostics, script, options);
+
+ if (options.globals) {
+ Scripting.resetScriptingGlobals();
+ }
+ return result;
}
Scripting.addGlobal(CompileScript); \ No newline at end of file
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index 338628960..ee5a83710 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -2,31 +2,44 @@ import * as rp from 'request-promise';
import { DocServer } from '../DocServer';
import { Doc } from '../../new_fields/Doc';
import { Id } from '../../new_fields/FieldSymbols';
+import { Utils } from '../../Utils';
export namespace SearchUtil {
+ export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
+
export interface IdSearchResult {
ids: string[];
numFound: number;
+ highlighting: HighlightingResult | undefined;
}
export interface DocSearchResult {
docs: Doc[];
numFound: number;
+ highlighting: HighlightingResult | undefined;
}
- export function Search(query: string, returnDocs: true): Promise<DocSearchResult>;
- export function Search(query: string, returnDocs: false): Promise<IdSearchResult>;
- export async function Search(query: string, returnDocs: boolean) {
- const result: IdSearchResult = JSON.parse(await rp.get(DocServer.prepend("/search"), {
- qs: { query }
+ export interface SearchParams {
+ hl?: boolean;
+ "hl.fl"?: string;
+ start?: number;
+ rows?: number;
+ fq?: string;
+ }
+ export function Search(query: string, returnDocs: true, options?: SearchParams): Promise<DocSearchResult>;
+ export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
+ 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 result: IdSearchResult = JSON.parse(await rp.get(Utils.prepend("/search"), {
+ qs: { ...options, q: query },
}));
if (!returnDocs) {
return result;
}
- const { ids, numFound } = result;
+ const { ids, numFound, highlighting } = result;
const docMap = await DocServer.GetRefFields(ids);
const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc);
- return { docs, numFound };
+ return { docs, numFound, highlighting };
}
export async function GetAliasesOfDocument(doc: Doc): Promise<Doc[]>;
@@ -35,31 +48,31 @@ export namespace SearchUtil {
const proto = Doc.GetProto(doc);
const protoId = proto[Id];
if (returnDocs) {
- return (await Search(`proto_i:"${protoId}"`, returnDocs)).docs;
+ return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"` })).docs;
} else {
- return (await Search(`proto_i:"${protoId}"`, returnDocs)).ids;
+ return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"` })).ids;
}
// return Search(`{!join from=id to=proto_i}id:${protoId}`, true);
}
export async function GetViewsOfDocument(doc: Doc): Promise<Doc[]> {
- const results = await Search(`proto_i:"${doc[Id]}"`, true);
+ const results = await Search("", true, { fq: `proto_i:"${doc[Id]}"` });
return results.docs;
}
export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[], aliasContexts: Doc[] }> {
- const docContexts = (await Search(`data_l:"${doc[Id]}"`, true)).docs;
+ const docContexts = (await Search("", true, { fq: `data_l:"${doc[Id]}"` })).docs;
const aliases = await GetAliasesOfDocument(doc, false);
- const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, true))));
+ const aliasContexts = (await Promise.all(aliases.map(doc => Search("", true, { fq: `data_l:"${doc}"` }))));
const contexts = { contexts: docContexts, aliasContexts: [] as Doc[] };
aliasContexts.forEach(result => contexts.aliasContexts.push(...result.docs));
return contexts;
}
export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[], aliasContexts: string[] }> {
- const docContexts = (await Search(`data_l:"${doc[Id]}"`, false)).ids;
+ const docContexts = (await Search("", false, { fq: `data_l:"${doc[Id]}"` })).ids;
const aliases = await GetAliasesOfDocument(doc, false);
- const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, false))));
+ const aliasContexts = (await Promise.all(aliases.map(doc => Search("", false, { fq: `data_l:"${doc}"` }))));
const contexts = { contexts: docContexts, aliasContexts: [] as string[] };
aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids));
return contexts;
diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts
index a7246d7c4..dca539f3b 100644
--- a/src/client/util/SerializationHelper.ts
+++ b/src/client/util/SerializationHelper.ts
@@ -1,5 +1,6 @@
import { PropSchema, serialize, deserialize, custom, setDefaultModelSchema, getDefaultModelSchema, primitive, SKIP } from "serializr";
import { Field } from "../../new_fields/Doc";
+import { ClientUtils } from "./ClientUtils";
export namespace SerializationHelper {
let serializing: number = 0;
@@ -9,7 +10,7 @@ export namespace SerializationHelper {
export function Serialize(obj: Field): any {
if (obj === undefined || obj === null) {
- return undefined;
+ return null;
}
if (typeof obj !== 'object') {
@@ -38,7 +39,12 @@ export namespace SerializationHelper {
serializing += 1;
if (!obj.__type) {
- throw Error("No property 'type' found in JSON.");
+ if (ClientUtils.RELEASE) {
+ console.warn("No property 'type' found in JSON.");
+ return undefined;
+ } else {
+ throw Error("No property 'type' found in JSON.");
+ }
}
if (!(obj.__type in serializationTypes)) {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 103157bbc..b3b7848e8 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -24,6 +24,7 @@ import { FormattedTextBoxProps, FormattedTextBox } from "../views/nodes/Formatte
import { typeAlias } from "babel-types";
import React from "react";
import ReactDOM from "react-dom";
+import { Utils } from "../../Utils";
//appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc.
export class TooltipTextMenu {
@@ -66,6 +67,7 @@ export class TooltipTextMenu {
this.tooltip.className = "tooltipMenu";
this.dragElement(this.tooltip);
+ this.dragElement(this.tooltip);
// this.createCollapse();
// if (this._collapseBtn) {
// this.tooltip.appendChild(this._collapseBtn.render(this.view).dom);
@@ -137,6 +139,8 @@ export class TooltipTextMenu {
this.fontSizeToNum.set(schema.marks.p12, 12);
this.fontSizeToNum.set(schema.marks.p14, 14);
this.fontSizeToNum.set(schema.marks.p16, 16);
+ this.fontSizeToNum.set(schema.marks.p18, 18);
+ this.fontSizeToNum.set(schema.marks.p20, 20);
this.fontSizeToNum.set(schema.marks.p24, 24);
this.fontSizeToNum.set(schema.marks.p32, 32);
this.fontSizeToNum.set(schema.marks.p48, 48);
@@ -152,6 +156,7 @@ export class TooltipTextMenu {
this.listTypes = Array.from(this.listTypeToIcon.keys());
//custom tools
+ // this.tooltip.appendChild(this.createLink().render(this.view).dom);
this._brushdom = this.createBrush().render(this.view).dom;
this.tooltip.appendChild(this._brushdom);
@@ -283,8 +288,8 @@ export class TooltipTextMenu {
let link = node && node.marks.find(m => m.type.name === "link");
if (link) {
let href: string = link.attrs.href;
- if (href.indexOf(DocServer.prepend("/doc/")) === 0) {
- let docid = href.replace(DocServer.prepend("/doc/"), "");
+ if (href.indexOf(Utils.prepend("/doc/")) === 0) {
+ let docid = href.replace(Utils.prepend("/doc/"), "");
DocServer.GetRefField(docid).then(action((f: Opt<Field>) => {
if (f instanceof Doc) {
if (DocumentManager.Instance.getDocumentView(f)) {
@@ -310,12 +315,21 @@ export class TooltipTextMenu {
this.linkDrag.onpointerdown = (e: PointerEvent) => {
let dragData = new DragManager.LinkDragData(this.editorProps.Document);
dragData.dontClearTextBox = true;
+ // hack to get source context -sy
+ let docView = DocumentManager.Instance.getDocumentView(this.editorProps.Document);
+ e.stopPropagation();
+ let ctrlKey = e.ctrlKey;
DragManager.StartLinkDrag(this.linkDrag!, dragData, e.clientX, e.clientY,
{
handlers: {
dragComplete: action(() => {
- let m = dragData.droppedDocuments;
- this.makeLink(DocServer.prepend("/doc/" + m[0][Id]));
+ // let m = dragData.droppedDocuments;
+ let linkDoc = dragData.linkDocument;
+ let proto = Doc.GetProto(linkDoc);
+ if (docView && docView.props.ContainingCollectionView) {
+ proto.sourceContext = docView.props.ContainingCollectionView.props.Document;
+ }
+ linkDoc instanceof Doc && this.makeLink(Utils.prepend("/doc/" + linkDoc[Id]), ctrlKey ? "onRight" : "inTab");
}),
},
hideSource: false
@@ -335,17 +349,17 @@ export class TooltipTextMenu {
this.linkText.onkeydown = (e: KeyboardEvent) => {
if (e.key === "Enter") {
- this.makeLink(this.linkText!.textContent!);
+ // this.makeLink(this.linkText!.textContent!);
e.stopPropagation();
e.preventDefault();
}
};
- this.tooltip.appendChild(this.linkEditor);
+ // this.tooltip.appendChild(this.linkEditor);
}
- makeLink = (target: string) => {
+ makeLink = (target: string, location: string) => {
let node = this.view.state.selection.$from.nodeAfter;
- let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target });
+ let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location });
this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link));
this.view.dispatch(this.view.state.tr.addMark(this.view.state.selection.from, this.view.state.selection.to, link));
node = this.view.state.selection.$from.nodeAfter;
@@ -586,7 +600,7 @@ export class TooltipTextMenu {
let node = state.doc.nodeAt(from);
node && node.marks.map(m => {
m.type === markType && (curLink = m.attrs.href);
- })
+ });
//toggleMark(markType)(state, dispatch);
//return true;
}
diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d
index 2cbe1dd40..1f95af00c 100644
--- a/src/client/util/type_decls.d
+++ b/src/client/util/type_decls.d
@@ -204,3 +204,5 @@ declare const Docs: {
TreeDocument(documents: Doc[], options?: DocumentOptions): Doc;
StackingDocument(documents: Doc[], options?: DocumentOptions): Doc;
};
+
+declare function d(...args:any[]):any;