]> BookStack Code Mirror - bookstack/blob - resources/assets/js/components/image-manager.vue
Added custom user avatars
[bookstack] / resources / assets / js / components / image-manager.vue
1 <template>
2     <div id="image-manager">
3         <div class="overlay" v-el:overlay @click="overlayClick">
4             <div class="image-manager-body">
5                 <div class="image-manager-content">
6                     <div class="image-manager-list">
7                         <div v-for="image in images">
8                             <img class="anim fadeIn"
9                                  :class="{selected: (image==selectedImage)}"
10                                  :src="image.thumbs.gallery" :alt="image.title" :title="image.name"
11                                  @click="imageClick(image)"
12                                  :style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}">
13                         </div>
14                         <div class="load-more" v-show="hasMore" @click="fetchData">Load More</div>
15                     </div>
16                 </div>
17                 <button class="neg button image-manager-close" @click="hide">x</button>
18                 <div class="image-manager-sidebar">
19                     <h2 v-el:image-title>Images</h2>
20                     <hr class="even">
21                     <div class="dropzone-container" v-el:drop-zone>
22                         <div class="dz-message">Drop files or click here to upload</div>
23                     </div>
24                     <div class="image-manager-details anim fadeIn" v-show="selectedImage">
25                         <hr class="even">
26                         <form @submit="saveImageDetails" v-el:image-form>
27                             <div class="form-group">
28                                 <label for="name">Image Name</label>
29                                 <input type="text" id="name" name="name" v-model="selectedImage.name">
30                             </div>
31                         </form>
32                         <hr class="even">
33                         <div v-show="dependantPages">
34                             <p class="text-neg text-small">
35                                 This image is used in the pages below, Click delete again to confirm you want to delete
36                                 this image.
37                             </p>
38                             <ul class="text-neg">
39                                 <li v-for="page in dependantPages">
40                                     <a :href="page.url" target="_blank" class="text-neg">{{ page.name }}</a>
41                                 </li>
42                             </ul>
43                         </div>
44
45                         <form @submit="deleteImage" v-el:image-delete-form>
46                             <button class="button neg"><i class="zmdi zmdi-delete"></i>Delete Image</button>
47                         </form>
48                     </div>
49                     <div class="image-manager-bottom">
50                         <button class="button pos anim fadeIn" v-show="selectedImage" @click="selectButtonClick"><i
51                                 class="zmdi zmdi-square-right"></i>Select Image
52                         </button>
53                     </div>
54                 </div>
55             </div>
56         </div>
57     </div>
58 </template>
59
60 <script>
61
62     var Dropzone = require('dropzone');
63
64     module.exports = {
65         data: function () {
66             return {
67                 images: [],
68                 hasMore: false,
69                 page: 0,
70                 cClickTime: 0,
71                 selectedImage: false,
72                 dependantPages: false,
73                 deleteForm: {},
74                 token: document.querySelector('meta[name=token]').getAttribute('content'),
75                 dataLoaded: false
76             }
77         },
78
79         props: {
80             imageType: {
81                 type: String,
82                 required: true
83             }
84         },
85
86         created: function () {
87             window.ImageManager = this;
88         },
89
90         ready: function () {
91             // Create dropzone
92             this.setupDropZone();
93         },
94
95         methods: {
96             fetchData: function () {
97                 var _this = this;
98                 this.$http.get('/images/' + _this.imageType + '/all/' + _this.page, function (data) {
99                     _this.images = _this.images.concat(data.images);
100                     _this.hasMore = data.hasMore;
101                     _this.page++;
102                 });
103             },
104
105             setupDropZone: function () {
106                 var _this = this;
107                 var dropZone = new Dropzone(_this.$els.dropZone, {
108                     url: '/images/' + _this.imageType + '/upload',
109                     init: function () {
110                         var dz = this;
111                         this.on("sending", function (file, xhr, data) {
112                             data.append("_token", _this.token);
113                         });
114                         this.on("success", function (file, data) {
115                             _this.images.unshift(data);
116                             $(file.previewElement).fadeOut(400, function () {
117                                 dz.removeFile(file);
118                             });
119                         });
120                         this.on('error', function (file, errorMessage, xhr) {
121                             if (errorMessage.file) {
122                                 $(file.previewElement).find('[data-dz-errormessage]').text(errorMessage.file[0]);
123                             }
124                             console.log(errorMessage);
125                         });
126                     }
127                 });
128             },
129
130             returnCallback: function (image) {
131                 this.callback(image);
132             },
133
134             imageClick: function (image) {
135                 var dblClickTime = 380;
136                 var cTime = (new Date()).getTime();
137                 var timeDiff = cTime - this.cClickTime;
138                 if (this.cClickTime !== 0 && timeDiff < dblClickTime && this.selectedImage === image) {
139                     // DoubleClick
140                     if (this.callback) {
141                         this.returnCallback(image);
142                     }
143                     this.hide();
144                 } else {
145                     this.selectedImage = (this.selectedImage === image) ? false : image;
146                     this.dependantPages = false;
147                 }
148                 this.cClickTime = cTime;
149             },
150
151             selectButtonClick: function () {
152                 if (this.callback) {
153                     this.returnCallback(this.selectedImage);
154                 }
155                 this.hide();
156             },
157
158             show: function (callback) {
159                 this.callback = callback;
160                 this.$els.overlay.style.display = 'block';
161                 // Get initial images if they have not yet been loaded in.
162                 if (!this.dataLoaded) {
163                     this.fetchData(this.page);
164                     this.dataLoaded = true;
165                 }
166             },
167
168             overlayClick: function (e) {
169                 if (e.target.className === 'overlay') {
170                     this.hide();
171                 }
172             },
173
174             hide: function () {
175                 this.$els.overlay.style.display = 'none';
176             },
177
178             saveImageDetails: function (e) {
179                 e.preventDefault();
180                 var _this = this;
181                 _this.selectedImage._token = _this.token;
182                 var form = $(_this.$els.imageForm);
183                 $.ajax('/images/update/' + _this.selectedImage.id, {
184                     method: 'PUT',
185                     data: _this.selectedImage
186                 }).done(function () {
187                     form.showSuccess('Image name updated');
188                 }).fail(function (jqXHR) {
189                     form.showFailure(jqXHR.responseJSON);
190                 })
191             },
192
193             deleteImage: function (e) {
194                 e.preventDefault();
195                 var _this = this;
196                 _this.deleteForm.force = _this.dependantPages !== false;
197                 _this.deleteForm._token = _this.token;
198                 $.ajax('/images/' + _this.selectedImage.id, {
199                     method: 'DELETE',
200                     data: _this.deleteForm
201                 }).done(function () {
202                     _this.images.splice(_this.images.indexOf(_this.selectedImage), 1);
203                     _this.selectedImage = false;
204                     $(_this.$els.imageTitle).showSuccess('Image Deleted');
205                 }).fail(function (jqXHR, textStatus) {
206                     // Pages failure
207                     if (jqXHR.status === 400) {
208                         _this.dependantPages = jqXHR.responseJSON;
209                     }
210                 });
211             }
212
213         }
214
215     };
216 </script>