aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/client/views/collections/CollectionMenu.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx6
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx72
-rw-r--r--src/fields/Doc.ts2
5 files changed, 44 insertions, 39 deletions
diff --git a/.gitignore b/.gitignore
index 7d3a4d214..e94da5580 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ src/scraping/buxton/final/source/
src/scraping/buxton/final/json/
src/scraping/buxton/source/
src/server/public/files/
+src/server/stats/userLoginStats.csv
src/scraping/acm/package-lock.json
src/server/session_manager/logs/**/*.log
*.crt
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5b631676e..2154016bd 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1329,7 +1329,7 @@ export class Collection3DCarouselViewChrome extends React.Component<CollectionVi
return (
<div className="collection3DCarouselViewChrome-cont">
<div className="collection3DCarouselViewChrome-scrollSpeed-cont">
- {FormattedTextBox.Focused ? <RichTextMenu /> : null}
+ {/* {FormattedTextBox.Focused ? <RichTextMenu /> : null} */}
<div className="collectionStackingViewChrome-scrollSpeed-label">AUTOSCROLL SPEED:</div>
<div className="collection3DCarouselViewChrome-scrollSpeed">
<EditableView GetValue={() => StrCast(this.scrollSpeed)} oneLine SetValue={this.setValue} contents={this.scrollSpeed ? this.scrollSpeed : 1000} />
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 7f1e15c2f..0dfd119d7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -1,6 +1,6 @@
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
-import { Doc, Field } from '../../../../fields/Doc';
+import { CssSym, Doc, Field } from '../../../../fields/Doc';
import { Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
import { Cast, NumCast, StrCast } from '../../../../fields/Types';
@@ -35,10 +35,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
() => [
this.props.A.props.ScreenToLocalTransform(),
Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
- Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?._highlights,
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.[CssSym],
this.props.B.props.ScreenToLocalTransform(),
Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
- Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?._highlights,
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.[CssSym],
],
action(() => {
this._start = Date.now();
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 5719ea83c..f5826ef95 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1,7 +1,7 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { isEqual } from 'lodash';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { baseKeymap, selectAll } from 'prosemirror-commands';
import { history } from 'prosemirror-history';
@@ -11,13 +11,13 @@ import { Fragment, Mark, Node, Slice } from 'prosemirror-model';
import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import { DateField } from '../../../../fields/DateField';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, Doc, DocListCast, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym } from '../../../../fields/Doc';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, CssSym, Doc, DocListCast, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym } from '../../../../fields/Doc';
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { PrefetchProxy } from '../../../../fields/Proxy';
import { RichTextField } from '../../../../fields/RichTextField';
import { RichTextUtils } from '../../../../fields/RichTextUtils';
-import { ComputedField, ScriptField } from '../../../../fields/ScriptField';
+import { ComputedField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
@@ -29,6 +29,7 @@ import { DictationManager } from '../../../util/DictationManager';
import { DocumentManager } from '../../../util/DocumentManager';
import { DragManager } from '../../../util/DragManager';
import { MakeTemplate } from '../../../util/DropConverter';
+import { IsFollowLinkScript } from '../../../util/LinkFollower';
import { LinkManager } from '../../../util/LinkManager';
import { SelectionManager } from '../../../util/SelectionManager';
import { SnappingManager } from '../../../util/SnappingManager';
@@ -64,7 +65,6 @@ import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
import applyDevTools = require('prosemirror-dev-tools');
import React = require('react');
-import { IsFollowLinkScript } from '../../../util/LinkFollower';
const translateGoogleApi = require('translate-google-api');
export const GoogleRef = 'googleDocId';
@@ -79,7 +79,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
public static Instance: FormattedTextBox;
public static LiveTextUndo: UndoManager.Batch | undefined;
- static _globalHighlights: string[] = ['Audio Tags', 'Text from Others', 'Todo Items', 'Important Items', 'Disagree Items', 'Ignore Items'];
+ static _globalHighlightsCache: string = '';
+ static _globalHighlights = new ObservableSet<string>(['Audio Tags', 'Text from Others', 'Todo Items', 'Important Items', 'Disagree Items', 'Ignore Items']);
static _highlightStyleSheet: any = addStyleSheet();
static _bulletStyleSheet: any = addStyleSheet();
static _userStyleSheet: any = addStyleSheet();
@@ -193,7 +194,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
constructor(props: any) {
super(props);
FormattedTextBox.Instance = this;
- this.updateHighlights();
this._recordingStart = Date.now();
}
@@ -605,45 +605,46 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
return ret;
}
- updateHighlights = () => {
- const highlights = FormattedTextBox._globalHighlights;
+ updateHighlights = (highlights: string[]) => {
+ if (Array.from(highlights).join('') === FormattedTextBox._globalHighlightsCache) return;
+ setTimeout(() => (FormattedTextBox._globalHighlightsCache = Array.from(highlights).join('')));
clearStyleSheetRules(FormattedTextBox._userStyleSheet);
- if (highlights.indexOf('Audio Tags') === -1) {
+ if (highlights.includes('Audio Tags')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'audiotag', { display: 'none' }, '');
}
- if (highlights.indexOf('Text from Others') !== -1) {
+ if (highlights.includes('Text from Others')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-remote', { background: 'yellow' });
}
- if (highlights.indexOf('My Text') !== -1) {
+ if (highlights.includes('My Text')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace('.', '').replace('@', ''), { background: 'moccasin' });
}
- if (highlights.indexOf('Todo Items') !== -1) {
+ if (highlights.includes('Todo Items')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-todo', { outline: 'black solid 1px' });
}
- if (highlights.indexOf('Important Items') !== -1) {
+ if (highlights.includes('Important Items')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-important', { 'font-size': 'larger' });
}
- if (highlights.indexOf('Bold Text') !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner-selected .ProseMirror strong > span', { 'font-size': 'large' }, '');
- addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner-selected .ProseMirror :not(strong > span)', { 'font-size': '0px' }, '');
+ if (highlights.includes('Bold Text')) {
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner .ProseMirror strong > span', { 'font-size': 'large' }, '');
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner .ProseMirror :not(strong > span)', { 'font-size': '0px' }, '');
}
- if (highlights.indexOf('Disagree Items') !== -1) {
+ if (highlights.includes('Disagree Items')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-disagree', { 'text-decoration': 'line-through' });
}
- if (highlights.indexOf('Ignore Items') !== -1) {
+ if (highlights.includes('Ignore Items')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-ignore', { 'font-size': '1' });
}
- if (highlights.indexOf('By Recent Minute') !== -1) {
+ if (highlights.includes('By Recent Minute')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace('.', '').replace('@', ''), { opacity: '0.1' });
const min = Math.round(Date.now() / 1000 / 60);
numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-min-' + (min - i), { opacity: ((10 - i - 1) / 10).toString() }));
- setTimeout(this.updateHighlights);
}
- if (highlights.indexOf('By Recent Hour') !== -1) {
+ if (highlights.includes('By Recent Hour')) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace('.', '').replace('@', ''), { opacity: '0.1' });
const hr = Math.round(Date.now() / 1000 / 60 / 60);
numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-hr-' + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }));
}
+ this.layoutDoc[CssSym] = this.layoutDoc[CssSym] + 1; // css changes happen outside of react/mobx. so we need to set a flag that will notify anyone intereted in layout changes triggered by css changes (eg., CollectionLinkView)
};
@observable _showSidebar = false;
@@ -781,18 +782,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const expertHighlighting = [...noviceHighlighting, 'Important Items', 'Ignore Items', 'Disagree Items', 'By Recent Minute', 'By Recent Hour'];
(Doc.noviceMode ? noviceHighlighting : expertHighlighting).forEach(option =>
highlighting.push({
- description: (FormattedTextBox._globalHighlights.indexOf(option) === -1 ? 'Highlight ' : 'Unhighlight ') + option,
- event: () => {
+ description: (!FormattedTextBox._globalHighlights.has(option) ? 'Highlight ' : 'Unhighlight ') + option,
+ event: action(() => {
e.stopPropagation();
- if (FormattedTextBox._globalHighlights.indexOf(option) === -1) {
- FormattedTextBox._globalHighlights.push(option);
+ if (!FormattedTextBox._globalHighlights.has(option)) {
+ FormattedTextBox._globalHighlights.add(option);
} else {
- FormattedTextBox._globalHighlights.splice(FormattedTextBox._globalHighlights.indexOf(option), 1);
+ FormattedTextBox._globalHighlights.delete(option);
}
- runInAction(() => (this.layoutDoc._highlights = FormattedTextBox._globalHighlights.join('')));
- this.updateHighlights();
- },
- icon: FormattedTextBox._globalHighlights.indexOf(option) === -1 ? 'highlighter' : 'remove-format',
+ }),
+ icon: !FormattedTextBox._globalHighlights.has(option) ? 'highlighter' : 'remove-format',
})
);
@@ -1031,6 +1030,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
() => this.autoHeight,
autoHeight => autoHeight && this.tryUpdateScrollHeight()
);
+ this._disposers.highlights = reaction(
+ () => Array.from(FormattedTextBox._globalHighlights).slice(),
+ highlights => this.updateHighlights(highlights),
+ { fireImmediately: true }
+ );
this._disposers.width = reaction(
() => this.props.PanelWidth(),
width => this.tryUpdateScrollHeight()
@@ -1115,7 +1119,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._disposers.selected = reaction(
() => this.props.isSelected(),
action(selected => {
- this.layoutDoc._highlights = selected ? FormattedTextBox._globalHighlights.join('') : '';
+ if (FormattedTextBox._globalHighlights.has('Bold Text')) {
+ this.layoutDoc[CssSym] = this.layoutDoc[CssSym] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed
+ }
if (RichTextMenu.Instance?.view === this._editorView && !selected) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
}
@@ -1431,7 +1437,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
componentWillUnmount() {
- FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined);
Object.values(this._disposers).forEach(disposer => disposer?.());
this.endUndoTypingBatch();
this.unhighlightSearchTerms();
@@ -1532,11 +1537,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
@action
onFocused = (e: React.FocusEvent): void => {
//applyDevTools.applyDevTools(this._editorView);
- FormattedTextBox.Focused = this;
this.ProseRef?.children[0] === e.nativeEvent.target && this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props);
this.startUndoTypingBatch();
};
- @observable public static Focused: FormattedTextBox | undefined;
onClick = (e: React.MouseEvent): void => {
if (!this.props.isContentActive()) return;
@@ -1633,7 +1636,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
tr && this._editorView.dispatch(tr);
}
}
- FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined);
if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 662792ff0..6c808c145 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -96,6 +96,7 @@ export const HighlightSym = Symbol('Highlight');
export const DataSym = Symbol('Data');
export const LayoutSym = Symbol('Layout');
export const FieldsSym = Symbol('Fields');
+export const CssSym = Symbol('Css');
export const AclSym = Symbol('Acl');
export const DirectLinksSym = Symbol('DirectLinks');
export const AclUnset = Symbol('AclUnset');
@@ -341,6 +342,7 @@ export class Doc extends RefField {
@observable private ___fieldKeys: any = {};
/// all of the raw acl's that have been set on this document. Use GetEffectiveAcl to determine the actual ACL of the doc for editing
@observable public [AclSym]: { [key: string]: symbol } = {};
+ @observable public [CssSym]: number = 0; // incrementer denoting a change to CSS layout
@observable public [DirectLinksSym]: Set<Doc> = new Set();
@observable public [AnimationSym]: Opt<Doc>;
@observable public [HighlightSym]: boolean = false;