aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx130
-rw-r--r--src/client/views/collections/CollectionView.tsx14
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx81
3 files changed, 84 insertions, 141 deletions
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index c3ba04aa8..282ac90fe 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -6,7 +6,7 @@ import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction } from '../../../Utils';
-import { StopEvent, returnFalse, returnOne, returnZero } from '../../../ClientUtils';
+import { StopEvent, returnFalse, returnOne, returnTrue, returnZero } from '../../../ClientUtils';
import { Doc, Opt } from '../../../fields/Doc';
import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -17,6 +17,8 @@ import { FieldViewProps } from '../nodes/FieldView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import './CollectionCarouselView.scss';
import { CollectionSubView } from './CollectionSubView';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
@observer
export class CollectionCarouselView extends CollectionSubView() {
@@ -42,91 +44,49 @@ export class CollectionCarouselView extends CollectionSubView() {
return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK);
}
+ move = (dir: number) => {
+ const moveToCardWithField = (match: (doc: Doc) => boolean): boolean => {
+ let startInd = (NumCast(this.layoutDoc._carousel_index) + dir) % this.carouselItems.length;
+ while (!match(this.carouselItems?.[startInd].layout) && (startInd + dir + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
+ startInd = (startInd + dir + this.carouselItems.length) % this.carouselItems.length;
+ }
+ this.layoutDoc._carousel_index = startInd;
+ return match(this.carouselItems?.[startInd].layout);
+ };
+ switch (StrCast(this.layoutDoc.filterOp)) {
+ case 'star': // go to a flashcard that is starred, skip the ones that aren't
+ if (!moveToCardWithField((doc: Doc) => !!doc[`${this.fieldKey}_star`])) {
+ this.layoutDoc.filterOp = undefined; // if there aren't any starred, show all cards
+ }
+ break;
+ case 'practice': // go to a new index that is missed, skip the ones that are correct
+ if (!moveToCardWithField((doc: Doc) => doc[`${this.fieldKey}_missed`] !== 'correct')) {
+ this.layoutDoc.filterOp = undefined; // if all of the cards are correct, show all cards and exit practice mode
+
+ // set all the cards to missed
+ this.carouselItems.forEach(item => {
+ item.layout[`${this.fieldKey}_missed`] = undefined;
+ });
+ }
+ break;
+ default: moveToCardWithField( returnTrue);
+ } // prettier-ignore
+ };
+
/**
- * Goes to the next flashcard in the stack and filters
- * based on the the currently selected option.
+ * Goes to the next Doc in the stack subject to the currently selected filter option.
*/
advance = (e: React.MouseEvent) => {
e.stopPropagation();
- this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) + 1) % this.carouselItems.length;
- let startInd = this.layoutDoc._carousel_index;
-
- // if the star filter is selected
- if (this.layoutDoc.filterOp === 'star') {
- // go to a flashcard that is starred, skip the ones that aren't
- while (!this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_star`] && (startInd + 1) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
- startInd = (startInd + 1) % this.carouselItems.length;
- }
- this.layoutDoc._carousel_index = startInd;
- // if there aren't any starred, show all cards
- if (!this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_star`]) {
- this.layoutDoc.filterOp = 'all';
- }
- }
-
- // if the practice filter is selected
- if (this.layoutDoc.filterOp === 'practice') {
- // go to a new index that is missed, skip the ones that are correct
- while (this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_missed`] === 'correct' && (startInd + 1) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
- startInd = (startInd + 1) % this.carouselItems.length;
- }
- this.layoutDoc._carousel_index = startInd;
-
- // if the user has gone through all of the cards and gotten them all correct, show all cards and exit practice mode
- if (this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_missed`] === 'correct') {
- this.layoutDoc.filterOp = 'all';
-
- // set all the cards to missed
- for (let i = 0; i < this.carouselItems.length; i++) {
- const curDoc = this.carouselItems?.[NumCast(i)];
- curDoc.layout[`${this.fieldKey}_missed`] = undefined;
- }
- }
- }
+ this.move(1);
};
/**
- * Goes to the previous flashcard in the stack and filters
- * based on the the currently selected option.
+ * Goes to the previous Doc in the stack subject to the currently selected filter option.
*/
goback = (e: React.MouseEvent) => {
e.stopPropagation();
- this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) - 1 + this.carouselItems.length) % this.carouselItems.length;
-
- let startInd = this.layoutDoc._carousel_index;
-
- // if the star filter is selected
- if (this.layoutDoc.filterOp === 'star') {
- // go to a new index that is starred, skip the ones that aren't
- while (!this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_star`] && (startInd - 1 + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
- startInd = (startInd - 1 + this.carouselItems.length) % this.carouselItems.length;
- }
- this.layoutDoc._carousel_index = startInd;
- // if there aren't any starred, show all cards
- if (!this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_star`]) {
- this.layoutDoc.filterOp = 'all';
- }
- }
-
- // if the practice filter is selected
- if (this.layoutDoc.filterOp === 'practice') {
- // go to a new index that is missed, skip the ones that are correct
- while (this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_missed`] === 'correct' && (startInd - 1 + this.carouselItems.length) % this.carouselItems.length !== this.layoutDoc._carousel_index) {
- startInd = (startInd - 1 + this.carouselItems.length) % this.carouselItems.length;
- }
-
- this.layoutDoc._carousel_index = startInd;
-
- // See all flashcards when finish going through practice mode and set all of the flashcards back to
- if (this.carouselItems?.[NumCast(startInd)].layout[`${this.fieldKey}_missed`] === 'correct') {
- this.layoutDoc.filterOp = 'all';
-
- for (let i = 0; i < this.carouselItems.length; i++) {
- const curDoc = this.carouselItems?.[NumCast(i)];
- curDoc.layout[`${this.fieldKey}_missed`] = undefined;
- }
- }
- }
+ this.move(-1);
};
/*
@@ -134,10 +94,8 @@ export class CollectionCarouselView extends CollectionSubView() {
*/
star = (e: React.MouseEvent) => {
e.stopPropagation();
- const curDoc = this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)];
- if (!curDoc) return;
- if (curDoc.layout[`${this.fieldKey}_star`] === undefined) curDoc.layout[`${this.fieldKey}_star`] = true;
- else curDoc.layout[`${this.fieldKey}_star`] = !curDoc.layout[`${this.fieldKey}_star`];
+ const curDoc = this.carouselItems[NumCast(this.layoutDoc._carousel_index)];
+ curDoc.layout[`${this.fieldKey}_star`] = curDoc.layout[`${this.fieldKey}_star`] ? undefined : true;
};
/*
@@ -228,12 +186,24 @@ export class CollectionCarouselView extends CollectionSubView() {
</>
);
}
+ specificMenu = (): void => {
+ const cm = ContextMenu.Instance;
+
+ const revealOptions = cm.findByDescription('Filter Flashcards');
+ const revealItems: ContextMenuProps[] = revealOptions && 'subitems' in revealOptions ? revealOptions.subitems : [];
+ revealItems.push({description: 'All', event: () => {this.layoutDoc.filterOp = undefined;}, icon: 'layer-group',}); // prettier-ignore
+ revealItems.push({description: 'Star', event: () => {this.layoutDoc.filterOp = 'star';}, icon: 'star',}); // prettier-ignore
+ revealItems.push({description: 'Practice Mode', event: () => {this.layoutDoc.filterOp = 'practice';}, icon: 'check',}); // prettier-ignore
+ revealItems.push({description: 'Quiz Cards', event: () => {this.layoutDoc.filterOp = 'quiz';}, icon: 'pencil',}); // prettier-ignore
+ !revealOptions && cm.addItem({ description: 'Filter Flashcards', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' });
+ };
render() {
return (
<div
className="collectionCarouselView-outer"
ref={this.createDashEventsTarget}
+ onContextMenu={this.specificMenu}
style={{
background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor),
color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color),
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index d084a2aec..5c304b4a9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -52,7 +52,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
super(props);
makeObservable(this);
this._annotationKeySuffix = returnEmptyString;
- this.layoutDoc[`filterOp`] = 'all';
}
componentDidMount() {
@@ -151,19 +150,6 @@ export class CollectionView extends ViewBoxAnnotatableComponent<CollectionViewPr
return newRendition;
});
- // creates menu option for flashcard filters
- const revealOptions = cm.findByDescription('Filter Flashcards');
- const revealItems: ContextMenuProps[] = revealOptions && 'subitems' in revealOptions ? revealOptions.subitems : [];
- revealItems.push({ description: 'All', event: () => (this.layoutDoc[`filterOp`] = 'all'), icon: 'layer-group' });
- revealItems.push({ description: 'Star', event: () => (this.layoutDoc[`filterOp`] = 'star'), icon: 'star' });
- revealItems.push({ description: 'Practice Mode', event: () => (this.layoutDoc[`filterOp`] = 'practice'), icon: 'check' });
- revealItems.push({ description: 'Quiz Cards', event: () => (this.layoutDoc[`filterOp`] = 'quiz'), icon: 'pencil' });
-
- // only show the filter options if it is a collection of type Carousel view
- if (this.Document?._type_collection === CollectionViewType.Carousel) {
- !revealOptions && cm.addItem({ description: 'Filter Flashcards', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' });
- }
-
const options = cm.findByDescription('Options...');
const optionItems = options && 'subitems' in options ? options.subitems : [];
!Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.Document.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => {this.Document.forceActive = !this.Document.forceActive}, icon: 'project-diagram' }) : null; // prettier-ignore
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 110f7816c..be96b914c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -517,6 +517,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, hit !== -1, false);
}
break;
+ default:
}
}
}
@@ -767,10 +768,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
insideEraserOutline = (eraserOutline: InkData, point: { X: number; Y: number }) => {
let isInside = false;
if (!isNaN(eraserOutline[0].X) && !isNaN(eraserOutline[0].Y)) {
- let minX = eraserOutline[0].X,
- maxX = eraserOutline[0].X;
- let minY = eraserOutline[0].Y,
- maxY = eraserOutline[0].Y;
+ let [minX, minY] = [eraserOutline[0].X, eraserOutline[0].Y];
+ let [maxX, maxY] = [eraserOutline[0].X, eraserOutline[0].Y];
for (let i = 1; i < eraserOutline.length; i++) {
const currPoint: { X: number; Y: number } = eraserOutline[i];
minX = Math.min(currPoint.X, minX);
@@ -784,7 +783,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
for (let i = 0, j = eraserOutline.length - 1; i < eraserOutline.length; j = i, i++) {
- if (eraserOutline[i].Y > point.Y != eraserOutline[j].Y > point.Y && point.X < ((eraserOutline[j].X - eraserOutline[i].X) * (point.Y - eraserOutline[i].Y)) / (eraserOutline[j].Y - eraserOutline[i].Y) + eraserOutline[i].X) {
+ if (eraserOutline[i].Y > point.Y !== eraserOutline[j].Y > point.Y && point.X < ((eraserOutline[j].X - eraserOutline[i].X) * (point.Y - eraserOutline[i].Y)) / (eraserOutline[j].Y - eraserOutline[i].Y) + eraserOutline[i].X) {
isInside = !isInside;
}
}
@@ -845,7 +844,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
getRadiusEraserIntersections = (lastPoint: { X: number; Y: number }, currPoint: { X: number; Y: number }) => {
// set distance of the eraser's bounding box based on the zoom
let boundingBoxDist = ActiveEraserWidth() + 5;
- this.zoomScaling() < 1 ? (boundingBoxDist = boundingBoxDist / (this.zoomScaling() * 1.5)) : (boundingBoxDist *= this.zoomScaling());
+ this.zoomScaling() < 1 ? (boundingBoxDist /= this.zoomScaling() * 1.5) : (boundingBoxDist *= this.zoomScaling());
const eraserMin = { X: Math.min(lastPoint.X, currPoint.X) - boundingBoxDist, Y: Math.min(lastPoint.Y, currPoint.Y) - boundingBoxDist };
const eraserMax = { X: Math.max(lastPoint.X, currPoint.X) + boundingBoxDist, Y: Math.max(lastPoint.Y, currPoint.Y) + boundingBoxDist };
@@ -961,29 +960,25 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
} else if (segmentTs[j] === Math.floor(inkData.length / 4) + 1) {
// the last end
break;
+ } else if (!continueErasing) {
+ currSegment.push(inkBezier.split(0, segmentTs[j] - currCurveT));
+ continueErasing = true;
} else {
- if (!continueErasing) {
- currSegment.push(inkBezier.split(0, segmentTs[j] - currCurveT));
- continueErasing = true;
- } else {
- // we've reached the end of the part to take out...
- continueErasing = false;
- if (currSegment.length > 0) {
- segments.push(currSegment); // ...so we add it to the list and reset currSegment
- if (firstSegment.length === 0) {
- firstSegment = currSegment;
- }
- currSegment = [];
+ // we've reached the end of the part to take out...
+ continueErasing = false;
+ if (currSegment.length > 0) {
+ segments.push(currSegment); // ...so we add it to the list and reset currSegment
+ if (firstSegment.length === 0) {
+ firstSegment = currSegment;
}
- currSegment.push(inkBezier.split(segmentTs[j] - currCurveT, 1));
+ currSegment = [];
}
+ currSegment.push(inkBezier.split(segmentTs[j] - currCurveT, 1));
}
}
- } else {
- if (!continueErasing) {
- // push the bezier piece if not in the eraser circle
- currSegment.push(inkBezier);
- }
+ } else if (!continueErasing) {
+ // push the bezier piece if not in the eraser circle
+ currSegment.push(inkBezier);
}
}
@@ -1078,13 +1073,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
segment2.push(inkSegment.split(intersections[closestTs[1]] - currCurveT, 1));
continueErasing = false;
hasSplit = true;
- } else {
- if (!continueErasing && !hasSplit) {
- // segment doesn't get pushed if continueErasing is true
- segment1.push(inkSegment);
- } else if (!continueErasing && hasSplit) {
- segment2.push(inkSegment);
- }
+ } else if (!continueErasing && !hasSplit) {
+ // segment doesn't get pushed if continueErasing is true
+ segment1.push(inkSegment);
+ } else if (!continueErasing && hasSplit) {
+ segment2.push(inkSegment);
}
} else if (splitSegment1 === -1) {
// case where first end is erased
@@ -1096,13 +1089,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
segment2.push(inkSegment.split(intersections[closestTs[1]] - currCurveT, 1));
}
hasSplit = true;
- } else {
- if (isClosedCurve && currCurveT === segmentIndexes.lastElement()) {
- segment2.push(inkSegment.split(0, intersections.lastElement() - currCurveT));
- continueErasing = true;
- } else if (hasSplit && !continueErasing) {
- segment2.push(inkSegment);
- }
+ } else if (isClosedCurve && currCurveT === segmentIndexes.lastElement()) {
+ segment2.push(inkSegment.split(0, intersections.lastElement() - currCurveT));
+ continueErasing = true;
+ } else if (hasSplit && !continueErasing) {
+ segment2.push(inkSegment);
}
} else {
// case where last end is erased
@@ -1118,10 +1109,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
segment1.push(inkSegment.split(0, intersections[closestTs[0]] - currCurveT));
hasSplit = true;
continueErasing = true;
- } else {
- if ((isClosedCurve && hasSplit && !continueErasing) || (!isClosedCurve && !hasSplit)) {
- segment1.push(inkSegment);
- }
+ } else if ((isClosedCurve && hasSplit && !continueErasing) || (!isClosedCurve && !hasSplit)) {
+ segment1.push(inkSegment);
}
}
}
@@ -1165,12 +1154,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
} else {
return this.getClosestTs(tVals, excludeT, mid + 1, endIndex);
}
+ } else if (mid - 1 >= startIndex && tVals[mid - 1] < excludeT) {
+ return [mid - 1, mid];
} else {
- if (mid - 1 >= startIndex && tVals[mid - 1] < excludeT) {
- return [mid - 1, mid];
- } else {
- return this.getClosestTs(tVals, excludeT, startIndex, mid - 1);
- }
+ return this.getClosestTs(tVals, excludeT, startIndex, mid - 1);
}
}
};