alchemy-media 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## 0.7.2 (2023-01-23)
2
+
3
+ * Make `al-icon` center its contents
4
+ * Make the file upload action use the extra given filename
5
+ * Rename most route names & make them not-postponable
6
+
7
+ ## 0.7.1 (2022-12-23)
8
+
9
+ * Cascade `al-svg` role attribute to child `svg` elements
10
+ * Add `img` role fallback when using `graphics-symbol`
11
+ * Also add default role to `al-icon` element
12
+ * Make `al-file` catch errors and report them to a possible `al-field` parent
13
+ * Add the `accept` attribute to `al-file`
14
+ * Add the `accept` option to `File` fields
15
+ * Add `width_hint` field to `image` widget. This field allows users to specify the approximate maximum width of an image in pixels or as a percentage of the total page width.
16
+ * Add `lazy_load` field to `image` widget
17
+
1
18
  ## 0.7.0 (2022-11-02)
2
19
 
3
20
  * Use the `al-` prefix for custom elements
package/README.md CHANGED
@@ -75,7 +75,7 @@ you can do so like this on Debian/Ubuntu
75
75
 
76
76
  Install the requirements of the `veronica` module:
77
77
 
78
- apt-get install graphicsmagick webp libgif-dev
78
+ apt-get install graphicsmagick webp libgif-dev libcairo2-dev libpango1.0-dev libjpeg-dev librsvg2-dev
79
79
 
80
80
  This plugin requires exiv2
81
81
 
@@ -1,12 +1,26 @@
1
1
  al-icon {
2
2
  // inline-flex breaks certain (duotone) icons
3
- //--fa-display: inline-flex;
3
+ --fa-display: inline-flex;
4
+ display: inline-flex;
4
5
  flex-flow: column;
5
6
  justify-content: center;
6
7
  align-content: center;
7
8
  text-align: center;
9
+ position: relative;
8
10
 
9
11
  &[hidden] {
10
12
  display: none !important;
11
13
  }
14
+
15
+ // Fix Fontawesome duotone icons
16
+ &[icon-style="duotone"] {
17
+ position: relative;
18
+
19
+ &::before {
20
+ position: absolute;
21
+ top: 50%;
22
+ left: 50%;
23
+ transform: translate(-50%, -50%);
24
+ }
25
+ }
12
26
  }
package/bootstrap.js CHANGED
@@ -40,32 +40,95 @@ alchemy.createDir(options.scratch);
40
40
  alchemy.createDir(options.cache);
41
41
 
42
42
  // Create routes
43
- Router.get('Media::static', /\/media\/static\/(.*)*/, 'MediaFile#serveStatic');
44
- Router.get('Media::image', options.url + '/{id}', 'MediaFile#image');
43
+ Router.add({
44
+ name : 'MediaFile#serveStatic',
45
+ methods : ['get'],
46
+ can_be_postponed : false,
47
+ paths : /\/media\/static\/(.*)*/,
48
+ });
49
+
50
+ Router.add({
51
+ name : 'MediaFile#image',
52
+ methods : ['get'],
53
+ can_be_postponed : false,
54
+ paths : options.url + '/{id}',
55
+ });
45
56
 
46
57
  // The prefix is added at the end of the route so it does not
47
58
  // change the user's active_prefix
48
- Router.get('MediaFile#data', '/media/data/{prefix}/{id}', 'MediaFile#data');
49
- Router.get('MediaFile#info', '/media/info', 'MediaFile#info');
59
+ Router.add({
60
+ name : 'MediaFile#data',
61
+ methods : ['get'],
62
+ can_be_postponed : false,
63
+ paths : '/media/data/{prefix}/{id}',
64
+ });
50
65
 
51
66
  Router.add({
52
- name : 'MediaFile#recordsource',
53
- methods : ['get'],
54
- paths : '/media/recordsource',
55
- permission : 'media.recordsource',
67
+ name : 'MediaFile#info',
68
+ methods : ['get'],
69
+ can_be_postponed : false,
70
+ paths : '/media/info',
71
+ });
72
+
73
+ Router.add({
74
+ name : 'MediaFile#recordsource',
75
+ methods : ['get'],
76
+ can_be_postponed : false,
77
+ paths : '/media/recordsource',
78
+ permission : 'media.recordsource',
56
79
  });
57
80
 
58
81
  // Allow dummy extensions
59
- Router.get('Media::fileextension', '/media/file/{id}.{extension}', 'MediaFile#file');
82
+ Router.add({
83
+ name : 'Media#fileextension',
84
+ methods : ['get'],
85
+ can_be_postponed : false,
86
+ paths : '/media/file/{id}.{extension}',
87
+ handler : 'MediaFile#file'
88
+ });
60
89
 
61
90
  // Allow direct file downloads
62
- Router.get('Media::file', '/media/file/{id}', 'MediaFile#file');
63
- Router.get('Media#download', '/media/download/{id}', 'MediaFile#downloadFile');
91
+ Router.add({
92
+ name : 'MediaFile#file',
93
+ methods : ['get'],
94
+ can_be_postponed : false,
95
+ paths : '/media/file/{id}',
96
+ });
64
97
 
65
- Router.get('Media::thumb', '/media/thumbnail/{id}', 'MediaFile#thumbnail');
66
- Router.get('Media::placeholder', '/media/placeholder', 'MediaFile#placeholder');
67
- Router.post('Media::upload', '/media/upload', 'MediaFile#upload');
68
- Router.post('Media::uploadsingle', '/media/uploadsingle', 'MediaFile#uploadsingle');
98
+ Router.add({
99
+ name : 'MediaFile#downloadFile',
100
+ methods : ['get'],
101
+ can_be_postponed : false,
102
+ paths : '/media/download/{id}',
103
+ });
104
+
105
+ Router.add({
106
+ name : 'MediaFile#thumbnail',
107
+ methods : ['get'],
108
+ can_be_postponed : false,
109
+ paths : '/media/thumbnail/{id}',
110
+ });
111
+
112
+ Router.add({
113
+ name : 'MediaFile#placeholder',
114
+ methods : ['get'],
115
+ can_be_postponed : false,
116
+ paths : '/media/placeholder',
117
+ });
118
+
119
+ Router.add({
120
+ name : 'MediaFile#upload',
121
+ methods : ['post'],
122
+ can_be_postponed : false,
123
+ paths : '/media/upload',
124
+ });
125
+
126
+ Router.add({
127
+ name : 'MediaFile#uploadsingle',
128
+ methods : ['post'],
129
+ can_be_postponed : false,
130
+ paths : '/media/uploadsingle',
131
+ });
69
132
 
70
133
  var profiles = alchemy.shared('Media.profiles');
71
134
 
@@ -206,7 +206,7 @@ MediaFiles.setAction(function downloadFile(conduit, id, extension) {
206
206
  *
207
207
  * @author Jelle De Loecker <jelle@develry.be>
208
208
  * @since 0.0.1
209
- * @version 0.4.2
209
+ * @version 0.7.2
210
210
  *
211
211
  * @param {Conduit} conduit
212
212
  */
@@ -215,22 +215,29 @@ MediaFiles.setAction(function upload(conduit) {
215
215
  var MediaFile = this.getModel('MediaFile'),
216
216
  files = conduit.files,
217
217
  tasks = [],
218
- file;
218
+ accept = conduit.body?.accept;
219
219
 
220
220
  if (files && files.files && typeof files.files == 'object') {
221
221
  files = files.files;
222
222
  }
223
223
 
224
- // Iterate over every file
225
- Object.each(files, function eachFile(file, key) {
224
+ for (let key in files) {
225
+ let file = files[key];
226
+
227
+ tasks.push(async next => {
228
+
229
+ let filename = file.name;
230
+
231
+ if (key == 'uploaded_file' && conduit.body.filename) {
232
+ filename = conduit.body.filename;
233
+ }
226
234
 
227
- tasks[tasks.length] = function storeFile(next) {
228
235
  let options = {
229
236
  move: true,
230
- filename: file.name
237
+ filename: filename,
231
238
  };
232
239
 
233
- let name = file.name.split('.');
240
+ let name = filename.split('.');
234
241
 
235
242
  // Remove the last piece if there are more than 1
236
243
  if (name.length > 1) {
@@ -242,9 +249,20 @@ MediaFiles.setAction(function upload(conduit) {
242
249
 
243
250
  options.name = name;
244
251
 
252
+ // @TODO: don't trust the browser to dictate the type
253
+ if (accept) {
254
+ let file_type = await file.getMimetype();
255
+
256
+ if (file_type === accept || accept.includes(file_type)) {
257
+ // OK!
258
+ } else {
259
+ return next(new Error('File upload failed: Expected filetype "' + accept + '", but got "' + file_type + '"'));
260
+ }
261
+ }
262
+
245
263
  MediaFile.addFile(file.path, options, next);
246
- };
247
- });
264
+ });
265
+ }
248
266
 
249
267
  // Store every file
250
268
  Function.parallel(tasks, function storedFiles(err, result) {
@@ -79,6 +79,15 @@ AlFile.addElementGetter('icon_uploading', '.uploading-icon');
79
79
  */
80
80
  AlFile.addElementGetter('icon_empty', '.empty-icon');
81
81
 
82
+ /**
83
+ * Set the accepted types
84
+ *
85
+ * @author Jelle De Loecker <jelle@elevenways.be>
86
+ * @since 0.7.1
87
+ * @version 0.7.1
88
+ */
89
+ AlFile.setAttribute('accept');
90
+
82
91
  /**
83
92
  * Set the value
84
93
  *
@@ -135,7 +144,7 @@ AlFile.setMethod(function updatePreview(value) {
135
144
  *
136
145
  * @author Jelle De Loecker <jelle@elevenways.be>
137
146
  * @since 0.6.0
138
- * @version 0.6.2
147
+ * @version 0.7.1
139
148
  */
140
149
  AlFile.setMethod(async function uploadFile(config) {
141
150
 
@@ -159,6 +168,10 @@ AlFile.setMethod(async function uploadFile(config) {
159
168
  form_data.append('format', format);
160
169
  }
161
170
 
171
+ if (this.accept) {
172
+ form_data.append('accept', this.accept);
173
+ }
174
+
162
175
  let response;
163
176
 
164
177
  try {
@@ -167,7 +180,15 @@ AlFile.setMethod(async function uploadFile(config) {
167
180
  post : form_data,
168
181
  });
169
182
  } catch (err) {
170
- console.error('Failed to upload file:', err);
183
+
184
+ let alchemy_field = this.queryUp('al-field');
185
+
186
+ if (alchemy_field) {
187
+ alchemy_field.showError(err);
188
+ } else {
189
+ console.error('Failed to upload file:', err);
190
+ alert('Failed to upload file: ' + err);
191
+ }
171
192
  }
172
193
 
173
194
  this.classList.remove('uploading');
@@ -282,12 +303,20 @@ AlFile.setMethod(function _getContent(callback) {
282
303
  *
283
304
  * @author Jelle De Loecker <jelle@elevenways.be>
284
305
  * @since 0.7.0
285
- * @version 0.7.0
306
+ * @version 0.7.1
286
307
  */
287
308
  AlFile.setMethod(async function showExistingFileSelection() {
288
309
 
289
310
  let variables = {};
290
311
 
312
+ if (this.accept) {
313
+ let filters = {
314
+ type : this.accept,
315
+ };
316
+
317
+ variables.filters = filters;
318
+ }
319
+
291
320
  await hawkejs.scene.render('element/al_file_selection', variables);
292
321
 
293
322
  let dialog_contents = document.querySelector('he-dialog [data-he-template="element/al_file_selection"]');
@@ -47,6 +47,15 @@ Icon.setAttribute('icon-name');
47
47
  */
48
48
  Icon.setAttribute('icon-flags');
49
49
 
50
+ /**
51
+ * Set the default role
52
+ *
53
+ * @author Jelle De Loecker <jelle@elevenways.be>
54
+ * @since 0.7.1
55
+ * @version 0.7.1
56
+ */
57
+ Icon.setRole('graphics-symbol');
58
+
50
59
  /**
51
60
  * Refresh the icon when these attributes change
52
61
  *
@@ -85,7 +94,7 @@ Icon.setMethod(function introduced() {
85
94
  *
86
95
  * @author Jelle De Loecker <jelle@elevenways.be>
87
96
  * @since 0.7.0
88
- * @version 0.7.0
97
+ * @version 0.7.1
89
98
  *
90
99
  * @param {Boolean} force
91
100
  */
@@ -95,6 +104,14 @@ Icon.setMethod(function refresh(force) {
95
104
  return;
96
105
  }
97
106
 
107
+ if (this.role == 'graphics-symbol') {
108
+ this.role = 'graphics-symbol img';
109
+
110
+ if (!this.hasAttribute('aria-label')) {
111
+ this.setAttribute('aria-label', '');
112
+ }
113
+ }
114
+
98
115
  if (!force && Blast.isNode) {
99
116
  return;
100
117
  }
package/element/al_svg.js CHANGED
@@ -21,7 +21,7 @@ Svg.setAttribute('src');
21
21
  *
22
22
  * @author Jelle De Loecker <jelle@elevenways.be>
23
23
  * @since 0.5.1
24
- * @version 0.5.1
24
+ * @version 0.7.1
25
25
  */
26
26
  Svg.setMethod(async function injectSvg() {
27
27
 
@@ -50,6 +50,29 @@ Svg.setMethod(async function injectSvg() {
50
50
 
51
51
  this.innerHTML = contents;
52
52
 
53
+ if (this.role) {
54
+
55
+ // Do not allow `graphics-symbol` role, because it is not widely supported
56
+ // and google doesn't know it either
57
+ if (this.role == 'graphics-symbol') {
58
+ this.role = 'img';
59
+
60
+ if (!this.hasAttribute('aria-label')) {
61
+ this.setAttribute('aria-label', '');
62
+ }
63
+ }
64
+
65
+ let svg = this.querySelector('svg');
66
+
67
+ if (svg) {
68
+ svg.setAttribute('role', this.role);
69
+
70
+ if (this.hasAttribute('aria-label')) {
71
+ svg.setAttribute('aria-label', this.getAttribute('aria-label'));
72
+ }
73
+ }
74
+ }
75
+
53
76
  if (this._resolve_me_too) {
54
77
  this._resolve_me_too.resolve();
55
78
  }
@@ -115,7 +115,7 @@ Media.setMethod(function loadIconFont() {
115
115
  *
116
116
  * @author Jelle De Loecker <jelle@develry.be>
117
117
  * @since 0.5.0
118
- * @version 0.6.2
118
+ * @version 0.7.1
119
119
  *
120
120
  * @param {Element} element The element to apply to
121
121
  * @param {String} image The image identifier
@@ -160,6 +160,12 @@ Media.setMethod(function applyDirective(element, image, options) {
160
160
  options.height = height;
161
161
  }
162
162
 
163
+ if (options.lazy_load) {
164
+ if (!element.hasAttribute('loading')) {
165
+ element.setAttribute('loading', 'lazy');
166
+ }
167
+ }
168
+
163
169
  let url = this.imageUrl(image, options),
164
170
  clone = url.clone();
165
171
 
@@ -224,7 +230,7 @@ Media.setMethod(function applyDirective(element, image, options) {
224
230
  *
225
231
  * @author Jelle De Loecker <jelle@develry.be>
226
232
  * @since 0.4.0
227
- * @version 0.4.0
233
+ * @version 0.7.2
228
234
  *
229
235
  * @param {String} image_id
230
236
  *
@@ -234,7 +240,7 @@ Media.setMethod(function fileAnchor(file_id, options) {
234
240
 
235
241
  var url;
236
242
 
237
- return this.view.helpers.Router.printRoute('Media::file', {id: file_id}, options);
243
+ return this.view.helpers.Router.printRoute('MediaFile#file', {id: file_id}, options);
238
244
  });
239
245
 
240
246
  /**
@@ -242,7 +248,7 @@ Media.setMethod(function fileAnchor(file_id, options) {
242
248
  *
243
249
  * @author Jelle De Loecker <jelle@develry.be>
244
250
  * @since 0.2.0
245
- * @version 0.5.1
251
+ * @version 0.7.2
246
252
  *
247
253
  * @param {String} image_id
248
254
  *
@@ -263,7 +269,7 @@ Media.setMethod(function imageUrl(image_id, options) {
263
269
  if (options.route) {
264
270
  routeName = options.route;
265
271
  } else {
266
- routeName = 'Media::image';
272
+ routeName = 'MediaFile#image';
267
273
  }
268
274
 
269
275
  url = this.parseURL(this.view.helpers.Router.routeUrl(routeName, {id: image_id}));
@@ -305,7 +311,7 @@ Media.setMethod(function imageUrl(image_id, options) {
305
311
  *
306
312
  * @author Jelle De Loecker <jelle@elevenways.be>
307
313
  * @since 0.2.0
308
- * @version 0.6.2
314
+ * @version 0.7.2
309
315
  *
310
316
  * @param {Object} options
311
317
  *
@@ -315,7 +321,7 @@ Media.setMethod(function placeholderUrl(options) {
315
321
 
316
322
  var url;
317
323
 
318
- url = this.parseURL(this.view.helpers.Router.routeUrl('Media::placeholder'));
324
+ url = this.parseURL(this.view.helpers.Router.routeUrl('MediaFile#placeholder'));
319
325
 
320
326
  if (options != null) {
321
327
 
@@ -16,12 +16,25 @@ const Image = Function.inherits('Alchemy.Widget', 'Image');
16
16
  *
17
17
  * @author Jelle De Loecker <jelle@elevenways.be>
18
18
  * @since 0.6.0
19
- * @version 0.6.0
19
+ * @version 0.7.1
20
20
  */
21
21
  Image.constitute(function prepareSchema() {
22
22
 
23
23
  this.schema.addField('image', 'File', {
24
+ description : 'Upload/select the image to display',
25
+ widget_config_editable: true,
26
+ });
27
+
28
+ this.schema.addField('width_hint', 'Number', {
29
+ description : 'Approximate maximum width of the image in pixels or as a percentage of the total page width.',
30
+ widget_config_editable: true,
31
+ default: '25%',
32
+ });
33
+
34
+ this.schema.addField('lazy_load', 'Boolean', {
35
+ description : 'Determines whether the image should be loaded lazily or not',
24
36
  widget_config_editable: true,
37
+ default: true,
25
38
  });
26
39
  });
27
40
 
@@ -30,7 +43,7 @@ Image.constitute(function prepareSchema() {
30
43
  *
31
44
  * @author Jelle De Loecker <jelle@elevenways.be>
32
45
  * @since 0.6.0
33
- * @version 0.6.4
46
+ * @version 0.7.1
34
47
  *
35
48
  * @param {HTMLElement} widget
36
49
  */
@@ -38,7 +51,18 @@ Image.setMethod(function populateWidget() {
38
51
 
39
52
  let img = this.createElement('img');
40
53
 
41
- this.hawkejs_renderer.helpers.Media.applyDirective(img, this.config.image);
54
+ let width_hint = this.config.width_hint,
55
+ lazy_load = this.config.lazy_load;
56
+
57
+ if (width_hint === null || width_hint === '' || typeof width_hint == 'undefined') {
58
+ width_hint = '25%';
59
+ }
60
+
61
+ if (lazy_load == null) {
62
+ lazy_load = true;
63
+ }
64
+
65
+ this.hawkejs_renderer.helpers.Media.applyDirective(img, this.config.image, {width: width_hint, lazy_load});
42
66
 
43
67
  this.widget.append(img);
44
68
 
@@ -16,6 +16,48 @@ var FileField = Function.inherits('Alchemy.Field.ObjectId', 'File');
16
16
  */
17
17
  FileField.setProperty('deferCast', true);
18
18
 
19
+ /**
20
+ * Get the accepted types
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 0.7.1
24
+ * @version 0.7.1
25
+ *
26
+ * @return {Array|null}
27
+ */
28
+ FileField.setMethod(function getAcceptedTypes() {
29
+
30
+ let accept = this.options?.accept;
31
+
32
+ if (!accept) {
33
+ return null;
34
+ }
35
+
36
+ accept = Array.cast(accept);
37
+
38
+ return accept;
39
+ });
40
+
41
+ /**
42
+ * Get the accepted types string, for the input element
43
+ *
44
+ * @author Jelle De Loecker <jelle@elevenways.be>
45
+ * @since 0.7.1
46
+ * @version 0.7.1
47
+ *
48
+ * @return {String|null}
49
+ */
50
+ FileField.setMethod(function getAcceptedTypesString() {
51
+
52
+ let types = this.getAcceptedTypes();
53
+
54
+ if (!types?.length) {
55
+ return null;
56
+ }
57
+
58
+ return types.join(', ');
59
+ });
60
+
19
61
  if (Blast.isBrowser) {
20
62
  return;
21
63
  }
@@ -225,20 +225,33 @@ MediaFile.setMethod(function getFile(id, callback) {
225
225
  *
226
226
  * @author Jelle De Loecker <jelle@develry.be>
227
227
  * @since 0.0.1
228
- * @version 0.2.0
228
+ * @version 0.7.1
229
229
  *
230
230
  * @param {String} file The path to the file, can be a URL
231
231
  * @param {Object} options
232
232
  * @param {Function} callback
233
+ *
234
+ * @return {Pledge}
233
235
  */
234
236
  MediaFile.setMethod(function addFile(file, options, callback) {
235
237
 
236
- var that = this;
238
+ const that = this,
239
+ pledge = new Pledge();
240
+
241
+ pledge.done(callback);
237
242
 
238
243
  this.queue.add(function(done) {
239
244
  that.getModel('MediaRaw').addFile(file, options, function(err, response) {
240
- callback(err, response);
245
+
241
246
  done();
247
+
248
+ if (err) {
249
+ pledge.reject(err);
250
+ } else {
251
+ pledge.resolve(response);
252
+ }
242
253
  });
243
254
  });
255
+
256
+ return pledge;
244
257
  });
@@ -168,7 +168,7 @@ MediaRaw.Document.setMethod(function extraImportFromStream(input) {
168
168
  *
169
169
  * @author Jelle De Loecker <jelle@develry.be>
170
170
  * @since 0.0.1
171
- * @version 0.4.2
171
+ * @version 0.7.1
172
172
  *
173
173
  * @param {String} file The path to the file, can be a URL
174
174
  * @param {Object} options
@@ -185,6 +185,14 @@ MediaRaw.setMethod(function addFile(file, options, callback) {
185
185
  options = {};
186
186
  }
187
187
 
188
+ if (!options) {
189
+ options = {};
190
+ }
191
+
192
+ if (file && typeof file == 'object' && file instanceof Classes.Alchemy.Inode.File) {
193
+ file = file.path;
194
+ }
195
+
188
196
  // If the given file is actually a url, we'll need to download it first
189
197
  if (file.startsWith('http://') || file.startsWith('https://')) {
190
198
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemy-media",
3
3
  "description": "The media plugin for Alchemy",
4
- "version": "0.7.0",
4
+ "version": "0.7.2",
5
5
  "repository": {
6
6
  "type" : "git",
7
7
  "url" : "https://github.com/11ways/alchemy-media.git"
@@ -12,7 +12,7 @@
12
12
  "veronica" : "~0.2.2"
13
13
  },
14
14
  "peerDependencies": {
15
- "alchemymvc" : ">=1.2.0"
15
+ "alchemymvc" : ">=1.3.0"
16
16
  },
17
17
  "license": "MIT",
18
18
  "engines": {
@@ -13,7 +13,13 @@
13
13
  class="empty-icon"
14
14
  ><% if (self.value) $0.hidden = true %></al-icon>
15
15
 
16
- <input type="file" tabindex="-1" class="al-file-input" hidden>
16
+ <input
17
+ class="al-file-input"
18
+ type="file"
19
+ tabindex="-1"
20
+ accept={% self.accept %}
21
+ hidden
22
+ >
17
23
  </label>
18
24
 
19
25
  <div class="al-file-right">
@@ -25,6 +25,7 @@ fieldset.addField('type');
25
25
  mode="inline"
26
26
  page-size=20
27
27
  show-filters
28
+ #filters={% filters %}
28
29
  #fieldset={% fieldset %}
29
30
  #recordsource={% {route: 'MediaFile#recordsource'} %}
30
31
  ></al-table>
@@ -3,6 +3,7 @@ script('chimera/mediafield');
3
3
  style('chimera/mediafield');
4
4
  %>
5
5
  <al-file
6
- value=<% value %>
7
6
  class="alchemy-field-value"
7
+ value=<% value %>
8
+ accept={% alchemy_field.config.getAcceptedTypesString() %}
8
9
  ></al-file>
@@ -3,6 +3,6 @@
3
3
  {% if value %}
4
4
  <img
5
5
  !Media={% value %}
6
- +media-route="Media::thumb"
6
+ +media-route="MediaFile#thumbnail"
7
7
  >
8
8
  {% /if %}
@@ -3,6 +3,6 @@
3
3
  {% if value %}
4
4
  <img
5
5
  !Media={% value %}
6
- +media-route="Media::thumb"
6
+ +media-route="MediaFile#thumbnail"
7
7
  >
8
8
  {% /if %}