Skip to content

Commit 40a61d8

Browse files
committed
first commit
1 parent 1eecb9d commit 40a61d8

13 files changed

+665
-3
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface IListItemAttachmentFile{
2+
FileName : string;
3+
ServerRelativeUrl: string;
4+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { WebPartContext } from "@microsoft/sp-webpart-base";
2+
import { ApplicationCustomizerContext } from "@microsoft/sp-application-base";
3+
4+
export interface IListItemAttachmentsProps {
5+
listId: string;
6+
itemId: number;
7+
className?: string;
8+
webUrl?:string;
9+
disabled?: boolean;
10+
context: WebPartContext | ApplicationCustomizerContext;
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {IListItemAttachmentFile } from '../spentities/IListItemAttachmentFile';
2+
export interface IListItemAttachmentsState {
3+
file: IListItemAttachmentFile;
4+
showDialog: boolean;
5+
dialogMessage: string;
6+
Documents: IListItemAttachmentFile[];
7+
deleteAttachment: boolean;
8+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { WebPartContext } from "@microsoft/sp-webpart-base";
2+
import { ApplicationCustomizerContext } from "@microsoft/sp-application-base";
3+
4+
export interface IUploadAttachmentProps {
5+
listId: string;
6+
itemId: number;
7+
className?: string;
8+
webUrl?:string;
9+
disabled?: boolean;
10+
context: WebPartContext | ApplicationCustomizerContext;
11+
onAttachmentUpload: () => void;
12+
iconButton: boolean;
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
export interface IUploadAttachmentState {
3+
file: any;
4+
showDialog: boolean;
5+
dialogMessage: string;
6+
isLoading: boolean;
7+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
2+
.ListItemAttachments {
3+
.documentCard {
4+
-webkit-font-smoothing: antialiased;
5+
background-color: #ffffff;
6+
border: 1px solid #eaeaea;
7+
-webkit-box-sizing: border-box;
8+
box-sizing: border-box;
9+
max-width: 320px;
10+
min-width: 187px;
11+
-webkit-user-select: none;
12+
-moz-user-select: none;
13+
-ms-user-select: none;
14+
user-select: none;
15+
position: relative;
16+
}
17+
.documentCardWrapper {
18+
margin-top: 15px;
19+
min-Width: 187px;
20+
width: 187px;
21+
display: inline-block;
22+
margin-Left: 12px
23+
}
24+
25+
.fileLabel {
26+
margin-Left: 12px;
27+
margin-Right: 12px;
28+
overflow: 'hidden';
29+
white-Space: 'nowrap';
30+
text-overflow: 'ellipsis';
31+
}
32+
.uploadfile {
33+
background-color:transparent !important;
34+
font-size: 15px;
35+
}
36+
}
37+
38+
39+
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// Joao Mendes November 2018, SPFx reusable Control ListItemAttachments
2+
import * as React from 'react';
3+
import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
4+
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
5+
import { Icon, IconType } from 'office-ui-fabric-react/lib/Icon';
6+
import { Label } from "office-ui-fabric-react/lib/Label";
7+
import { Link } from 'office-ui-fabric-react/lib/Link';
8+
import * as strings from 'ControlStrings';
9+
import styles from './ListItemAttachments.module.scss';
10+
import { UploadAttachment } from './uploadAttachment';
11+
import { IListItemAttachmentFile } from './IListItemAttachmentFile';
12+
import {
13+
DocumentCard,
14+
DocumentCardActions,
15+
DocumentCardPreview,
16+
DocumentCardTitle,
17+
IDocumentCardPreviewImage
18+
} from 'office-ui-fabric-react/lib/DocumentCard';
19+
import { ImageFit } from 'office-ui-fabric-react/lib/Image';
20+
import { IListItemAttachmentsProps } from '.';
21+
import { IListItemAttachmentsState } from '.';
22+
import SPservice from "../../services/SPService";
23+
import { TooltipHost, DirectionalHint } from 'office-ui-fabric-react/lib/Tooltip';
24+
import utilities from './utilities';
25+
26+
27+
export class ListItemAttachments extends React.Component<IListItemAttachmentsProps, IListItemAttachmentsState> {
28+
private _spservice: SPservice;
29+
private previewImages: IDocumentCardPreviewImage[];
30+
private _utilities: utilities;
31+
32+
constructor(props: IListItemAttachmentsProps) {
33+
super(props);
34+
35+
this.state = {
36+
file: null,
37+
showDialog: false,
38+
dialogMessage: '',
39+
Documents: [],
40+
deleteAttachment: false
41+
};
42+
// Get SPService Factory
43+
this._spservice = new SPservice(this.props.context);
44+
this._utilities = new utilities();
45+
46+
// registo de event handlers
47+
this._onDeleteAttachment = this._onDeleteAttachment.bind(this);
48+
this._closeDialog = this._closeDialog.bind(this);
49+
this._onAttachmentpload = this._onAttachmentpload.bind(this);
50+
this._onConfirmedDeleteAttachment = this._onConfirmedDeleteAttachment.bind(this);
51+
}
52+
// Load Item Attachments
53+
private async _loadAttachments() {
54+
this.previewImages = [];
55+
try {
56+
const files: IListItemAttachmentFile[] = await this._spservice.getListItemAttachments(this.props.listId, this.props.itemId);
57+
for (const _file of files) {
58+
59+
this.previewImages.push({
60+
name: _file.FileName,
61+
previewImageSrc: await this._utilities.GetFileImageUrl(_file),
62+
iconSrc: '',
63+
imageFit: ImageFit.center,
64+
width: 187,
65+
height: 130,
66+
});
67+
}
68+
this.setState({
69+
showDialog: false,
70+
dialogMessage: '',
71+
Documents: files
72+
});
73+
}
74+
catch (error) {
75+
this.setState({
76+
showDialog: true,
77+
dialogMessage: strings.ListItemAttachmentserrorLoadAttachments.replace('{0}', error.message)
78+
});
79+
}
80+
}
81+
// LoadAttachments
82+
public componentDidMount() {
83+
this._loadAttachments();
84+
}
85+
86+
// Render Attachments
87+
public render() {
88+
return (
89+
90+
<div className={styles.ListItemAttachments}>
91+
<UploadAttachment
92+
listId={this.props.listId}
93+
itemId={this.props.itemId}
94+
iconButton={true}
95+
disabled={this.props.disabled}
96+
context={this.props.context}
97+
onAttachmentUpload={this._onAttachmentpload}
98+
/>
99+
100+
{this.state.Documents.map((_file, i: number) => {
101+
return (
102+
<div className={styles.documentCardWrapper}>
103+
<TooltipHost
104+
content={_file.FileName}
105+
calloutProps={{ gapSpace: 0, isBeakVisible: true }}
106+
closeDelay={200}
107+
directionalHint={DirectionalHint.rightCenter}>
108+
109+
<DocumentCard
110+
onClickHref={_file.ServerRelativeUrl}
111+
className={styles.documentCard}>
112+
<DocumentCardPreview previewImages={[this.previewImages[i]]} />
113+
<Label className={styles.fileLabel}>
114+
{_file.FileName}
115+
</Label>
116+
<DocumentCardActions
117+
actions={
118+
[
119+
{
120+
iconProps: {
121+
iconName: 'Delete',
122+
title: strings.ListItemAttachmentsActionDeleteIconTitle,
123+
},
124+
title: strings.ListItemAttachmentsactionDeleteTitle,
125+
text: strings.ListItemAttachmentsactionDeleteTitle,
126+
disabled: this.props.disabled,
127+
onClick: (ev) => {
128+
ev.preventDefault();
129+
ev.stopPropagation();
130+
this._onDeleteAttachment(_file);
131+
}
132+
},
133+
]
134+
}
135+
/>
136+
</DocumentCard>
137+
</TooltipHost>
138+
</div>
139+
);
140+
})}
141+
{
142+
<Dialog
143+
isOpen={this.state.showDialog}
144+
type={DialogType.normal}
145+
onDismiss={this._closeDialog}
146+
title={strings.ListItemAttachmentsdialogTitle}
147+
subText={this.state.dialogMessage}
148+
isBlocking={true}>
149+
<DialogFooter>
150+
{
151+
this.state.deleteAttachment ? (<PrimaryButton onClick={this._onConfirmedDeleteAttachment}>{strings.dialogOKbuttonLabelOnDelete}</PrimaryButton>) : ""
152+
}
153+
{
154+
this.state.deleteAttachment ? (<DefaultButton onClick={this._closeDialog}>{strings.dialogCancelButtonLabel}</DefaultButton>) : <PrimaryButton onClick={this._closeDialog}>{strings.dialogOKbuttonLabel}</PrimaryButton>
155+
}
156+
</DialogFooter>
157+
</Dialog>
158+
}
159+
</div>
160+
);
161+
}
162+
163+
// close dialog
164+
private _closeDialog(e) {
165+
e.preventDefault();
166+
167+
this.setState({
168+
showDialog: false,
169+
dialogMessage: '',
170+
file: null,
171+
deleteAttachment: false,
172+
});
173+
this._loadAttachments();
174+
}
175+
176+
// On onAttachmentpload
177+
private _onAttachmentpload() {
178+
// load Attachments
179+
this._loadAttachments();
180+
}
181+
182+
// On _onDeleteAttachment
183+
private _onDeleteAttachment(_file: IListItemAttachmentFile) {
184+
this.setState({
185+
showDialog: true,
186+
deleteAttachment: true,
187+
file: _file,
188+
dialogMessage: strings.ListItemAttachmentsconfirmDelete.replace('{0}', _file.FileName),
189+
});
190+
}
191+
/*
192+
* Confirmed Delete
193+
*/
194+
private _onConfirmedDeleteAttachment() {
195+
// Delete Attachment
196+
const _file = this.state.file;
197+
this._spservice.deleteAttachment(_file.FileName, this.props.listId, this.props.itemId, this.props.webUrl)
198+
.then(() => {
199+
200+
this.setState({
201+
showDialog: true,
202+
deleteAttachment: false,
203+
file: null,
204+
dialogMessage: strings.ListItemAttachmentsfileDeletedMsg.replace('{0}', _file.FileName),
205+
});
206+
207+
})
208+
.catch((reason) => {
209+
210+
this.setState({
211+
showDialog: true,
212+
file: null,
213+
deleteAttachment: false,
214+
dialogMessage: strings.ListItemAttachmentsfileDeleteError.replace('{0}', _file.FileName).replace('{1}', reason)
215+
});
216+
217+
});
218+
}
219+
}
220+
export default ListItemAttachments;

0 commit comments

Comments
 (0)