Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.

Commit d38a070

Browse files
feat(#313): copy/clone slide
1 parent 0e32f3c commit d38a070

File tree

11 files changed

+167
-71
lines changed

11 files changed

+167
-71
lines changed

studio/src/app/components/editor/actions/app-editor-actions/app-editor-actions.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Component, Element, Event, EventEmitter, h, Listen, Prop} from '@stencil/core';
1+
import {Component, Element, Event, EventEmitter, h, JSX, Listen, Prop} from '@stencil/core';
22
import {OverlayEventDetail} from '@ionic/core';
33

44
import {get, set} from 'idb-keyval';
@@ -27,13 +27,13 @@ export class AppEditorActions {
2727
fullscreen: boolean = false;
2828

2929
@Prop()
30-
slides: any[] = [];
30+
slides: JSX.IntrinsicElements[] = [];
3131

3232
private anonymousService: AnonymousService;
3333

3434
@Event() signIn: EventEmitter<void>;
3535

36-
@Event() addSlide: EventEmitter<any>;
36+
@Event() addSlide: EventEmitter<JSX.IntrinsicElements>;
3737

3838
@Event() animatePrevNextSlide: EventEmitter<boolean>;
3939

@@ -57,7 +57,7 @@ export class AppEditorActions {
5757
const couldAddSlide: boolean = await this.anonymousService.couldAddSlide(this.slides);
5858

5959
if (!couldAddSlide) {
60-
await this.signIn.emit();
60+
this.signIn.emit();
6161
return;
6262
}
6363

@@ -77,7 +77,7 @@ export class AppEditorActions {
7777
}
7878

7979
if (detail.data.slide) {
80-
await this.addSlide.emit(detail.data.slide);
80+
this.addSlide.emit(detail.data.slide);
8181
}
8282
}
8383
});
@@ -117,9 +117,9 @@ export class AppEditorActions {
117117
}
118118

119119
const url: string = gif.media[0].gif.url;
120-
const slide: any = await CreateSlidesUtils.createSlideGif(url);
120+
const slide: JSX.IntrinsicElements = await CreateSlidesUtils.createSlideGif(url);
121121

122-
await this.addSlide.emit(slide);
122+
this.addSlide.emit(slide);
123123

124124
resolve();
125125
});
@@ -132,9 +132,9 @@ export class AppEditorActions {
132132
return;
133133
}
134134

135-
const slide: any = await CreateSlidesUtils.createSlideYoutube(youtubeUrl);
135+
const slide: JSX.IntrinsicElements = await CreateSlidesUtils.createSlideYoutube(youtubeUrl);
136136

137-
await this.addSlide.emit(slide);
137+
this.addSlide.emit(slide);
138138

139139
resolve();
140140
});
@@ -152,7 +152,7 @@ export class AppEditorActions {
152152

153153
modal.onDidDismiss().then(async (detail: OverlayEventDetail) => {
154154
if (detail.data >= 0) {
155-
await this.slideTo.emit(detail.data);
155+
this.slideTo.emit(detail.data);
156156
}
157157
});
158158

@@ -187,7 +187,7 @@ export class AppEditorActions {
187187
} else if (detail.data.action === MoreAction.REMOTE) {
188188
await this.openRemoteControl();
189189
} else if (detail.data.action === MoreAction.SHARE) {
190-
await this.openShare.emit();
190+
this.openShare.emit();
191191
} else if (detail.data.action === MoreAction.PUBLISH) {
192192
this.actionPublish.emit();
193193
}
@@ -199,7 +199,7 @@ export class AppEditorActions {
199199

200200
private toggleFullScreenMode(): Promise<void> {
201201
return new Promise<void>(async (resolve) => {
202-
await this.toggleFullScreen.emit();
202+
this.toggleFullScreen.emit();
203203

204204
await this.openFullscreenInfo();
205205

studio/src/app/components/editor/actions/app-share-action/app-share-action.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class AppShareAction {
5858
popover.onDidDismiss().then(async (detail: OverlayEventDetail) => {
5959
if (detail && detail.data) {
6060
if (detail.data.action === MoreAction.SHARE) {
61-
await this.openShare.emit();
61+
this.openShare.emit();
6262
} else if (detail.data.action === MoreAction.PUBLISH) {
6363
this.actionPublish.emit();
6464
}

studio/src/app/components/editor/app-editor-toolbar/app-editor-toolbar.scss

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,14 @@ app-editor-toolbar {
5959
color: var(--ion-color-light);
6060
}
6161
}
62+
}
6263

63-
&.delete {
64-
margin-left: auto;
65-
}
64+
div.editor-toolbar-edit {
65+
margin-left: auto;
66+
67+
display: flex;
68+
justify-content: flex-end;
69+
align-items: center;
6670
}
6771
}
6872
}

studio/src/app/components/editor/app-editor-toolbar/app-editor-toolbar.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export class AppEditorToolbar {
6666
@Event() private codeDidChange: EventEmitter<HTMLElement>;
6767
@Event() private imgDidChange: EventEmitter<HTMLElement>;
6868

69+
@Event() private slideCopy: EventEmitter<HTMLElement>;
70+
6971
private subscription: Subscription;
7072
private busyService: BusyService;
7173

@@ -456,6 +458,28 @@ export class AppEditorToolbar {
456458
});
457459
}
458460

461+
private cloneSlide(): Promise<void> {
462+
return new Promise<void>(async (resolve) => {
463+
if (!this.selectedElement) {
464+
resolve();
465+
return;
466+
}
467+
468+
if (this.deckBusy || !this.deckOrSlide) {
469+
resolve();
470+
return;
471+
}
472+
473+
this.busyService.deckBusy(true);
474+
475+
this.slideCopy.emit(this.selectedElement);
476+
477+
await this.hideToolbar();
478+
479+
resolve();
480+
});
481+
}
482+
459483
private async openSlotType() {
460484
if (this.deckOrSlide) {
461485
return;
@@ -884,18 +908,33 @@ export class AppEditorToolbar {
884908
{this.renderImages()}
885909
{this.renderYoutube()}
886910
{this.renderCodeOptions()}
887-
{this.renderDelete()}
911+
912+
<div class="editor-toolbar-edit">
913+
{this.renderCopy()}
914+
{this.renderDelete()}
915+
</div>
888916
</div>
889917
];
890918
}
891919

892920
private renderDelete() {
893921
return <a onClick={() => this.deleteElement()} title="Delete"
894-
class={this.deckBusy && this.deckOrSlide ? "delete disabled" : "delete"}>
922+
class={this.deckBusy && this.deckOrSlide ? "disabled" : ""}>
895923
<ion-icon name="trash"></ion-icon>
896924
</a>
897925
}
898926

927+
private renderCopy() {
928+
if (!this.deckOrSlide) {
929+
return undefined;
930+
} else {
931+
return <a onClick={() => this.cloneSlide()} title="Copy"
932+
class={this.deckBusy ? "disabled" : ""}>
933+
<ion-icon name="copy"></ion-icon>
934+
</a>
935+
}
936+
}
937+
899938
private renderColor() {
900939
return <a onClick={() => this.openColor()} title="Color">
901940
<ion-icon name="color-fill"></ion-icon>

studio/src/app/helpers/editor/editor.helper.tsx

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import {JSX} from '@stencil/core';
2+
import {take} from 'rxjs/operators';
3+
14
import {Slide} from '../../models/data/slide';
25
import {Deck} from '../../models/data/deck';
36

@@ -82,16 +85,52 @@ export class EditorHelper {
8285
});
8386
}
8487

85-
private fetchSlide(deckId: string, slideId: string): Promise<any> {
88+
private fetchSlide(deckId: string, slideId: string): Promise<JSX.IntrinsicElements> {
8689
return new Promise<any>(async (resolve) => {
8790
try {
8891
const slide: Slide = await this.slideService.get(deckId, slideId);
89-
const element: any = await ParseSlidesUtils.parseSlide(slide, true);
92+
const element: JSX.IntrinsicElements = await ParseSlidesUtils.parseSlide(slide, true);
9093

9194
resolve(element);
9295
} catch (err) {
9396
this.errorService.error('Something went wrong while loading and parsing a slide');
94-
resolve();
97+
resolve(null);
98+
}
99+
});
100+
}
101+
102+
copySlide(slide: HTMLElement): Promise<JSX.IntrinsicElements> {
103+
return new Promise<JSX.IntrinsicElements>(async (resolve) => {
104+
try {
105+
if (!slide) {
106+
resolve(null);
107+
return;
108+
}
109+
110+
if (!slide.getAttribute('slide_id')) {
111+
this.errorService.error('Slide is not defined');
112+
resolve(null);
113+
return;
114+
}
115+
116+
const slideId: string = slide.getAttribute('slide_id');
117+
118+
this.deckEditorService.watch().pipe(take(1)).subscribe(async (deck: Deck) => {
119+
let element: JSX.IntrinsicElements = null;
120+
121+
if (deck && deck.data) {
122+
const slide: Slide = await this.slideService.get(deck.id, slideId);
123+
element = await ParseSlidesUtils.parseSlide(slide, true, true);
124+
}
125+
126+
this.busyService.deckBusy(false);
127+
128+
resolve(element);
129+
});
130+
} catch (err) {
131+
this.errorService.error(err);
132+
this.busyService.deckBusy(false);
133+
resolve(null);
95134
}
96135
});
97136
}

studio/src/app/pages/core/app-dashboard/app-dashboard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Component, h, State} from '@stencil/core';
1+
import {Component, h, JSX, State} from '@stencil/core';
22

33
import {filter, take} from 'rxjs/operators';
44

@@ -16,7 +16,7 @@ import {ParseBackgroundUtils} from '../../../utils/editor/parse-background.utils
1616

1717
interface DeckAndFirstSlide {
1818
deck: Deck;
19-
slide: any;
19+
slide: JSX.IntrinsicElements;
2020
style: any;
2121
background: any;
2222
}
@@ -85,7 +85,7 @@ export class AppDashboard {
8585
return new Promise<DeckAndFirstSlide>(async (resolve) => {
8686
try {
8787
const slide: Slide = await this.slideService.get(deck.id, slideId);
88-
const element: any = await ParseSlidesUtils.parseSlide(slide, false);
88+
const element: JSX.IntrinsicElements = await ParseSlidesUtils.parseSlide(slide, false);
8989

9090
let style: any;
9191
if (deck.data && deck.data.attributes && deck.data.attributes.style) {

studio/src/app/pages/editor/app-editor/app-editor.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Component, Element, Listen, Prop, State, h} from '@stencil/core';
1+
import {Component, Element, Listen, Prop, State, h, JSX} from '@stencil/core';
22

33
import {ItemReorderEventDetail} from '@ionic/core';
44

@@ -44,7 +44,7 @@ export class AppEditor {
4444
deckId: string;
4545

4646
@State()
47-
private slides: any[] = [];
47+
private slides: JSX.IntrinsicElements[] = [];
4848

4949
@State()
5050
private background: any;
@@ -61,6 +61,8 @@ export class AppEditor {
6161
private remoteEventsHandler: RemoteEventsHandler = new RemoteEventsHandler();
6262
private editorEventsHandler: EditorEventsHandler = new EditorEventsHandler();
6363

64+
private editorHelper: EditorHelper = new EditorHelper();
65+
6466
private authService: AuthService;
6567
private anonymousService: AnonymousService;
6668
private navService: NavService;
@@ -197,7 +199,7 @@ export class AppEditor {
197199
return;
198200
}
199201

200-
const slide: any = await CreateSlidesUtils.createSlide(SlideTemplate.TITLE);
202+
const slide: JSX.IntrinsicElements = await CreateSlidesUtils.createSlide(SlideTemplate.TITLE);
201203

202204
await this.concatSlide(slide);
203205

@@ -212,8 +214,7 @@ export class AppEditor {
212214
return;
213215
}
214216

215-
const helper: EditorHelper = new EditorHelper();
216-
const slides: any[] = await helper.loadDeckAndRetrieveSlides(this.deckId);
217+
const slides: any[] = await this.editorHelper.loadDeckAndRetrieveSlides(this.deckId);
217218

218219
if (slides && slides.length > 0) {
219220
this.slides = [...slides];
@@ -241,7 +242,7 @@ export class AppEditor {
241242
});
242243
}
243244

244-
private concatSlide(extraSlide: any): Promise<void> {
245+
private concatSlide(extraSlide: JSX.IntrinsicElements): Promise<void> {
245246
return new Promise<void>((resolve) => {
246247
this.slides = [...this.slides, extraSlide];
247248

@@ -294,7 +295,19 @@ export class AppEditor {
294295
await (deck as any).slideTo($event.detail);
295296
}
296297

297-
private async addSlide($event: CustomEvent<any>) {
298+
private async copySlide($event: CustomEvent<HTMLElement>) {
299+
if (!$event || !$event.detail) {
300+
return;
301+
}
302+
303+
const slide: JSX.IntrinsicElements = await this.editorHelper.copySlide($event.detail);
304+
305+
if (slide) {
306+
await this.concatSlide(slide);
307+
}
308+
}
309+
310+
private async addSlide($event: CustomEvent<JSX.IntrinsicElements>) {
298311
if (!$event) {
299312
return;
300313
}
@@ -552,13 +565,13 @@ export class AppEditor {
552565
</deckgo-deck>
553566
<deckgo-remote autoConnect={false}></deckgo-remote>
554567
</main>
555-
<app-editor-toolbar></app-editor-toolbar>
568+
<app-editor-toolbar onSlideCopy={($event: CustomEvent<HTMLElement>) => this.copySlide($event)}></app-editor-toolbar>
556569
</ion-content>,
557570
<ion-footer class={this.presenting ? 'idle' : undefined}>
558571
<app-editor-actions hideFooterActions={this.hideFooterActions} fullscreen={this.fullscreen}
559572
slides={this.slides}
560573
onSignIn={() => this.signIn()}
561-
onAddSlide={($event: CustomEvent<any>) => this.addSlide($event)}
574+
onAddSlide={($event: CustomEvent<JSX.IntrinsicElements>) => this.addSlide($event)}
562575
onAnimatePrevNextSlide={($event: CustomEvent<boolean>) => this.animatePrevNextSlide($event)}
563576
onSlideTo={($event: CustomEvent<number>) => this.slideTo($event)}
564577
onToggleFullScreen={() => this.toggleFullScreen()}></app-editor-actions>

0 commit comments

Comments
 (0)