aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/RichTextSchema.tsx21
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/MetadataEntryMenu.scss57
-rw-r--r--src/client/views/MetadataEntryMenu.tsx54
4 files changed, 124 insertions, 10 deletions
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index b6402da13..e0ff3074b 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -518,28 +518,39 @@ export class SummarizedView {
_view: any;
constructor(node: any, view: any, getPos: any) {
this._collapsed = document.createElement("span");
- this._collapsed.textContent = "㊉";
+ this._collapsed.textContent = node.attrs.visibility ? "㊀" : "㊉";
this._collapsed.style.opacity = "0.5";
this._collapsed.style.position = "relative";
this._collapsed.style.width = "40px";
this._collapsed.style.height = "20px";
let self = this;
this._view = view;
+ const js = node.toJSON;
+ node.toJSON = function () {
+
+ return js.apply(this, arguments);
+ };
this._collapsed.onpointerdown = function (e: any) {
if (node.attrs.visibility) {
- node.attrs.visibility = !node.attrs.visibility;
+ // node.attrs.visibility = !node.attrs.visibility;
let y = getPos();
+ const attrs = { ...node.attrs };
+ attrs.visibility = !attrs.visibility;
let { from, to } = self.updateSummarizedText(y + 1, view.state.schema.marks.highlight);
let length = to - from;
let newSelection = TextSelection.create(view.state.doc, y + 1, y + 1 + length);
// update attrs of node
- node.attrs.text = newSelection.content();
- node.attrs.textslice = newSelection.content().toJSON();
+ attrs.text = newSelection.content();
+ attrs.textslice = newSelection.content().toJSON();
+ view.dispatch(view.state.tr.setNodeMarkup(y, undefined, attrs));
view.dispatch(view.state.tr.setSelection(newSelection).deleteSelection(view.state, () => { }));
self._collapsed.textContent = "㊉";
} else {
- node.attrs.visibility = !node.attrs.visibility;
+ // node.attrs.visibility = !node.attrs.visibility;
let y = getPos();
+ const attrs = { ...node.attrs };
+ attrs.visibility = !attrs.visibility;
+ view.dispatch(view.state.tr.setNodeMarkup(y, undefined, attrs));
let mark = view.state.schema.mark(view.state.schema.marks.highlight);
view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1)));
const from = view.state.selection.from;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 56fbd75a0..2cb3de50f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -639,7 +639,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
return (
<div className="linkButtonWrapper">
<Flyout anchorPoint={anchorPoints.TOP_LEFT}
- content={<MetadataEntryMenu docs={() => SelectionManager.SelectedDocuments().map(dv => dv.props.Document)} />}>{/* tfs: @bcz This might need to be the data document? */}
+ content={<MetadataEntryMenu docs={() => SelectionManager.SelectedDocuments().map(dv => dv.props.Document)} suggestWithFunction />}>{/* tfs: @bcz This might need to be the data document? */}
<div className="docDecs-tagButton" title="Add fields"><FontAwesomeIcon className="documentdecorations-icon" icon="tag" size="sm" /></div>
</Flyout>
</div>
diff --git a/src/client/views/MetadataEntryMenu.scss b/src/client/views/MetadataEntryMenu.scss
index 73e5b6a73..469843350 100644
--- a/src/client/views/MetadataEntryMenu.scss
+++ b/src/client/views/MetadataEntryMenu.scss
@@ -7,4 +7,61 @@
.metadataEntry-outerDiv {
display: flex;
width: 300px;
+}
+
+.react-autosuggest__container {
+ position: relative;
+}
+
+.react-autosuggest__input {
+ width: 240px;
+ height: 30px;
+ padding: 10px 20px;
+ font-family: Helvetica, sans-serif;
+ font-weight: 300;
+ font-size: 16px;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+}
+
+.react-autosuggest__input--focused {
+ outline: none;
+}
+
+.react-autosuggest__input--open {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.react-autosuggest__suggestions-container {
+ display: none;
+}
+
+.react-autosuggest__suggestions-container--open {
+ display: block;
+ position: fixed;
+ width: 280px;
+ border: 1px solid #aaa;
+ background-color: #fff;
+ font-family: Helvetica, sans-serif;
+ font-weight: 300;
+ font-size: 16px;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ z-index: 2;
+}
+
+.react-autosuggest__suggestions-list {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+
+.react-autosuggest__suggestion {
+ cursor: pointer;
+ padding: 10px 20px;
+}
+
+.react-autosuggest__suggestion--highlighted {
+ background-color: #ddd;
} \ No newline at end of file
diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx
index 0dc7e0220..cb574aa96 100644
--- a/src/client/views/MetadataEntryMenu.tsx
+++ b/src/client/views/MetadataEntryMenu.tsx
@@ -1,24 +1,27 @@
import * as React from 'react';
import "./MetadataEntryMenu.scss";
import { observer } from 'mobx-react';
-import { observable, action } from 'mobx';
+import { observable, action, runInAction, trace } from 'mobx';
import { KeyValueBox } from './nodes/KeyValueBox';
import { Doc } from '../../new_fields/Doc';
+import * as Autosuggest from 'react-autosuggest';
export type DocLike = Doc | Doc[] | Promise<Doc> | Promise<Doc[]>;
export interface MetadataEntryProps {
docs: DocLike | (() => DocLike);
onError?: () => boolean;
+ suggestWithFunction?: boolean;
}
@observer
export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
@observable private _currentKey: string = "";
@observable private _currentValue: string = "";
+ @observable private suggestions: string[] = [];
@action
- onKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._currentKey = e.target.value;
+ onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
+ this._currentKey = newValue;
}
@action
@@ -61,11 +64,54 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
this._currentValue = "";
}
+ getKeySuggestions = async (value: string): Promise<string[]> => {
+ value = value.toLowerCase();
+ let docs = this.props.docs;
+ if (typeof docs === "function") {
+ if (this.props.suggestWithFunction) {
+ docs = docs();
+ } else {
+ return [];
+ }
+ }
+ docs = await docs;
+ if (docs instanceof Doc) {
+ return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value));
+ } else {
+ const keys = new Set<string>();
+ docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
+ return Array.from(keys).filter(key => key.toLowerCase().startsWith(value));
+ }
+ }
+ getSuggestionValue = (suggestion: string) => suggestion;
+
+ renderSuggestion = (suggestion: string) => {
+ return <p>{suggestion}</p>;
+ }
+
+ onSuggestionFetch = async ({ value }: { value: string }) => {
+ const sugg = await this.getKeySuggestions(value);
+ runInAction(() => {
+ this.suggestions = sugg;
+ });
+ }
+
+ @action
+ onSuggestionClear = () => {
+ this.suggestions = [];
+ }
+
render() {
+ trace();
return (
<div className="metadataEntry-outerDiv">
Key:
- <input className="metadataEntry-input" value={this._currentKey} onChange={this.onKeyChange} />
+ <Autosuggest inputProps={{ value: this._currentKey, onChange: this.onKeyChange, className: "metadataEntry-input" }}
+ getSuggestionValue={this.getSuggestionValue}
+ suggestions={this.suggestions}
+ renderSuggestion={this.renderSuggestion}
+ onSuggestionsFetchRequested={this.onSuggestionFetch}
+ onSuggestionsClearRequested={this.onSuggestionClear} />
Value:
<input className="metadataEntry-input" value={this._currentValue} onChange={this.onValueChange} onKeyDown={this.onValueKeyDown} />
</div>