Skip to content

Commit

Permalink
[TASK] Add copy/move/delete/download resources
Browse files Browse the repository at this point in the history
Fixes: #23, #31, #83, #102
  • Loading branch information
NeoBlack authored Apr 5, 2019
1 parent d2537ea commit 5b1f130
Show file tree
Hide file tree
Showing 20 changed files with 1,338 additions and 194 deletions.
13 changes: 7 additions & 6 deletions Build/Vue/src/components/AllSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {Component, Prop, Vue} from 'vue-property-decorator';
import {VNode} from 'vue';
import {Mutation, State} from 'vuex-class';
import {Mutations} from '@/enums/Mutations';
import {ResourceInterface} from '@/interfaces/ResourceInterface';

@Component
export default class AllSelector extends Vue {
Expand All @@ -16,10 +17,10 @@ export default class AllSelector extends Vue {
unselectItems: any;

@State
selected!: Array<object>;
selected!: Array<ResourceInterface>;

@Prop()
listOfIdentifiers!: Array<String>;
listOfResources!: Array<ResourceInterface>;

constructor(props: any) {
super(props);
Expand All @@ -30,7 +31,7 @@ export default class AllSelector extends Vue {
return (
<span class='component-checkbox'>
<input class='component-checkbox-input' type='checkbox' id={'component-datatable-selectall-' + randomPart}
value='1' onClick={(event: Event) => this.toggleSelect(event, this.listOfIdentifiers)} />
value='1' onClick={(event: Event) => this.toggleSelect(event, this.listOfResources)} />
<label class='component-checkbox-label' for={'component-datatable-selectall-' + randomPart}>
<span class='component-visually-hidden'>
{this.isSelected ? TYPO3.lang['AllSelector.label.deselect'] : TYPO3.lang['AllSelector.label.select']}
Expand All @@ -40,10 +41,10 @@ export default class AllSelector extends Vue {
);
}

private toggleSelect(event: Event, listOfIdentifiers: Array<String>): void {
private toggleSelect(event: Event, listOfResources: Array<ResourceInterface>): void {
event.stopPropagation();
this.selected.length > 0
? this.unselectItems(listOfIdentifiers)
: this.selectItems(listOfIdentifiers);
? this.unselectItems(listOfResources)
: this.selectItems(listOfResources);
}
}
199 changes: 193 additions & 6 deletions Build/Vue/src/components/ButtonBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,201 @@
import {Component, Vue} from 'vue-property-decorator';
import {VNode} from 'vue';
import {Action, Mutation, State} from 'vuex-class';
import {AjaxRoutes} from '@/enums/AjaxRoutes';
import {Mutations} from '@/enums/Mutations';
import CopyMoveModal from '@/components/CopyMoveModal';
import {CopyMoveRequestInterface} from '@/interfaces/request/CopyMoveRequestInterface';
import {ResourceInterface} from '@/interfaces/ResourceInterface';
import client from '@/services/http/Typo3Client';
import Modal from 'TYPO3/CMS/Backend/Modal';
import {DeleteRequestInterface} from '@/interfaces/request/DeleteRequestInterface';
import {DownloadRequestInterface} from '@/interfaces/request/DownloadRequestInterface';

@Component
export default class ButtonBar extends Vue {
constructor(props: any) {
super(props);
@Action(AjaxRoutes.damGetFolderItems)
fetchData: any;

@Mutation(Mutations.SET_MODAL_CONTENT)
setModalContent!: Function;

@Mutation(Mutations.NAVIGATE)
navigate!: Function;

@State
selected!: Array<ResourceInterface>;

@State
current!: string;

private modal: any;

constructor(props: any) {
super(props);
}

private async copyResources(request: CopyMoveRequestInterface): Promise<any> {
const identifiers: Array<string> = [];
Object.values(request.resources).map((item: ResourceInterface) => {
identifiers.push(item.identifier);
});

const response = await client.get(
TYPO3.settings.ajaxUrls[AjaxRoutes.damCopyResources]
+ '&conflictMode=rename'
+ '&identifiers[]=' + identifiers.join('&identifiers[]=')
+ '&targetFolderIdentifier=' + request.target,
);

if (response.status === 200) {
this.modal.trigger('modal-dismiss');
this.fetchData(request.target);
this.navigate(request.target);
}
}

private async moveResources(request: CopyMoveRequestInterface): Promise<any> {
const identifiers: Array<string> = [];
Object.values(request.resources).map((item: ResourceInterface) => {
identifiers.push(item.identifier);
});

const response = await client.get(
TYPO3.settings.ajaxUrls[AjaxRoutes.damMoveResources]
+ '&conflictMode=rename'
+ '&identifiers[]=' + identifiers.join('&identifiers[]=')
+ '&targetFolderIdentifier=' + request.target,
);

if (response.status === 200) {
this.modal.trigger('modal-dismiss');
this.fetchData(request.target);
this.navigate(request.target);
}
private render(): VNode {
return (
<div><button>ButtonBar</button></div>
);
}

private async deleteResources(request: DeleteRequestInterface): Promise<any> {
const identifiers: Array<string> = [];
Object.values(request.resources).map((item: ResourceInterface) => {
identifiers.push(item.identifier);
});

const response = await client.get(
TYPO3.settings.ajaxUrls[AjaxRoutes.damDeleteResources]
+ '&identifiers[]=' + identifiers.join('&identifiers[]='),
);

if (response.status === 200) {
this.modal.trigger('modal-dismiss');
this.fetchData(this.current);
this.navigate(this.current);
}
}

private async downloadResources(request: DownloadRequestInterface): Promise<any> {
const identifiers: Array<string> = [];
Object.values(request.resources).map((item: ResourceInterface) => {
identifiers.push(item.identifier);
});

const response = await client.get(
TYPO3.settings.ajaxUrls[AjaxRoutes.damPrepareDownload]
+ '&identifiers[]=' + identifiers.join('&identifiers[]='),
{responseType: 'blob'},
).then((resp) => {
const url = window.URL.createObjectURL(new Blob([resp.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', resp.headers.filename);
document.body.appendChild(link);
link.click();
});
}

private selectTarget(action: Function): void {
this.setModalContent(<CopyMoveModal />);
let content: any = jQuery('#vue-modalContent');
this.modal = Modal.advanced({
content: content,
additionalCssClasses: ['modal-select-target'],
buttons: [
{
btnClass: 'btn-default',
dataAttributes: {
method: 'dismiss',
},
icon: 'actions-close',
text: 'Cancel',
},
{
btnClass: 'btn-primary',
dataAttributes: {
method: 'select',
},
text: 'Select target',
},
],
callback: (currentModal: any): void => {
currentModal.on('button.clicked', (e: any): void => {
const method = $(e.target).data('method');
if (method === 'dismiss') {
currentModal.trigger('modal-dismiss');
}
if (method === 'select') {
const target: string = $(e.currentTarget).find('.list-tree .list-tree-group.active').data('identifier');
action({
'resources': this.selected,
'target': target,
});
// currentModal.trigger('modal-dismiss');
}
});
},
title: 'Select target folder',
});
}

private confirm(action: Function): void {
this.modal = Modal.confirm('Are you sure?', 'Do you want delete the selected resources?')
.on('confirm.button.cancel', (): void => {
this.modal.trigger('modal-dismiss');
})
.on('confirm.button.ok', (): void => {
action({
'resources': this.selected,
});
});
}


private render(): VNode {
const disabled = this.selected.length === 0;
const cssClasses = 'btn btn-default' + (disabled ? ' disabled' : '');
const moveResources = (e: Event) => {
e.stopPropagation();
this.selectTarget(this.moveResources);
};
const copyResources = (e: Event) => {
e.stopPropagation();
this.selectTarget(this.copyResources);
};
const deleteResources = (e: Event) => {
e.stopPropagation();
this.confirm(this.deleteResources);
};
const downloadResources = (e: Event) => {
e.stopPropagation();
this.downloadResources({
'resources': this.selected,
});
};
return (
<div class='btn-group'>
<a href='#' class={cssClasses} disabled={disabled} onClick={downloadResources}><i class='fa fa-download'/> Download</a>
<a href='#' class={cssClasses} disabled={disabled} onClick={deleteResources}><i class='fa fa-trash'/> Delete</a>
<a href='#' class={cssClasses} disabled={disabled} onClick={moveResources}><i class='fa fa-crosshairs'/> Move to</a>
<a href='#' class={cssClasses} disabled={disabled} onClick={copyResources}><i class='fa fa-clipboard'/> Copy to</a>
</div>
);
}
}
3 changes: 2 additions & 1 deletion Build/Vue/src/components/ContentPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import StorageSelector from '@/components/StorageSelector';
import {Action, State} from 'vuex-class';
import TreeToggle from '@/components/TreeToggle';
import DropZone from '@/components/DropZone';
import ButtonBar from '@/components/ButtonBar';

@Component
export default class ContentPanel extends Vue {
Expand All @@ -39,7 +40,7 @@ export default class ContentPanel extends Vue {
<template slot='beforeUploadTable'>
<DocHeader>
<template slot='topBarLeft'><TreeToggle v-show={this.activeStorage}/><ViewSelector/></template>
<template slot='topBarRight'><SortingSelector/></template>
<template slot='topBarRight'><ButtonBar /><SortingSelector/></template>
<template slot='bottomBarLeft'><StorageSelector /><Breadcrumb v-show={this.activeStorage}/></template>
<template slot='bottomBarRight'><SelectIndicator v-show={this.activeStorage}/></template>
</DocHeader>
Expand Down
Loading

0 comments on commit 5b1f130

Please sign in to comment.