aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.DS_Storebin0 -> 8196 bytes
-rw-r--r--src/Utils.ts4
-rw-r--r--src/client/util/CurrentUserUtils.ts21
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx1
-rw-r--r--src/client/views/nodes/AudioBox.scss11
-rw-r--r--src/client/views/nodes/AudioBox.tsx380
-rw-r--r--src/client/views/nodes/FieldView.tsx7
-rw-r--r--src/mobile/ImageUpload.tsx2
-rw-r--r--src/mobile/MobileInterface.tsx2
-rw-r--r--src/mobile/MobileMenu.scss271
10 files changed, 410 insertions, 289 deletions
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 000000000..299b902c6
--- /dev/null
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/Utils.ts b/src/Utils.ts
index 0be27b25d..d9a5353e8 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -547,7 +547,7 @@ export function setupMoveUpEvents(
target: object,
e: React.PointerEvent,
moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean,
- upEvent: (e: PointerEvent) => void,
+ upEvent: (e: PointerEvent, movement: number[]) => void,
clickEvent: (e: PointerEvent, doubleTap?: boolean) => void,
stopPropagation: boolean = true,
stopMovePropagation: boolean = true
@@ -571,7 +571,7 @@ export function setupMoveUpEvents(
const _upEvent = (e: PointerEvent): void => {
(target as any)._doubleTap = (Date.now() - (target as any)._lastTap < 300);
(target as any)._lastTap = Date.now();
- upEvent(e);
+ upEvent(e, [e.clientX - (target as any)._downX, e.clientY - (target as any)._downY]);
if (Math.abs(e.clientX - (target as any)._downX) < 4 && Math.abs(e.clientY - (target as any)._downY) < 4) {
clickEvent(e, (target as any)._doubleTap);
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 49377a728..817125752 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -658,8 +658,25 @@ export class CurrentUserUtils {
return Cast(userDoc.thumbDoc, Doc);
}
- // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
- // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
+ static setupMobileInkingDoc(userDoc: Doc) {
+ return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white" });
+ }
+
+ static setupMobileUploadDoc(userDoc: Doc) {
+ // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" })
+ const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", {
+ title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true
+ });
+ const uploadDoc = Docs.Create.StackingDocument([], {
+ title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true
+ });
+ return Docs.Create.StackingDocument([webDoc, uploadDoc], {
+ _width: screen.width, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray"
+ });
+ }
+
+ // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker.
+ // when clicked, this panel will be displayed in the target container (ie, sidebarContainer)
static async setupToolsBtnPanel(doc: Doc) {
// setup a masonry view of all he creators
const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ef4b7b9d2..509d7cda8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -605,6 +605,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => {
// bcz: theres should be a better way of doing these than referencing these static instances directly
MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2
+ // PDFMenu.Instance.fadeOut(true); (commented out for mobile)
const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true);
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index c0743933e..0d787d9af 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -179,7 +179,16 @@
height: 100%;
overflow: hidden;
z-index: -1000;
- bottom: -30%;
+ bottom: 0;
+ pointer-events: none;
+ div {
+ height: 100% !important;
+ width: 100% !important;
+ }
+ canvas {
+ height: 100% !important;
+ width: 100% !important;
+ }
}
.audiobox-linker,
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 4805b8643..bc89cb6f9 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -31,9 +31,7 @@ declare class MediaRecorder {
// whatever MediaRecorder has
constructor(e: any);
}
-export const audioSchema = createSchema({
- playOnSelect: "boolean"
-});
+export const audioSchema = createSchema({ playOnSelect: "boolean" });
type AudioDocument = makeInterface<[typeof documentSchema, typeof audioSchema]>;
const AudioDocument = makeInterface(documentSchema, audioSchema);
@@ -64,24 +62,24 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
_dragging = false;
_count: Array<any> = [];
+ _audioRef = React.createRef<HTMLDivElement>();
_timeline: Opt<HTMLDivElement>;
_duration = 0;
- _containerX: number = 0;
- _invertedX: boolean = false;
- private _isPointerDown = false;
+ _markerStart: number = 0;
private _currMarker: any;
@observable _visible: boolean = false;
- @observable _currX: number = 0;
+ @observable _markerEnd: number = 0;
@observable _position: number = 0;
@observable _buckets: Array<number> = new Array<number>();
- @observable _waveHeight: number | undefined = this.layoutDoc._height;
+ @observable _waveHeight: Opt<number> = this.layoutDoc._height;
@observable private _paused: boolean = false;
@observable private static _scrubTime = 0;
@computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); }
set audioState(value) { this.dataDoc.audioState = value; }
- public static SetScrubTime = (timeInMillisFrom1970: number) => { runInAction(() => AudioBox._scrubTime = 0); runInAction(() => AudioBox._scrubTime = timeInMillisFrom1970); };
+ public static SetScrubTime = action((timeInMillisFrom1970: number) => { AudioBox._scrubTime = 0; AudioBox._scrubTime = timeInMillisFrom1970; });
@computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
+ @computed get audioDuration() { return NumCast(this.dataDoc.duration); }
async slideTemplate() { return (await Cast((await Cast(Doc.UserDoc().slidesBtn, Doc) as Doc).dragFactory, Doc) as Doc); }
constructor(props: Readonly<FieldViewProps>) {
@@ -137,21 +135,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
la2 = l.anchor1 as Doc;
linkTime = NumCast(l.anchor1_timecode);
}
- if (la2.audioStart) {
- linkTime = NumCast(la2.audioStart);
- }
-
- if (la1.audioStart) {
- linkTime = NumCast(la1.audioStart);
- }
+ if (la2.audioStart) linkTime = NumCast(la2.audioStart);
+ if (la1.audioStart) linkTime = NumCast(la1.audioStart);
- if (la1.audioEnd) {
- endTime = NumCast(la1.audioEnd);
- }
-
- if (la2.audioEnd) {
- endTime = NumCast(la2.audioEnd);
- }
+ if (la1.audioEnd) endTime = NumCast(la1.audioEnd);
+ if (la2.audioEnd) endTime = NumCast(la2.audioEnd);
if (linkTime) {
link = true;
@@ -203,7 +191,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
// play back the audio from time
@action
- playFrom = (seekTimeInSeconds: number, endTime: number = this.dataDoc.duration) => {
+ playFrom = (seekTimeInSeconds: number, endTime: number = this.audioDuration) => {
let play;
clearTimeout(play);
this._duration = endTime - seekTimeInSeconds;
@@ -218,7 +206,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
this._ele.currentTime = seekTimeInSeconds;
this._ele.play();
runInAction(() => this.audioState = "playing");
- if (endTime !== this.dataDoc.duration) {
+ if (endTime !== this.audioDuration) {
play = setTimeout(() => this.pause(), (this._duration) * 1000); // use setTimeout to play a specific duration
}
} else {
@@ -230,11 +218,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
// update the recording time
updateRecordTime = () => {
if (this.audioState === "recording") {
+ setTimeout(this.updateRecordTime, 30);
if (this._paused) {
- setTimeout(this.updateRecordTime, 30);
this._pausedTime += (new Date().getTime() - this._recordStart) / 1000;
} else {
- setTimeout(this.updateRecordTime, 30);
this.layoutDoc.currentTimecode = (new Date().getTime() - this._recordStart - this.pauseTime) / 1000;
}
}
@@ -353,74 +340,55 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
// return the total time paused to update the correct time
@computed get pauseTime() {
- return (this._pauseEnd - this._pauseStart);
+ return this._pauseEnd - this._pauseStart;
}
// starting the drag event for marker resizing
@action
onPointerDownTimeline = (e: React.PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isPointerDown = true;
- this._timeline?.setPointerCapture(e.pointerId);
-
- this.start(this._ele!.currentTime);
-
const rect = (e.target as any).getBoundingClientRect();
- this._containerX = this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
- document.removeEventListener("pointermove", this.onPointerMoveTimeline);
- document.addEventListener("pointermove", this.onPointerMoveTimeline);
- document.removeEventListener("pointerup", this.onPointerUpTimeline);
- document.addEventListener("pointerup", this.onPointerUpTimeline);
+ const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration;
+ this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x);
+ setupMoveUpEvents(this, e, action((e: PointerEvent) => {
+ this._visible = true;
+ this._markerEnd = toTimeline(e.clientX - rect.x);
+ if (this._markerEnd < this._markerStart) {
+ const tmp = this._markerStart;
+ this._markerStart = this._markerEnd;
+ this._markerEnd = tmp;
+ }
+ return false;
+ }),
+ action((e: PointerEvent, movement: number[]) => {
+ if (Math.abs(movement[0]) > 15) {
+ this.createNewMarker(this._markerStart, toTimeline(e.clientX - rect.x));
+ }
+ this._visible = false;
+ }),
+ emptyFunction);
}
-
- // ending the drag event for marker resizing
- @action
- onPointerUpTimeline = (e: PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isPointerDown = false;
-
- const rect = (e.target as any).getBoundingClientRect();
- const time = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
- // if drag is greater than 15px (didn't use setupMoveEvent)
- (this._visible && Math.abs(this._currX - this._containerX) * rect.width / NumCast(this.dataDoc.duration) > 15) ? this.end(time) : this._start = 0;
- this._visible = false;
-
- this._containerX = 0;
- this._timeline?.releasePointerCapture(e.pointerId);
-
- document.removeEventListener("pointermove", this.onPointerMoveTimeline);
- document.removeEventListener("pointerup", this.onPointerUpTimeline);
+ // returns the selection container
+ @computed get container() {
+ return <div className="audiobox-container" style={{
+ left: `${NumCast(this._markerStart) / this.audioDuration * 100}%`,
+ width: `${Math.abs(this._markerStart - this._markerEnd) / this.audioDuration * 100}%`, height: "100%", top: "0%"
+ }}></div>;
}
- // resizes the marker while dragging
+ // creates a new marker
@action
- onPointerMoveTimeline = (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
-
- if (!this._isPointerDown) {
- return;
- }
- this._visible = true;
- const rect = (e.target as any).getBoundingClientRect();
-
- this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
- (this._currX - this._containerX < 0) ? this._invertedX = true : this._invertedX = false;
- }
-
- // returns the selection container
- @computed get container() {
- return <div className="audiobox-container" style={{ left: !this._invertedX ? `${NumCast(this._containerX) / NumCast(this.dataDoc.duration, 1) * 100}%` : `${this._currX / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${Math.abs(this._containerX - this._currX) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: "100%", top: "0%" }}></div>
+ createNewMarker(audioStart: number, audioEnd: number) {
+ const newMarker = Docs.Create.LabelDocument({
+ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false,
+ useLinkSmallAnchor: true, hideLinkButton: true, audioStart, audioEnd, _showSidebar: false,
+ _autoHeight: true, annotationOn: this.props.Document
+ });
+ this.addMark(newMarker);
}
- // creates a new label
+ // adds an annotation marker or label
@action
- newMarker(marker: Doc) {
+ addMark(marker: Doc) {
marker.data = "";
if (this.dataDoc[this.annotationKey]) {
this.dataDoc[this.annotationKey].push(marker);
@@ -429,104 +397,39 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
}
}
- // the starting time of the marker
- start(startingPoint: number) {
- this._hold = true;
- this._start = startingPoint;
- }
-
- // creates a new marker
- @action
- end(marker: number) {
- this._hold = false;
- const newMarker = this._invertedX ?
- Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: marker, audioEnd: this._start, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document })
- :
- Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document });
- newMarker.data = "";
- if (this.dataDoc[this.annotationKey]) {
- this.dataDoc[this.annotationKey].push(newMarker);
- } else {
- this.dataDoc[this.annotationKey] = new List<Doc>([newMarker]);
- }
-
- this._start = 0;
- }
-
// starting the drag event for marker resizing
onPointerDown = (e: React.PointerEvent, m: any, left: boolean): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isPointerDown = true;
this._currMarker = m;
- this._timeline?.setPointerCapture(e.pointerId);
this._left = left;
-
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- // ending the drag event for marker resizing
- @action
- onPointerUp = (e: PointerEvent): void => {
- e.stopPropagation();
- e.preventDefault();
- this._isPointerDown = false;
- this._dragging = false;
-
const rect = (e.target as any).getBoundingClientRect();
- this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
- this._timeline?.releasePointerCapture(e.pointerId);
-
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
-
- // resizes the marker while dragging
- onPointerMove = async (e: PointerEvent) => {
- e.stopPropagation();
- e.preventDefault();
-
- if (!this._isPointerDown) {
- return;
- }
-
- const rect = await (e.target as any).getBoundingClientRect();
-
- const newTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
-
- this.changeMarker(this._currMarker, newTime);
+ const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration;
+ setupMoveUpEvents(this, e, () => {
+ this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x));
+ return false;
+ },
+ () => this._ele!.currentTime = this.layoutDoc.currentTimecode = toTimeline(e.clientX - rect.x),
+ emptyFunction);
}
// updates the marker with the new time
@action
changeMarker = (m: any, time: any) => {
- DocListCast(this.dataDoc[this.annotationKey]).forEach((marker: Doc) => {
- if (this.isSame(marker, m)) {
- this._left ? marker.audioStart = time : marker.audioEnd = time;
- }
- });
+ DocListCast(this.dataDoc[this.annotationKey]).filter(marker => this.isSame(marker, m)).forEach(marker =>
+ this._left ? marker.audioStart = time : marker.audioEnd = time);
}
// checks if the two markers are the same with start and end time
isSame = (m1: any, m2: any) => {
- if (m1.audioStart === m2.audioStart && m1.audioEnd === m2.audioEnd) {
- return true;
- }
- return false;
+ return m1.audioStart === m2.audioStart && m1.audioEnd === m2.audioEnd;
}
// instantiates a new array of size 500 for marker layout
markers = () => {
- const increment = NumCast(this.layoutDoc.duration) / 500;
+ const increment = this.audioDuration / 500;
this._count = [];
for (let i = 0; i < 500; i++) {
this._count.push([increment * i, 0]);
}
-
}
// makes sure no markers overlaps each other by setting the correct position and width
@@ -551,7 +454,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
if (this._count[i][0] >= m.audioStart && this._count[i][0] <= m.audioEnd) {
this._count[i][1] = max;
}
-
}
if (this.dataDoc.markerAmount < max) {
@@ -567,8 +469,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
height={this._waveHeight}
barWidth={0.1}
// pos={this.layoutDoc.currentTimecode} need to correctly resize parent to make this work (not very necessary for function)
- pos={this.dataDoc.duration}
- duration={this.dataDoc.duration}
+ pos={this.audioDuration}
+ duration={this.audioDuration}
peaks={this._buckets.length === 100 ? this._buckets : undefined}
progressColor={"blue"} />;
}
@@ -609,74 +511,31 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
return this.buckets();
}
- // for updating the width and height of the waveform with timeline ref
- timelineRef = (timeline: HTMLDivElement) => {
- const observer = new _global.ResizeObserver(action((entries: any) => {
- for (const entry of entries) {
- this.update(entry.contentRect.width, entry.contentRect.height);
- this._position = entry.contentRect.width;
- }
- }));
- timeline && observer.observe(timeline);
-
- this._timeline = timeline;
- }
-
- // update the width and height of the audio waveform
- @action
- update = (width: number, height: number) => {
- if (height) {
- const height = 0.8 * NumCast(this.layoutDoc._height);
- let canvas2 = document.getElementsByTagName("canvas")[0];
- if (canvas2) {
- let oldWidth = canvas2.width;
- let oldHeight = canvas2.height;
- canvas2.style.height = `${height}`;
- canvas2.style.width = `${width}`;
-
- const ratio1 = oldWidth / window.innerWidth;
- const ratio2 = oldHeight / window.innerHeight;
- const context = canvas2.getContext('2d');
- if (context) {
- context.scale(ratio1, ratio2);
- }
- }
-
- const canvas1 = document.getElementsByTagName("canvas")[1];
- if (canvas1) {
- const oldWidth = canvas1.width;
- const oldHeight = canvas1.height;
- canvas1.style.height = `${height}`;
- canvas1.style.width = `${width}`;
-
- const ratio1 = oldWidth / window.innerWidth;
- const ratio2 = oldHeight / window.innerHeight;
- const context = canvas1.getContext('2d');
- if (context) {
- context.scale(ratio1, ratio2);
- }
-
- const parent = canvas1.parentElement;
- if (parent) {
- parent.style.width = `${width}`;
- parent.style.height = `${height}`;
- }
- }
- }
- }
-
rangeScript = () => AudioBox.RangeScript;
-
labelScript = () => AudioBox.LabelScript;
- // for indicating the first marker that is rendered
- reset = () => this._first = true;
-
render() {
const interactive = this.active() ? "-interactive" : "";
- this.reset();
+ this._first = true; // for indicating the first marker that is rendered
this.path && this._buckets.length !== 100 ? this.peaks : null; // render waveform if audio is done recording
- return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}>
+ const markerDoc = (mark: Doc, script: undefined | (() => ScriptField)) => {
+ return <DocumentView {...this.props}
+ Document={mark}
+ pointerEvents={true}
+ NativeHeight={returnZero}
+ NativeWidth={returnZero}
+ rootSelected={returnFalse}
+ LayoutTemplate={undefined}
+ ContainingCollectionDoc={this.props.Document}
+ removeDocument={this.removeDocument}
+ parentActive={returnTrue}
+ onClick={this.layoutDoc.playOnClick ? script : undefined}
+ ignoreAutoHeight={false}
+ bringToFront={emptyFunction}
+ scriptContext={this} />;
+ };
+ return <div className={`audiobox-container`} onContextMenu={this.specificContextMenu} onClick={!this.path ? this.recordClick : undefined}
+ style={{ pointerEvents: !interactive ? "none" : undefined }}>
{!this.path ?
<div className="audiobox-buttons">
<div className="audiobox-dictation" onClick={this.onFile}>
@@ -701,88 +560,51 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
<div className="audiobox-dictation"></div>
<div className="audiobox-player" >
<div className="audiobox-playhead" title={this.audioState === "paused" ? "play" : "pause"} onClick={this.onPlay}> <FontAwesomeIcon style={{ width: "100%", position: "absolute", left: "0px", top: "5px", borderWidth: "thin", borderColor: "white" }} icon={this.audioState === "paused" ? "play" : "pause"} size={"1x"} /></div>
- <div className="audiobox-timeline" ref={this.timelineRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }}
+ <div className="audiobox-timeline" onClick={e => { e.stopPropagation(); e.preventDefault(); }}
onPointerDown={e => {
e.stopPropagation();
e.preventDefault();
if (e.button === 0 && !e.ctrlKey) {
const rect = (e.target as any).getBoundingClientRect();
-
- if (e.target as HTMLElement !== document.getElementById("current")) {
+ if (e.target !== this._audioRef.current) {
const wasPaused = this.audioState === "paused";
- this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+ this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration;
wasPaused && this.pause();
}
this.onPointerDownTimeline(e);
}
if (e.button === 0 && e.shiftKey) {
- this.newMarker(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
+ this.addMark(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }));
}
-
- // if (e.button === 0 && e.shiftKey) {
- // const rect = (e.target as any).getBoundingClientRect();
- // this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
- // this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime);
- // }
}}>
- <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px", pointerEvents: "none" }}>
+ <div className="waveform">
{this.waveform}
</div>
- {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) => {
- let rect;
+ {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) =>
(!m.isLabel) ?
(this.layoutDoc.hideMarkers) ? (null) :
- rect =
- <div key={i} id={"audiobox-marker-container1"} className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container1"}
+ <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container1`} key={i}
title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`}
style={{
- left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`,
+ left: `${NumCast(m.audioStart) / this.audioDuration * 100}%`,
top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`,
- width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
+ width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`
}}
onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
<div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div>
- <DocumentView {...this.props}
- Document={m}
- pointerEvents={true}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- rootSelected={returnFalse}
- LayoutTemplate={undefined}
- ContainingCollectionDoc={this.props.Document}
- removeDocument={this.removeDocument}
- parentActive={returnTrue}
- onClick={this.layoutDoc.playOnClick ? this.rangeScript : undefined}
- ignoreAutoHeight={false}
- bringToFront={emptyFunction}
- scriptContext={this} />
+ {markerDoc(m, this.rangeScript)}
<div className="resizer" onPointerDown={e => this.onPointerDown(e, m, false)}></div>
</div>
:
(this.layoutDoc.hideLabels) ? (null) :
- rect =
- <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={i} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
- <DocumentView {...this.props}
- Document={m}
- pointerEvents={true}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- rootSelected={returnFalse}
- LayoutTemplate={undefined}
- ContainingCollectionDoc={this.props.Document}
- removeDocument={this.removeDocument}
- parentActive={returnTrue}
- onClick={this.layoutDoc.playOnClick ? this.labelScript : undefined}
- ignoreAutoHeight={false}
- bringToFront={emptyFunction}
- scriptContext={this} />
- </div>;
- return rect;
- })}
+ <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={i}
+ style={{ left: `${NumCast(m.audioStart) / this.audioDuration * 100}%` }}>
+ {markerDoc(m, this.labelScript)}
+ </div>
+ )}
{DocListCast(this.dataDoc.links).map((l, i) => {
-
let la1 = l.anchor1 as Doc;
let la2 = l.anchor2 as Doc;
let linkTime = NumCast(l.anchor2_timecode);
@@ -797,7 +619,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
}
return !linkTime ? (null) :
- <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }} onClick={e => e.stopPropagation()}>
+ <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={l[Id]} style={{ left: `${linkTime / this.audioDuration * 100}%` }} onClick={e => e.stopPropagation()}>
<DocumentView {...this.props}
Document={l}
NativeHeight={returnZero}
@@ -814,19 +636,19 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(l, la2)}`)}
/>
<div key={i} className={`audiobox-marker`} onPointerEnter={() => Doc.linkFollowHighlight(la1)}
- onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { const wasPaused = this.audioState === "paused"; this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
+ onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} />
</div>;
})}
{this._visible ? this.container : null}
- <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%`, pointerEvents: "none" }} />
+ <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} />
{this.audio}
</div>
<div className="current-time">
{formatTime(Math.round(NumCast(this.layoutDoc.currentTimecode)))}
</div>
<div className="total-time">
- {formatTime(Math.round(NumCast(this.dataDoc.duration)))}
+ {formatTime(Math.round(this.audioDuration))}
</div>
</div>
</div>
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index e631ad5fe..dd70fb1db 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -102,9 +102,10 @@ export class FieldView extends React.Component<FieldViewProps> {
else if (field instanceof VideoField) {
return <VideoBox {...this.props} />;
}
- else if (field instanceof AudioField) {
- return <AudioBox {...this.props} />;
- } else if (field instanceof DateField) {
+ // else if (field instanceof AudioField) {
+ // return <AudioBox {...this.props} />;
+ //}
+ else if (field instanceof DateField) {
return <p>{field.date.toLocaleString()}</p>;
}
else if (field instanceof Doc) {
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index c6420bab5..d21d326f6 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -177,4 +177,4 @@ export class Uploader extends React.Component<ImageUploadProps> {
);
}
-}
+} \ No newline at end of file
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 40aa65372..02993fdcb 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -681,4 +681,4 @@ Scripting.addGlobal(function openMobileSettings() { return SettingsManager.Insta
// Other global functions for mobile
Scripting.addGlobal(function switchMobileView(doc: Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); },
- "changes the active document displayed on the Dash Mobile", "(doc: any)");
+ "changes the active document displayed on the Dash Mobile", "(doc: any)"); \ No newline at end of file
diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss
index e69de29bb..7f286efc4 100644
--- a/src/mobile/MobileMenu.scss
+++ b/src/mobile/MobileMenu.scss
@@ -0,0 +1,271 @@
+$navbar-height: 120px;
+$pathbar-height: 50px;
+
+* {
+ margin: 0px;
+ padding: 0px;
+ box-sizing: border-box;
+ font-family: "Open Sans";
+}
+
+body {
+ overflow: hidden;
+}
+
+.navbar {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100vw;
+ height: $navbar-height;
+ background-color: whitesmoke;
+ border-bottom: 5px solid black;
+}
+
+.navbar .toggle-btn {
+ position: absolute;
+ right: 20px;
+ top: 30px;
+ height: 70px;
+ width: 70px;
+ transition: all 300ms ease-in-out 200ms;
+}
+
+.navbar .header {
+ position: absolute;
+ top: 50%;
+ top: calc(9px + 50%);
+ right: 50%;
+ transform: translate(50%, -50%);
+ font-size: 40;
+ user-select: none;
+ text-transform: uppercase;
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+.navbar .toggle-btn span {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 70%;
+ height: 4px;
+ background: black;
+ transition: all 200ms ease;
+}
+
+.navbar .toggle-btn span:nth-child(1) {
+ transition: top 200ms ease-in-out;
+ top: 30%;
+}
+
+.navbar .toggle-btn span:nth-child(3) {
+ transition: top 200ms ease-in-out;
+ top: 70%;
+}
+
+.navbar .toggle-btn.active {
+ transition: transform 200ms ease-in-out 200ms;
+ transform: rotate(135deg);
+}
+
+.navbar .toggle-btn.active span:nth-child(1) {
+ top: 50%;
+}
+
+.navbar .toggle-btn.active span:nth-child(2) {
+ transform: translate(-50%, -50%) rotate(90deg);
+}
+
+.navbar .toggle-btn.active span:nth-child(3) {
+ top: 50%;
+}
+// .navbar .home {
+// position: relative;
+// right: 5px;
+// transform: translate(50%, -50%);
+// font-size: 40;
+// user-select: none;
+// text-transform: uppercase;
+// font-family: Arial, Helvetica, sans-serif;
+// z-index: 200;
+// }
+
+.sidebar {
+ position: absolute;
+ top: 200px;
+ opacity: 0;
+ right: -100%;
+ width: 100%;
+ height: calc(100% - (200px));
+ z-index: 5;
+ background-color: whitesmoke;
+ transition: all 400ms ease 50ms;
+ padding: 20px;
+ // overflow-y: auto;
+ // -webkit-overflow-scrolling: touch;
+
+ // border-right: 5px solid black;
+}
+
+.sidebar .item {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 35px;
+ text-transform: uppercase;
+ color: black;
+
+}
+
+.sidebar .ink {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 35px;
+ text-transform: uppercase;
+ color: black;
+}
+
+.sidebar .ink:focus {
+ outline: 1px solid blue;
+}
+
+.sidebar .home {
+ position: absolute;
+ top: -135px;
+ right: calc(50% + 80px);
+ transform: translate(0%, -50%);
+ font-size: 40;
+ user-select: none;
+ text-transform: uppercase;
+ font-family: Arial, Helvetica, sans-serif;
+ z-index: 200;
+}
+
+.type {
+ display: inline;
+ text-transform: lowercase;
+ margin-left: 20px;
+ font-size: 35px;
+ font-style: italic;
+ color: rgb(28, 28, 28);
+}
+
+.right {
+ margin-left: 20px;
+ z-index: 200;
+}
+
+.left {
+ width: 100%;
+ height: 100%;
+}
+
+.sidebar .logout {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 30px;
+ text-transform: uppercase;
+ color: black;
+}
+
+.sidebar .settings {
+ width: 100%;
+ padding: 13px 12px;
+ border-bottom: 1px solid rgba(200, 200, 200, 0.7);
+ font-family: Arial, Helvetica, sans-serif;
+ font-style: normal;
+ font-weight: normal;
+ user-select: none;
+ font-size: 30px;
+ text-transform: uppercase;
+ color: black;
+}
+
+
+.sidebar.active {
+ right: 0%;
+ opacity: 1;
+}
+
+.back {
+ position: absolute;
+ top: -140px;
+ left: 50px;
+ transform: translate(0%, -50%);
+ color: black;
+ font-size: 60;
+ user-select: none;
+ text-transform: uppercase;
+ z-index: 100;
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+
+.pathbar {
+ position: absolute;
+ top: 118px;
+ background: #1a1a1a;
+ z-index: 20;
+ border-radius: 0px;
+ width: 100%;
+ height: 80px;
+ transition: all 400ms ease 50ms;
+}
+
+.pathname {
+ position: relative;
+ font-size: 25;
+ top: 50%;
+ width: 90%;
+ left: 3%;
+ color: whitesmoke;
+ transform: translate(0%, -50%);
+ z-index: 20;
+ font-family: sans-serif;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ direction: rtl;
+ text-align: left;
+ text-transform: uppercase;
+}
+
+.homeContainer {
+ position: relative;
+ top: 200px;
+ height: calc(100% - 250px);
+ width: 90%;
+ overflow: scroll;
+ left: 5%;
+ background-color: lightpink;
+}
+
+.pinButton {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ font-size: 90px;
+ text-align: center;
+ left: 50%;
+ transform: translate(-50%, 0);
+ border-style: solid;
+ border-radius: 50px;
+ border-width: medium;
+ background-color: pink;
+ z-index: 100;
+} \ No newline at end of file