alchemy-media 0.6.2 → 0.6.4
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 +14 -0
- package/assets/stylesheets/alchemy_icons.scss +5 -61
- package/assets/stylesheets/alchemy_icons_fafree.scss +59 -0
- package/assets/stylesheets/element/alchemy_file.scss +26 -0
- package/bootstrap.js +11 -2
- package/controller/media_files_controller.js +31 -20
- package/element/al_ico_element.js +130 -1
- package/helper/media_helper.js +36 -6
- package/helper/widgets/image_widget.js +8 -8
- package/lib/media_types/image_media_type.js +3 -3
- package/model/media_file_model.js +44 -13
- package/package.json +1 -1
- package/view/element/al_file.hwk +2 -1
- package/view/form/inputs/edit/file_preview.hwk +5 -0
- package/view/form/inputs/view_inline/file.hwk +8 -0
- package/view/form/inputs/view_inline/file_preview.hwk +8 -0
- package/view/form/wrappers/edit/file_preview.hwk +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 0.6.4 (2022-10-13)
|
|
2
|
+
|
|
3
|
+
* Add the `Media#loadIconFont()` helper method
|
|
4
|
+
* Make the `image` route serve up filetype thumbnails for non-images
|
|
5
|
+
* Add file preview image to the chimera edit view of MediaFile
|
|
6
|
+
* Add thumbnail column to MediaFile chimera index view
|
|
7
|
+
* Add `prefix` parameter to the `MediaFile#data` route
|
|
8
|
+
|
|
9
|
+
## 0.6.3 (2022-07-23)
|
|
10
|
+
|
|
11
|
+
* Fix `al-file` element showing wrong buttons on load
|
|
12
|
+
* Always add `role="presentation"` to images that get a simple placeholder
|
|
13
|
+
* Add support for Fontawesome Pro with the `media.fontawesome_pro` setting
|
|
14
|
+
|
|
1
15
|
## 0.6.2 (2022-07-06)
|
|
2
16
|
|
|
3
17
|
* Upgrade to Fontawesome 6
|
|
@@ -1,66 +1,10 @@
|
|
|
1
|
-
@import "fontawesome6/fontawesome.scss";
|
|
2
|
-
@import "fontawesome6/solid.scss";
|
|
3
|
-
@import "fontawesome6/brands.scss";
|
|
4
|
-
|
|
5
1
|
al-ico {
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
// inline-flex breaks certain (duotone) icons
|
|
3
|
+
//--fa-display: inline-flex;
|
|
8
4
|
flex-flow: column;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
&[type="arrow-left"] {
|
|
14
|
-
@extend .fas, .fa-angle-left;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
&[type="arrow-left-double"] {
|
|
18
|
-
@extend .fas, .fa-angle-double-left;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
&[type="arrow-right"] {
|
|
22
|
-
@extend .fas, .fa-angle-right;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
&[type="arrow-right-double"] {
|
|
26
|
-
@extend .fas, .fa-angle-double-right;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
&[type="sorting-arrow"] {
|
|
30
|
-
@extend .fas;
|
|
31
|
-
|
|
32
|
-
&.down {
|
|
33
|
-
@extend .fa-sort-alpha-up;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
&.up {
|
|
37
|
-
@extend .fa-sort-alpha-down;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
&[type="menu"] {
|
|
42
|
-
@extend .fas, .fa-bars;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
&[type="edit"] {
|
|
46
|
-
@extend .fas, .fa-pencil-alt;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
&[type="zoom-in"] {
|
|
50
|
-
@extend .fas, .fa-search-plus;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
&[type="microphone"] {
|
|
54
|
-
@extend .fas, .fa-microphone-alt;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
&[type="video"] {
|
|
58
|
-
@extend .fas, .fa-video;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&[type="plus"] {
|
|
62
|
-
@extend .fas, .fa-plus;
|
|
63
|
-
}
|
|
5
|
+
justify-content: center;
|
|
6
|
+
align-content: center;
|
|
7
|
+
text-align: center;
|
|
64
8
|
|
|
65
9
|
&[hidden] {
|
|
66
10
|
display: none !important;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@use "fontawesome6/fontawesome.scss";
|
|
2
|
+
@use "fontawesome6/solid.scss";
|
|
3
|
+
@use "fontawesome6/brands.scss";
|
|
4
|
+
|
|
5
|
+
al-ico {
|
|
6
|
+
@extend %fa-icon;
|
|
7
|
+
|
|
8
|
+
&[type="arrow-left"] {
|
|
9
|
+
@extend .fas, .fa-angle-left;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&[type="arrow-left-double"] {
|
|
13
|
+
@extend .fas, .fa-angle-double-left;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&[type="arrow-right"] {
|
|
17
|
+
@extend .fas, .fa-angle-right;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&[type="arrow-right-double"] {
|
|
21
|
+
@extend .fas, .fa-angle-double-right;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&[type="sorting-arrow"] {
|
|
25
|
+
@extend .fas;
|
|
26
|
+
|
|
27
|
+
&.down {
|
|
28
|
+
@extend .fa-sort-alpha-up;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&.up {
|
|
32
|
+
@extend .fa-sort-alpha-down;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&[type="menu"] {
|
|
37
|
+
@extend .fas, .fa-bars;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&[type="edit"] {
|
|
41
|
+
@extend .fas, .fa-pencil-alt;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&[type="zoom-in"] {
|
|
45
|
+
@extend .fas, .fa-search-plus;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&[type="microphone"] {
|
|
49
|
+
@extend .fas, .fa-microphone-alt;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&[type="video"] {
|
|
53
|
+
@extend .fas, .fa-video;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&[type="plus"] {
|
|
57
|
+
@extend .fas, .fa-plus;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -92,4 +92,30 @@ al-file {
|
|
|
92
92
|
button {
|
|
93
93
|
min-height: 2rem;
|
|
94
94
|
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
alchemy-field[field-view="file_preview"] {
|
|
98
|
+
[data-he-name="field"] .field {
|
|
99
|
+
padding: 0;
|
|
100
|
+
|
|
101
|
+
img {
|
|
102
|
+
max-height: 25rem;
|
|
103
|
+
object-fit: contain;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
alchemy-field[field-view="file_preview"],
|
|
109
|
+
alchemy-field[field-view="file"],
|
|
110
|
+
alchemy-field[field-type="file"] {
|
|
111
|
+
|
|
112
|
+
&[mode="inline"] {
|
|
113
|
+
.field img {
|
|
114
|
+
object-fit: contain;
|
|
115
|
+
width: 100px;
|
|
116
|
+
height: 100px;
|
|
117
|
+
display: block;
|
|
118
|
+
margin: auto;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
95
121
|
}
|
package/bootstrap.js
CHANGED
|
@@ -21,7 +21,10 @@ var options = {
|
|
|
21
21
|
scratch: path.resolve(PATH_TEMP, 'scratch'),
|
|
22
22
|
|
|
23
23
|
// The cache map for resized images & thumbnails
|
|
24
|
-
cache: path.resolve(PATH_TEMP, 'imagecache')
|
|
24
|
+
cache: path.resolve(PATH_TEMP, 'imagecache'),
|
|
25
|
+
|
|
26
|
+
// Path to fontawesome pro
|
|
27
|
+
fontawesome_pro: null,
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
// Inject the user-overridden options
|
|
@@ -40,7 +43,9 @@ alchemy.createDir(options.cache);
|
|
|
40
43
|
Router.get('Media::static', /\/media\/static\/(.*)*/, 'MediaFile#serveStatic');
|
|
41
44
|
Router.get('Media::image', options.url + '/{id}', 'MediaFile#image');
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
// The prefix is added at the end of the route so it does not
|
|
47
|
+
// change the user's active_prefix
|
|
48
|
+
Router.get('MediaFile#data', '/media/data/{prefix}/{id}', 'MediaFile#data');
|
|
44
49
|
Router.get('MediaFile#info', '/media/info', 'MediaFile#info');
|
|
45
50
|
|
|
46
51
|
// Allow dummy extensions
|
|
@@ -66,6 +71,10 @@ options.veronica = new Veronica({
|
|
|
66
71
|
|
|
67
72
|
alchemy.hawkejs.addRawHtml(`<script>document.cookie = 'mediaResolution=' + encodeURIComponent(JSON.stringify({width:Math.max(screen.availWidth||0, window.outerWidth||0) || 1024,height:Math.max(screen.availHeight||0, window.outerHeight||0) || 768,dpr:window.devicePixelRatio}))</script>`);
|
|
68
73
|
|
|
74
|
+
if (options.fontawesome_pro) {
|
|
75
|
+
alchemy.exposeStatic('fontawesome_pro', options.fontawesome_pro);
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
/**
|
|
70
79
|
* Register a profile under the given name
|
|
71
80
|
*
|
|
@@ -13,16 +13,14 @@ var fs = require('fs'),
|
|
|
13
13
|
* @since 0.0.1
|
|
14
14
|
* @version 0.3.0
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
MediaFile.super.call(this, conduit, options);
|
|
18
|
-
});
|
|
16
|
+
const MediaFiles = Function.inherits('Alchemy.Controller', 'MediaFile');
|
|
19
17
|
|
|
20
18
|
/**
|
|
21
19
|
* Serve a thumbnail
|
|
22
20
|
*
|
|
23
21
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
24
22
|
* @since 0.0.1
|
|
25
|
-
* @version 0.4
|
|
23
|
+
* @version 0.6.4
|
|
26
24
|
*
|
|
27
25
|
* @param {Conduit} conduit
|
|
28
26
|
*/
|
|
@@ -35,21 +33,15 @@ MediaFiles.setAction(function thumbnail(conduit, id) {
|
|
|
35
33
|
// Get the requested file
|
|
36
34
|
this.getModel('MediaFile').getFile(id, function gotFile(err, record) {
|
|
37
35
|
|
|
38
|
-
var Type;
|
|
39
|
-
|
|
40
36
|
if (err) {
|
|
41
37
|
return conduit.notFound(err);
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
Type = MediaTypes[record.type];
|
|
45
|
-
|
|
46
|
-
if (!Type) {
|
|
47
|
-
Type = Classes.Alchemy.MediaType;
|
|
48
|
-
}
|
|
40
|
+
const Type = MediaTypes[record.type] || Classes.Alchemy.MediaType;
|
|
49
41
|
|
|
50
42
|
if (Type) {
|
|
51
|
-
|
|
52
|
-
|
|
43
|
+
let instance = new Type();
|
|
44
|
+
instance.thumbnail(conduit, record);
|
|
53
45
|
} else {
|
|
54
46
|
conduit.error('Error generating thumbnail of ' + record.type);
|
|
55
47
|
}
|
|
@@ -100,7 +92,7 @@ MediaFiles.setAction(function serveStatic(conduit, path) {
|
|
|
100
92
|
*
|
|
101
93
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
102
94
|
* @since 0.0.1
|
|
103
|
-
* @version 0.4
|
|
95
|
+
* @version 0.6.4
|
|
104
96
|
*
|
|
105
97
|
* @param {Conduit} conduit
|
|
106
98
|
*/
|
|
@@ -112,12 +104,22 @@ MediaFiles.setAction(function image(conduit, id) {
|
|
|
112
104
|
|
|
113
105
|
this.getModel('MediaFile').getFile(id, function gotFile(err, record) {
|
|
114
106
|
|
|
115
|
-
|
|
107
|
+
if (err) {
|
|
108
|
+
return conduit.error(err);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const Image = new MediaTypes.image;
|
|
116
112
|
|
|
117
113
|
if (!record) {
|
|
118
114
|
return Image.placeholder(conduit, {text: 404, status: 404});
|
|
119
115
|
}
|
|
120
116
|
|
|
117
|
+
if (record.type != 'image') {
|
|
118
|
+
const Type = MediaTypes[record.type] || Classes.Alchemy.MediaType;
|
|
119
|
+
let instance = new Type();
|
|
120
|
+
return instance.thumbnail(conduit, record);
|
|
121
|
+
}
|
|
122
|
+
|
|
121
123
|
Image.serve(conduit, record);
|
|
122
124
|
});
|
|
123
125
|
});
|
|
@@ -315,14 +317,23 @@ MediaFiles.setAction(function uploadsingle(conduit) {
|
|
|
315
317
|
/**
|
|
316
318
|
* Get the file data
|
|
317
319
|
*
|
|
318
|
-
* @author Jelle De Loecker <jelle@
|
|
320
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
319
321
|
* @since 0.5.1
|
|
320
|
-
* @version 0.
|
|
322
|
+
* @version 0.6.4
|
|
321
323
|
*
|
|
322
|
-
* @param {Conduit}
|
|
323
|
-
* @param {
|
|
324
|
+
* @param {Conduit} conduit
|
|
325
|
+
* @param {ObjectId} media_file_id
|
|
324
326
|
*/
|
|
325
|
-
MediaFiles.setAction(function data(conduit,
|
|
327
|
+
MediaFiles.setAction(async function data(conduit, prefix, media_file_id) {
|
|
328
|
+
|
|
329
|
+
conduit.prefix = prefix;
|
|
330
|
+
|
|
331
|
+
let media_file = await this.model.findById(media_file_id);
|
|
332
|
+
|
|
333
|
+
if (!media_file) {
|
|
334
|
+
return conduit.notFound();
|
|
335
|
+
}
|
|
336
|
+
|
|
326
337
|
conduit.setHeader('cache-control', 'public, max-age=3600, must-revalidate');
|
|
327
338
|
|
|
328
339
|
conduit.end({
|
|
@@ -14,4 +14,133 @@ const Icon = Function.inherits('Alchemy.Element', 'AlIco');
|
|
|
14
14
|
* @since 0.6.0
|
|
15
15
|
* @version 0.6.0
|
|
16
16
|
*/
|
|
17
|
-
Icon.setStylesheetFile('alchemy_icons');
|
|
17
|
+
Icon.setStylesheetFile('alchemy_icons');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The source to use
|
|
21
|
+
* (Will default to Fontawesome)
|
|
22
|
+
*
|
|
23
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
24
|
+
* @since 0.6.3
|
|
25
|
+
* @version 0.6.3
|
|
26
|
+
*/
|
|
27
|
+
Icon.setAttribute('source');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The icon-style to use
|
|
31
|
+
* (Will default to regular for fontawesome)
|
|
32
|
+
*
|
|
33
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
34
|
+
* @since 0.6.3
|
|
35
|
+
* @version 0.6.3
|
|
36
|
+
*/
|
|
37
|
+
Icon.setAttribute('icon-style');
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The actual icon name to use
|
|
41
|
+
*
|
|
42
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
43
|
+
* @since 0.6.3
|
|
44
|
+
* @version 0.6.3
|
|
45
|
+
*/
|
|
46
|
+
Icon.setAttribute('icon-name');
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The element is being retained
|
|
50
|
+
*
|
|
51
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
52
|
+
* @since 0.6.3
|
|
53
|
+
* @version 0.6.3
|
|
54
|
+
*/
|
|
55
|
+
Icon.setMethod(function retained() {
|
|
56
|
+
this.setCssClasses();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The element has been introduced to the DOM for the first time
|
|
61
|
+
*
|
|
62
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
63
|
+
* @since 0.6.3
|
|
64
|
+
* @version 0.6.3
|
|
65
|
+
*/
|
|
66
|
+
Icon.setMethod(function introduced() {
|
|
67
|
+
this.setCssClasses();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Try to set the correct icon
|
|
72
|
+
*
|
|
73
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
74
|
+
* @since 0.6.3
|
|
75
|
+
* @version 0.6.3
|
|
76
|
+
*/
|
|
77
|
+
Icon.setMethod(function setIcon(info) {
|
|
78
|
+
|
|
79
|
+
if (!info) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof info == 'string') {
|
|
84
|
+
info = info.split(' ');
|
|
85
|
+
|
|
86
|
+
if (info.length == 2) {
|
|
87
|
+
this.icon_style = info[0];
|
|
88
|
+
this.icon_name = info[1];
|
|
89
|
+
} else {
|
|
90
|
+
this.icon_name = info[0];
|
|
91
|
+
}
|
|
92
|
+
} else if (typeof info == 'object') {
|
|
93
|
+
let style = info.style || info.icon_style,
|
|
94
|
+
name = info.name || info.icon_name;
|
|
95
|
+
|
|
96
|
+
if (style) {
|
|
97
|
+
this.icon_style = style;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (name) {
|
|
101
|
+
this.icon_name = name;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!this.icon_style) {
|
|
106
|
+
this.icon_style = 'duotone';
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Set the CSS classes
|
|
112
|
+
*
|
|
113
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
114
|
+
* @since 0.6.3
|
|
115
|
+
* @version 0.6.4
|
|
116
|
+
*/
|
|
117
|
+
Icon.setMethod(function setCssClasses() {
|
|
118
|
+
|
|
119
|
+
if (this.source && this.source != 'fontawesome') {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Load the appropriate font style
|
|
124
|
+
this.hawkejs_renderer.helpers.Media.loadIconFont();
|
|
125
|
+
|
|
126
|
+
let fa_pro = this.hawkejs_renderer.expose('fontawesome_pro'),
|
|
127
|
+
style = this.icon_style || 'regular';
|
|
128
|
+
|
|
129
|
+
if (!fa_pro) {
|
|
130
|
+
if (style == 'duotone' || style == 'light' || style == 'thin' || style == 'regular') {
|
|
131
|
+
style = 'solid';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let existing_classes = Array.cast(this.classList);
|
|
136
|
+
|
|
137
|
+
// Remove existing fontawesome classes
|
|
138
|
+
for (let entry of existing_classes) {
|
|
139
|
+
if (entry.startsWith('fa')) {
|
|
140
|
+
this.classList.remove(entry);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.classList.add('fa-' + (this.icon_style || 'solid'));
|
|
145
|
+
this.classList.add('fa-' + this.icon_name);
|
|
146
|
+
});
|
package/helper/media_helper.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const PLACEHOLDER = Symbol('placeholder');
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* The Media helper
|
|
3
5
|
*
|
|
@@ -7,9 +9,7 @@
|
|
|
7
9
|
*
|
|
8
10
|
* @param {ViewRender} view
|
|
9
11
|
*/
|
|
10
|
-
|
|
11
|
-
Media.super.call(this, view);
|
|
12
|
-
});
|
|
12
|
+
const Media = Function.inherits('Alchemy.Helper', 'Media');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Function to execute on the client side, when the scene is made
|
|
@@ -88,6 +88,28 @@ Media.setStatic(function loadImagesBasedOnSize() {
|
|
|
88
88
|
}
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Load the icon font
|
|
93
|
+
*
|
|
94
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
95
|
+
* @since 0.6.4
|
|
96
|
+
* @version 0.6.4
|
|
97
|
+
*
|
|
98
|
+
* @return {string}
|
|
99
|
+
*/
|
|
100
|
+
Media.setMethod(function loadIconFont() {
|
|
101
|
+
|
|
102
|
+
let font_style = this.hawkejs_renderer.expose('fontawesome_pro');
|
|
103
|
+
|
|
104
|
+
if (!font_style) {
|
|
105
|
+
font_style = 'alchemy_icons_fafree';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.hawkejs_renderer.style(font_style);
|
|
109
|
+
|
|
110
|
+
return font_style;
|
|
111
|
+
});
|
|
112
|
+
|
|
91
113
|
/**
|
|
92
114
|
* Apply directive to an element
|
|
93
115
|
*
|
|
@@ -159,6 +181,11 @@ Media.setMethod(function applyDirective(element, image, options) {
|
|
|
159
181
|
return;
|
|
160
182
|
}
|
|
161
183
|
|
|
184
|
+
if (options[PLACEHOLDER]) {
|
|
185
|
+
element.setAttribute('alt', '');
|
|
186
|
+
element.setAttribute('role', 'presentation');
|
|
187
|
+
}
|
|
188
|
+
|
|
162
189
|
if (!String(image).isHex()) {
|
|
163
190
|
return;
|
|
164
191
|
}
|
|
@@ -168,7 +195,8 @@ Media.setMethod(function applyDirective(element, image, options) {
|
|
|
168
195
|
this.view.helpers.Alchemy.getResource({
|
|
169
196
|
name: 'MediaFile#data',
|
|
170
197
|
params: {
|
|
171
|
-
id: image
|
|
198
|
+
id : image,
|
|
199
|
+
prefix : this.view.expose('active_prefix') || '__',
|
|
172
200
|
}
|
|
173
201
|
}, function gotResult(err, data) {
|
|
174
202
|
|
|
@@ -275,9 +303,9 @@ Media.setMethod(function imageUrl(image_id, options) {
|
|
|
275
303
|
/**
|
|
276
304
|
* Create a base placeholder image url
|
|
277
305
|
*
|
|
278
|
-
* @author Jelle De Loecker <jelle@
|
|
306
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
279
307
|
* @since 0.2.0
|
|
280
|
-
* @version 0.2
|
|
308
|
+
* @version 0.6.2
|
|
281
309
|
*
|
|
282
310
|
* @param {Object} options
|
|
283
311
|
*
|
|
@@ -306,6 +334,8 @@ Media.setMethod(function placeholderUrl(options) {
|
|
|
306
334
|
if (options.text) {
|
|
307
335
|
url.addQuery('text', options.text);
|
|
308
336
|
}
|
|
337
|
+
|
|
338
|
+
options[PLACEHOLDER] = true;
|
|
309
339
|
}
|
|
310
340
|
|
|
311
341
|
return url;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* @constructor
|
|
5
5
|
*
|
|
6
6
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
|
-
* @since 0.
|
|
8
|
-
* @version 0.
|
|
7
|
+
* @since 0.6.0
|
|
8
|
+
* @version 0.6.0
|
|
9
9
|
*
|
|
10
10
|
* @param {Object} data
|
|
11
11
|
*/
|
|
@@ -15,8 +15,8 @@ const Image = Function.inherits('Alchemy.Widget', 'Image');
|
|
|
15
15
|
* Prepare the schema
|
|
16
16
|
*
|
|
17
17
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
18
|
-
* @since 0.
|
|
19
|
-
* @version 0.
|
|
18
|
+
* @since 0.6.0
|
|
19
|
+
* @version 0.6.0
|
|
20
20
|
*/
|
|
21
21
|
Image.constitute(function prepareSchema() {
|
|
22
22
|
|
|
@@ -29,8 +29,8 @@ Image.constitute(function prepareSchema() {
|
|
|
29
29
|
* Populate the widget
|
|
30
30
|
*
|
|
31
31
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
32
|
-
* @since 0.
|
|
33
|
-
* @version 0.
|
|
32
|
+
* @since 0.6.0
|
|
33
|
+
* @version 0.6.4
|
|
34
34
|
*
|
|
35
35
|
* @param {HTMLElement} widget
|
|
36
36
|
*/
|
|
@@ -40,7 +40,7 @@ Image.setMethod(function populateWidget() {
|
|
|
40
40
|
|
|
41
41
|
this.hawkejs_renderer.helpers.Media.applyDirective(img, this.config.image);
|
|
42
42
|
|
|
43
|
-
populateWidget.super.call(this);
|
|
44
|
-
|
|
45
43
|
this.widget.append(img);
|
|
44
|
+
|
|
45
|
+
return populateWidget.super.call(this);
|
|
46
46
|
});
|
|
@@ -14,10 +14,10 @@ var exiv2 = alchemy.use('@11ways/exiv2'),
|
|
|
14
14
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
15
15
|
* @since 0.0.1
|
|
16
16
|
* @version 0.2.0
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} options
|
|
17
19
|
*/
|
|
18
|
-
|
|
19
|
-
ImageMediaType.super.call(this, options);
|
|
20
|
-
});
|
|
20
|
+
const ImageMedia = Function.inherits('Alchemy.MediaType', 'ImageMediaType');
|
|
21
21
|
|
|
22
22
|
ImageMedia.setProperty('exivPath', alchemy.plugins.media.exiv2);
|
|
23
23
|
ImageMedia.setProperty('hashType', alchemy.plugins.media.hash);
|
|
@@ -19,32 +19,48 @@ var MediaFile = Function.inherits('Alchemy.Model', function MediaFile(options) {
|
|
|
19
19
|
|
|
20
20
|
MediaFile.setProperty('types', alchemy.shared('Media.types'));
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* The default sort options
|
|
24
|
+
*
|
|
25
|
+
* @type {Object}
|
|
26
|
+
*/
|
|
27
|
+
MediaFile.prepareProperty('sort', function sort() {
|
|
28
|
+
return {created: -1};
|
|
29
|
+
});
|
|
30
|
+
|
|
22
31
|
/**
|
|
23
32
|
* Constitute the class wide schema
|
|
24
33
|
*
|
|
25
|
-
* @author Jelle De Loecker <jelle@
|
|
34
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
26
35
|
* @since 0.2.0
|
|
27
|
-
* @version 0.
|
|
36
|
+
* @version 0.6.4
|
|
28
37
|
*/
|
|
29
38
|
MediaFile.constitute(function addFields() {
|
|
30
39
|
|
|
31
|
-
this.addField('name', 'String'
|
|
32
|
-
|
|
40
|
+
this.addField('name', 'String', {
|
|
41
|
+
description: 'The name of the file',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this.addField('filename', 'String', {
|
|
45
|
+
description : 'The actual filename',
|
|
46
|
+
});
|
|
33
47
|
|
|
34
48
|
this.addField('type', 'Enum', {
|
|
35
|
-
values: alchemy.getClassGroup('media_type')
|
|
49
|
+
values: alchemy.getClassGroup('media_type'),
|
|
50
|
+
description: 'The type of file',
|
|
36
51
|
});
|
|
37
52
|
|
|
38
53
|
this.addField('extra', 'Object');
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
55
|
+
this.addField('title', 'String', {
|
|
56
|
+
translatable : alchemy.plugins.media.translatable,
|
|
57
|
+
description : 'The title of the file (will be used in the title attribute)',
|
|
58
|
+
});
|
|
45
59
|
|
|
46
|
-
this.addField('
|
|
47
|
-
|
|
60
|
+
this.addField('alt', 'String', {
|
|
61
|
+
translatable : alchemy.plugins.media.translatable,
|
|
62
|
+
description : 'The alternative information of the file (will be used in the alt attribute)',
|
|
63
|
+
});
|
|
48
64
|
|
|
49
65
|
this.belongsTo('MediaRaw');
|
|
50
66
|
});
|
|
@@ -54,7 +70,7 @@ MediaFile.constitute(function addFields() {
|
|
|
54
70
|
*
|
|
55
71
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
56
72
|
* @since 0.2.0
|
|
57
|
-
* @version 0.
|
|
73
|
+
* @version 0.6.4
|
|
58
74
|
*/
|
|
59
75
|
MediaFile.constitute(function chimeraConfig() {
|
|
60
76
|
|
|
@@ -69,6 +85,15 @@ MediaFile.constitute(function chimeraConfig() {
|
|
|
69
85
|
// Get the list group
|
|
70
86
|
list = this.chimera.getActionFields('list');
|
|
71
87
|
|
|
88
|
+
list.addField('_id', {
|
|
89
|
+
view : 'file_preview',
|
|
90
|
+
wrapper : 'file_preview',
|
|
91
|
+
title : 'Thumbnail',
|
|
92
|
+
filter : false,
|
|
93
|
+
sortable : false,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
list.addField('created');
|
|
72
97
|
list.addField('name');
|
|
73
98
|
list.addField('filename');
|
|
74
99
|
list.addField('type');
|
|
@@ -78,6 +103,12 @@ MediaFile.constitute(function chimeraConfig() {
|
|
|
78
103
|
// Get the edit group
|
|
79
104
|
edit = this.chimera.getActionFields('edit');
|
|
80
105
|
|
|
106
|
+
edit.addField('_id', {
|
|
107
|
+
view : 'file_preview',
|
|
108
|
+
wrapper : 'file_preview',
|
|
109
|
+
title : 'Preview',
|
|
110
|
+
});
|
|
111
|
+
|
|
81
112
|
edit.addField('name');
|
|
82
113
|
edit.addField('filename');
|
|
83
114
|
edit.addField('type');
|
package/package.json
CHANGED
package/view/element/al_file.hwk
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<label class="al-file-drop-target">
|
|
2
2
|
<div class="al-file-preview"></div>
|
|
3
3
|
<al-ico class="uploading-icon fa-solid fa-spinner fa-spin-pulse"></al-ico>
|
|
4
|
-
<al-ico class="empty-icon fa-solid fa-file-arrow-up" hidden
|
|
4
|
+
<al-ico class="empty-icon fa-solid fa-file-arrow-up"><% if (self.value) $0.hidden = true %></al-ico>
|
|
5
5
|
<input type="file" tabindex="-1" class="al-file-input" hidden>
|
|
6
6
|
</label>
|
|
7
7
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
</button>
|
|
13
13
|
|
|
14
14
|
<button class="al-file-remove">
|
|
15
|
+
<% if (!self.value) $0.hidden = true %>
|
|
15
16
|
<al-ico class="fa-solid fa-trash-can"></al-ico>
|
|
16
17
|
{%t "remove-current-file" %}
|
|
17
18
|
</button>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="form-field-info">
|
|
2
|
+
<alchemy-label>
|
|
3
|
+
<span
|
|
4
|
+
data-he-name="field-title"
|
|
5
|
+
data-he-slot="field-title"
|
|
6
|
+
><%= alchemy_field.field_title %></span>
|
|
7
|
+
<small
|
|
8
|
+
data-he-name="field-description"
|
|
9
|
+
data-he-slot="field-description"
|
|
10
|
+
><%= alchemy_field.field_description %></small>
|
|
11
|
+
</alchemy-label>
|
|
12
|
+
</div>
|
|
13
|
+
<div data-he-name="field"></div>
|