diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/RichTextSchema.tsx | 21 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 2 | ||||
-rw-r--r-- | src/client/views/MetadataEntryMenu.scss | 57 | ||||
-rw-r--r-- | src/client/views/MetadataEntryMenu.tsx | 54 |
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> |