From 8c801b3c98e1eaae297b0f1682b42fc478a1b887 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 14 Apr 2019 00:44:02 -0400 Subject: Got a basic version of search working --- src/client/SocketStub.ts | 2 +- src/fields/Document.ts | 6 +++--- src/server/Search.ts | 27 +++++++++++++++++++++++++++ src/server/ServerUtil.ts | 4 ++-- src/server/database.ts | 12 ++++++++++++ src/server/index.ts | 12 +++++++++++- 6 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 src/server/Search.ts (limited to 'src') diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index 5e2ca6a98..df5d12827 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -37,7 +37,7 @@ export class SocketStub { // document.fields.forEach((f, key) => (this.FieldStore.get(document.Id) as Document)._proxies.set(key.Id, (f as Field).Id)); console.log("sending " + document.Title); - Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())); + // Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())); } public static SEND_FIELD_REQUEST(fieldid: FieldId): Promise>; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 628fe684c..884e7374b 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -410,11 +410,11 @@ export class Document extends Field { return copy; } - ToJson(): { type: Types; data: [string, string][]; _id: string } { - let fields: [string, string][] = []; + ToJson(): { type: Types; data: { key: string, field: string }[]; _id: string } { + let fields: { key: string, field: string }[] = []; this._proxies.forEach((field, key) => { if (field) { - fields.push([key, field]); + fields.push({ key, field }); } }); diff --git a/src/server/Search.ts b/src/server/Search.ts new file mode 100644 index 000000000..f9babc433 --- /dev/null +++ b/src/server/Search.ts @@ -0,0 +1,27 @@ +import * as rp from 'request-promise'; +import { Database } from './database'; + +export class Search { + public static Instance = new Search(); + private url = 'http://localhost:8983/solr/'; + + public updateDocument(document: any): rp.RequestPromise { + return rp.post(this.url + "dash/update/json/docs", { + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(document) + }); + } + + public async search(query: string) { + const searchResults = JSON.parse(await rp.get(this.url + "dash/select", { + qs: { + q: query + } + })); + const fields = searchResults.response.docs; + const ids = fields.map((field: any) => field.id); + const docs = await Database.Instance.searchQuery(ids); + const docIds = docs.map((doc: any) => doc._id); + return docIds; + } +} \ No newline at end of file diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 0973f82b1..dc8687b7e 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -73,9 +73,9 @@ export class ServerUtils { return InkField.FromJson(id, data); case Types.Document: let doc: Document = new Document(id, false); - let fields: [string, string][] = data as [string, string][]; + let fields: { key: string, field: string }[] = data as { key: string, field: string }[]; fields.forEach(element => { - doc._proxies.set(element[0], element[1]); + doc._proxies.set(element.key, element.field); }); return doc; default: diff --git a/src/server/database.ts b/src/server/database.ts index 3290edde0..4011f26bd 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -71,6 +71,18 @@ export class Database { }); } + public searchQuery(ids: string[], collectionName = Database.DocumentsCollection): Promise { + return new Promise(resolve => { + this.db && this.db.collection(collectionName).find({ "data.field": { "$in": ids } }).toArray((err, docs) => { + if (err) { + console.log(err.message); + console.log(err.errmsg); + } + resolve(docs); + }); + }); + } + public print() { console.log("db says hi!"); } diff --git a/src/server/index.ts b/src/server/index.ts index a6fe6fa2c..fef26f78a 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -22,7 +22,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo import { DashUserModel } from './authentication/models/user_model'; import { Client } from './Client'; import { Database } from './database'; -import { MessageStore, Transferable } from "./Message"; +import { MessageStore, Transferable, Types } from "./Message"; import { RouteStore } from './RouteStore'; const app = express(); const config = require('../../webpack.config'); @@ -32,6 +32,7 @@ const serverPort = 4321; import expressFlash = require('express-flash'); import flash = require('connect-flash'); import c = require("crypto"); +import { Search } from './Search'; const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); @@ -118,6 +119,12 @@ app.get("/pull", (req, res) => // GETTERS +app.get("/search", async (req, res) => { + let query = req.query.query || "hello"; + let results = await Search.Instance.search(query); + res.send(results); +}); + // anyone attempting to navigate to localhost at this port will // first have to login addSecureRoute( @@ -258,6 +265,9 @@ function getFields([ids, callback]: [string[], (result: any) => void]) { function setField(socket: Socket, newValue: Transferable) { Database.Instance.update(newValue._id, newValue, () => socket.broadcast.emit(MessageStore.SetField.Message, newValue)); + if (newValue.type === Types.Text) { + Search.Instance.updateDocument({ id: newValue._id, data: (newValue as any).data }); + } } server.listen(serverPort); -- cgit v1.2.3-70-g09d2 From be1976fb0ba33064978ee973993b3a2316cdf43c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sun, 14 Apr 2019 01:02:25 -0400 Subject: deleting database now also clears Solr indexes --- src/server/Search.ts | 11 +++++++++++ src/server/index.ts | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/Search.ts b/src/server/Search.ts index f9babc433..7d8602346 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -24,4 +24,15 @@ export class Search { const docIds = docs.map((doc: any) => doc._id); return docIds; } + + public async clear() { + return rp.post(this.url + "dash/update", { + body: { + delete: { + query: "*:*" + } + }, + json: true + }); + } } \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index bea84c6ed..cb4268a2d 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -11,6 +11,7 @@ import { ObservableMap } from 'mobx'; import * as passport from 'passport'; import * as path from 'path'; import * as request from 'request'; +import * as rp from 'request-promise'; import * as io from 'socket.io'; import { Socket } from 'socket.io'; import * as webpack from 'webpack'; @@ -241,14 +242,16 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); }); -function deleteFields() { - return Database.Instance.deleteAll(); +async function deleteFields() { + await Database.Instance.deleteAll(); + await Search.Instance.clear(); } async function deleteAll() { await Database.Instance.deleteAll(); await Database.Instance.deleteAll('sessions'); await Database.Instance.deleteAll('users'); + await Search.Instance.clear(); } function barReceived(guid: String) { -- cgit v1.2.3-70-g09d2 From 04fd1451fb33bba806f9fe406d51c13d8d4dd541 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 16 Apr 2019 17:17:41 -0400 Subject: checking other search --- src/client/views/Main.scss | 39 ++++++++++++++++++++++++++++----------- src/client/views/Main.tsx | 3 +++ 2 files changed, 31 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 4373534b2..26284974a 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -1,5 +1,6 @@ @import "globalCssVariables"; @import "nodeModuleOverrides"; + html, body { width: 100%; @@ -7,9 +8,9 @@ body { overflow: auto; font-family: $sans-serif; margin: 0; - position:absolute; + position: absolute; top: 0; - left:0; + left: 0; } #dash-title { @@ -42,7 +43,7 @@ h1 { } .jsx-parser { - width:100% + width: 100% } p { @@ -80,6 +81,10 @@ button:hover { cursor: pointer; } +search { + background: $dark-color; +} + .clear-db-button { position: absolute; right: 45%; @@ -114,6 +119,7 @@ button:hover { position: absolute; bottom: 62px; left: 24px; + .toolbar-button { display: block; margin-bottom: 10px; @@ -125,6 +131,7 @@ button:hover { position: absolute; bottom: 24px; left: 24px; + label { background: $dark-color; color: $light-color; @@ -137,44 +144,53 @@ button:hover { cursor: pointer; transition: transform 0.2s; } + label p { padding-left: 10.5px; padding-top: 3px; } + label:hover { background: $main-accent; transform: scale(1.15); } + input { display: none; } + input:not(:checked)~#add-options-content { display: none; } + input:checked~label { transform: rotate(45deg); transition: transform 0.5s; cursor: pointer; } } + #root { overflow: visible; } + #main-div { - width:100%; - height:100%; - position:absolute; + width: 100%; + height: 100%; + position: absolute; top: 0; - left:0; + left: 0; overflow: scroll; } + #mainContent-div { - width:100%; - height:100%; - position:absolute; + width: 100%; + height: 100%; + position: absolute; top: 0; - left:0; + left: 0; } + #add-options-content { display: table; opacity: 1; @@ -189,6 +205,7 @@ button:hover { ul#add-options-list { list-style: none; padding: 0; + li { display: inline-block; padding: 0; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 0469211fa..7d47c9932 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -262,6 +262,9 @@ export class Main extends React.Component { ,
, + +
hello
, +
]; -- cgit v1.2.3-70-g09d2 From 2181bc0f19b04a5c1a3e6e20206fc04a086995d2 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 16 Apr 2019 17:28:56 -0400 Subject: attempting graphics --- src/client/views/Main.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 7d47c9932..92c7fa7dd 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -263,7 +263,7 @@ export class Main extends React.Component {
, -
hello
, +
,
-- cgit v1.2.3-70-g09d2 From 94fa065ae2a0f3ccb6a16141a45f11543add3b63 Mon Sep 17 00:00:00 2001 From: ab Date: Mon, 22 Apr 2019 19:56:49 -0400 Subject: exploratory sprint --- src/server/Search.ts | 1 + src/server/index.ts | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/server/Search.ts b/src/server/Search.ts index 7d8602346..bcea03d5c 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -6,6 +6,7 @@ export class Search { private url = 'http://localhost:8983/solr/'; public updateDocument(document: any): rp.RequestPromise { + console.log(JSON.stringify(document)); return rp.post(this.url + "dash/update/json/docs", { headers: { 'content-type': 'application/json' }, body: JSON.stringify(document) diff --git a/src/server/index.ts b/src/server/index.ts index a68dabc0c..b3df90199 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -34,6 +34,7 @@ import expressFlash = require('express-flash'); import flash = require('connect-flash'); import c = require("crypto"); import { Search } from './Search'; +import { debug } from 'util'; const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); @@ -276,6 +277,7 @@ function setField(socket: Socket, newValue: Transferable) { socket.broadcast.emit(MessageStore.SetField.Message, newValue)); if (newValue.type === Types.Text) { Search.Instance.updateDocument({ id: newValue.id, data: (newValue as any).data }); + console.log("set field"); } } @@ -286,10 +288,17 @@ function GetRefField([id, callback]: [string, (result?: Transferable) => void]) function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); + //if (diff.diff === Types.Text) { + Search.Instance.updateDocument({ name: "john", burns: "true" }); + Search.Instance.updateDocument({ id: diff.id, data: diff.diff.data }); + //console.log("set field"); + //} + console.log("updated field", diff.diff); } function CreateField(newValue: any) { Database.Instance.insert(newValue, "newDocuments"); + console.log("created field"); } server.listen(serverPort); -- cgit v1.2.3-70-g09d2 From 85ce4c9a3cd665983067d7783e20eb7701376503 Mon Sep 17 00:00:00 2001 From: ab Date: Tue, 23 Apr 2019 19:00:15 -0400 Subject: idk --- src/server/index.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/index.ts b/src/server/index.ts index b3df90199..464d3f68f 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -35,6 +35,7 @@ import flash = require('connect-flash'); import c = require("crypto"); import { Search } from './Search'; import { debug } from 'util'; +import _ = require('lodash'); const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); @@ -289,11 +290,32 @@ function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); //if (diff.diff === Types.Text) { - Search.Instance.updateDocument({ name: "john", burns: "true" }); - Search.Instance.updateDocument({ id: diff.id, data: diff.diff.data }); + //Search.Instance.updateDocument({ name: "john", burns: "true" }); + //Search.Instance.updateDocument({ id: diff.id, data: diff.diff.data }); //console.log("set field"); //} - console.log("updated field", diff.diff); + const docid = { id: diff.id }; + const docfield = diff.diff; + console.log("FIELD: ", docfield); + var dynfield = false; + for (var key in docfield) { + const val = docfield[key]; + if (typeof val === 'number') { + key = key + "_n"; + dynfield = true; + } + else if (typeof val === 'string') { + key = key + "_t"; + dynfield = true; + } + console.log(key); + } + var merged = {}; + _.extend(merged, docid, docfield); + if (dynfield) { + console.log("dynamic field detected!"); + Search.Instance.updateDocument(merged); + } } function CreateField(newValue: any) { -- cgit v1.2.3-70-g09d2 From 39bb878a32821d2e14110f4158471890234f4769 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Mon, 29 Apr 2019 19:52:35 -0400 Subject: search UI --- src/client/views/Main.scss | 4 -- src/client/views/Main.tsx | 5 ++- src/client/views/SearchBox.scss | 64 +++++++++++++++++++++++++++++ src/client/views/SearchBox.tsx | 89 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 src/client/views/SearchBox.scss create mode 100644 src/client/views/SearchBox.tsx (limited to 'src') diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 26284974a..bca75da47 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -81,10 +81,6 @@ button:hover { cursor: pointer; } -search { - background: $dark-color; -} - .clear-db-button { position: absolute; right: 45%; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 92c7fa7dd..87eefe67f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -38,6 +38,7 @@ import "./Main.scss"; import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; +import { SearchBox } from './SearchBox'; @observer @@ -263,9 +264,9 @@ export class Main extends React.Component {
, -
, +
, -
+
]; } diff --git a/src/client/views/SearchBox.scss b/src/client/views/SearchBox.scss new file mode 100644 index 000000000..e1a1de142 --- /dev/null +++ b/src/client/views/SearchBox.scss @@ -0,0 +1,64 @@ +@import "globalCssVariables"; + +.searchBox { + height: 32px; + //display: flex; + //padding: 4px; + -webkit-transition: width 0.4s ease-in-out; + transition: width 0.4s ease-in-out; + align-items: center; + + .submit-search { + display: inline-block; + text-align: right; + color: $dark-color; + -webkit-transition: right 0.4s; + transition: right 0.4s; + } + + .submit-search:hover { + color: $main-accent; + transform: scale(1.05); + cursor: pointer; + } + + input[type=text] { + width: 130px; + -webkit-transition: width 0.4s; + transition: width 0.4s; + position: absolute; + right: 100px; + } + + input[type=text]:focus { + width: 500px; + outline: 3px solid lightblue; + } + + .filter-button { + position: absolute; + right: 30px; + } +} + +.filter-form { + background: $dark-color; + height: 400px; + width: 400px; + position: relative; + right: 1px; + color: $light-color; + padding: 10px; + flex-direction: column; +} + +#header { + text-transform: uppercase; + letter-spacing: 2px; + font-size: 100%; + height: 40px; +} + +#option { + height: 20px; +} \ No newline at end of file diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx new file mode 100644 index 000000000..7f388719d --- /dev/null +++ b/src/client/views/SearchBox.tsx @@ -0,0 +1,89 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { observable, action } from 'mobx'; +import { Utils } from '../../Utils'; +import { MessageStore } from '../../server/Message'; +import { Server } from '../Server'; +import "./SearchBox.scss"; +import { faSearch } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { actionFieldDecorator } from 'mobx/lib/internal'; + +library.add(faSearch); + +@observer +export class SearchBox extends React.Component { + @observable + searchString: string = ""; + + @observable private _open: boolean = false; + + @action.bound + onChange(e: React.ChangeEvent) { + this.searchString = e.target.value; + + } + + submitSearch = () => { + Utils.EmitCallback(Server.Socket, MessageStore.SearchFor, this.searchString, (results: string[]) => { + for (const result of results) { + console.log(result); + Utils.GetQueryVariable() + } + }); + } + + @action + handleClick = (e: Event): void => { + var className = (e.target as any).className; + var id = (e.target as any).id; + console.log(id); + //let imgPrev = document.getElementById("img_preview"); + console.log(className); + if (className !== "filter-button" && className !== "filter-form") { + console.log("false"); + this._open = false; + } + + } + + componentWillMount() { + document.addEventListener('mousedown', this.handleClick, false); + } + + componentWillUnmount() { + document.removeEventListener('mousedown', this.handleClick, false); + } + + @action + toggleDisplay = () => { + this._open = !this._open; + } + + render() { + return ( +
+
+ {/* + +
+
+
+ +
+ filter by collection, key, type of node +
+ +
+
+ + ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From df9fa3e362a6bdd616bc0b46ef9b425cfc5a010d Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 30 Apr 2019 16:17:39 -0400 Subject: before pull --- src/client/views/SearchBox.scss | 1 - src/fields/Document.ts | 15 +++++++-------- src/server/Search.ts | 38 ++++++++++++++++++++++++++++++++++++++ src/server/database.ts | 12 ++++++++++++ src/server/index.ts | 19 ++++++++++++++++--- 5 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 src/server/Search.ts (limited to 'src') diff --git a/src/client/views/SearchBox.scss b/src/client/views/SearchBox.scss index e1a1de142..92363e681 100644 --- a/src/client/views/SearchBox.scss +++ b/src/client/views/SearchBox.scss @@ -9,7 +9,6 @@ align-items: center; .submit-search { - display: inline-block; text-align: right; color: $dark-color; -webkit-transition: right 0.4s; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 2797efc09..6f6533754 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -29,15 +29,14 @@ export class Document extends Field { } static FromJson(data: any, id: string, save: boolean): Document { let doc = new Document(id, save); - let fields = data as [string, string][]; - fields.forEach(pair => doc._proxies.set(pair[0], pair[1])); + let fields = data as { key: string, field: string }[]; + fields.forEach(pair => doc._proxies.set(pair.key, pair.field)); return doc; } - UpdateFromServer(data: [string, string][]) { - for (const key in data) { - const element = data[key]; - this._proxies.set(element[0], element[1]); + UpdateFromServer(data: { key: string, field: string }[]) { + for (const kv of data) { + this._proxies.set(kv.key, kv.field); } } @@ -448,9 +447,9 @@ export class Document extends Field { } ToJson() { - let fields: [string, string][] = []; + let fields: { key: string, field: string }[] = []; this._proxies.forEach((field, key) => - field && fields.push([key, field])); + field && fields.push({ key, field })); return { type: Types.Document, diff --git a/src/server/Search.ts b/src/server/Search.ts new file mode 100644 index 000000000..7d8602346 --- /dev/null +++ b/src/server/Search.ts @@ -0,0 +1,38 @@ +import * as rp from 'request-promise'; +import { Database } from './database'; + +export class Search { + public static Instance = new Search(); + private url = 'http://localhost:8983/solr/'; + + public updateDocument(document: any): rp.RequestPromise { + return rp.post(this.url + "dash/update/json/docs", { + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(document) + }); + } + + public async search(query: string) { + const searchResults = JSON.parse(await rp.get(this.url + "dash/select", { + qs: { + q: query + } + })); + const fields = searchResults.response.docs; + const ids = fields.map((field: any) => field.id); + const docs = await Database.Instance.searchQuery(ids); + const docIds = docs.map((doc: any) => doc._id); + return docIds; + } + + public async clear() { + return rp.post(this.url + "dash/update", { + body: { + delete: { + query: "*:*" + } + }, + json: true + }); + } +} \ No newline at end of file diff --git a/src/server/database.ts b/src/server/database.ts index 5457e4dd5..d5905c7b3 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -72,6 +72,18 @@ export class Database { }); } + public searchQuery(ids: string[], collectionName = Database.DocumentsCollection): Promise { + return new Promise(resolve => { + this.db && this.db.collection(collectionName).find({ "data.field": { "$in": ids } }).toArray((err, docs) => { + if (err) { + console.log(err.message); + console.log(err.errmsg); + } + resolve(docs); + }); + }); + } + public print() { console.log("db says hi!"); } diff --git a/src/server/index.ts b/src/server/index.ts index 70a7d266c..cb4268a2d 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -11,6 +11,7 @@ import { ObservableMap } from 'mobx'; import * as passport from 'passport'; import * as path from 'path'; import * as request from 'request'; +import * as rp from 'request-promise'; import * as io from 'socket.io'; import { Socket } from 'socket.io'; import * as webpack from 'webpack'; @@ -22,7 +23,7 @@ import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLo import { DashUserModel } from './authentication/models/user_model'; import { Client } from './Client'; import { Database } from './database'; -import { MessageStore, Transferable } from "./Message"; +import { MessageStore, Transferable, Types } from "./Message"; import { RouteStore } from './RouteStore'; const app = express(); const config = require('../../webpack.config'); @@ -32,6 +33,7 @@ const serverPort = 4321; import expressFlash = require('express-flash'); import flash = require('connect-flash'); import c = require("crypto"); +import { Search } from './Search'; const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); @@ -120,6 +122,12 @@ app.get("/pull", (req, res) => // GETTERS +app.get("/search", async (req, res) => { + let query = req.query.query || "hello"; + let results = await Search.Instance.search(query); + res.send(results); +}); + // anyone attempting to navigate to localhost at this port will // first have to login addSecureRoute( @@ -234,14 +242,16 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); }); -function deleteFields() { - return Database.Instance.deleteAll(); +async function deleteFields() { + await Database.Instance.deleteAll(); + await Search.Instance.clear(); } async function deleteAll() { await Database.Instance.deleteAll(); await Database.Instance.deleteAll('sessions'); await Database.Instance.deleteAll('users'); + await Search.Instance.clear(); } function barReceived(guid: String) { @@ -260,6 +270,9 @@ function getFields([ids, callback]: [string[], (result: Transferable[]) => void] function setField(socket: Socket, newValue: Transferable) { Database.Instance.update(newValue.id, newValue, () => socket.broadcast.emit(MessageStore.SetField.Message, newValue)); + if (newValue.type === Types.Text) { + Search.Instance.updateDocument({ id: newValue.id, data: (newValue as any).data }); + } } server.listen(serverPort); -- cgit v1.2.3-70-g09d2 From da792d534024d8e0d266e291f92b9a1e83be51c2 Mon Sep 17 00:00:00 2001 From: ab Date: Tue, 30 Apr 2019 18:38:05 -0400 Subject: set not working --- src/debug/Test.tsx | 50 +++++++++++++++++++++++++------------------------- src/server/index.ts | 14 ++++++++++---- 2 files changed, 35 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 6a677f80f..47cfac2c1 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -46,34 +46,34 @@ class Test extends React.Component { doc.fields = "test"; doc.test = "hello doc"; doc.url = url; - doc.testDoc = doc2; + //doc.testDoc = doc2; - const test1: TestDoc = TestDoc(doc); - const test2: Test2Doc = Test2Doc(doc); - assert(test1.hello === 5); - assert(test1.fields === undefined); - assert(test1.test === "hello doc"); - assert(test1.url === url); - assert(test1.testDoc === doc2); - test1.myField = 20; - assert(test1.myField === 20); + // const test1: TestDoc = TestDoc(doc); + // const test2: Test2Doc = Test2Doc(doc); + // assert(test1.hello === 5); + // assert(test1.fields === undefined); + // assert(test1.test === "hello doc"); + // assert(test1.url === url); + // //assert(test1.testDoc === doc2); + // test1.myField = 20; + // assert(test1.myField === 20); - assert(test2.hello === undefined); - // assert(test2.fields === "test"); - assert(test2.test === undefined); - assert(test2.url === undefined); - assert(test2.testDoc === undefined); - test2.url = 35; - assert(test2.url === 35); - const l = new List(); - //TODO push, and other array functions don't go through the proxy - l.push(1); - //TODO currently length, and any other string fields will get serialized - l.length = 3; - l[2] = 5; - console.log(l.slice()); - console.log(SerializationHelper.Serialize(l)); + // assert(test2.hello === undefined); + // // assert(test2.fields === "test"); + // assert(test2.test === undefined); + // assert(test2.url === undefined); + // assert(test2.testDoc === undefined); + // test2.url = 35; + // assert(test2.url === 35); + // const l = new List(); + // //TODO push, and other array functions don't go through the proxy + // l.push(1); + // //TODO currently length, and any other string fields will get serialized + // l.length = 3; + // l[2] = 5; + // console.log(l.slice()); + // console.log(SerializationHelper.Serialize(l)); } render() { diff --git a/src/server/index.ts b/src/server/index.ts index 464d3f68f..b57e5c482 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -295,23 +295,29 @@ function UpdateField(socket: Socket, diff: Diff) { //console.log("set field"); //} const docid = { id: diff.id }; - const docfield = diff.diff; + var docfield = diff.diff; + docfield = JSON.parse(JSON.stringify(docfield).split("fields.").join("")); console.log("FIELD: ", docfield); var dynfield = false; for (var key in docfield) { const val = docfield[key]; if (typeof val === 'number') { - key = key + "_n"; + const new_key: string = key + "_n"; + docfield = JSON.parse(JSON.stringify(docfield).split(key).join(new_key)); + //docfield[new_key] = { 'set': val }; dynfield = true; } else if (typeof val === 'string') { - key = key + "_t"; + const new_key: string = key + "_t"; + docfield = JSON.parse(JSON.stringify(docfield).split(key).join(new_key)); + docfield[new_key] = { 'set': val }; dynfield = true; } - console.log(key); } var merged = {}; _.extend(merged, docid, docfield); + console.log(merged); + console.log(docfield); if (dynfield) { console.log("dynamic field detected!"); Search.Instance.updateDocument(merged); -- cgit v1.2.3-70-g09d2 From b269ce7d85a9b83280d2b5b23299aa16e6cc5a92 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 30 Apr 2019 19:59:38 -0400 Subject: confused but still goin --- src/client/views/SearchBox.tsx | 2 +- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 7f388719d..7ceaf1da6 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -29,7 +29,7 @@ export class SearchBox extends React.Component { Utils.EmitCallback(Server.Socket, MessageStore.SearchFor, this.searchString, (results: string[]) => { for (const result of results) { console.log(result); - Utils.GetQueryVariable() + //Utils.GetQueryVariable(); } }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8647ded8a..08c28e76f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -48,9 +48,13 @@ export class CollectionFreeFormView extends CollectionSubView { this.addDocument(newBox, false); } - public addDocument = (newBox: Document, allowDuplicates: boolean) => this.props.addDocument(this.bringToFront(newBox), false); + public addDocument = (newBox: Document, allowDuplicates: boolean) => { + this.props.addDocument(newBox, false); + this.bringToFront(newBox); + return true; + } - public selectDocuments = (docs: Document[]) => { + private selectDocuments = (docs: Document[]) => { SelectionManager.DeselectAll; docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv => SelectionManager.SelectDoc(dv!, true)); -- cgit v1.2.3-70-g09d2 From eed0866d6148dfdb29c3f87b42afe365231f258c Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 30 Apr 2019 21:47:03 -0400 Subject: i am CONFUSED --- src/client/views/SearchBox.tsx | 31 ++++++++++++++++++++++++------- src/server/Search.ts | 2 ++ 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 7ceaf1da6..0670360a2 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -9,6 +9,10 @@ import { faSearch } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; import { actionFieldDecorator } from 'mobx/lib/internal'; +// const app = express(); +// import * as express from 'express'; +import { Search } from '../../server/Search'; + library.add(faSearch); @@ -26,12 +30,25 @@ export class SearchBox extends React.Component { } submitSearch = () => { - Utils.EmitCallback(Server.Socket, MessageStore.SearchFor, this.searchString, (results: string[]) => { - for (const result of results) { - console.log(result); - //Utils.GetQueryVariable(); - } - }); + // Utils.EmitCallback(Server.Socket, MessageStore.SearchFor, this.searchString, (results: string[]) => { + // for (const result of results) { + // console.log(result); + // //Utils.GetQueryVariable(); + // } + // }); + + let query = this.searchString; + console.log(query); + //something bad is happening here + let results = Search.Instance.search(query); + console.log(results); + + // app.get("/search", async (req, res) => { + // //let query = req.query.query || "hello"; + // let query = this.searchString; + // let results = await Search.Instance.search(query); + // res.send(results); + // }); } @action @@ -73,7 +90,7 @@ export class SearchBox extends React.Component { map(prop => )} */} -
+
diff --git a/src/server/Search.ts b/src/server/Search.ts index 7d8602346..8ae996e9e 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -13,6 +13,8 @@ export class Search { } public async search(query: string) { + console.log("____________________________"); + console.log(query); const searchResults = JSON.parse(await rp.get(this.url + "dash/select", { qs: { q: query -- cgit v1.2.3-70-g09d2 From 0c28cabf0d496be24da3e5ee414a8fcd925250ab Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 3 May 2019 01:42:54 -0400 Subject: Got part of search working --- src/server/Search.ts | 13 ++++++------- src/server/database.ts | 12 ------------ src/server/index.ts | 4 ++-- 3 files changed, 8 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/server/Search.ts b/src/server/Search.ts index bcea03d5c..9e462f0ae 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -1,15 +1,16 @@ import * as rp from 'request-promise'; import { Database } from './database'; +import { thisExpression } from 'babel-types'; export class Search { public static Instance = new Search(); private url = 'http://localhost:8983/solr/'; - public updateDocument(document: any): rp.RequestPromise { - console.log(JSON.stringify(document)); - return rp.post(this.url + "dash/update/json/docs", { + public async updateDocument(document: any) { + console.log("UPDATE: ", JSON.stringify(document)); + return rp.post(this.url + "dash/update", { headers: { 'content-type': 'application/json' }, - body: JSON.stringify(document) + body: JSON.stringify([document]) }); } @@ -21,9 +22,7 @@ export class Search { })); const fields = searchResults.response.docs; const ids = fields.map((field: any) => field.id); - const docs = await Database.Instance.searchQuery(ids); - const docIds = docs.map((doc: any) => doc._id); - return docIds; + return ids; } public async clear() { diff --git a/src/server/database.ts b/src/server/database.ts index 1e8004328..a61b4d823 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -74,18 +74,6 @@ export class Database { }); } - public searchQuery(ids: string[], collectionName = Database.DocumentsCollection): Promise { - return new Promise(resolve => { - this.db && this.db.collection(collectionName).find({ "data.field": { "$in": ids } }).toArray((err, docs) => { - if (err) { - console.log(err.message); - console.log(err.errmsg); - } - resolve(docs); - }); - }); - } - public print() { console.log("db says hi!"); } diff --git a/src/server/index.ts b/src/server/index.ts index b57e5c482..b4252c2a1 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -316,8 +316,8 @@ function UpdateField(socket: Socket, diff: Diff) { } var merged = {}; _.extend(merged, docid, docfield); - console.log(merged); - console.log(docfield); + console.log("MERGED: ", merged); + console.log("DOC_FIELD: ", docfield); if (dynfield) { console.log("dynamic field detected!"); Search.Instance.updateDocument(merged); -- cgit v1.2.3-70-g09d2 From 189eeefbb3e7f3d96d1d140beff74fcffe305786 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 3 May 2019 20:28:22 -0400 Subject: Added debugging support and added removing of unused keys in Solr --- .vscode/launch.json | 9 +++++++++ package.json | 3 ++- src/server/index.ts | 40 +++++++++++++++------------------------- 3 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/.vscode/launch.json b/.vscode/launch.json index fb91a1080..e92a4949a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,6 +13,15 @@ "url": "http://localhost:1050/login", "webRoot": "${workspaceFolder}", }, + { + "type": "node", + "request": "attach", + "name": "Typescript Server", + "protocol": "inspector", + "port": 9229, + "localRoot": "${workspaceFolder}", + "remoteRoot": "." + }, { "type": "node", "request": "launch", diff --git a/package.json b/package.json index 1eb546a80..fd794d062 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "start": "ts-node-dev -- src/server/index.ts", + "debug": "ts-node-dev --inspect -- src/server/index.ts", "build": "webpack --env production", "test": "mocha -r ts-node/register test/**/*.ts", "tsc": "tsc" @@ -171,4 +172,4 @@ "uuid": "^3.3.2", "xoauth2": "^1.2.0" } -} +} \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index b4252c2a1..f90724152 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -286,41 +286,31 @@ function GetRefField([id, callback]: [string, (result?: Transferable) => void]) Database.Instance.getDocument(id, callback, "newDocuments"); } +const suffixMap: { [type: string]: string } = { + "number": "_n", + "string": "_t" +}; function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); - //if (diff.diff === Types.Text) { - //Search.Instance.updateDocument({ name: "john", burns: "true" }); - //Search.Instance.updateDocument({ id: diff.id, data: diff.diff.data }); - //console.log("set field"); - //} - const docid = { id: diff.id }; - var docfield = diff.diff; - docfield = JSON.parse(JSON.stringify(docfield).split("fields.").join("")); + const docfield = diff.diff; + const update: any = { id: diff.id }; console.log("FIELD: ", docfield); - var dynfield = false; - for (var key in docfield) { + let dynfield = false; + for (let key in docfield) { + if (!key.startsWith("fields.")) continue; const val = docfield[key]; - if (typeof val === 'number') { - const new_key: string = key + "_n"; - docfield = JSON.parse(JSON.stringify(docfield).split(key).join(new_key)); - //docfield[new_key] = { 'set': val }; - dynfield = true; - } - else if (typeof val === 'string') { - const new_key: string = key + "_t"; - docfield = JSON.parse(JSON.stringify(docfield).split(key).join(new_key)); - docfield[new_key] = { 'set': val }; + const suffix = suffixMap[typeof val]; + if (suffix !== undefined) { + key = key.substring(7); + Object.values(suffixMap).forEach(suf => update[key + suf] = null); + update[key + suffix] = { set: val }; dynfield = true; } } - var merged = {}; - _.extend(merged, docid, docfield); - console.log("MERGED: ", merged); - console.log("DOC_FIELD: ", docfield); if (dynfield) { console.log("dynamic field detected!"); - Search.Instance.updateDocument(merged); + Search.Instance.updateDocument(update); } } -- cgit v1.2.3-70-g09d2 From e19fdbba4cf672aee5bfb59b91b6162431d146d3 Mon Sep 17 00:00:00 2001 From: ab Date: Sat, 4 May 2019 18:48:01 -0400 Subject: queries semi work --- package.json | 3 ++- src/debug/Test.tsx | 19 ++++++++++++++++++- src/server/Search.ts | 25 +++++++++++++++++++++++++ src/server/index.ts | 3 +++ 4 files changed, 48 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/package.json b/package.json index fd794d062..3393eacc6 100644 --- a/package.json +++ b/package.json @@ -167,9 +167,10 @@ "serializr": "^1.5.1", "socket.io": "^2.2.0", "socket.io-client": "^2.2.0", + "solr-node": "^1.1.3", "typescript-collections": "^1.3.2", "url-loader": "^1.1.2", "uuid": "^3.3.2", "xoauth2": "^1.2.0" } -} \ No newline at end of file +} diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 47cfac2c1..7d72a1ba0 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -3,6 +3,9 @@ import * as ReactDOM from 'react-dom'; import { serialize, deserialize, map } from 'serializr'; import { URLField, Doc, createSchema, makeInterface, makeStrictInterface, List, ListSpec } from '../fields/NewDoc'; import { SerializationHelper } from '../client/util/SerializationHelper'; +import { Search } from '../server/Search'; +import { restProperty } from 'babel-types'; +import * as rp from 'request-promise'; const schema1 = createSchema({ hello: "number", @@ -76,8 +79,22 @@ class Test extends React.Component { // console.log(SerializationHelper.Serialize(l)); } + onEnter = async (e: any) => { + var key = e.keyCode || e.which; + if (key === 13) { + var query = e.target.value; + await rp.get('http://localhost:1050/search', { + qs: { + query + } + }); + } + } + render() { - return ; + return
+ +
; } } diff --git a/src/server/Search.ts b/src/server/Search.ts index 9e462f0ae..4911edd1d 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -5,6 +5,31 @@ import { thisExpression } from 'babel-types'; export class Search { public static Instance = new Search(); private url = 'http://localhost:8983/solr/'; + private client: any; + + constructor() { + console.log("Search Instantiated!"); + var SolrNode = require('solr-node'); + this.client = new SolrNode({ + host: 'localhost', + port: '8983', + core: 'dash', + protocol: 'http' + }); + var strQuery = this.client.query().q('text:test'); + + console.log(strQuery); + + // Search documents using strQuery + // client.search(strQuery, (err: any, result: any) => { + // if (err) { + // console.log(err); + // return; + // } + // console.log('Response:', result.response); + // }); + } + public async updateDocument(document: any) { console.log("UPDATE: ", JSON.stringify(document)); diff --git a/src/server/index.ts b/src/server/index.ts index f90724152..f2bcd3f00 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -122,11 +122,14 @@ app.get("/pull", (req, res) => res.redirect("/"); })); +// SEARCH + // GETTERS app.get("/search", async (req, res) => { let query = req.query.query || "hello"; let results = await Search.Instance.search(query); + console.log(results); res.send(results); }); -- cgit v1.2.3-70-g09d2 From c9f3a1934548169ebe3c2e97968680ff339e304e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 4 May 2019 18:59:30 -0400 Subject: initial commit - todo: use cursor field rather than generic tuple field --- .../northstar/operations/HistogramOperation.ts | 5 +- src/client/util/DragManager.ts | 8 +-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/PresentationView.tsx | 4 +- src/client/views/PreviewCursor.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 6 ++- src/client/views/collections/CollectionSubView.tsx | 9 ++-- .../views/collections/CollectionTreeView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 7 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 ++-- src/client/views/nodes/FormattedTextBox.tsx | 8 +-- src/client/views/nodes/PDFBox.tsx | 5 +- src/new_fields/InkField.ts | 2 +- src/new_fields/ObjectField.ts | 2 +- src/new_fields/TupleField.ts | 63 ++++++++++++++++++++++ 16 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 src/new_fields/TupleField.ts (limited to 'src') diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 5c9c832c0..78b206bdc 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -65,7 +65,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @computed public get FilterString(): string { if (this.OverridingFilters.length > 0) { - return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; + return "(" + this.OverridingFilters.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")"; } let filterModels: FilterModel[] = []; return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true); @@ -89,8 +89,9 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @action public DrillDown(up: boolean) { if (!up) { - if (!this.BarFilterModels.length) + if (!this.BarFilterModels.length) { return; + } this._stackedFilters.push(this.BarFilterModels.map(f => f)); this.OverridingFilters.length = 0; this.OverridingFilters.push(...this._stackedFilters[this._stackedFilters.length - 1]); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index a3dbe6e43..8f27f5b21 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -155,9 +155,9 @@ export namespace DragManager { export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { StartDrag(eles, dragData, downX, downY, options, (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.userDropAction == "alias" || (!dragData.userDropAction && dragData.dropAction == "alias") ? + (dropData.droppedDocuments = dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? dragData.draggedDocuments.map(d => Doc.MakeAlias(d)) : - dragData.userDropAction == "copy" || (!dragData.userDropAction && dragData.dropAction == "copy") ? + dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? dragData.draggedDocuments.map(d => Doc.MakeCopy(d, true)) : dragData.draggedDocuments)); } @@ -280,7 +280,7 @@ export namespace DragManager { }; let hideDragElements = () => { - dragElements.map(dragElement => dragElement.parentNode == dragDiv && dragDiv.removeChild(dragElement)); + dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.map(ele => (ele.hidden = false)); }; let endDrag = () => { @@ -289,7 +289,7 @@ export namespace DragManager { if (options) { options.handlers.dragComplete({}); } - } + }; AbortDrag = () => { hideDragElements(); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 693d6ec55..16e5b6b48 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -278,7 +278,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> iconDoc = this.createIcon([docView], layout); } if (SelectionManager.SelectedDocuments()[0].props.addDocument !== undefined) { - SelectionManager.SelectedDocuments()[0].props.addDocument!(iconDoc!); + SelectionManager.SelectedDocuments()[0].props.addDocument!(iconDoc); } return iconDoc; } diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index b4c12d057..d8bdbacca 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; -import React = require("react") +import React = require("react"); import { observable, action } from "mobx"; -import "./PresentationView.scss" +import "./PresentationView.scss"; import "./Main.tsx"; import { DocumentManager } from "../util/DocumentManager"; import { Utils } from "../../Utils"; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 4359ba093..9520f489c 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -17,7 +17,7 @@ export class PreviewCursor extends React.Component<{}> { constructor(props: any) { super(props); - document.addEventListener("keydown", this.onKeyPress) + document.addEventListener("keydown", this.onKeyPress); } @action @@ -27,7 +27,7 @@ export class PreviewCursor extends React.Component<{}> { // the keyPress here. //if not these keys, make a textbox if preview cursor is active! if (e.key.startsWith("F") && !e.key.endsWith("F")) { - } else if (e.key != "Escape" && e.key != "Alt" && e.key != "Shift" && e.key != "Meta" && e.key != "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { + } else if (e.key !== "Escape" && e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { if ((!e.ctrlKey && !e.metaKey) || e.key === "v") { PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e); PreviewCursor.Visible = false; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index cfb1aef7d..725f0ab51 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -350,13 +350,15 @@ export class DockedFrameRenderer extends React.Component { get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } get content() { - if (!this._document) + if (!this._document) { return (null); + } return (
- boolean; @@ -66,12 +67,12 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { if (!proto) { return; } - let cursors = await Cast(proto.cursors, listSpec(ObjectField)); + let cursors = await Cast(proto!.cursors, listSpec(TupleField)); if (!cursors) { - proto.cursors = cursors = new List(); + proto!.cursors = cursors = new List>(); } - if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.Data[0][0] === id)) > -1) { - cursors[ind].Data[1] = position; + if (cursors!.length > 0 && (ind = cursors!.findIndex(entry => entry.data[0][0] === id)) > -1) { + cursors![ind].data[1] = position; } else { let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); cursors.push(entry); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index b67d6f965..7898d74ce 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -117,8 +117,8 @@ class TreeView extends React.Component { } } - onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; } - onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; } + onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; }; render() { let bulletType = BulletType.List; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9dee217cb..cb3fd1ba4 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -90,7 +90,7 @@ export class CollectionVideoView extends React.Component { } } - setVideoBox = (player: VideoBox) => { this._videoBox = player; } + setVideoBox = (player: VideoBox) => { this._videoBox = player; }; private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8c81f6990..a9e627188 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -139,7 +139,7 @@ export class MarqueeView extends React.Component if (this._commandExecuted) { return; } - if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") { + if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") { this._commandExecuted = true; this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = Cast(this.props.container.props.Document.ink, InkField); @@ -154,8 +154,9 @@ export class MarqueeView extends React.Component e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { - if (e.key !== "r") + if (e.key !== "r") { this.props.removeDocument(d); + } d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; d.page = -1; @@ -194,7 +195,7 @@ export class MarqueeView extends React.Component let maxy = NumCast(maximizedDoc.y, undefined); let maxw = NumCast(maximizedDoc.width, undefined); let maxh = NumCast(maximizedDoc.height, undefined); - maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); }); } else { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 2ba0458f5..6186cf348 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -148,7 +148,7 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]); } } }); @@ -167,16 +167,17 @@ export class CollectionFreeFormDocumentView extends DocComponent d instanceof Doc).map(maxDoc => this.props.addDocument!(maxDoc, false)); + } this.toggleIcon(); } } } } - onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; } - onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; } + onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; borderRounding = () => { let br = NumCast(this.props.Document.borderRounding); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index eeb60cb3d..3873dfd62 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -91,7 +91,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let titlestr = str.substr(0, Math.min(40, str.length)); let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; target.title = "-" + titlestr + (str.length > 40 ? "..." : ""); - }; + } } } @@ -176,8 +176,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); - if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "0"; + } } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; @@ -185,8 +186,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } onPointerUp = (e: React.PointerEvent): void => { - if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "1"; + } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index eb45ea273..caa66cbeb 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -215,8 +215,9 @@ export class PDFBox extends DocComponent(PdfDocumen if (e.altKey) { this._alt = true; } else { - if (e.metaKey) + if (e.metaKey) { e.stopPropagation(); + } } document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); @@ -286,7 +287,7 @@ export class PDFBox extends DocComponent(PdfDocumen renderHeight = 2400; @computed get pdfPage() { - return + return ; } @computed get pdfContent() { diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 86a8bd18a..a3157857f 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -39,6 +39,6 @@ export class InkField extends ObjectField { } [Copy]() { - return new InkField(deepCopy(this.inkData)) + return new InkField(deepCopy(this.inkData)); } } diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts index 0f3777af6..715c6a924 100644 --- a/src/new_fields/ObjectField.ts +++ b/src/new_fields/ObjectField.ts @@ -5,7 +5,7 @@ export const Parent = Symbol("Parent"); export const Copy = Symbol("Copy"); export abstract class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; + protected [OnUpdate](diff?: any) { }; private [Parent]?: Doc; abstract [Copy](): ObjectField; } diff --git a/src/new_fields/TupleField.ts b/src/new_fields/TupleField.ts new file mode 100644 index 000000000..1ff57fefc --- /dev/null +++ b/src/new_fields/TupleField.ts @@ -0,0 +1,63 @@ +import { ObjectField, Copy } from "./ObjectField"; +import { IObservableArray, IArrayChange, IArraySplice, observe, Lambda, observable } from "mobx"; +import { UndoManager } from "../client/util/UndoManager"; +import { Field } from "./Doc"; +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, createSimpleSchema, list, object } from "serializr"; +import { array } from "prop-types"; + +const tupleSchema = createSimpleSchema({ + +}); + +@Deserializable("tuple") +export class TupleField extends ObjectField { + + + @serializable(list(object(tupleSchema))) + private Data: [T, U]; + + public get data() { + return this.Data; + } + + constructor(data: [T, U]) { + super(); + this.Data = data; + this.observeTuple(); + } + + private observeDisposer: Lambda | undefined; + private observeTuple(): void { + this.observeDisposer = observe(this.Data as (T | U)[] as IObservableArray, (change: IArrayChange | IArraySplice) => { + if (change.type === "update") { + UndoManager.AddEvent({ + undo: () => this.Data[change.index] = change.oldValue, + redo: () => this.Data[change.index] = change.newValue + }); + } else { + throw new Error("Why are you messing with the length of a tuple, huh?"); + } + }); + } + + protected setData(value: [T, U]) { + if (this.observeDisposer) { + this.observeDisposer(); + } + this.Data = observable(value) as (T | U)[] as [T, U]; + this.observeTuple(); + } + + UpdateFromServer(values: [T, U]) { + this.setData(values); + } + + ToScriptString(): string { + return `new TupleField([${this.Data[0], this.Data[1]}])`; + } + + [Copy]() { + return new TupleField(this.Data); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 364396d9062381d72c618c5b9931267c6cc55c97 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Mon, 6 May 2019 19:37:37 -0400 Subject: things happening --- src/client/views/SearchBox.tsx | 87 +++++++++++++++++++++++++++++------------ src/client/views/SearchItem.tsx | 34 ++++++++++++++++ 2 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 src/client/views/SearchItem.tsx (limited to 'src') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 0670360a2..2fd809d9e 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -12,6 +12,9 @@ import { actionFieldDecorator } from 'mobx/lib/internal'; // const app = express(); // import * as express from 'express'; import { Search } from '../../server/Search'; +import * as rp from 'request-promise'; +import { Document } from '../../fields/Document'; +import { SearchItem } from './SearchItem'; library.add(faSearch); @@ -23,43 +26,74 @@ export class SearchBox extends React.Component { @observable private _open: boolean = false; + @observable + private _results: any; + + constructor(props: any) { + super(props); + let searchInput = document.getElementById("input"); + if (searchInput) { + searchInput.addEventListener("keydown", this.onKeyPress) + } + } + + //this is not working????? + @action + onKeyPress = (e: KeyboardEvent) => { + console.log('things happening') + //Number 13 is the "Enter" key on the keyboard + if (e.keyCode === 13) { + console.log("happi") + // Cancel the default action, if needed + e.preventDefault(); + // Trigger the button element with a click + let btn = document.getElementById("submit"); + if (btn) { + console.log("yesyesyes") + btn.click(); + } + } + } + @action.bound onChange(e: React.ChangeEvent) { this.searchString = e.target.value; + }; - } - - submitSearch = () => { - // Utils.EmitCallback(Server.Socket, MessageStore.SearchFor, this.searchString, (results: string[]) => { - // for (const result of results) { - // console.log(result); - // //Utils.GetQueryVariable(); - // } - // }); + submitSearch = async () => { let query = this.searchString; - console.log(query); - //something bad is happening here - let results = Search.Instance.search(query); - console.log(results); - - // app.get("/search", async (req, res) => { - // //let query = req.query.query || "hello"; - // let query = this.searchString; - // let results = await Search.Instance.search(query); - // res.send(results); - // }); + + let response = await rp.get('http://localhost:1050/search', { + qs: { + query + } + }); + + let results = JSON.parse(response); + + this._results = results; + + let doc = await Server.GetField(this._results[1]); + if (doc instanceof Document) { + console.log("doc"); + console.log(doc.Title); + } + + // console.log("results") + // console.log(results); + // console.log("type") + // console.log(results.type) + console.log(this._results); + + } @action handleClick = (e: Event): void => { var className = (e.target as any).className; var id = (e.target as any).id; - console.log(id); - //let imgPrev = document.getElementById("img_preview"); - console.log(className); if (className !== "filter-button" && className !== "filter-form") { - console.log("false"); this._open = false; } @@ -85,12 +119,13 @@ export class SearchBox extends React.Component { {/* -
+
diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx new file mode 100644 index 000000000..f030e011b --- /dev/null +++ b/src/client/views/SearchItem.tsx @@ -0,0 +1,34 @@ +import React = require("react"); +import { Document } from "../../fields/Document"; + +export interface SearchProps { + doc: Document; + //description: string; + //event: (e: React.MouseEvent) => void; +} + +// export interface SubmenuProps { +// description: string; +// subitems: ContextMenuProps[]; +// } + +// export interface ContextMenuItemProps { +// type: ContextMenuProps | SubmenuProps; +// } + + + +export class SearchItem extends React.Component { + + onClick = () => { + console.log("clicked search item"); + }; + + render() { + return ( +
+
{this.props.doc.Title}
+
+ ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 4ba63508738ec7ea68d7e8a9a7932c2e764ac545 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 6 May 2019 23:25:25 -0400 Subject: fixed undo for minimizing docs --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f1083f859..c4f85847a 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -12,6 +12,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { Doc, DocListCast, HeightSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { } @@ -95,6 +96,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { let now = Date.now(); let progress = Math.min(1, (now - stime) / 200); @@ -133,6 +137,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); if (!iconAnimating || (Date.now() - iconAnimating[6] > 1000)) { @@ -148,14 +153,18 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]) } } }); + setTimeout(() => { + CollectionFreeFormDocumentView._undoBatch && CollectionFreeFormDocumentView._undoBatch.end(); + CollectionFreeFormDocumentView._undoBatch = undefined; + }, 500); } } + static _undoBatch?: UndoManager.Batch = undefined; onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; -- cgit v1.2.3-70-g09d2 From 337335bc3f7daa61ca9116feaec85882ffd0853a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 6 May 2019 23:50:59 -0400 Subject: added some undo support for creating and editing text boxes --- .../views/collections/collectionFreeForm/MarqueeView.tsx | 5 ++++- src/client/views/nodes/FormattedTextBox.tsx | 13 ++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 805921ad4..0484c181e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { Docs } from "../../../documents/Documents"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; -import { undoBatch } from "../../../util/UndoManager"; +import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { InkingCanvas } from "../../InkingCanvas"; import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; @@ -17,6 +17,8 @@ import { Templates } from "../../Templates"; import { List } from "../../../../new_fields/List"; import { emitKeypressEvents } from "readline"; import { listSpec } from "../../../../new_fields/Schema"; +import { undo } from "prosemirror-history"; +import { FormattedTextBox } from "../../nodes/FormattedTextBox"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -50,6 +52,7 @@ export class MarqueeView extends React.Component this._visible = false; } + @undoBatch @action onKeyPress = (e: KeyboardEvent) => { //make textbox and add it to this collection diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 65b8b805f..ffd68fd48 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -23,6 +23,7 @@ import { InkingControl } from "../InkingControl"; import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; import { RichTextField } from "../../../new_fields/RichTextField"; import { Id } from "../../../new_fields/RefField"; +import { UndoManager } from "../../util/UndoManager"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -271,7 +272,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } }); } - + onBlur = (e: any) => { + if (this._undoTyping) { + this._undoTyping.end(); + this._undoTyping = undefined; + } + } + public _undoTyping?: UndoManager.Batch; onKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Escape") { SelectionManager.DeselectAll(); @@ -287,6 +294,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; target.title = "-" + titlestr + (str.length > 40 ? "..." : ""); } + if (!this._undoTyping) { + this._undoTyping = UndoManager.StartBatch("undoTyping"); + } } render() { let style = this.props.isOverlay ? "scroll" : "hidden"; @@ -303,6 +313,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onKeyPress={this.onKeyPress} onFocus={this.onFocused} onClick={this.onClick} + onBlur={this.onBlur} onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onMouseDown={this.onMouseDown} -- cgit v1.2.3-70-g09d2 From 5ffd715a2ce6c25daff22410ed9b6b009e8938d3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 7 May 2019 00:21:03 -0400 Subject: playing with templates for text. weird stuff happens 50% of the time with text typing backward. --- src/client/views/DocumentDecorations.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 693d6ec55..e2f445874 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -78,11 +78,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (SelectionManager.SelectedDocuments().length > 0) { let field = SelectionManager.SelectedDocuments()[0].props.Document[this._fieldKey]; if (typeof field === "number") { - SelectionManager.SelectedDocuments().forEach(d => - d.props.Document[this._fieldKey] = +this._title); + SelectionManager.SelectedDocuments().forEach(d => { + let doc = d.props.Document.proto ? d.props.Document.proto : d.props.Document; + doc[this._fieldKey] = +this._title; + }); } else { - SelectionManager.SelectedDocuments().forEach(d => - d.props.Document[this._fieldKey] = this._title); + SelectionManager.SelectedDocuments().forEach(d => { + let doc = d.props.Document.proto ? d.props.Document.proto : d.props.Document; + doc[this._fieldKey] = this._title; + }); } } } -- cgit v1.2.3-70-g09d2 From 20f31796ed6f6c9fb71fa80cf858a7ac353300cf Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 7 May 2019 00:22:01 -0400 Subject: from last --- src/client/views/Templates.tsx | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 5858ee014..738272913 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -51,24 +51,22 @@ export namespace Templates { ); export const Title = new Template("Title", TemplatePosition.InnerTop, - `
{layout}
{props.Document.title}
` + `
{layout}
+
{props.Document.title}
` ); export const Summary = new Template("Title", TemplatePosition.InnerTop, - `
{layout}
{props.Document.doc1.title}
` + `
+
+ {layout} +
+
+ +
+
+ +
+
` ); - // export const Summary = new Template("Title", TemplatePosition.InnerTop, - // `
- //
- // {layout} - //
- //
- // - //
- //
- // - //
- //
` - // ); export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption]; -- cgit v1.2.3-70-g09d2 From c3e613aebc056fd75bb1a5b3ac95f2367532b098 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 7 May 2019 13:11:13 -0400 Subject: type issues?? --- src/client/views/SearchBox.tsx | 87 ++++++++++++++++++++++++++--------------- src/client/views/SearchItem.tsx | 2 +- 2 files changed, 56 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 2fd809d9e..eb3cd56fd 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -15,6 +15,7 @@ import { Search } from '../../server/Search'; import * as rp from 'request-promise'; import { Document } from '../../fields/Document'; import { SearchItem } from './SearchItem'; +import { isString } from 'util'; library.add(faSearch); @@ -26,40 +27,41 @@ export class SearchBox extends React.Component { @observable private _open: boolean = false; - @observable - private _results: any; - - constructor(props: any) { - super(props); - let searchInput = document.getElementById("input"); - if (searchInput) { - searchInput.addEventListener("keydown", this.onKeyPress) - } - } - - //this is not working????? - @action - onKeyPress = (e: KeyboardEvent) => { - console.log('things happening') - //Number 13 is the "Enter" key on the keyboard - if (e.keyCode === 13) { - console.log("happi") - // Cancel the default action, if needed - e.preventDefault(); - // Trigger the button element with a click - let btn = document.getElementById("submit"); - if (btn) { - console.log("yesyesyes") - btn.click(); - } - } - } + //@observable + private _results: Document[] = []; + + // constructor(props: any) { + // super(props); + // let searchInput = document.getElementById("input"); + // if (searchInput) { + // // searchInput.addEventListener("keydown", this.onKeyPress) + // } + // } + + // //this is not working????? + // @action + // onKeyPress = (e: KeyboardEvent) => { + // console.log('things happening') + // //Number 13 is the "Enter" key on the keyboard + // if (e.keyCode === 13) { + // console.log("happi") + // // Cancel the default action, if needed + // e.preventDefault(); + // // Trigger the button element with a click + // let btn = document.getElementById("submit"); + // if (btn) { + // console.log("yesyesyes") + // btn.click(); + // } + // } + // } @action.bound onChange(e: React.ChangeEvent) { this.searchString = e.target.value; - }; + } + //@action submitSearch = async () => { let query = this.searchString; @@ -74,17 +76,38 @@ export class SearchBox extends React.Component { this._results = results; - let doc = await Server.GetField(this._results[1]); + let doc = await Server.GetField(results[1]); if (doc instanceof Document) { console.log("doc"); console.log(doc.Title); } + // weird things happening // console.log("results") // console.log(results); // console.log("type") // console.log(results.type) - console.log(this._results); + let temp: string = this._results[1].Id; + // console.log(this._results) + // console.log(this._results[1]) + + console.log(this._results[1].constructor.name) + + if (this._results[1] instanceof Document) { + console.log("is a doc") + } + + if (this._results[1]) { + console.log("is a string") + } + + console.log(temp); + let doc2 = await Server.GetField(temp); + console.log(doc2); + if (doc2 instanceof Document) { + console.log("doc2"); + console.log(doc2.Title); + } } @@ -122,7 +145,7 @@ export class SearchBox extends React.Component { {/* {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1). map(prop => )} */} - {/* {this._results.map(doc => )} */} + {this._results.map(doc => )}
diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx index f030e011b..c8fd6457b 100644 --- a/src/client/views/SearchItem.tsx +++ b/src/client/views/SearchItem.tsx @@ -22,7 +22,7 @@ export class SearchItem extends React.Component { onClick = () => { console.log("clicked search item"); - }; + } render() { return ( -- cgit v1.2.3-70-g09d2 From dc9275ec0308ecca1246942a1cf9ef342e9e3300 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 7 May 2019 13:48:49 -0400 Subject: changed css for text background colors. made api to add text to new textboxes.. added ctrl-q to paste text in boxes based on "paragraph" recognition rules. --- src/client/documents/Documents.ts | 2 +- src/client/views/PreviewCursor.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 23 ++++++++++++++++++++-- src/client/views/globalCssVariables.scss | 2 +- src/client/views/nodes/FormattedTextBox.scss | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 5 +++++ 6 files changed, 30 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 37d263e75..a770ccc93 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -132,7 +132,7 @@ export namespace Docs { } function CreateTextPrototype(): Doc { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 150 }); + { x: 0, y: 0, width: 300, height: 150, backgroundColor: "#f1efeb" }); return textProto; } function CreatePdfPrototype(): Doc { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 4359ba093..4ac4b9c95 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -28,7 +28,7 @@ export class PreviewCursor extends React.Component<{}> { //if not these keys, make a textbox if preview cursor is active! if (e.key.startsWith("F") && !e.key.endsWith("F")) { } else if (e.key != "Escape" && e.key != "Alt" && e.key != "Shift" && e.key != "Meta" && e.key != "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { - if ((!e.ctrlKey && !e.metaKey) || e.key === "v") { + if ((!e.ctrlKey && !e.metaKey) || e.key === "v" || e.key === "q") { PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e); PreviewCursor.Visible = false; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0484c181e..c9b0b28f7 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -57,8 +57,27 @@ export class MarqueeView extends React.Component onKeyPress = (e: KeyboardEvent) => { //make textbox and add it to this collection let [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY); - let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); - this.props.addLiveTextDocument(newBox); + if (e.key === "q" && e.ctrlKey) { + e.preventDefault(); + (async () => { + let text = await navigator.clipboard.readText(); + let ns = text.split("\n").filter(t => t != "\r"); + for (let i = 0; i < ns.length - 1; i++) { + while (!(ns[i].endsWith("-\r") || ns[i].endsWith(".\r") || ns[i].endsWith(":\r")) && i < ns.length - 1) { + ns.splice(i, 2, ns[i].substr(0, ns[i].length - 1) + ns[i + 1].trimLeft()); + } + } + ns.map(line => { + let indent = line.search(/\S|$/); + let newBox = Docs.TextDocument({ width: 200, height: 35, x: x + indent / 3 * 10, y: y, documentText: "@@@" + line, title: line }); + this.props.addDocument(newBox, false); + y += 40 * this.props.getTransform().Scale; + }) + })(); + } else { + let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" }); + this.props.addLiveTextDocument(newBox); + } e.stopPropagation(); } @action diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index 4f68b71b0..cb4d1ad87 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -1,7 +1,7 @@ @import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700|Crimson+Text:400,400i,700"); // colors $light-color: #fcfbf7; -$light-color-secondary: rgb(241, 239, 235); +$light-color-secondary:#f1efeb; $main-accent: #61aaa3; // $alt-accent: #cdd5ec; // $alt-accent: #cdeceb; diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index d43aa4e02..9e58a8e7f 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -11,7 +11,7 @@ } .formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden { - background: $light-color-secondary; + background: inherit; padding: 0; border-width: 0px; border-radius: inherit; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ffd68fd48..8d2f1c780 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -151,6 +151,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction }); + let text = StrCast(this.props.Document.documentText); + if (text.startsWith("@@@")) { + this.props.Document.proto!.documentText = undefined; + this._editorView.dispatch(this._editorView.state.tr.insertText(text.substr(3))); + } } if (this.props.selectOnLoad) { -- cgit v1.2.3-70-g09d2 From f8f96fe4006f96459e6ad4b9889fdaefc339467e Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 7 May 2019 13:57:57 -0400 Subject: fixed calling whenActiveChanged so you can drag text box when parent collection is active. --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 17c25c9db..7fa945891 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -265,7 +265,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, parentActive: this.props.active, - whenActiveChanged: this.props.active, + whenActiveChanged: this.props.whenActiveChanged, bringToFront: this.bringToFront, }; } @@ -274,7 +274,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { get views() { let curPage = FieldValue(this.Document.curPage, -1); let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { - if (!FieldValue(doc)) return prev; + if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); if (page === curPage || page === -1) { let minim = Cast(doc.isMinimized, "boolean"); -- cgit v1.2.3-70-g09d2 From 96d9bd38cb3ae6d59945d15071e1b346e4d0a8e2 Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 7 May 2019 14:38:23 -0400 Subject: hacky way of getting search to work --- src/client/views/SearchBox.scss | 52 ++++++++++++++++++++++++++++++++--------- src/client/views/SearchBox.tsx | 52 +++++++++++------------------------------ 2 files changed, 55 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.scss b/src/client/views/SearchBox.scss index 92363e681..1aad13b2e 100644 --- a/src/client/views/SearchBox.scss +++ b/src/client/views/SearchBox.scss @@ -8,18 +8,7 @@ transition: width 0.4s ease-in-out; align-items: center; - .submit-search { - text-align: right; - color: $dark-color; - -webkit-transition: right 0.4s; - transition: right 0.4s; - } - .submit-search:hover { - color: $main-accent; - transform: scale(1.05); - cursor: pointer; - } input[type=text] { width: 130px; @@ -38,6 +27,19 @@ position: absolute; right: 30px; } + + .submit-search { + text-align: right; + color: $dark-color; + -webkit-transition: right 0.4s; + transition: right 0.4s; + } + + .submit-search:hover { + color: $main-accent; + transform: scale(1.05); + cursor: pointer; + } } .filter-form { @@ -60,4 +62,32 @@ #option { height: 20px; +} + +.search-item { + width: 500px; + height: 50px; + background: $light-color-secondary; + display: flex; + justify-content: left; + align-items: center; + transition: all 0.1s; + border-width: 0.11px; + border-style: none; + border-color: $intermediate-color; + border-bottom-style: solid; + padding: 10px; + white-space: nowrap; + font-size: 13px; +} + +.search-item:hover { + transition: all 0.1s; + background: $lighter-alt-accent; +} + +.search-title { + text-transform: uppercase; + text-align: left; + width: 8vw; } \ No newline at end of file diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index eb3cd56fd..eecd9c8bb 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -74,42 +74,19 @@ export class SearchBox extends React.Component { let results = JSON.parse(response); - this._results = results; - - let doc = await Server.GetField(results[1]); - if (doc instanceof Document) { - console.log("doc"); - console.log(doc.Title); - } - - // weird things happening - // console.log("results") - // console.log(results); - // console.log("type") - // console.log(results.type) - let temp: string = this._results[1].Id; - // console.log(this._results) - // console.log(this._results[1]) - - console.log(this._results[1].constructor.name) - - if (this._results[1] instanceof Document) { - console.log("is a doc") - } - - if (this._results[1]) { - console.log("is a string") - } - - console.log(temp); - let doc2 = await Server.GetField(temp); - console.log(doc2); - if (doc2 instanceof Document) { - console.log("doc2"); - console.log(doc2.Title); - } + //gets json result into a list of documents that can be used + this.getResults(results); + } + getResults = async (res: string[]) => { + let doc; + res.map(async result => { + doc = await Server.GetField(result); + if (doc instanceof Document) { + this._results.push(doc); + } + }); } @action @@ -143,10 +120,9 @@ export class SearchBox extends React.Component {
-- cgit v1.2.3-70-g09d2 From 26141a697ae52a7edf3cc6845ce2153111f8860e Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 7 May 2019 15:26:29 -0400 Subject: added Bullet template --- src/client/views/DocumentDecorations.tsx | 15 ++++++++++++--- src/client/views/TemplateMenu.tsx | 20 +++++++++++++++----- src/client/views/Templates.tsx | 18 +++++------------- src/client/views/collections/CollectionBaseView.tsx | 10 +++++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 +++++---- 5 files changed, 44 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e2f445874..8ae71fdc8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -507,9 +507,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } let templates: Map = new Map(); - let doc = SelectionManager.SelectedDocuments()[0]; Array.from(Object.values(Templates.TemplateList)).map(template => { - let docTemps = doc.templates; + let docTemps = SelectionManager.SelectedDocuments().reduce((res: string[], doc: DocumentView, i) => { + let temps = doc.props.Document.templates; + if (temps instanceof List) { + temps.map(temp => { + if (temp !== Templates.Bullet.Layout || i === 0) { + res.push(temp); + } + }) + } + return res + }, [] as string[]); let checked = false; docTemps.forEach(temp => { if (template.Layout === temp) { @@ -560,7 +569,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
- + diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index f29d9c8a1..376feb5a5 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -4,6 +4,8 @@ import { observer } from "mobx-react"; import './DocumentDecorations.scss'; import { Template } from "./Templates"; import { DocumentView } from "./nodes/DocumentView"; +import { List } from "../../new_fields/List"; +import { Doc } from "../../new_fields/Doc"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -25,24 +27,32 @@ class TemplateToggle extends React.Component<{ template: Template, checked: bool } export interface TemplateMenuProps { - doc: DocumentView; + docs: DocumentView[]; templates: Map; } @observer export class TemplateMenu extends React.Component { - @observable private _hidden: boolean = true; - @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { if (event.target.checked) { - this.props.doc.addTemplate(template); + if (template.Name == "Bullet") { + this.props.docs[0].addTemplate(template); + this.props.docs[0].props.Document.maximizedDocs = new List(this.props.docs.filter((v, i) => i !== 0).map(v => v.props.Document)); + } else { + this.props.docs.map(d => d.addTemplate(template)); + } this.props.templates.set(template, true); this.props.templates.forEach((checked, template) => console.log("Set Checked + " + checked + " " + this.props.templates.get(template))); } else { - this.props.doc.removeTemplate(template); + if (template.Name == "Bullet") { + this.props.docs[0].removeTemplate(template); + this.props.docs[0].props.Document.maximizedDocs = undefined; + } else { + this.props.docs.map(d => d.removeTemplate(template)); + } this.props.templates.set(template, false); this.props.templates.forEach((checked, template) => console.log("Unset Checked + " + checked + " " + this.props.templates.get(template))); } diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 738272913..51fca4c41 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -54,21 +54,13 @@ export namespace Templates { `
{layout}
{props.Document.title}
` ); - export const Summary = new Template("Title", TemplatePosition.InnerTop, - `
-
- {layout} -
-
- -
-
- -
-
` + + export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, + `
{layout}
+
` ); - export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption]; + export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption, Bullet]; export function sortTemplates(a: Template, b: Template) { if (a.Position < b.Position) { return -1; } diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index cbb568c07..14b92af48 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -95,15 +95,18 @@ export class CollectionBaseView extends React.Component { if (!this.createsCycle(doc, props.Document)) { //TODO This won't create the field if it doesn't already exist const value = Cast(props.Document[props.fieldKey], listSpec(Doc)); + let alreadyAdded = true; if (value !== undefined) { - if (allowDuplicates || !value.some(v => v[Id] === doc[Id])) { + if (allowDuplicates || !value.some(v => v instanceof Doc && v[Id] === doc[Id])) { + alreadyAdded = false; value.push(doc); } } else { + alreadyAdded = false; Doc.SetOnPrototype(this.props.Document, this.props.fieldKey, new List([doc])); } // set the ZoomBasis only if hasn't already been set -- bcz: maybe set/resetting the ZoomBasis should be a parameter to addDocument? - if (this.collectionViewType === CollectionViewType.Freeform || this.collectionViewType === CollectionViewType.Invalid) { + if (!alreadyAdded && (this.collectionViewType === CollectionViewType.Freeform || this.collectionViewType === CollectionViewType.Invalid)) { let zoom = NumCast(this.props.Document.scale, 1); Doc.SetOnPrototype(doc, "zoomBasis", zoom); } @@ -118,7 +121,8 @@ export class CollectionBaseView extends React.Component { const value = Cast(props.Document[props.fieldKey], listSpec(Doc), []); let index = -1; for (let i = 0; i < value.length; i++) { - if (value[i][Id] === doc[Id]) { + let v = value[i]; + if (v instanceof Doc && v[Id] === doc[Id]) { index = i; break; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c4f85847a..df78d92e2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -127,6 +127,7 @@ export class CollectionFreeFormDocumentView extends DocComponent => { + UndoManager.GetOpenBatches().forEach(batch => console.log(batch.batchName)); SelectionManager.DeselectAll(); let isMinimized: boolean | undefined; let maximizedDocs = await DocListCast(this.props.Document.maximizedDocs); @@ -144,8 +145,8 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]) } } @@ -175,7 +176,7 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Tue, 7 May 2019 15:51:00 -0400 Subject: things showing up --- src/client/views/SearchBox.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index eecd9c8bb..0760578a8 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import { observable, action, runInAction } from 'mobx'; import { Utils } from '../../Utils'; import { MessageStore } from '../../server/Message'; import { Server } from '../Server'; @@ -8,7 +8,6 @@ import "./SearchBox.scss"; import { faSearch } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; -import { actionFieldDecorator } from 'mobx/lib/internal'; // const app = express(); // import * as express from 'express'; import { Search } from '../../server/Search'; @@ -26,8 +25,9 @@ export class SearchBox extends React.Component { searchString: string = ""; @observable private _open: boolean = false; + @observable private _resultsOpen: boolean = false; - //@observable + @observable private _results: Document[] = []; // constructor(props: any) { @@ -61,7 +61,7 @@ export class SearchBox extends React.Component { this.searchString = e.target.value; } - //@action + @action submitSearch = async () => { let query = this.searchString; @@ -71,20 +71,20 @@ export class SearchBox extends React.Component { query } }); - let results = JSON.parse(response); //gets json result into a list of documents that can be used this.getResults(results); + runInAction(() => { this._resultsOpen = true; }); } + @action getResults = async (res: string[]) => { - let doc; res.map(async result => { - doc = await Server.GetField(result); + const doc = await Server.GetField(result); if (doc instanceof Document) { - this._results.push(doc); + runInAction(() => this._results.push(doc)); } }); } @@ -120,7 +120,7 @@ export class SearchBox extends React.Component { -- cgit v1.2.3-70-g09d2 From 93d2214b84eaef61c9a9f980d24b5c1addbd67dc Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 7 May 2019 16:26:51 -0400 Subject: things working --- src/client/views/SearchBox.scss | 6 ++++++ src/client/views/SearchBox.tsx | 46 ++++++++++++----------------------------- src/client/views/SearchItem.tsx | 2 +- 3 files changed, 20 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.scss b/src/client/views/SearchBox.scss index 1aad13b2e..f4fc0029e 100644 --- a/src/client/views/SearchBox.scss +++ b/src/client/views/SearchBox.scss @@ -64,6 +64,12 @@ height: 20px; } +.results { + top: 300px; + display: flex; + flex-direction: column; +} + .search-item { width: 500px; height: 50px; diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 0760578a8..ff215efab 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -15,6 +15,7 @@ import * as rp from 'request-promise'; import { Document } from '../../fields/Document'; import { SearchItem } from './SearchItem'; import { isString } from 'util'; +import { constant } from 'async'; library.add(faSearch); @@ -30,40 +31,15 @@ export class SearchBox extends React.Component { @observable private _results: Document[] = []; - // constructor(props: any) { - // super(props); - // let searchInput = document.getElementById("input"); - // if (searchInput) { - // // searchInput.addEventListener("keydown", this.onKeyPress) - // } - // } - - // //this is not working????? - // @action - // onKeyPress = (e: KeyboardEvent) => { - // console.log('things happening') - // //Number 13 is the "Enter" key on the keyboard - // if (e.keyCode === 13) { - // console.log("happi") - // // Cancel the default action, if needed - // e.preventDefault(); - // // Trigger the button element with a click - // let btn = document.getElementById("submit"); - // if (btn) { - // console.log("yesyesyes") - // btn.click(); - // } - // } - // } - @action.bound onChange(e: React.ChangeEvent) { this.searchString = e.target.value; + console.log(this.searchString) } @action submitSearch = async () => { - + runInAction(() => this._results = []); let query = this.searchString; let response = await rp.get('http://localhost:1050/search', { @@ -112,19 +88,23 @@ export class SearchBox extends React.Component { this._open = !this._open; } + enter = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + this.submitSearch(); + } + } + render() { return (
- {/* -
+
+ {this._results.map(result => )} +
diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx index c8fd6457b..6021c0736 100644 --- a/src/client/views/SearchItem.tsx +++ b/src/client/views/SearchItem.tsx @@ -21,7 +21,7 @@ export interface SearchProps { export class SearchItem extends React.Component { onClick = () => { - console.log("clicked search item"); + console.log("document clicked: ", this.props.doc); } render() { -- cgit v1.2.3-70-g09d2 From 6683c5450eb25da291090091421e791bf0498aba Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 7 May 2019 16:56:41 -0400 Subject: Fix after merge --- src/server/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/index.ts b/src/server/index.ts index 2381f9840..6b92e8e8e 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -303,7 +303,10 @@ const suffixMap: { [type: string]: string } = { function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); - const docfield = diff.diff; + const docfield = diff.diff.$set; + if (!docfield) { + return; + } const update: any = { id: diff.id }; console.log("FIELD: ", docfield); let dynfield = false; -- cgit v1.2.3-70-g09d2 From 11ab63f6c91093951fdc293c3d67e63073fb2f4c Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Tue, 7 May 2019 17:42:37 -0400 Subject: navigate to searched doc --- src/client/util/DocumentManager.ts | 30 +++++++++++++++++++++++++++++- src/client/views/Main.tsx | 2 +- src/client/views/SearchBox.tsx | 2 +- src/client/views/SearchItem.tsx | 16 ++-------------- src/client/views/nodes/LinkBox.tsx | 23 +---------------------- 5 files changed, 34 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 69964e2c9..3151bcfb5 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,8 +1,10 @@ import { computed, observable } from 'mobx'; import { DocumentView } from '../views/nodes/DocumentView'; import { Doc } from '../../new_fields/Doc'; -import { FieldValue, Cast } from '../../new_fields/Types'; +import { FieldValue, Cast, NumCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; +import { undoBatch } from './UndoManager'; +import { CollectionDockingView } from '../views/collections/CollectionDockingView'; export class DocumentManager { @@ -87,4 +89,30 @@ export class DocumentManager { return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); } + + @undoBatch + public jumpToDocument = async (doc: Doc): Promise => { + let docView = DocumentManager.Instance.getDocumentView(doc); + if (docView) { + docView.props.focus(docView.props.Document); + } else { + const contextDoc = await Cast(doc.annotationOn, Doc); + if (!contextDoc) { + CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(doc)); + } else { + const page = NumCast(doc.page, undefined); + const curPage = NumCast(contextDoc.curPage, undefined); + if (page !== curPage) { + contextDoc.curPage = page; + } + let contextView = DocumentManager.Instance.getDocumentView(contextDoc); + if (contextView) { + contextDoc.panTransformType = "Ease"; + contextView.props.focus(contextDoc); + } else { + CollectionDockingView.Instance.AddRightSplit(contextDoc); + } + } + } + } } \ No newline at end of file diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 677902c5b..c9d5c395c 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -267,7 +267,7 @@ export class Main extends React.Component {
,
, -
+
]; diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index a52598f4c..827d468df 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -17,6 +17,7 @@ import { constant } from 'async'; import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; import { Id } from '../../new_fields/RefField'; +import { DocumentManager } from '../util/DocumentManager'; library.add(faSearch); @@ -35,7 +36,6 @@ export class SearchBox extends React.Component { @action.bound onChange(e: React.ChangeEvent) { this.searchString = e.target.value; - console.log(this.searchString) } @action diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx index 82cb5404c..81da7ebd2 100644 --- a/src/client/views/SearchItem.tsx +++ b/src/client/views/SearchItem.tsx @@ -1,27 +1,15 @@ import React = require("react"); import { Doc } from "../../new_fields/Doc"; +import { DocumentManager } from "../util/DocumentManager"; export interface SearchProps { doc: Doc; - //description: string; - //event: (e: React.MouseEvent) => void; } -// export interface SubmenuProps { -// description: string; -// subitems: ContextMenuProps[]; -// } - -// export interface ContextMenuItemProps { -// type: ContextMenuProps | SubmenuProps; -// } - - - export class SearchItem extends React.Component { onClick = () => { - console.log("document clicked: ", this.props.doc); + DocumentManager.Instance.jumpToDocument(this.props.doc) } render() { diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 08cfa590b..611cb66b6 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -31,28 +31,7 @@ export class LinkBox extends React.Component { @undoBatch onViewButtonPressed = async (e: React.PointerEvent): Promise => { e.stopPropagation(); - let docView = DocumentManager.Instance.getDocumentView(this.props.pairedDoc); - if (docView) { - docView.props.focus(docView.props.Document); - } else { - const contextDoc = await Cast(this.props.pairedDoc.annotationOn, Doc); - if (!contextDoc) { - CollectionDockingView.Instance.AddRightSplit(Doc.MakeDelegate(this.props.pairedDoc)); - } else { - const page = NumCast(this.props.pairedDoc.page, undefined); - const curPage = NumCast(contextDoc.curPage, undefined); - if (page !== curPage) { - contextDoc.curPage = page; - } - let contextView = DocumentManager.Instance.getDocumentView(contextDoc); - if (contextView) { - contextDoc.panTransformType = "Ease"; - contextView.props.focus(contextDoc); - } else { - CollectionDockingView.Instance.AddRightSplit(contextDoc); - } - } - } + DocumentManager.Instance.jumpToDocument(this.props.pairedDoc); } onEditButtonPressed = (e: React.PointerEvent): void => { -- cgit v1.2.3-70-g09d2 From 152fadbad5d3c4e9c452bb6a1ade543bd84c6416 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 7 May 2019 19:26:36 -0400 Subject: Added copy fields to search to enable easier searching --- solr/conf/schema.xml | 13 ++++++++++--- src/server/Search.ts | 26 -------------------------- src/server/index.ts | 3 --- 3 files changed, 10 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/solr/conf/schema.xml b/solr/conf/schema.xml index 5e80b17d9..99087a1db 100644 --- a/solr/conf/schema.xml +++ b/solr/conf/schema.xml @@ -40,10 +40,17 @@ - + - - + + + + + + + + + diff --git a/src/server/Search.ts b/src/server/Search.ts index 4911edd1d..59bdd4803 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -5,34 +5,8 @@ import { thisExpression } from 'babel-types'; export class Search { public static Instance = new Search(); private url = 'http://localhost:8983/solr/'; - private client: any; - - constructor() { - console.log("Search Instantiated!"); - var SolrNode = require('solr-node'); - this.client = new SolrNode({ - host: 'localhost', - port: '8983', - core: 'dash', - protocol: 'http' - }); - var strQuery = this.client.query().q('text:test'); - - console.log(strQuery); - - // Search documents using strQuery - // client.search(strQuery, (err: any, result: any) => { - // if (err) { - // console.log(err); - // return; - // } - // console.log('Response:', result.response); - // }); - } - public async updateDocument(document: any) { - console.log("UPDATE: ", JSON.stringify(document)); return rp.post(this.url + "dash/update", { headers: { 'content-type': 'application/json' }, body: JSON.stringify([document]) diff --git a/src/server/index.ts b/src/server/index.ts index 6b92e8e8e..44251de3d 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -308,7 +308,6 @@ function UpdateField(socket: Socket, diff: Diff) { return; } const update: any = { id: diff.id }; - console.log("FIELD: ", docfield); let dynfield = false; for (let key in docfield) { if (!key.startsWith("fields.")) continue; @@ -322,14 +321,12 @@ function UpdateField(socket: Socket, diff: Diff) { } } if (dynfield) { - console.log("dynamic field detected!"); Search.Instance.updateDocument(update); } } function CreateField(newValue: any) { Database.Instance.insert(newValue, "newDocuments"); - console.log("created field"); } server.listen(serverPort); -- cgit v1.2.3-70-g09d2 From 85d8e29c15b45cd83d258f185d3d55ff400a145e Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 7 May 2019 21:57:48 -0400 Subject: Added date support --- solr/conf/schema.xml | 1 + solr/conf/solrconfig.xml | 2 +- src/server/index.ts | 24 ++++++++++++++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/solr/conf/schema.xml b/solr/conf/schema.xml index 99087a1db..3d1ccb698 100644 --- a/solr/conf/schema.xml +++ b/solr/conf/schema.xml @@ -46,6 +46,7 @@ + diff --git a/solr/conf/solrconfig.xml b/solr/conf/solrconfig.xml index 981500022..90eff5363 100644 --- a/solr/conf/solrconfig.xml +++ b/solr/conf/solrconfig.xml @@ -696,7 +696,7 @@ explicit 10 - data + text diff --git a/src/server/index.ts b/src/server/index.ts index 44251de3d..5023bf717 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -296,10 +296,17 @@ function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => v } -const suffixMap: { [type: string]: string } = { +const suffixMap: { [type: string]: string | [string, string] | [string, string, (json: any) => any] } = { "number": "_n", - "string": "_t" + "string": "_t", + "image": ["_t", "url"], + "video": ["_t", "url"], + "pdf": ["_t", "url"], + "audio": ["_t", "url"], + "web": ["_t", "url"], + "date": ["_d", "date", millis => new Date(millis).toISOString()], }; + function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); @@ -311,9 +318,18 @@ function UpdateField(socket: Socket, diff: Diff) { let dynfield = false; for (let key in docfield) { if (!key.startsWith("fields.")) continue; - const val = docfield[key]; - const suffix = suffixMap[typeof val]; + let val = docfield[key]; + const type = val.__type || typeof val; + let suffix = suffixMap[type]; if (suffix !== undefined) { + if (Array.isArray(suffix)) { + val = val[suffix[1]]; + const func = suffix[2]; + if (func) { + val = func(val); + } + suffix = suffix[0]; + } key = key.substring(7); Object.values(suffixMap).forEach(suf => update[key + suf] = null); update[key + suffix] = { set: val }; -- cgit v1.2.3-70-g09d2 From 823b04d8084f14e298a408615eccf712dd76e2b9 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 7 May 2019 22:27:15 -0400 Subject: Removed console.logs --- src/server/Search.ts | 2 -- src/server/index.ts | 1 - 2 files changed, 3 deletions(-) (limited to 'src') diff --git a/src/server/Search.ts b/src/server/Search.ts index 7a670e21b..59bdd4803 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -14,8 +14,6 @@ export class Search { } public async search(query: string) { - console.log("____________________________"); - console.log(query); const searchResults = JSON.parse(await rp.get(this.url + "dash/select", { qs: { q: query diff --git a/src/server/index.ts b/src/server/index.ts index 5023bf717..5c54babb2 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -128,7 +128,6 @@ app.get("/pull", (req, res) => app.get("/search", async (req, res) => { let query = req.query.query || "hello"; let results = await Search.Instance.search(query); - console.log(results); res.send(results); }); -- cgit v1.2.3-70-g09d2 From d588a4543f1ccc06d1e45fe748007b730c18c042 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 8 May 2019 00:45:14 -0400 Subject: small fixes to titles, templates, minimizing, and keyvalue deletion --- src/client/views/Templates.tsx | 12 ++++++++++-- .../views/collections/collectionFreeForm/MarqueeView.tsx | 13 +++++++++++-- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 6 +++--- src/client/views/nodes/DocumentContentsView.tsx | 14 ++++++++++---- src/client/views/nodes/KeyValuePair.tsx | 5 +++-- 5 files changed, 37 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 51fca4c41..de94a1578 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -50,6 +50,10 @@ export namespace Templates { `
{layout}
` ); + export const TitleOverlay = new Template("TitleOverlay", TemplatePosition.InnerTop, + `
{layout}
+
{props.Document.title}
` + ); export const Title = new Template("Title", TemplatePosition.InnerTop, `
{layout}
{props.Document.title}
` @@ -57,10 +61,14 @@ export namespace Templates { export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, `
{layout}
-
` +
+ +
+
` ); - export const TemplateList: Template[] = [Title, OuterCaption, InnerCaption, SideCaption, Bullet]; + export const TemplateList: Template[] = [Title, TitleOverlay, OuterCaption, InnerCaption, SideCaption, Bullet]; export function sortTemplates(a: Template, b: Template) { if (a.Position < b.Position) { return -1; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c9b0b28f7..b9a6792ed 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -63,8 +63,17 @@ export class MarqueeView extends React.Component let text = await navigator.clipboard.readText(); let ns = text.split("\n").filter(t => t != "\r"); for (let i = 0; i < ns.length - 1; i++) { - while (!(ns[i].endsWith("-\r") || ns[i].endsWith(".\r") || ns[i].endsWith(":\r")) && i < ns.length - 1) { - ns.splice(i, 2, ns[i].substr(0, ns[i].length - 1) + ns[i + 1].trimLeft()); + if (ns[i].trim() === "") { + ns.splice(i, 1); + continue; + } + while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || + ns[i].endsWith(".\r") || ns[i].endsWith(".") || + ns[i].endsWith(":\r") || ns[i].endsWith(":")) && i < ns.length - 1) { + let sub = ns[i].endsWith("\r") ? 1 : 0; + let br = ns[i + 1].trim() === ""; + ns.splice(i, 2, ns[i].substr(0, ns[i].length - sub) + ns[i + 1].trimLeft()); + if (br) break; } } ns.map(line => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index df78d92e2..0e34cb626 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -145,8 +145,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { - layout = template.replace("{layout}", base); - base = layout; - }); + // bcz: templates are intended for the main document layout. However, + // a DocumentContentsView is also used to render the annotation overlay for a document. + // So we detect that here by checking the layoutKey. This should probably be moved into + // a prop so that the overlay can explicitly turn off templates. + if (this.props.layoutKey !== "backgroundLayout") { + this.templates.forEach(template => { + layout = template.replace("{layout}", base); + base = layout; + }); + } return layout; } diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 203fb5625..5de660d57 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -46,8 +46,9 @@ export class KeyValuePair extends React.Component {
-- cgit v1.2.3-70-g09d2 From a8a5cf33985c47cb6e7c68f30c482232fc8d023a Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 8 May 2019 10:13:13 -0400 Subject: converted template constants to screen space - need to think about more flexible api --- src/client/views/Templates.tsx | 8 ++++++-- src/client/views/nodes/DocumentContentsView.tsx | 14 ++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index de94a1578..6f706bdc5 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -52,11 +52,15 @@ export namespace Templates { export const TitleOverlay = new Template("TitleOverlay", TemplatePosition.InnerTop, `
{layout}
-
{props.Document.title}
` +
+ {props.Document.title} +
` ); export const Title = new Template("Title", TemplatePosition.InnerTop, `
{layout}
-
{props.Document.title}
` +
+ {props.Document.title} +
` ); export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 1dc6343e8..294e17720 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -64,13 +64,19 @@ export class DocumentContentsView extends React.Component { - layout = template.replace("{layout}", base); + let self = this; + function convertConstantsToNative(match: string, offset: number, x: string) { + let px = Number(match.replace("px", "")); + return `${px * self.props.ScreenToLocalTransform().Scale}px`; + } + let nativizedTemplate = template.replace(/([0-9]+)px/g, convertConstantsToNative); + layout = nativizedTemplate.replace("{layout}", base); base = layout; }); } -- cgit v1.2.3-70-g09d2 From a573867d2443a806f174db58e2a920db3405934c Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 8 May 2019 10:23:28 -0400 Subject: added delete from non-data keys in tree view. fixed undo iconanimating problem --- src/client/views/collections/CollectionTreeView.tsx | 20 ++++++++++++-------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 6fa374464..6e690236f 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -68,8 +68,8 @@ class TreeView extends React.Component { } @action - remove = (document: Document) => { - let children = Cast(this.props.document.data, listSpec(Doc), []); + remove = (document: Document, key: string) => { + let children = Cast(this.props.document[key], listSpec(Doc), []); if (children) { children.splice(children.indexOf(document), 1); } @@ -81,7 +81,7 @@ class TreeView extends React.Component { return true; } //TODO This should check if it was removed - this.remove(document); + this.remove(document, "data"); return addDoc(document); } @@ -136,7 +136,11 @@ class TreeView extends React.Component { if (DocumentManager.Instance.getDocumentViews(this.props.document).length) { ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document)) }); } - ContextMenu.Instance.addItem({ description: "Delete", event: undoBatch(() => this.props.deleteDoc(this.props.document)) }); + ContextMenu.Instance.addItem({ + description: "Delete", event: undoBatch(() => { + this.props.deleteDoc(this.props.document); + }) + }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); e.stopPropagation(); } @@ -160,7 +164,7 @@ class TreeView extends React.Component { contentElement.push(
    {(key === "data") ? (null) : {key}} - {TreeView.GetChildElements(docList, key !== "data", this.remove, this.move, this.props.dropAction)} + {TreeView.GetChildElements(docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)}
); } else bulletType = BulletType.Collapsed; @@ -175,9 +179,9 @@ class TreeView extends React.Component {
; } - public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child => - ); + public static GetChildElements(docs: (Doc | Promise)[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { + return docs.filter(child => child instanceof Doc && !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child => + ); } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 0e34cb626..5efc75793 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -138,7 +138,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); if (!iconAnimating || (Date.now() - iconAnimating[6] > 1000)) { -- cgit v1.2.3-70-g09d2 From 9573fe783fe9edfa38421d806a473d4cc496733f Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 8 May 2019 11:16:30 -0400 Subject: cleaned up template menu. made icon doc deletable. --- src/client/util/UndoManager.ts | 5 ++++- src/client/views/DocumentDecorations.scss | 7 ++++--- src/client/views/DocumentDecorations.tsx | 7 +++---- src/client/views/TemplateMenu.tsx | 4 +--- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 - 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index 0b5280c4a..c0ed015bd 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -1,7 +1,6 @@ import { observable, action, runInAction } from "mobx"; import 'source-map-support/register'; import { Without } from "../../Utils"; -import { string } from "prop-types"; function getBatchName(target: any, key: string | symbol): string { let keyName = key.toString(); @@ -94,6 +93,10 @@ export namespace UndoManager { return redoStack.length > 0; } + export function PrintBatches(): void { + GetOpenBatches().forEach(batch => console.log(batch.batchName)); + } + let openBatches: Batch[] = []; export function GetOpenBatches(): Without[] { return openBatches; diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 158b02b5a..6a2e33836 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -210,14 +210,15 @@ $linkGap : 3px; position: absolute; top: 0; left: 30px; - width: 150px; - line-height: 25px; - max-height: 175px; + width: max-content; font-family: $sans-serif; font-size: 12px; background-color: $light-color-secondary; padding: 2px 12px; list-style: none; + .templateToggle { + text-align: left; + } input { margin-right: 10px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8ae71fdc8..e3eb034fa 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -29,6 +29,7 @@ import { CollectionFreeFormView } from "./collections/collectionFreeForm/Collect import { CollectionView } from "./collections/CollectionView"; import { createCipher } from "crypto"; import { FieldView } from "./nodes/FieldView"; +import { DocumentManager } from "../util/DocumentManager"; library.add(faLink); @@ -277,13 +278,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> public getIconDoc = async (docView: DocumentView): Promise => { let doc = docView.props.Document; let iconDoc: Doc | undefined = await Cast(doc.minimizedDoc, Doc); - if (!iconDoc) { + + if (!iconDoc || !DocumentManager.Instance.getDocumentView(iconDoc)) { const layout = StrCast(doc.backgroundLayout, StrCast(doc.layout, FieldView.LayoutString(DocumentView))); iconDoc = this.createIcon([docView], layout); } - if (SelectionManager.SelectedDocuments()[0].props.addDocument !== undefined) { - SelectionManager.SelectedDocuments()[0].props.addDocument!(iconDoc!); - } return iconDoc; } moveIconDoc(iconDoc: Doc) { diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 376feb5a5..d74982ef8 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -15,7 +15,7 @@ class TemplateToggle extends React.Component<{ template: Template, checked: bool render() { if (this.props.template) { return ( -
  • +
  • this.props.toggle(event, this.props.template)} /> {this.props.template.Name}
  • @@ -45,7 +45,6 @@ export class TemplateMenu extends React.Component { this.props.docs.map(d => d.addTemplate(template)); } this.props.templates.set(template, true); - this.props.templates.forEach((checked, template) => console.log("Set Checked + " + checked + " " + this.props.templates.get(template))); } else { if (template.Name == "Bullet") { this.props.docs[0].removeTemplate(template); @@ -54,7 +53,6 @@ export class TemplateMenu extends React.Component { this.props.docs.map(d => d.removeTemplate(template)); } this.props.templates.set(template, false); - this.props.templates.forEach((checked, template) => console.log("Unset Checked + " + checked + " " + this.props.templates.get(template))); } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 5efc75793..a9c53933e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -127,7 +127,6 @@ export class CollectionFreeFormDocumentView extends DocComponent => { - UndoManager.GetOpenBatches().forEach(batch => console.log(batch.batchName)); SelectionManager.DeselectAll(); let isMinimized: boolean | undefined; let maximizedDocs = await DocListCast(this.props.Document.maximizedDocs); -- cgit v1.2.3-70-g09d2 From 6f9316683929b86e27fd4e2e30609670cd89f964 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 8 May 2019 12:10:07 -0400 Subject: adjusted titling of icons and summaries. --- .../collectionFreeForm/MarqueeView.scss | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 55 ++++++++++++---------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 23 ++++++--- src/client/views/nodes/IconBox.tsx | 11 ----- 5 files changed, 48 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index ae0a9fd48..6e8ec8662 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -21,6 +21,6 @@ white-space:nowrap; } .marquee-legend::after { - content: "Press: C (collection), or Delete" + content: "Press: c (collection), s (summary), r (replace) or Delete" } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b9a6792ed..9764db1d4 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -9,7 +9,7 @@ import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); -import { Utils } from "../../../../Utils"; +import { Utils, deepCopy } from "../../../../Utils"; import { Doc } from "../../../../new_fields/Doc"; import { NumCast, Cast } from "../../../../new_fields/Types"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; @@ -68,6 +68,7 @@ export class MarqueeView extends React.Component continue; } while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || + ns[i].endsWith(";\r") || ns[i].endsWith(";") || ns[i].endsWith(".\r") || ns[i].endsWith(".") || ns[i].endsWith(":\r") || ns[i].endsWith(":")) && i < ns.length - 1) { let sub = ns[i].endsWith("\r") ? 1 : 0; @@ -182,12 +183,19 @@ export class MarqueeView extends React.Component this.cleanupInteractions(false); e.stopPropagation(); } - if (e.key === "c" || e.key === "r" || e.key === "R" || e.key === "e") { + if (e.key === "c" || e.key === "r" || e.key === "s" || e.key === "e") { this._commandExecuted = true; e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { - if (e.key !== "R") { + if (e.key === "s") { + let dCopy = Doc.MakeCopy(d); + dCopy.x = NumCast(d.x) - bounds.left - bounds.width / 2; + dCopy.y = NumCast(d.y) - bounds.top - bounds.height / 2; + dCopy.page = -1; + return dCopy; + } + else if (e.key !== "r") { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; @@ -208,25 +216,20 @@ export class MarqueeView extends React.Component width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, ink: inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined, - title: "a nested collection" + title: "a nested collection", }); this.marqueeInkDelete(inkData); // SelectionManager.DeselectAll(); - if (e.key === "r" || e.key === "R") { + if (e.key === "s" || e.key === "r") { e.preventDefault(); let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - if (e.key === "r") { + if (e.key === "s") { summary.proto!.maximizeOnRight = true; - let list = Cast(newCollection.data, listSpec(Doc)); - if (list && list.length === 1) { - selected = list; - } else { - selected = [newCollection]; - this.props.addDocument(newCollection, false); - } + newCollection.proto!.summaryDoc = summary; + selected = [newCollection]; } summary.proto!.maximizedDocs = new List(selected); summary.proto!.isButton = true; @@ -243,20 +246,20 @@ export class MarqueeView extends React.Component this.props.addDocument(newCollection, false); } this.cleanupInteractions(false); - } - if (e.key === "s") { - this._commandExecuted = true; - e.stopPropagation(); - e.preventDefault(); - let bounds = this.Bounds; - let selected = this.marqueeSelect(); - SelectionManager.DeselectAll(); - let summary = Docs.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - this.props.addLiveTextDocument(summary); - selected.forEach(select => Doc.MakeLink(summary.proto!, select.proto!)); + } else + if (e.key === "s") { + // this._commandExecuted = true; + // e.stopPropagation(); + // e.preventDefault(); + // let bounds = this.Bounds; + // let selected = this.marqueeSelect(); + // SelectionManager.DeselectAll(); + // let summary = Docs.TextDocument({ x: bounds.left + bounds.width + 25, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + // this.props.addLiveTextDocument(summary); + // selected.forEach(select => Doc.MakeLink(summary.proto!, select.proto!)); - this.cleanupInteractions(false); - } + // this.cleanupInteractions(false); + } } @action marqueeInkSelect(ink: Map) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a9c53933e..1f8d22ab0 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -185,6 +185,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { + maxDoc.isMinimized = false; if (!dataDocs || dataDocs.indexOf(maxDoc) == -1) { CollectionDockingView.Instance.AddRightSplit(maxDoc); } else { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a20a8a93b..38efeeba5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,4 +1,4 @@ -import { action, computed, runInAction } from "mobx"; +import { action, computed, runInAction, reaction, IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; import { emptyFunction, Utils } from "../../../Utils"; import { Docs } from "../../documents/Documents"; @@ -16,10 +16,10 @@ import { Template, Templates } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Opt, Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; +import { Opt, Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { FieldValue, StrCast, BoolCast } from "../../../new_fields/Types"; +import { FieldValue, StrCast, BoolCast, Cast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; @@ -99,6 +99,7 @@ export class DocumentView extends DocComponent(Docu set templates(templates: List) { this.props.Document.templates = templates; } screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect(); + _reactionDisposer?: IReactionDisposer; @action componentDidMount() { if (this._mainCont.current) { @@ -106,6 +107,17 @@ export class DocumentView extends DocComponent(Docu handlers: { drop: this.drop.bind(this) } }); } + this._reactionDisposer = reaction(() => [this.props.Document.maximizedDocs, this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""], + async () => { + let maxDoc = await DocListCast(this.props.Document.maximizedDocs); + if (maxDoc && StrCast(this.props.Document.layout).indexOf("IconBox") !== -1) { + this.props.Document.title = (maxDoc && maxDoc.length === 1 ? maxDoc[0].title + ".icon" : ""); + } + let sumDoc = Cast(this.props.Document.summaryDoc, Doc); + if (sumDoc instanceof Doc) { + this.props.Document.title = sumDoc.title + ".expanded"; + } + }, { fireImmediately: true }); DocumentManager.Instance.DocumentViews.push(this); } @action @@ -121,9 +133,8 @@ export class DocumentView extends DocComponent(Docu } @action componentWillUnmount() { - if (this._dropDisposer) { - this._dropDisposer(); - } + if (this._reactionDisposer) this._reactionDisposer(); + if (this._dropDisposer) this._dropDisposer(); DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 19abec4af..4bcb4c636 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -24,17 +24,6 @@ library.add(faFilm); @observer export class IconBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(IconBox); } - _reactionDisposer?: IReactionDisposer; - componentDidMount() { - this._reactionDisposer = reaction(() => [this.props.Document.maximizedDocs], - async () => { - let maxDoc = await DocListCast(this.props.Document.maximizedDocs); - this.props.Document.title = (maxDoc && maxDoc.length === 1 ? maxDoc[0].title + ".icon" : ""); - }, { fireImmediately: true }); - } - componentWillUnmount() { - if (this._reactionDisposer) this._reactionDisposer(); - } @computed get layout(): string { const field = Cast(this.props.Document[this.props.fieldKey], IconField); return field ? field.icon : "

    Error loading icon data

    "; } @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } -- cgit v1.2.3-70-g09d2 From c67fc234cf4a524c19989134d878797563207e93 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 8 May 2019 16:05:02 -0400 Subject: fixes for templates and for dragging --- src/client/util/DragManager.ts | 16 +++++++++------- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 ++++-------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 13 +++++++------ src/client/views/nodes/FormattedTextBox.tsx | 2 +- 5 files changed, 22 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index a3dbe6e43..ec192eaff 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -3,7 +3,7 @@ import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; -import { Doc } from "../../new_fields/Doc"; +import { Doc, DocListCast } from "../../new_fields/Doc"; import { Cast } from "../../new_fields/Types"; import { listSpec } from "../../new_fields/Schema"; @@ -42,12 +42,14 @@ export function SetupDrag(_reference: React.RefObject, docFunc: export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) { let srcTarg = sourceDoc.proto; - let draggedDocs = srcTarg ? - Cast(srcTarg.linkedToDocs, listSpec(Doc), []).map(linkDoc => - Cast(linkDoc.linkedTo, Doc) as Doc) : []; - let draggedFromDocs = srcTarg ? - Cast(srcTarg.linkedFromDocs, listSpec(Doc), []).map(linkDoc => - Cast(linkDoc.linkedFrom, Doc) as Doc) : []; + let draggedDocs: Doc[] = []; + let draggedFromDocs: Doc[] = [] + if (srcTarg) { + let linkToDocs = await DocListCast(srcTarg.linkedToDocs); + let linkFromDocs = await DocListCast(srcTarg.linkedFromDocs); + if (linkToDocs) draggedDocs = linkToDocs.map(linkDoc => Cast(linkDoc.linkedTo, Doc) as Doc); + if (linkFromDocs) draggedFromDocs = linkFromDocs.map(linkDoc => Cast(linkDoc.linkedFrom, Doc) as Doc); + } draggedDocs.push(...draggedFromDocs); if (draggedDocs.length) { let moddrag: Doc[] = []; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7fa945891..fcc73d5b6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -326,10 +326,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @observer class CollectionFreeFormOverlayView extends React.Component { @computed get overlayView() { - let overlayLayout = Cast(this.props.Document.overlayLayout, "string", ""); - return !overlayLayout ? (null) : - (); + return (); } render() { return this.overlayView; @@ -339,10 +337,8 @@ class CollectionFreeFormOverlayView extends React.Component { @observer class CollectionFreeFormBackgroundView extends React.Component boolean }> { @computed get backgroundView() { - let backgroundLayout = Cast(this.props.Document.backgroundLayout, "string", ""); - return !backgroundLayout ? (null) : - (); + return (); } render() { return this.backgroundView; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 1f8d22ab0..470c0c2f8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -170,7 +170,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { this._downX = e.clientX; this._downY = e.clientY; - e.stopPropagation(); + // e.stopPropagation(); } onClick = async (e: React.MouseEvent) => { e.stopPropagation(); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 294e17720..f404b7bc6 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,4 +1,4 @@ -import { computed } from "mobx"; +import { computed, trace } from "mobx"; import { observer } from "mobx-react"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; @@ -45,7 +45,7 @@ export class DocumentContentsView extends React.Component void, layoutKey: string }> { - @computed get layout(): string { return Cast(this.props.Document[this.props.layoutKey], "string", "

    Error loading layout data

    "); } + @computed get layout(): string { return Cast(this.props.Document[this.props.layoutKey], "string", this.props.layoutKey === "layout" ? "

    Error loading layout data

    " : ""); } CreateBindings(): JsxBindings { return { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive).omit }; @@ -58,17 +58,17 @@ export class DocumentContentsView extends React.Component(); } - set templates(templates: List) { this.props.Document.templates = templates; } - get finalLayout() { + @computed get finalLayout() { const baseLayout = this.layout; let base = baseLayout; let layout = baseLayout; - // bcz: templates are intended only for a document's primary layout (not background). However, + // bcz: templates are intended only for a document's primary layout or overlay (not background). However, // a DocumentContentsView is used to render annotation overlays, so we detect that here // by checking the layoutKey. This should probably be moved into // a prop so that the overlay can explicitly turn off templates. - if (this.props.layoutKey !== "backgroundLayout") { + if ((this.props.layoutKey === "overlayLayout" && StrCast(this.props.Document.layout).indexOf("CollectionView") !== -1) || + (this.props.layoutKey === "layout" && StrCast(this.props.Document.layout).indexOf("CollectionView") === -1)) { this.templates.forEach(template => { let self = this; function convertConstantsToNative(match: string, offset: number, x: string) { @@ -84,6 +84,7 @@ export class DocumentContentsView extends React.Component Date: Wed, 8 May 2019 18:31:14 -0400 Subject: fixes for templates including changing the relative order of CollectionOverlayView in the stack --- src/client/views/MainOverlayTextBox.tsx | 1 + src/client/views/Templates.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormLinksView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.scss | 8 ++++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 15 +++++---------- .../views/collections/collectionFreeForm/MarqueeView.tsx | 3 +++ src/client/views/nodes/FormattedTextBox.scss | 1 + src/client/views/nodes/FormattedTextBox.tsx | 6 ++---- 8 files changed, 20 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index d32e3f21b..3b75c248a 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -43,6 +43,7 @@ export class MainOverlayTextBox extends React.Component this._textXf = tx ? tx : () => Transform.Identity(); this._textTargetDiv = div; if (div) { + if (div.parentElement && div.parentElement instanceof HTMLDivElement && div.parentElement.id === "screenSpace") this._textXf = () => Transform.Identity(); this._textColor = div.style.color; div.style.color = "transparent"; this.TextScroll = div.scrollTop; diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 6f706bdc5..02f9aa510 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -39,7 +39,7 @@ export namespace Templates { // export const BasicLayout = new Template("Basic layout", "{layout}"); export const OuterCaption = new Template("Outer caption", TemplatePosition.OutterBottom, - `
    {layout}
    ` + `
    ` ); export const InnerCaption = new Template("Inner caption", TemplatePosition.InnerBottom, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 2d815a302..cbfbb1d2c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,4 +1,4 @@ -import { computed, IReactionDisposer, reaction } from "mobx"; +import { computed, IReactionDisposer, reaction, trace } from "mobx"; import { observer } from "mobx-react"; import { Utils } from "../../../../Utils"; import { DocumentManager } from "../../../util/DocumentManager"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index cb849b325..063c9e2cf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -37,7 +37,9 @@ border-radius: $border-radius; box-sizing: border-box; position: absolute; - overflow: hidden; + .marqueeView { + overflow: hidden; + } top: 0; left: 0; width: 100%; @@ -61,7 +63,9 @@ border-radius: $border-radius; box-sizing: border-box; position:absolute; - overflow: hidden; + .marqueeView { + overflow: hidden; + } top: 0; left: 0; width: 100%; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fcc73d5b6..797f94d5f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -110,15 +110,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerDown = (e: React.PointerEvent): void => { - let childSelected = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), [] as Doc[]).filter(doc => doc).reduce((childSelected, doc) => { - var dv = DocumentManager.Instance.getDocumentView(doc); - return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false); - }, false); if ((CollectionFreeFormView.RIGHT_BTN_DRAG && (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || - (e.button === 0 && e.altKey)) && (childSelected || this.props.active()))) || + (e.button === 0 && e.altKey)) && this.props.active())) || (!CollectionFreeFormView.RIGHT_BTN_DRAG && - ((e.button === 0 && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && (childSelected || this.props.active())))) { + ((e.button === 0 && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && this.props.active()))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); @@ -233,7 +229,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return NumCast(doc1.zIndex) - NumCast(doc2.zIndex); }).forEach((doc, index) => doc.zIndex = index + 1); doc.zIndex = docs.length + 1; - return doc; } focusDocument = (doc: Doc) => { @@ -316,18 +311,18 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {/* */} - +
    ); } } @observer -class CollectionFreeFormOverlayView extends React.Component { +class CollectionFreeFormOverlayView extends React.Component boolean }> { @computed get overlayView() { return (); + isTopMost={this.props.isTopMost} isSelected={this.props.isSelected} select={emptyFunction} />); } render() { return this.overlayView; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 9764db1d4..740c50297 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -101,6 +101,8 @@ export class MarqueeView extends React.Component document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); + console.log(this.props.container.props.Document.title); + e.stopPropagation(); } if (e.altKey) { e.preventDefault(); @@ -180,6 +182,7 @@ export class MarqueeView extends React.Component if (ink) { this.marqueeInkDelete(ink.inkData); } + SelectionManager.DeselectAll(); this.cleanupInteractions(false); e.stopPropagation(); } diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 9e58a8e7f..458a62c5b 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -17,6 +17,7 @@ border-radius: inherit; border-color: $intermediate-color; box-sizing: border-box; + background-color: inherit; border-style: solid; overflow-y: scroll; overflow-x: hidden; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ee6000da7..4b3172e82 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -24,8 +24,8 @@ import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; import { RichTextField } from "../../../new_fields/RichTextField"; import { Id } from "../../../new_fields/RefField"; import { UndoManager } from "../../util/UndoManager"; -const { buildMenuItems } = require("prosemirror-example-setup"); -const { menuBar } = require("prosemirror-menu"); +import { Transform } from "prosemirror-transform"; +import { Transform as MatrixTransform } from "../../util/Transform"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -306,13 +306,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe render() { let style = this.props.isOverlay ? "scroll" : "hidden"; let rounded = NumCast(this.props.Document.borderRounding) < 0 ? "-rounded" : ""; - let color = StrCast(this.props.Document.backgroundColor); let interactive = InkingControl.Instance.selectedTool ? "" : "interactive"; return (
    Date: Wed, 8 May 2019 18:41:15 -0400 Subject: fixed selection after marquee. --- .../views/collections/collectionFreeForm/MarqueeView.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 740c50297..0345d5efd 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -9,16 +9,11 @@ import { PreviewCursor } from "../../PreviewCursor"; import { CollectionFreeFormView } from "./CollectionFreeFormView"; import "./MarqueeView.scss"; import React = require("react"); -import { Utils, deepCopy } from "../../../../Utils"; +import { Utils } from "../../../../Utils"; import { Doc } from "../../../../new_fields/Doc"; import { NumCast, Cast } from "../../../../new_fields/Types"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; -import { Templates } from "../../Templates"; import { List } from "../../../../new_fields/List"; -import { emitKeypressEvents } from "readline"; -import { listSpec } from "../../../../new_fields/Schema"; -import { undo } from "prosemirror-history"; -import { FormattedTextBox } from "../../nodes/FormattedTextBox"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -101,7 +96,6 @@ export class MarqueeView extends React.Component document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); - console.log(this.props.container.props.Document.title); e.stopPropagation(); } if (e.altKey) { @@ -247,6 +241,8 @@ export class MarqueeView extends React.Component } else { this.props.addDocument(newCollection, false); + SelectionManager.DeselectAll(); + this.props.selectDocuments([newCollection]); } this.cleanupInteractions(false); } else -- cgit v1.2.3-70-g09d2 From b5fac34cf22bcb47854c00671848e25b7ee9d37f Mon Sep 17 00:00:00 2001 From: Monika Hedman Date: Wed, 8 May 2019 20:38:02 -0400 Subject: issues with icon --- src/client/views/SearchBox.scss | 50 ++++++++++++++++++++--------------------- src/client/views/SearchBox.tsx | 24 +++++++++++++++----- src/client/views/SearchItem.tsx | 36 ++++++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/client/views/SearchBox.scss b/src/client/views/SearchBox.scss index f4fc0029e..792d6dd3c 100644 --- a/src/client/views/SearchBox.scss +++ b/src/client/views/SearchBox.scss @@ -68,32 +68,32 @@ top: 300px; display: flex; flex-direction: column; -} -.search-item { - width: 500px; - height: 50px; - background: $light-color-secondary; - display: flex; - justify-content: left; - align-items: center; - transition: all 0.1s; - border-width: 0.11px; - border-style: none; - border-color: $intermediate-color; - border-bottom-style: solid; - padding: 10px; - white-space: nowrap; - font-size: 13px; -} + .search-item { + width: 500px; + height: 50px; + background: $light-color-secondary; + display: flex; + justify-content: space-between; + align-items: center; + transition: all 0.1s; + border-width: 0.11px; + border-style: none; + border-color: $intermediate-color; + border-bottom-style: solid; + padding: 10px; + white-space: nowrap; + font-size: 13px; + } -.search-item:hover { - transition: all 0.1s; - background: $lighter-alt-accent; -} + .search-item:hover { + transition: all 0.1s; + background: $lighter-alt-accent; + } -.search-title { - text-transform: uppercase; - text-align: left; - width: 8vw; + .search-title { + text-transform: uppercase; + text-align: left; + width: 8vw; + } } \ No newline at end of file diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx index 827d468df..7dd1af4e7 100644 --- a/src/client/views/SearchBox.tsx +++ b/src/client/views/SearchBox.tsx @@ -67,7 +67,7 @@ export class SearchBox extends React.Component { } @action - handleClick = (e: Event): void => { + handleClickFilter = (e: Event): void => { var className = (e.target as any).className; var id = (e.target as any).id; if (className !== "filter-button" && className !== "filter-form") { @@ -76,16 +76,28 @@ export class SearchBox extends React.Component { } + @action + handleClickResults = (e: Event): void => { + var className = (e.target as any).className; + var id = (e.target as any).id; + if (id !== "result") { + this._resultsOpen = false; + } + + } + componentWillMount() { - document.addEventListener('mousedown', this.handleClick, false); + document.addEventListener('mousedown', this.handleClickFilter, false); + document.addEventListener('mousedown', this.handleClickResults, false); } componentWillUnmount() { - document.removeEventListener('mousedown', this.handleClick, false); + document.removeEventListener('mousedown', this.handleClickFilter, false); + document.removeEventListener('mousedown', this.handleClickResults, false); } @action - toggleDisplay = () => { + toggleFilterDisplay = () => { this._open = !this._open; } @@ -101,9 +113,9 @@ export class SearchBox extends React.Component {
    - +
    -
    +
    {this._results.map(result => )}
    diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx index 81da7ebd2..539d6b5e5 100644 --- a/src/client/views/SearchItem.tsx +++ b/src/client/views/SearchItem.tsx @@ -1,21 +1,51 @@ import React = require("react"); import { Doc } from "../../new_fields/Doc"; import { DocumentManager } from "../util/DocumentManager"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Cast } from "../../new_fields/Types"; +import { FieldView, FieldViewProps } from './nodes/FieldView'; +import { computed } from "mobx"; +import { IconField } from "../../new_fields/IconField"; + export interface SearchProps { doc: Doc; } +library.add(faCaretUp); +library.add(faObjectGroup); +library.add(faStickyNote); +library.add(faFilePdf); +library.add(faFilm); + export class SearchItem extends React.Component { onClick = () => { - DocumentManager.Instance.jumpToDocument(this.props.doc) + DocumentManager.Instance.jumpToDocument(this.props.doc); + } + + //needs help + // @computed get layout(): string { const field = Cast(this.props.doc[fieldKey], IconField); return field ? field.icon : "

    Error loading icon data

    "; } + + + public static DocumentIcon(layout: string) { + let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf : + layout.indexOf("ImageBox") !== -1 ? faImage : + layout.indexOf("Formatted") !== -1 ? faStickyNote : + layout.indexOf("Video") !== -1 ? faFilm : + layout.indexOf("Collection") !== -1 ? faObjectGroup : + faCaretUp; + return ; } render() { return ( -
    -
    {this.props.doc.title}
    +
    +
    title: {this.props.doc.title}
    +
    Type: {this.props.doc.layout}
    + {/*
    {SearchItem.DocumentIcon(this.layout)}
    */}
    ); } -- cgit v1.2.3-70-g09d2 From 086391b7e45ed4b3cb29602a776f5812f142fff2 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 8 May 2019 22:30:46 -0400 Subject: restoration of cursor functionality: cursor field --- src/client/views/collections/CollectionSubView.tsx | 21 +++---- .../CollectionFreeFormRemoteCursors.tsx | 66 +++++++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/new_fields/CursorField.ts | 55 ++++++++++++++++++ src/new_fields/InkField.ts | 3 +- src/new_fields/List.ts | 39 +++++++++++-- src/new_fields/TupleField.ts | 63 --------------------- 7 files changed, 140 insertions(+), 111 deletions(-) create mode 100644 src/new_fields/CursorField.ts delete mode 100644 src/new_fields/TupleField.ts (limited to 'src') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1e8723fc6..232679a59 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,14 +10,14 @@ import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, Opt } from "../../../new_fields/Doc"; +import { Doc, Opt, FieldResult } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { listSpec } from "../../../new_fields/Schema"; -import { Cast, PromiseValue, FieldValue } from "../../../new_fields/Types"; +import { Cast, PromiseValue, FieldValue, ListSpec } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; import { ObjectField } from "../../../new_fields/ObjectField"; -import { TupleField } from "../../../new_fields/TupleField"; +import CursorField, { CursorPosition, CursorMetadata } from "../../../new_fields/CursorField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; @@ -31,8 +31,6 @@ export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: CollectionView | CollectionPDFView | CollectionVideoView; } -export type CursorEntry = TupleField<[string, string], [number, number]>; - export function CollectionSubView(schemaCtor: (doc: Doc) => T) { class CollectionSubView extends DocComponent(schemaCtor) { private dropDisposer?: DragManager.DragDropDisposer; @@ -56,25 +54,24 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @action protected async setCursorPosition(position: [number, number]) { - return; let ind; let doc = this.props.Document; let id = CurrentUserUtils.id; let email = CurrentUserUtils.email; + let pos = { x: position[0], y: position[1] }; if (id && email) { - let textInfo: [string, string] = [id, email]; const proto = await doc.proto; if (!proto) { return; } - let cursors = await Cast(proto!.cursors, listSpec(TupleField)); + let cursors = Cast(proto.cursors, listSpec(CursorField)); if (!cursors) { - proto!.cursors = cursors = new List>(); + proto.cursors = cursors = new List(); } - if (cursors!.length > 0 && (ind = cursors!.findIndex(entry => entry.data[0][0] === id)) > -1) { - cursors![ind].data[1] = position; + if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.data.metadata.id === id)) > -1) { + cursors[ind].setPosition(pos); } else { - let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); + let entry = new CursorField({ metadata: { id: id, identifier: email }, position: pos }); cursors.push(entry); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 036745eca..c22f430ac 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,26 +1,38 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { CollectionViewProps, CursorEntry } from "../CollectionSubView"; +import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); import v5 = require("uuid/v5"); import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; +import CursorField from "../../../../new_fields/CursorField"; +import { List } from "../../../../new_fields/List"; +import { Cast } from "../../../../new_fields/Types"; +import { listSpec } from "../../../../new_fields/Schema"; @observer export class CollectionFreeFormRemoteCursors extends React.Component { - protected getCursors(): CursorEntry[] { + + protected getCursors(): CursorField[] { let doc = this.props.Document; + let id = CurrentUserUtils.id; - let cursors = doc.GetList(KeyStore.Cursors, [] as CursorEntry[]); - let notMe = cursors.filter(entry => entry.Data[0][0] !== id); - return id ? notMe : []; + if (!id) { + return []; + } + + let cursors = Cast(doc.cursors, listSpec(CursorField)); + if (!cursors) { + doc.cursors = cursors = new List(); + } + + return cursors.filter(cursor => cursor.data.metadata.id !== id); } private crosshairs?: HTMLCanvasElement; drawCrosshairs = (backgroundColor: string) => { if (this.crosshairs) { - let c = this.crosshairs; - let ctx = c.getContext('2d'); + let ctx = this.crosshairs.getContext('2d'); if (ctx) { ctx.fillStyle = backgroundColor; ctx.fillRect(0, 0, 20, 20); @@ -49,29 +61,27 @@ export class CollectionFreeFormRemoteCursors extends React.Component { - if (entry.Data.length > 0) { - let id = entry.Data[0][0]; - let email = entry.Data[0][1]; - let point = entry.Data[1]; - this.drawCrosshairs("#" + v5(id, v5.URL).substring(0, 6).toUpperCase() + "22"); - return ( -
    - { if (el) this.crosshairs = el; }} - width={20} - height={20} - /> -

    - {email[0].toUpperCase()} -

    -
    - ); - } + return this.getCursors().map(c => { + let m = c.data.metadata; + let l = c.data.position; + this.drawCrosshairs("#" + v5(m.id, v5.URL).substring(0, 6).toUpperCase() + "22"); + return ( +
    + { if (el) this.crosshairs = el; }} + width={20} + height={20} + /> +

    + {m.identifier[0].toUpperCase()} +

    +
    + ); }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 17c25c9db..59f7fa442 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -70,7 +70,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } public getActiveDocuments = () => { const curPage = FieldValue(this.Document.curPage, -1); - return FieldValue(this.children, [] as Doc[]).filter(doc => { + return this.children.filter(doc => { var page = NumCast(doc.page, -1); return page === curPage || page === -1; }); @@ -314,7 +314,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.childViews} - {/* */} + diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts new file mode 100644 index 000000000..7fd326a5f --- /dev/null +++ b/src/new_fields/CursorField.ts @@ -0,0 +1,55 @@ +import { ObjectField, Copy, OnUpdate } from "./ObjectField"; +import { observable } from "mobx"; +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, createSimpleSchema, object } from "serializr"; + +export type CursorPosition = { + x: number, + y: number +} + +export type CursorMetadata = { + id: string, + identifier: string +} + +export type CursorData = { + metadata: CursorMetadata, + position: CursorPosition +} + +const PositionSchema = createSimpleSchema({ + x: true, + y: true +}); + +const MetadataSchema = createSimpleSchema({ + id: true, + identifier: true +}); + +const CursorSchema = createSimpleSchema({ + metadata: object(MetadataSchema), + position: object(PositionSchema) +}); + +@Deserializable("cursor") +export default class CursorField extends ObjectField { + + @serializable(object(CursorSchema)) + readonly data: CursorData; + + constructor(data: CursorData) { + super(); + this.data = data; + } + + setPosition(position: CursorPosition) { + this.data.position = position; + this[OnUpdate](); + } + + [Copy]() { + return new CursorField(this.data); + } +} \ No newline at end of file diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index a3157857f..2d75f8a19 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,8 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; import { ObjectField, Copy } from "./ObjectField"; -import { number } from "prop-types"; -import { any } from "bluebird"; import { deepCopy } from "../Utils"; export enum InkTool { @@ -11,6 +9,7 @@ export enum InkTool { Highlighter, Eraser } + export interface StrokeData { pathData: Array<{ x: number, y: number }>; color: string; diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 96018dafa..3e5fee646 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,9 +1,9 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; import { Field, Update, Self, FieldResult } from "./Doc"; -import { setter, getter, deleteProperty } from "./util"; +import { setter, getter, deleteProperty, updateFunction } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, action } from "mobx"; -import { ObjectField, OnUpdate, Copy } from "./ObjectField"; +import { ObjectField, OnUpdate, Copy, Parent } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; @@ -27,7 +27,17 @@ const listHandlers: any = { }, push: action(function (this: any, ...items: any[]) { items = items.map(toObjectField); - const res = this[Self].__fields.push(...items); + const list = this[Self]; + const length = list.__fields.length; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i + length, item, this); + } + } + const res = list.__fields.push(...items); this[Update](); return res; }), @@ -48,12 +58,33 @@ const listHandlers: any = { }, splice: action(function (this: any, start: number, deleteCount: number, ...items: any[]) { items = items.map(toObjectField); - const res = this[Self].__fields.splice(start, deleteCount, ...items); + const list = this[Self]; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + //TODO Need to change indices of other fields in array + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i + start, item, this); + } + } + const res = list.__fields.splice(start, deleteCount, ...items); this[Update](); return res.map(toRealField); }), unshift(...items: any[]) { items = items.map(toObjectField); + const list = this[Self]; + const length = list.__fields.length; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + //TODO Need to change indices of other fields in array + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i, item, this); + } + } const res = this[Self].__fields.unshift(...items); this[Update](); return res; diff --git a/src/new_fields/TupleField.ts b/src/new_fields/TupleField.ts deleted file mode 100644 index 1ff57fefc..000000000 --- a/src/new_fields/TupleField.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { ObjectField, Copy } from "./ObjectField"; -import { IObservableArray, IArrayChange, IArraySplice, observe, Lambda, observable } from "mobx"; -import { UndoManager } from "../client/util/UndoManager"; -import { Field } from "./Doc"; -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, createSimpleSchema, list, object } from "serializr"; -import { array } from "prop-types"; - -const tupleSchema = createSimpleSchema({ - -}); - -@Deserializable("tuple") -export class TupleField extends ObjectField { - - - @serializable(list(object(tupleSchema))) - private Data: [T, U]; - - public get data() { - return this.Data; - } - - constructor(data: [T, U]) { - super(); - this.Data = data; - this.observeTuple(); - } - - private observeDisposer: Lambda | undefined; - private observeTuple(): void { - this.observeDisposer = observe(this.Data as (T | U)[] as IObservableArray, (change: IArrayChange | IArraySplice) => { - if (change.type === "update") { - UndoManager.AddEvent({ - undo: () => this.Data[change.index] = change.oldValue, - redo: () => this.Data[change.index] = change.newValue - }); - } else { - throw new Error("Why are you messing with the length of a tuple, huh?"); - } - }); - } - - protected setData(value: [T, U]) { - if (this.observeDisposer) { - this.observeDisposer(); - } - this.Data = observable(value) as (T | U)[] as [T, U]; - this.observeTuple(); - } - - UpdateFromServer(values: [T, U]) { - this.setData(values); - } - - ToScriptString(): string { - return `new TupleField([${this.Data[0], this.Data[1]}])`; - } - - [Copy]() { - return new TupleField(this.Data); - } -} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 59c52553a942d327b3cdf7377eb85f4b0b19c2dd Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 8 May 2019 23:52:13 -0400 Subject: added imageResize handle in text boxes. --- src/client/util/RichTextSchema.tsx | 85 +++++++++++++++++++++- src/client/util/TooltipTextMenu.tsx | 1 + .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- src/client/views/nodes/FormattedTextBox.tsx | 22 ++---- 4 files changed, 91 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 9ef71e305..c036bfe97 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -84,6 +84,7 @@ export const nodes: { [index: string]: NodeSpec } = { inline: true, attrs: { src: {}, + width: { default: "100px" }, alt: { default: null }, title: { default: null } }, @@ -94,11 +95,16 @@ export const nodes: { [index: string]: NodeSpec } = { return { src: dom.getAttribute("src"), title: dom.getAttribute("title"), - alt: dom.getAttribute("alt") - }; + alt: dom.getAttribute("alt"), + width: Math.min(100, Number(dom.getAttribute("width"))), + } } }], - toDOM(node: any) { return ["img", node.attrs]; } + // TODO if we don't define toDom, something weird happens: dragging the image will not move it but clone it. Why? + toDOM(node) { + const attrs = { style: `width: ${node.attrs.width}` } + return ["img", { ...node.attrs, ...attrs }] + } }, // :: NodeSpec A hard line break, represented in the DOM as `
    `. @@ -290,6 +296,13 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + p14: { + parseDOM: [{ style: 'font-size: 14px;' }], + toDOM: () => ['span', { + style: 'font-size: 14px;' + }] + }, + p16: { parseDOM: [{ style: 'font-size: 16px;' }], toDOM: () => ['span', { @@ -325,7 +338,73 @@ export const marks: { [index: string]: MarkSpec } = { }] }, }; +function getFontSize(element: any) { + return parseFloat((getComputedStyle(element) as any).fontSize); +} + +export class ImageResizeView { + _handle: HTMLElement; + _img: HTMLElement; + _outer: HTMLElement; + constructor(node: any, view: any, getPos: any) { + this._handle = document.createElement("span"); + this._img = document.createElement("img"); + this._outer = document.createElement("span"); + this._outer.style.position = "relative"; + this._outer.style.width = node.attrs.width; + this._outer.style.display = "inline-block"; + this._outer.style.overflow = "hidden"; + + this._img.setAttribute("src", node.attrs.src); + this._img.style.width = "100%"; + this._handle.style.position = "absolute"; + this._handle.style.width = "20px"; + this._handle.style.height = "20px"; + this._handle.style.backgroundColor = "blue"; + this._handle.style.borderRadius = "15px"; + this._handle.style.display = "none"; + this._handle.style.bottom = "-10px"; + this._handle.style.right = "-10px"; + let self = this; + this._handle.onpointerdown = function (e: any) { + e.preventDefault(); + const startX = e.pageX; + const startWidth = parseFloat(node.attrs.width); + const onpointermove = (e: any) => { + const currentX = e.pageX; + const diffInPx = currentX - startX; + self._outer.style.width = `${startWidth + diffInPx}`; + } + + const onpointerup = () => { + document.removeEventListener("pointermove", onpointermove); + document.removeEventListener("pointerup", onpointerup); + view.dispatch( + view.state.tr.setNodeMarkup(getPos(), null, + { src: node.attrs.src, width: self._outer.style.width })); + } + + document.addEventListener("pointermove", onpointermove) + document.addEventListener("pointerup", onpointerup) + } + this._outer.appendChild(this._handle); + this._outer.appendChild(this._img); + (this as any).dom = this._outer; + } + + selectNode() { + this._img.classList.add("ProseMirror-selectednode"); + + this._handle.style.display = ""; + } + + deselectNode() { + this._img.classList.remove("ProseMirror-selectednode"); + + this._handle.style.display = "none"; + } +} // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 68a73375e..e33c53a1a 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -94,6 +94,7 @@ export class TooltipTextMenu { this.fontSizeToNum = new Map(); this.fontSizeToNum.set(schema.marks.p10, 10); 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.p24, 24); this.fontSizeToNum.set(schema.marks.p32, 32); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0345d5efd..6057aaeba 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -180,7 +180,7 @@ export class MarqueeView extends React.Component this.cleanupInteractions(false); e.stopPropagation(); } - if (e.key === "c" || e.key === "r" || e.key === "s" || e.key === "e") { + if (e.key === "c" || e.key === "r" || e.key === "s" || e.key === "e" || e.key === "p") { this._commandExecuted = true; e.stopPropagation(); let bounds = this.Bounds; @@ -218,12 +218,12 @@ export class MarqueeView extends React.Component this.marqueeInkDelete(inkData); // SelectionManager.DeselectAll(); - if (e.key === "s" || e.key === "r") { + if (e.key === "s" || e.key === "r" || e.key === "p") { e.preventDefault(); let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - if (e.key === "s") { + if (e.key === "s" || e.key === "p") { summary.proto!.maximizeOnRight = true; newCollection.proto!.summaryDoc = summary; selected = [newCollection]; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 4b3172e82..445a834ee 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -6,7 +6,7 @@ import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { schema } from "../../util/RichTextSchema"; +import { schema, ImageResizeView } from "../../util/RichTextSchema"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { ContextMenu } from "../../views/ContextMenu"; @@ -24,8 +24,6 @@ import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; import { RichTextField } from "../../../new_fields/RichTextField"; import { Id } from "../../../new_fields/RefField"; import { UndoManager } from "../../util/UndoManager"; -import { Transform } from "prosemirror-transform"; -import { Transform as MatrixTransform } from "../../util/Transform"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -149,7 +147,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._proseRef.current) { this._editorView = new EditorView(this._proseRef.current, { state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), - dispatchTransaction: this.dispatchTransaction + dispatchTransaction: this.dispatchTransaction, + nodeViews: { + image(node, view, getPos) { return new ImageResizeView(node, view, getPos) } + } }); let text = StrCast(this.props.Document.documentText); if (text.startsWith("@@@")) { @@ -228,19 +229,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.textCapability }); - - // ContextMenu.Instance.addItem({ - // description: "Submenu", - // items: [ - // { - // description: "item 1", event: - // }, - // { - // description: "item 2", event: - // } - // ] - // }) - // e.stopPropagation() } onPointerWheel = (e: React.WheelEvent): void => { -- cgit v1.2.3-70-g09d2 From fc21d178bd636229ba8338c3f3f9c12cc267a8d3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 9 May 2019 00:01:47 -0400 Subject: keep image selected on pointer up. --- src/client/util/RichTextSchema.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c036bfe97..c0e6f7899 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -368,6 +368,7 @@ export class ImageResizeView { let self = this; this._handle.onpointerdown = function (e: any) { e.preventDefault(); + e.stopPropagation(); const startX = e.pageX; const startWidth = parseFloat(node.attrs.width); const onpointermove = (e: any) => { @@ -381,7 +382,8 @@ export class ImageResizeView { document.removeEventListener("pointerup", onpointerup); view.dispatch( view.state.tr.setNodeMarkup(getPos(), null, - { src: node.attrs.src, width: self._outer.style.width })); + { src: node.attrs.src, width: self._outer.style.width }) + .setSelection(view.state.selection)); } document.addEventListener("pointermove", onpointermove) -- cgit v1.2.3-70-g09d2 From c7b2ccddb6d75283a7255b612693c5e809b68f5f Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 9 May 2019 00:26:09 -0400 Subject: Added lists and documents to search --- solr/conf/schema.xml | 12 +++++---- src/client/documents/Documents.ts | 1 + src/server/index.ts | 51 ++++++++++++++++++++++++++++----------- 3 files changed, 45 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/solr/conf/schema.xml b/solr/conf/schema.xml index 92ba9c6ff..a568db14c 100644 --- a/solr/conf/schema.xml +++ b/solr/conf/schema.xml @@ -35,19 +35,21 @@ - + - - - + + + - + + + diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a770ccc93..00233a989 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -175,6 +175,7 @@ export namespace Docs { if (!("creationDate" in protoProps)) { protoProps.creationDate = new DateField; } + protoProps.isPrototype = true; return SetDelegateOptions(SetInstanceOptions(proto, protoProps, data), delegateProps); } diff --git a/src/server/index.ts b/src/server/index.ts index 5c54babb2..93e4cafbf 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -295,7 +295,7 @@ function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => v } -const suffixMap: { [type: string]: string | [string, string] | [string, string, (json: any) => any] } = { +const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = { "number": "_n", "string": "_t", "image": ["_t", "url"], @@ -303,9 +303,40 @@ const suffixMap: { [type: string]: string | [string, string] | [string, string, "pdf": ["_t", "url"], "audio": ["_t", "url"], "web": ["_t", "url"], - "date": ["_d", "date", millis => new Date(millis).toISOString()], + "date": ["_d", value => new Date(value.date).toISOString()], + "proxy": ["_i", "fieldId"], + "list": ["_l", list => { + const results = []; + for (const value of list.fields) { + const term = ToSearchTerm(value); + if (term) { + results.push(term.value); + } + } + return results.length ? results : null; + }] }; +function ToSearchTerm(val: any): { suffix: string, value: any } | undefined { + const type = val.__type || typeof val; + let suffix = suffixMap[type]; + if (!suffix) { + return; + } + + if (Array.isArray(suffix)) { + const accessor = suffix[1]; + if (typeof accessor === "function") { + val = accessor(val); + } else { + val = val[accessor]; + } + suffix = suffix[0]; + } + + return { suffix, value: val } +} + function UpdateField(socket: Socket, diff: Diff) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false, "newDocuments"); @@ -318,20 +349,12 @@ function UpdateField(socket: Socket, diff: Diff) { for (let key in docfield) { if (!key.startsWith("fields.")) continue; let val = docfield[key]; - const type = val.__type || typeof val; - let suffix = suffixMap[type]; - if (suffix !== undefined) { - if (Array.isArray(suffix)) { - val = val[suffix[1]]; - const func = suffix[2]; - if (func) { - val = func(val); - } - suffix = suffix[0]; - } + let term = ToSearchTerm(val); + if (term !== undefined) { + let { suffix, value } = term; key = key.substring(7); Object.values(suffixMap).forEach(suf => update[key + suf] = null); - update[key + suffix] = { set: val }; + update[key + suffix] = { set: value }; dynfield = true; } } -- cgit v1.2.3-70-g09d2 From 9015421a227ab58f309906eabf884654d3a31a17 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 11:58:36 -0400 Subject: added start of hyperlinks to text boxes --- src/client/util/DragManager.ts | 3 +- src/client/util/TooltipTextMenu.tsx | 101 +++++++++++++++++++++++++++++++- src/client/views/nodes/DocumentView.tsx | 1 + 3 files changed, 102 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index ec192eaff..fbf20e244 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -172,6 +172,7 @@ export namespace DragManager { droppedDocuments: Doc[] = []; linkSourceDocument: Doc; blacklist: Doc[]; + dontClearTextBox?: boolean; [id: string]: any; } @@ -188,7 +189,7 @@ export namespace DragManager { dragDiv.style.pointerEvents = "none"; DragManager.Root().appendChild(dragDiv); } - MainOverlayTextBox.Instance.SetTextDoc(); + if (!dragData.dontClearTextBox) MainOverlayTextBox.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index e33c53a1a..15895fd1c 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -6,19 +6,28 @@ import { keymap } from "prosemirror-keymap"; import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; -import { Schema, NodeType, MarkType } from "prosemirror-model"; +import { Schema, NodeType, MarkType, Mark } from "prosemirror-model"; import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); import { library } from '@fortawesome/fontawesome-svg-core'; import { wrapInList, bulletList, liftListItem, listItem, } from 'prosemirror-schema-list'; -import { liftTarget } from 'prosemirror-transform'; +import { liftTarget, RemoveMarkStep, AddMarkStep } from 'prosemirror-transform'; import { faListUl, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FieldViewProps } from "../views/nodes/FieldView"; import { throwStatement } from "babel-types"; +import { View } from "@react-pdf/renderer"; +import { DragManager } from "./DragManager"; +import { Doc, Opt, Field } from "../../new_fields/Doc"; +import { Id } from "../../new_fields/RefField"; +import { Utils } from "../northstar/utils/Utils"; +import { DocServer } from "../DocServer"; +import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; +import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { DocumentManager } from "./DocumentManager"; const SVG = "http://www.w3.org/2000/svg"; @@ -37,6 +46,8 @@ export class TooltipTextMenu { private fontStylesToName: Map; private listTypeToIcon: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); + private linkEditor?: HTMLDivElement; + private linkText?: HTMLDivElement; //dropdown doms private fontSizeDom?: Node; private fontStyleDom?: Node; @@ -150,6 +161,90 @@ export class TooltipTextMenu { this.tooltip.appendChild(this.fontStyleDom); } + updateLinkMenu() { + if (!this.linkEditor || !this.linkText) { + this.linkEditor = document.createElement("div"); + this.linkEditor.style.color = "white"; + this.linkText = document.createElement("div"); + this.linkText.style.cssFloat = "left"; + this.linkText.style.marginRight = "5px"; + this.linkText.setAttribute("contenteditable", "true"); + this.linkText.style.color = "white"; + let linkBtn = document.createElement("div"); + linkBtn.textContent = ">>"; + linkBtn.style.width = "20px"; + linkBtn.style.height = "20px"; + linkBtn.style.color = "white"; + linkBtn.style.cssFloat = "left"; + linkBtn.onpointerdown = (e: PointerEvent) => { + let node = this.view.state.selection.$from.nodeAfter; + let link = node && node.marks.find(m => m.type.name === "link"); + if (link) { + console.log("Link to : " + link.attrs.href); + let href: string = link.attrs.href; + if (href.indexOf(DocServer.prepend("/doc/")) === 0) { + let docid = href.replace(DocServer.prepend("/doc/"), ""); + DocServer.GetRefField(docid).then(action((f: Opt) => { + if (f instanceof Doc) { + if (DocumentManager.Instance.getDocumentView(f)) + DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + else CollectionDockingView.Instance.AddRightSplit(f); + } + })); + } + e.stopPropagation(); + e.preventDefault(); + } + } + let linkDrag = document.createElement("div"); + linkDrag.textContent = "O"; + linkDrag.style.width = "20px"; + linkDrag.style.height = "20px"; + linkDrag.style.color = "white"; + linkDrag.style.cssFloat = "left"; + linkDrag.onpointerdown = (e: PointerEvent) => { + let dragData = new DragManager.LinkDragData(this.editorProps.Document); + dragData.dontClearTextBox = true; + DragManager.StartLinkDrag(this.linkEditor!, dragData, e.clientX, e.clientY, + { + handlers: { + dragComplete: action(() => { + let m = dragData.droppedDocuments as Doc[]; + this.makeLink(DocServer.prepend("/doc/" + m[0][Id])); + }), + }, + hideSource: false + }) + }; + this.linkEditor.appendChild(this.linkText); + this.linkEditor.appendChild(linkBtn); + this.linkEditor.appendChild(linkDrag) + this.tooltip.appendChild(this.linkEditor); + } + + let node = this.view.state.selection.$from.nodeAfter; + let link = node && node.marks.find(m => m.type.name === "link"); + this.linkText.textContent = link ? link.attrs.href : "-empty-"; + + this.linkText.onkeydown = (e: KeyboardEvent) => { + if (e.key === "Enter") { + this.makeLink(this.linkText!.textContent!); + e.stopPropagation(); + e.preventDefault(); + } + } + this.tooltip.appendChild(this.linkEditor); + } + + makeLink = (target: string) => { + let node = this.view.state.selection.$from.nodeAfter; + let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target }); + 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; + link = node && node.marks.find(m => m.type.name === "link"); + } + //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown updateListItemDropdown(label: string, listTypeBtn: Node) { //remove old btn @@ -348,6 +443,8 @@ export class TooltipTextMenu { } else { //multiple font sizes selected this.updateFontSizeDropdown("Various"); } + + this.updateLinkMenu(); } //finds all active marks on selection in given group diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 38efeeba5..c3bf36553 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -238,6 +238,7 @@ export class DocumentView extends DocComponent(Docu const protoDest = destDoc.proto; const protoSrc = sourceDoc.proto; Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + de.data.droppedDocuments.push(destDoc); e.stopPropagation(); } } -- cgit v1.2.3-70-g09d2 From 244d4d127e7e1a0faadbc5a8baed7922ef03522c Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 14:11:35 -0400 Subject: cleaned up textlinking a little. --- src/client/util/DragManager.ts | 13 ++-- src/client/util/SelectionManager.ts | 4 +- src/client/util/TooltipTextMenu.tsx | 25 +++--- src/client/views/DocumentDecorations.tsx | 8 +- src/client/views/MainOverlayTextBox.tsx | 30 ++++--- .../views/collections/CollectionSchemaView.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 91 ++++++++++++++++++---- 10 files changed, 122 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index fbf20e244..eaf851a75 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,11 +1,9 @@ -import { action } from "mobx"; +import { action, runInAction } from "mobx"; +import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Cast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; -import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; -import { Doc, DocListCast } from "../../new_fields/Doc"; -import { Cast } from "../../new_fields/Types"; -import { listSpec } from "../../new_fields/Schema"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag(_reference: React.RefObject, docFunc: () => Doc, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType) { @@ -154,7 +152,10 @@ export namespace DragManager { [id: string]: any; } + export let StartDragFunctions: (() => void)[] = []; + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { + runInAction(() => StartDragFunctions.map(func => func())); StartDrag(eles, dragData, downX, downY, options, (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.userDropAction == "alias" || (!dragData.userDropAction && dragData.dropAction == "alias") ? @@ -189,7 +190,6 @@ export namespace DragManager { dragDiv.style.pointerEvents = "none"; DragManager.Root().appendChild(dragDiv); } - if (!dragData.dontClearTextBox) MainOverlayTextBox.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; @@ -217,6 +217,7 @@ export namespace DragManager { dragElement.style.top = "0"; dragElement.style.bottom = ""; dragElement.style.left = "0"; + dragElement.style.color = "black"; dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index fe5acf4b4..a3a8172c7 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,7 +1,7 @@ import { observable, action } from "mobx"; import { Doc } from "../../new_fields/Doc"; -import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; import { DocumentView } from "../views/nodes/DocumentView"; +import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; export namespace SelectionManager { class Manager { @@ -25,7 +25,7 @@ export namespace SelectionManager { DeselectAll(): void { manager.SelectedDocuments.map(dv => dv.props.whenActiveChanged(false)); manager.SelectedDocuments = []; - MainOverlayTextBox.Instance.SetTextDoc(); + FormattedTextBox.InputBoxOverlay = undefined; } @action ReselectAll() { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 15895fd1c..6eb654319 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -48,6 +48,7 @@ export class TooltipTextMenu { private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); private linkEditor?: HTMLDivElement; private linkText?: HTMLDivElement; + private linkDrag?: HTMLImageElement; //dropdown doms private fontSizeDom?: Node; private fontStyleDom?: Node; @@ -168,8 +169,13 @@ export class TooltipTextMenu { this.linkText = document.createElement("div"); this.linkText.style.cssFloat = "left"; this.linkText.style.marginRight = "5px"; + this.linkText.style.marginLeft = "5px"; this.linkText.setAttribute("contenteditable", "true"); + this.linkText.style.whiteSpace = "nowrap"; + this.linkText.style.width = "150px"; + this.linkText.style.overflow = "hidden"; this.linkText.style.color = "white"; + this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); } let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; linkBtn.style.width = "20px"; @@ -196,16 +202,17 @@ export class TooltipTextMenu { e.preventDefault(); } } - let linkDrag = document.createElement("div"); - linkDrag.textContent = "O"; - linkDrag.style.width = "20px"; - linkDrag.style.height = "20px"; - linkDrag.style.color = "white"; - linkDrag.style.cssFloat = "left"; - linkDrag.onpointerdown = (e: PointerEvent) => { + this.linkDrag = document.createElement("img"); + this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; + this.linkDrag.style.width = "20px"; + this.linkDrag.style.height = "20px"; + this.linkDrag.style.color = "white"; + this.linkDrag.style.background = "black"; + this.linkDrag.style.cssFloat = "left"; + this.linkDrag.onpointerdown = (e: PointerEvent) => { let dragData = new DragManager.LinkDragData(this.editorProps.Document); dragData.dontClearTextBox = true; - DragManager.StartLinkDrag(this.linkEditor!, dragData, e.clientX, e.clientY, + DragManager.StartLinkDrag(this.linkDrag!, dragData, e.clientX, e.clientY, { handlers: { dragComplete: action(() => { @@ -216,9 +223,9 @@ export class TooltipTextMenu { hideSource: false }) }; + this.linkEditor.appendChild(this.linkDrag); this.linkEditor.appendChild(this.linkText); this.linkEditor.appendChild(linkBtn); - this.linkEditor.appendChild(linkDrag) this.tooltip.appendChild(this.linkEditor); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e3eb034fa..85ddadd64 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,7 +5,6 @@ import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; import './DocumentDecorations.scss'; -import { MainOverlayTextBox } from "./MainOverlayTextBox"; import { DocumentView, PositionDocument } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import { TemplateMenu } from "./TemplateMenu"; @@ -25,11 +24,9 @@ import { faLink } from '@fortawesome/free-solid-svg-icons'; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; -import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionView } from "./collections/CollectionView"; -import { createCipher } from "crypto"; -import { FieldView } from "./nodes/FieldView"; import { DocumentManager } from "../util/DocumentManager"; +import { FormattedTextBox } from "./nodes/FormattedTextBox"; library.add(faLink); @@ -328,6 +325,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let selDoc = SelectionManager.SelectedDocuments()[0]; let container = selDoc.props.ContainingCollectionView ? selDoc.props.ContainingCollectionView.props.Document.proto : undefined; let dragData = new DragManager.LinkDragData(selDoc.props.Document, container ? [container] : []); + FormattedTextBox.InputBoxOverlay = undefined; DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { dragComplete: action(emptyFunction), @@ -410,7 +408,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> break; } - MainOverlayTextBox.Instance.SetTextDoc(); + FormattedTextBox.InputBoxOverlay = undefined; SelectionManager.SelectedDocuments().forEach(element => { const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect(); diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 3b75c248a..91f626737 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -1,16 +1,12 @@ -import { action, observable, trace } from 'mobx'; +import { action, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import "normalize.css"; import * as React from 'react'; import { emptyFunction, returnTrue, returnZero } from '../../Utils'; -import '../northstar/model/ModelExtensions'; -import '../northstar/utils/Extensions'; import { DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; +import "normalize.css"; import "./MainOverlayTextBox.scss"; import { FormattedTextBox } from './nodes/FormattedTextBox'; -import { Doc } from '../../new_fields/Doc'; -import { NumCast } from '../../new_fields/Types'; interface MainOverlayTextBoxProps { } @@ -18,8 +14,6 @@ interface MainOverlayTextBoxProps { @observer export class MainOverlayTextBox extends React.Component { public static Instance: MainOverlayTextBox; - @observable public TextDoc?: Doc = undefined; - public TextScroll: number = 0; @observable _textXf: () => Transform = () => Transform.Identity(); private _textFieldKey: string = "data"; private _textColor: string | null = null; @@ -30,15 +24,18 @@ export class MainOverlayTextBox extends React.Component super(props); this._textProxyDiv = React.createRef(); MainOverlayTextBox.Instance = this; + reaction(() => FormattedTextBox.InputBoxOverlay, + (box?: FormattedTextBox) => { + if (box) this.setTextDoc(box.props.fieldKey, box.CurrentDiv, box.props.ScreenToLocalTransform); + else this.setTextDoc(); + }); } @action - SetTextDoc(textDoc?: Doc, textFieldKey?: string, div?: HTMLDivElement, tx?: () => Transform) { + private setTextDoc(textFieldKey?: string, div?: HTMLDivElement, tx?: () => Transform) { if (this._textTargetDiv) { this._textTargetDiv.style.color = this._textColor; } - - this.TextDoc = textDoc; this._textFieldKey = textFieldKey!; this._textXf = tx ? tx : () => Transform.Identity(); this._textTargetDiv = div; @@ -46,15 +43,13 @@ export class MainOverlayTextBox extends React.Component if (div.parentElement && div.parentElement instanceof HTMLDivElement && div.parentElement.id === "screenSpace") this._textXf = () => Transform.Identity(); this._textColor = div.style.color; div.style.color = "transparent"; - this.TextScroll = div.scrollTop; } } @action textScroll = (e: React.UIEvent) => { if (this._textProxyDiv.current && this._textTargetDiv) { - this.TextScroll = (e as any)._targetInst.stateNode.scrollTop;// this._textProxyDiv.current.children[0].scrollTop; - this._textTargetDiv.scrollTop = this.TextScroll; + this._textTargetDiv.scrollTop = (e as any)._targetInst.stateNode.scrollTop; } } @@ -64,11 +59,12 @@ export class MainOverlayTextBox extends React.Component document.addEventListener('pointerup', this.textBoxUp); } } + @action textBoxMove = (e: PointerEvent) => { if (e.movementX > 1 || e.movementY > 1) { document.removeEventListener("pointermove", this.textBoxMove); document.removeEventListener('pointerup', this.textBoxUp); - let dragData = new DragManager.DocumentDragData([this.TextDoc!]); + let dragData = new DragManager.DocumentDragData(FormattedTextBox.InputBoxOverlay ? [FormattedTextBox.InputBoxOverlay.props.Document] : []); const [left, top] = this._textXf().inverse().transformPoint(0, 0); dragData.xOffset = e.clientX - left; dragData.yOffset = e.clientY - top; @@ -86,13 +82,13 @@ export class MainOverlayTextBox extends React.Component } render() { - if (this.TextDoc && this._textTargetDiv) { + if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) { let textRect = this._textTargetDiv.getBoundingClientRect(); let s = this._textXf().Scale; return
    -
    diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 16818affd..6dd0e5935 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -322,8 +322,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { render() { library.add(faCog); library.add(faPlus); - //This can't just pass FieldValue to filter because filter passes other arguments to the passed in function, which end up as default values in FieldValue - const children = (this.children || []).filter(doc => FieldValue(doc)); + const children = this.children; return (
    this.onDrop(e, {})} ref={this.createTarget}> diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 828ac880a..082692d8d 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -50,7 +50,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get children() { //TODO tfs: This might not be what we want? //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) - return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => FieldValue(doc)); + return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => FieldValue(doc)).map(doc => doc as Doc); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 797f94d5f..c1d149098 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -70,7 +70,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } public getActiveDocuments = () => { const curPage = FieldValue(this.Document.curPage, -1); - return FieldValue(this.children, [] as Doc[]).filter(doc => { + return this.children.filter(doc => { var page = NumCast(doc.page, -1); return page === curPage || page === -1; }); @@ -169,7 +169,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // if (!this.props.active()) { // return; // } - let childSelected = (this.children || []).filter(doc => doc).some(doc => { + let childSelected = this.children.some(doc => { var dv = DocumentManager.Instance.getDocumentView(doc); return dv && SelectionManager.IsSelected(dv) ? true : false; }); @@ -222,7 +222,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } bringToFront = (doc: Doc) => { - const docs = (this.children || []); + const docs = this.children; docs.slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; if (doc2 === doc) return -1; @@ -268,7 +268,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed.struct get views() { let curPage = FieldValue(this.Document.curPage, -1); - let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { + let docviews = this.children.reduce((prev, doc) => { if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); if (page === curPage || page === -1) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 613c24fa4..cdc1bdc85 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { observer } from "mobx-react"; -import { computed } from "mobx"; +import { computed, observable } from "mobx"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; import { VideoBox } from "./VideoBox"; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 445a834ee..e7fb94777 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,29 +1,31 @@ -import { action, IReactionDisposer, reaction, trace, computed, _allowStateChangesInsideComputed } from "mobx"; +import { action, IReactionDisposer, observable, reaction } from "mobx"; +import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; +import { Doc, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { RichTextField } from "../../../new_fields/RichTextField"; +import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { DocServer } from "../../DocServer"; +import { DocumentManager } from "../../util/DocumentManager"; +import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { schema, ImageResizeView } from "../../util/RichTextSchema"; +import { ImageResizeView, schema } from "../../util/RichTextSchema"; +import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; import { ContextMenu } from "../../views/ContextMenu"; -import { MainOverlayTextBox } from "../MainOverlayTextBox"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { DocComponent } from "../DocComponent"; +import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); -import { SelectionManager } from "../../util/SelectionManager"; -import { DocComponent } from "../DocComponent"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Opt, Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; -import { observer } from "mobx-react"; -import { InkingControl } from "../InkingControl"; -import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { Id } from "../../../new_fields/RefField"; -import { UndoManager } from "../../util/UndoManager"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -62,15 +64,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe private _proseRef: React.RefObject; private _editorView: Opt; private _gotDown: boolean = false; + private _dropDisposer?: DragManager.DragDropDisposer; private _reactionDisposer: Opt; private _inputReactionDisposer: Opt; private _proxyReactionDisposer: Opt; + public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } + + @observable public static InputBoxOverlay?: FormattedTextBox = undefined; + public static InputBoxOverlayScroll: number = 0; constructor(props: FieldViewProps) { super(props); this._ref = React.createRef(); this._proseRef = React.createRef(); + if (this.props.isOverlay) { + DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined); + } } _applyingChange: boolean = false; @@ -94,7 +104,27 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } + @undoBatch + @action + drop = async (e: Event, de: DragManager.DropEvent) => { + if (de.data instanceof DragManager.LinkDragData) { + let sourceDoc = de.data.linkSourceDocument; + let destDoc = this.props.Document; + + const protoDest = destDoc.proto; + const protoSrc = sourceDoc.proto; + Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + de.data.droppedDocuments.push(destDoc); + e.stopPropagation(); + } + } + componentDidMount() { + if (this._ref.current) { + this._dropDisposer = DragManager.MakeDropTarget(this._ref.current, { + handlers: { drop: this.drop.bind(this) } + }); + } const config = { schema, inpRules, //these currently don't do anything, but could eventually be helpful @@ -117,7 +147,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }; if (this.props.isOverlay) { - this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc[Id], + this._inputReactionDisposer = reaction(() => FormattedTextBox.InputBoxOverlay, () => { if (this._editorView) { this._editorView.destroy(); @@ -127,7 +157,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ); } else { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), - () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform)); + () => { + if (this.props.isSelected()) { + FormattedTextBox.InputBoxOverlay = this; + FormattedTextBox.InputBoxOverlayScroll = this._ref.current!.scrollTop; + } + }); } @@ -178,6 +213,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._proxyReactionDisposer) { this._proxyReactionDisposer(); } + if (this._dropDisposer) { + this._dropDisposer(); + } } onPointerDown = (e: React.PointerEvent): void => { @@ -186,6 +224,24 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) this._toolTipTextMenu.tooltip.style.opacity = "0"; } + if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey) { + if (e.target && (e.target as any).href) { + let href = (e.target as any).href; + if (href.indexOf(DocServer.prepend("/doc/")) === 0) { + let docid = href.replace(DocServer.prepend("/doc/"), ""); + DocServer.GetRefField(docid).then(action((f: Opt) => { + if (f instanceof Doc) { + if (DocumentManager.Instance.getDocumentView(f)) + DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + else CollectionDockingView.Instance.AddRightSplit(f); + } + })); + } + e.stopPropagation(); + e.preventDefault(); + } + + } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; e.preventDefault(); @@ -199,12 +255,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } + @action onFocused = (e: React.FocusEvent): void => { if (!this.props.isOverlay) { - MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform); + FormattedTextBox.InputBoxOverlay = this; } else { if (this._proseRef.current) { - this._proseRef.current.scrollTop = MainOverlayTextBox.Instance.TextScroll; + this._proseRef.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; } } } -- cgit v1.2.3-70-g09d2 From b83cfb1c48cced31f930e3f72a9c5ae503b81790 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 14:15:42 -0400 Subject: from last --- src/client/views/DocumentDecorations.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 85ddadd64..2bde4e0c8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -318,6 +318,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.stopPropagation(); } + @action onLinkerButtonMoved = (e: PointerEvent): void => { if (this._linkerButton.current !== null) { document.removeEventListener("pointermove", this.onLinkerButtonMoved); -- cgit v1.2.3-70-g09d2 From 168cd36282087bbf9e0157352a129d90b20b7394 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 14:40:03 -0400 Subject: fixed some compile errors --- src/client/northstar/dash-nodes/HistogramBox.tsx | 8 ++++---- src/client/util/DocumentManager.ts | 2 +- src/client/views/DocumentDecorations.tsx | 1 + src/client/views/collections/CollectionBaseView.tsx | 4 ++-- src/client/views/collections/CollectionSchemaView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 3 ++- src/client/views/nodes/LinkMenu.tsx | 4 ++-- 7 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 765ecf8f0..5e7b867b3 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -117,15 +117,15 @@ export class HistogramBox extends React.Component { runInAction(() => { this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty; if (this.HistoOp !== HistogramOperation.Empty) { - reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); + reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); reaction(() => Cast(this.props.Document.brushingDocs, listSpec(Doc), []).length, () => { - let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []); + let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); const proto = this.props.Document.proto; if (proto) { this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => { - brush.bckgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; - let brushed = Cast(brush.brushingDocs, listSpec(Doc), []); + brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; + let brushed = Cast(brush.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; })); } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 69964e2c9..4c264c7ec 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -71,7 +71,7 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { return DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { - let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc)); + let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); if (linksList && linksList.length) { pairs.push(...linksList.reduce((pairs, link) => { if (link) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2bde4e0c8..705e7a6d8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -27,6 +27,7 @@ import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { CollectionView } from "./collections/CollectionView"; import { DocumentManager } from "../util/DocumentManager"; import { FormattedTextBox } from "./nodes/FormattedTextBox"; +import { FieldView } from "./nodes/FieldView"; library.add(faLink); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 14b92af48..2b1f7bb37 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -63,13 +63,13 @@ export class CollectionBaseView extends React.Component { if (!(documentToAdd instanceof Doc)) { return false; } - let data = Cast(documentToAdd.data, listSpec(Doc), []); + let data = Cast(documentToAdd.data, listSpec(Doc), []).filter(d => d).map(d => d as Doc); for (const doc of data.filter(d => d instanceof Document)) { if (this.createsCycle(doc, containerDocument)) { return true; } } - let annots = Cast(documentToAdd.annotations, listSpec(Doc), []); + let annots = Cast(documentToAdd.annotations, listSpec(Doc), []).filter(d => d).map(d => d as Doc); for (const annot of annots) { if (this.createsCycle(annot, containerDocument)) { return true; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 6dd0e5935..ae949b2ed 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -276,7 +276,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } get documentKeysCheckList() { - const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []); + const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(d => d).map(d => d as Doc); let keys: { [key: string]: boolean } = {}; // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index cdc1bdc85..8bdf34181 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -99,7 +99,8 @@ export class FieldView extends React.Component { ContainingCollectionView={this.props.ContainingCollectionView} parentActive={this.props.active} toggleMinimized={emptyFunction} - whenActiveChanged={this.props.whenActiveChanged} /> + whenActiveChanged={this.props.whenActiveChanged} + bringToFront={emptyFunction} /> ); } else if (field instanceof List) { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index e21adebbc..24901913d 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -31,8 +31,8 @@ export class LinkMenu extends React.Component { render() { //get list of links from document - let linkFrom: Doc[] = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []); - let linkTo: Doc[] = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []); + let linkFrom = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let linkTo = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); if (this._editingLink === undefined) { return (
    -- cgit v1.2.3-70-g09d2 From 39fd912fd4cd33f30a943290295a59992b9868eb Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 17:39:44 -0400 Subject: various cleanup to icons, summaries... --- src/client/util/DocumentManager.ts | 18 ++++++++++++-- src/client/util/SelectionManager.ts | 17 +++++++++++++ src/client/views/DocumentDecorations.tsx | 28 ++++++++++++++++++---- src/client/views/TemplateMenu.tsx | 16 +++++++++---- .../CollectionFreeFormLinkView.scss | 8 +++---- .../CollectionFreeFormLinkView.tsx | 6 ++--- .../CollectionFreeFormLinksView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 17 ++++++------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 17 ++++++------- src/client/views/nodes/DocumentView.tsx | 14 +++++++---- 10 files changed, 104 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 4c264c7ec..779b07ce5 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,8 +1,9 @@ import { computed, observable } from 'mobx'; import { DocumentView } from '../views/nodes/DocumentView'; import { Doc } from '../../new_fields/Doc'; -import { FieldValue, Cast } from '../../new_fields/Types'; +import { FieldValue, Cast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; +import { SelectionManager } from './SelectionManager'; export class DocumentManager { @@ -70,7 +71,7 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { - return DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { + return DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush, false)).reduce((pairs, dv) => { let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); if (linksList && linksList.length) { pairs.push(...linksList.reduce((pairs, link) => { @@ -84,6 +85,19 @@ export class DocumentManager { return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); } + linksList = Cast(dv.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + if (linksList && linksList.length) { + pairs.push(...linksList.reduce((pairs, link) => { + if (link) { + let linkFromDoc = FieldValue(Cast(link.linkedFrom, Doc)); + if (linkFromDoc) { + DocumentManager.Instance.getDocumentViews(linkFromDoc).map(docView1 => + pairs.push({ a: dv, b: docView1, l: link })); + } + } + return pairs; + }, pairs)); + } return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); } diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index a3a8172c7..8c92c2023 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -2,6 +2,7 @@ import { observable, action } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DocumentView } from "../views/nodes/DocumentView"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; +import { NumCast } from "../../new_fields/Types"; export namespace SelectionManager { class Manager { @@ -68,4 +69,20 @@ export namespace SelectionManager { export function SelectedDocuments(): Array { return manager.SelectedDocuments; } + export function ViewsSortedVertically(): DocumentView[] { + let sorted = SelectionManager.SelectedDocuments().slice().sort((doc1, doc2) => { + if (NumCast(doc1.props.Document.x) > NumCast(doc2.props.Document.x)) return 1; + if (NumCast(doc1.props.Document.x) < NumCast(doc2.props.Document.x)) return -1; + return 0; + }); + return sorted; + } + export function ViewsSortedHorizontally(): DocumentView[] { + let sorted = SelectionManager.SelectedDocuments().slice().sort((doc1, doc2) => { + if (NumCast(doc1.props.Document.y) > NumCast(doc2.props.Document.y)) return 1; + if (NumCast(doc1.props.Document.y) < NumCast(doc2.props.Document.y)) return -1; + return 0; + }); + return sorted; + } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 705e7a6d8..4786b4de6 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -249,7 +249,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (this._iconDoc && selectedDocs.length === 1 && this._removeIcon) { selectedDocs[0].props.removeDocument && selectedDocs[0].props.removeDocument(this._iconDoc); } - !this._removeIcon && selectedDocs.length === 1 && this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].props.toggleMinimized()); + if (!this._removeIcon) { + if (selectedDocs.length === 1) + this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].props.toggleMinimized()); + else { + let docViews = SelectionManager.ViewsSortedVertically(); + let topDocView = docViews[0]; + let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); + if (ind !== -1) { + topDocView.templates.splice(ind, 1); + topDocView.props.Document.subBulletDocs = undefined; + } else { + topDocView.addTemplate(Templates.Bullet); + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document)); + } + } + } this._removeIcon = false; } runInAction(() => this._minimizedX = this._minimizedY = 0); @@ -410,7 +425,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> break; } - FormattedTextBox.InputBoxOverlay = undefined; + runInAction(() => FormattedTextBox.InputBoxOverlay = undefined); SelectionManager.SelectedDocuments().forEach(element => { const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect(); @@ -507,7 +522,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let templates: Map = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => { - let docTemps = SelectionManager.SelectedDocuments().reduce((res: string[], doc: DocumentView, i) => { + let sorted = SelectionManager.ViewsSortedVertically().slice().sort((doc1, doc2) => { + if (NumCast(doc1.props.Document.x) > NumCast(doc2.props.Document.x)) return 1; + if (NumCast(doc1.props.Document.x) < NumCast(doc2.props.Document.x)) return -1; + return 0; + }); + let docTemps = sorted.reduce((res: string[], doc: DocumentView, i) => { let temps = doc.props.Document.templates; if (temps instanceof List) { temps.map(temp => { @@ -568,7 +588,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
    - +
    diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index d74982ef8..e2b3bd07a 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -6,6 +6,7 @@ import { Template } from "./Templates"; import { DocumentView } from "./nodes/DocumentView"; import { List } from "../../new_fields/List"; import { Doc } from "../../new_fields/Doc"; +import { NumCast } from "../../new_fields/Types"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -35,20 +36,27 @@ export interface TemplateMenuProps { export class TemplateMenu extends React.Component { @observable private _hidden: boolean = true; + constructor(props: TemplateMenuProps) { + super(props); + console.log(""); + } + @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { if (event.target.checked) { if (template.Name == "Bullet") { - this.props.docs[0].addTemplate(template); - this.props.docs[0].props.Document.maximizedDocs = new List(this.props.docs.filter((v, i) => i !== 0).map(v => v.props.Document)); + let topDocView = this.props.docs[0]; + topDocView.addTemplate(template); + topDocView.props.Document.subBulletDocs = new List(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document)); } else { this.props.docs.map(d => d.addTemplate(template)); } this.props.templates.set(template, true); } else { if (template.Name == "Bullet") { - this.props.docs[0].removeTemplate(template); - this.props.docs[0].props.Document.maximizedDocs = undefined; + let topDocView = this.props.docs[0]; + topDocView.removeTemplate(template); + topDocView.props.Document.subBulletDocs = undefined; } else { this.props.docs.map(d => d.removeTemplate(template)); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss index 3e8a8a442..737ffba7d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss @@ -1,12 +1,12 @@ .collectionfreeformlinkview-linkLine { stroke: black; - stroke-width: 3; transform: translate(10000px,10000px); + opacity: 0.5; pointer-events: all; } .collectionfreeformlinkview-linkCircle { - stroke: black; - stroke-width: 3; + stroke: rgb(0,0,0); + opacity: 0.5; transform: translate(10000px,10000px); pointer-events: all; -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3b700b053..63d2f7642 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -47,11 +47,11 @@ export class CollectionFreeFormLinkView extends React.Component - + ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index cbfbb1d2c..1d4584cfe 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -84,7 +84,7 @@ export class CollectionFreeFormLinksView extends React.Component d).map(d => d as Doc). filter(child => child[Id] === collid).map(view => DocumentManager.Instance.getDocumentViews(view).map(view => diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6057aaeba..d8855fe66 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -96,7 +96,8 @@ export class MarqueeView extends React.Component document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); - e.stopPropagation(); + // bcz: do we need this? it kills the context menu on the main collection + // e.stopPropagation(); } if (e.altKey) { e.preventDefault(); @@ -228,14 +229,14 @@ export class MarqueeView extends React.Component newCollection.proto!.summaryDoc = summary; selected = [newCollection]; } - summary.proto!.maximizedDocs = new List(selected); + summary.proto!.summarizedDocs = new List(selected); summary.proto!.isButton = true; - selected.map(maximizedDoc => { - let maxx = NumCast(maximizedDoc.x, undefined); - let maxy = NumCast(maximizedDoc.y, undefined); - let maxw = NumCast(maximizedDoc.width, undefined); - let maxh = NumCast(maximizedDoc.height, undefined); - maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) + selected.map(summarizedDoc => { + let maxx = NumCast(summarizedDoc.x, undefined); + let maxy = NumCast(summarizedDoc.y, undefined); + let maxw = NumCast(summarizedDoc.width, undefined); + let maxh = NumCast(summarizedDoc.height, undefined); + summarizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) }); this.props.addLiveTextDocument(summary); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 470c0c2f8..92033ea44 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -6,7 +6,7 @@ import "./DocumentView.scss"; import React = require("react"); import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; -import { FieldValue, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; +import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types"; import { OmitKeys, Utils } from "../../../Utils"; import { SelectionManager } from "../../util/SelectionManager"; import { Doc, DocListCast, HeightSym } from "../../../new_fields/Doc"; @@ -65,7 +65,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); - toggleMinimized = () => this.toggleIcon(); + toggleMinimized = async () => this.toggleIcon(await DocListCast(this.props.Document.maximizedDocs)); getTransform = (): Transform => this.props.ScreenToLocalTransform() .translate(-this.X, -this.Y) .scale(1 / this.contentScaling()).scale(1 / this.zoom) @@ -126,10 +126,9 @@ export class CollectionFreeFormDocumentView extends DocComponent => { + public toggleIcon = async (maximizedDocs: Doc[] | undefined): Promise => { SelectionManager.DeselectAll(); let isMinimized: boolean | undefined; - let maximizedDocs = await DocListCast(this.props.Document.maximizedDocs); let minimizedDoc: Doc | undefined = this.props.Document; if (!maximizedDocs) { minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc); @@ -177,8 +176,10 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.addDocument!(await maxDoc, false)); - this.toggleIcon(); + this.toggleIcon(maximizedDocs); } } } @@ -230,7 +231,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu handlers: { drop: this.drop.bind(this) } }); } + // bcz: kind of ugly .. setup a reaction to update the title of a summary document's target (maximizedDocs) whenver the summary doc's title changes this._reactionDisposer = reaction(() => [this.props.Document.maximizedDocs, this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""], async () => { let maxDoc = await DocListCast(this.props.Document.maximizedDocs); @@ -142,10 +143,11 @@ export class DocumentView extends DocComponent(Docu e.stopPropagation(); } - startDragging(x: number, y: number, dropAction: dropActionType) { + startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean) { if (this._mainCont.current) { + let allConnected = dragSubBullets ? [this.props.Document, ...Cast(this.props.Document.subBulletDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc)] : [this.props.Document]; const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0); - let dragData = new DragManager.DocumentDragData([this.props.Document]); + let dragData = new DragManager.DocumentDragData(allConnected); const [xoff, yoff] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.xOffset = xoff; @@ -167,15 +169,17 @@ export class DocumentView extends DocComponent(Docu SelectionManager.SelectDoc(this, e.ctrlKey); } } + _hitIsBullet = false; onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; if (CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && !this.isSelected()) { return; } + this._hitIsBullet = (e.target && (e.target as any).id === "isBullet"); if (e.shiftKey && e.buttons === 1) { if (this.props.isTopMost) { - this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined); + this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined, this._hitIsBullet); } else if (this.props.Document) { CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); } @@ -193,7 +197,7 @@ export class DocumentView extends DocComponent(Docu document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); if (!e.altKey && !this.topMost && (!CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 1) || (CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 2)) { - this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined); + this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitIsBullet); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers -- cgit v1.2.3-70-g09d2 From d6b7ee34014be0e990d0d3967225dde1daaed5d0 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 9 May 2019 18:45:20 -0400 Subject: removed template field, cleaned up cursor refactor --- src/client/documents/Documents.ts | 1 - src/fields/TemplateField.ts | 43 --------------------------------------- 2 files changed, 44 deletions(-) delete mode 100644 src/fields/TemplateField.ts (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a770ccc93..63ba01b6a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -19,7 +19,6 @@ import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; import { AggregateFunction } from "../northstar/model/idea/idea"; import { Template } from "../views/Templates"; -import { TemplateField } from "../../fields/TemplateField"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { IconBox } from "../views/nodes/IconBox"; import { Field, Doc, Opt } from "../../new_fields/Doc"; diff --git a/src/fields/TemplateField.ts b/src/fields/TemplateField.ts deleted file mode 100644 index 72ae13c2e..000000000 --- a/src/fields/TemplateField.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { BasicField } from "./BasicField"; -import { Types } from "../server/Message"; -import { FieldId } from "./Field"; -import { Template, TemplatePosition } from "../client/views/Templates"; - - -export class TemplateField extends BasicField> { - constructor(data: Array