Skip to content

Commit

Permalink
Add new options to medias and files form fields
Browse files Browse the repository at this point in the history
- filesizeMax, on the files field, to prevent selecting a file which filesize is above provided value in mb
- widthMin. on the medias field, to prevent selecting an image which width is below provided value in px
- heightMin. on the medias field, to prevent selecting an image which height is below provided value in px
  • Loading branch information
ifox committed Mar 17, 2020
1 parent c0c492c commit c564ecc
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 21 deletions.
15 changes: 12 additions & 3 deletions frontend/js/components/ItemList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
<tr class="itemlist__row"
v-for="item in items"
:key="`${item.endpointType}_${item.id}`"
:class="{ 's--picked': isSelected(item, keysToCheck)}"
:class="{
's--picked': isSelected(item, keysToCheck),
's--disabled': item.disabled
}"
@click.exact.prevent="toggleSelection(item)"
@click.shift.exact.prevent="shiftToggleSelection(item)">
<td class="itemlist__cell itemlist__cell--btn" v-if="item.hasOwnProperty('id')">
<a17-checkbox name="item_list" :value="item.endpointType + '_' + item.id" :initialValue="checkedItems" theme="bold"/>
<a17-checkbox name="item_list" :value="item.endpointType + '_' + item.id" :initialValue="checkedItems" theme="bold" :disabled="item.disabled" />
</td>
<td class="itemlist__cell itemlist__cell--thumb" v-if="item.hasOwnProperty('thumbnail')">
<img :src="item.thumbnail" />
Expand Down Expand Up @@ -73,7 +76,8 @@
return Object.keys(firstItem).filter(key => { // exclude columns here
return ![
'id', 'name', 'thumbnail', 'src', 'original', 'edit',
'crop', 'deleteUrl', 'updateUrl', 'updateBulkUrl', 'deleteBulkUrl', 'endpointType'
'crop', 'deleteUrl', 'updateUrl', 'updateBulkUrl',
'deleteBulkUrl', 'endpointType', 'filesizeInMb'
].includes(key) && typeof firstItem[key] === 'string' // only strings
})
},
Expand Down Expand Up @@ -146,6 +150,11 @@
&:hover {
background-color: $color__f--bg;
}
&.s--disabled {
color: $color__button_greyed--bg;
pointer-events: none;
}
}
.itemlist__row:first-child {
Expand Down
8 changes: 8 additions & 0 deletions frontend/js/components/MediaField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@
activeCrop: {
type: Boolean,
default: true
},
widthMin: {
type: Number,
default: 0
},
heightMin: {
type: Number,
default: 0
}
},
data: function () {
Expand Down
4 changes: 4 additions & 0 deletions frontend/js/components/files/FileField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
fieldNote: {
type: String,
default: ''
},
filesizeMax: {
type: Number,
default: 0
}
},
data: () => {
Expand Down
11 changes: 10 additions & 1 deletion frontend/js/components/media-library/MediaGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
</span>
</div>
<div class="mediagrid__item" v-for="item in items" :key="item.id">
<span class="mediagrid__button" :class="{ 's--picked': isSelected(item), 's--used': isUsed(item) }" @click.exact="toggleSelection(item)" @click.shift.exact="shiftToggleSelection(item)"><img :src="item.thumbnail" class="mediagrid__img" /></span>
<span class="mediagrid__button" :class="{
's--picked': isSelected(item),
's--used': isUsed(item),
's--disabled': item.disabled
}" @click.exact="toggleSelection(item)" @click.shift.exact="shiftToggleSelection(item)"><img :src="item.thumbnail" class="mediagrid__img" /></span>
</div>
</div>
</template>
Expand Down Expand Up @@ -157,6 +161,11 @@
opacity: 0.85;
}
}
&.s--disabled {
pointer-events: none;
opacity: 0.2;
}
}
.s--loading {
Expand Down
43 changes: 27 additions & 16 deletions frontend/js/components/media-library/MediaLibrary.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@
<a17-uploader v-if="authorized" @loaded="addMedia" @clear="clearSelectedMedias"
:type="currentTypeObject"/>
<div class="medialibrary__list-items">
<a17-itemlist v-if="type === 'file'" :items="fullMedias" :selected-items="selectedMedias"
<a17-itemlist v-if="type === 'file'" :items="renderedMediaItems" :selected-items="selectedMedias"
:used-items="usedMedias" @change="updateSelectedMedias"
@shiftChange="updateSelectedMedias"/>
<a17-mediagrid v-else :items="fullMedias" :selected-items="selectedMedias" :used-items="usedMedias"
<a17-mediagrid v-else :items="renderedMediaItems" :selected-items="selectedMedias" :used-items="usedMedias"
@change="updateSelectedMedias" @shiftChange="updateSelectedMedias"/>
<a17-spinner v-if="loading" class="medialibrary__spinner">Loading&hellip;</a17-spinner>
</div>
Expand Down Expand Up @@ -145,7 +145,7 @@
return {
loading: false,
maxPage: 20,
fullMedias: [],
mediaItems: [],
selectedMedias: [],
gridHeight: 0,
page: this.initialPage,
Expand All @@ -155,6 +155,14 @@
}
},
computed: {
renderedMediaItems: function () {
return this.mediaItems.map((item) => {
item.disabled = (this.filesizeMax > 0 && item.filesizeInMb > this.filesizeMax)
|| (this.widthMin > 0 && item.width < this.widthMin)
|| (this.heightMin > 0 && item.height < this.heightMin)
return item
})
},
currentTypeObject: function () {
return this.types.find((type) => {
return type.value === this.type
Expand Down Expand Up @@ -190,6 +198,9 @@
...mapState({
connector: state => state.mediaLibrary.connector,
max: state => state.mediaLibrary.max,
filesizeMax: state => state.mediaLibrary.filesizeMax,
widthMin: state => state.mediaLibrary.widthMin,
heightMin: state => state.mediaLibrary.heightMin,
type: state => state.mediaLibrary.type, // image, video, file
types: state => state.mediaLibrary.types,
strict: state => state.mediaLibrary.strict,
Expand All @@ -199,7 +210,7 @@
},
watch: {
type: function () {
this.clearFullMedias()
this.clearMediaItems()
this.gridLoaded = false
}
},
Expand Down Expand Up @@ -236,7 +247,7 @@
},
addMedia: function (media) {
// add media in first position of the available media
this.fullMedias.unshift(media)
this.mediaItems.unshift(media)
this.$store.commit(MEDIA_LIBRARY.INCREMENT_MEDIA_TYPE_TOTAL, this.type)
// select it
this.updateSelectedMedias(media.id)
Expand All @@ -254,8 +265,8 @@
if (shift && this.selectedMedias.length > 0) {
const lastSelectedMedia = this.selectedMedias[this.selectedMedias.length - 1]
const lastSelectedMediaIndex = this.fullMedias.findIndex((media) => media.id === lastSelectedMedia.id)
const selectedMediaIndex = this.fullMedias.findIndex((media) => media.id === id)
const lastSelectedMediaIndex = this.mediaItems.findIndex((media) => media.id === lastSelectedMedia.id)
const selectedMediaIndex = this.mediaItems.findIndex((media) => media.id === id)
if (selectedMediaIndex === -1 && lastSelectedMediaIndex === -1) return
let start = null
Expand All @@ -268,7 +279,7 @@
end = lastSelectedMediaIndex
}
const selectedMedias = this.fullMedias.slice(start, end)
const selectedMedias = this.mediaItems.slice(start, end)
selectedMedias.forEach((media) => {
if (this.selectedMedias.length >= this.max && this.max > 0) return
Expand All @@ -278,7 +289,7 @@
}
})
} else {
const mediaToSelect = this.fullMedias.filter(function (media) {
const mediaToSelect = this.mediaItems.filter(function (media) {
return media.id === id
})
Expand Down Expand Up @@ -322,16 +333,16 @@
mediasIds.forEach(() => {
this.$store.commit(MEDIA_LIBRARY.DECREMENT_MEDIA_TYPE_TOTAL, this.type)
})
this.fullMedias = this.fullMedias.filter((media) => {
this.mediaItems = this.mediaItems.filter((media) => {
return !this.selectedMedias.includes(media) || keepSelectedMedias.includes(media)
})
this.selectedMedias = keepSelectedMedias
if (this.fullMedias.length <= 40) {
if (this.mediaItems.length <= 40) {
this.reloadGrid()
}
},
clearFullMedias: function () {
this.fullMedias.splice(0)
clearMediaItems: function () {
this.mediaItems.splice(0)
},
reloadGrid: function () {
this.loading = true
Expand All @@ -350,8 +361,8 @@
api.get(this.endpoint, formdata, (resp) => {
// add medias here
resp.data.items.forEach(item => {
if (!this.fullMedias.find(media => media.id === item.id)) {
this.fullMedias.push(item)
if (!this.mediaItems.find(media => media.id === item.id)) {
this.mediaItems.push(item)
}
})
this.maxPage = resp.data.maxPage || 1
Expand All @@ -376,7 +387,7 @@
// when changing filters, reset the page to 1
this.page = 1
this.clearFullMedias()
this.clearMediaItems()
this.clearSelectedMedias()
if (el.scrollTop === 0) {
Expand Down
4 changes: 4 additions & 0 deletions frontend/js/mixins/mediaLibrary/mediaLibrary.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export default {
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_TYPE, this.type)
this.$store.commit(MEDIA_LIBRARY.UPDATE_REPLACE_INDEX, index)
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_MAX, max)
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_MODE, true)
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_FILESIZE_MAX, this.filesizeMax || 0)
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_WIDTH_MIN, this.widthMin || 0)
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_HEIGHT_MIN, this.heightMin || 0)
if (this.$root.$refs.mediaLibrary) this.$root.$refs.mediaLibrary.open()
}
}
Expand Down
3 changes: 3 additions & 0 deletions frontend/js/plugins/A17Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ const A17Config = {
this.$store.commit(MEDIA_LIBRARY.RESET_MEDIA_TYPE) // reset to first available type
this.$store.commit(MEDIA_LIBRARY.UPDATE_REPLACE_INDEX, -1) // we are not replacing an image here
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_MAX, 0) // set max to 0
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_FILESIZE_MAX, 0) // set filesize max to 0
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_WIDTH_MIN, 0) // set width min to 0
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_HEIGHT_MIN, 0) // set height min to 0
this.$store.commit(MEDIA_LIBRARY.UPDATE_MEDIA_MODE, false) // set the strict to false (you can change the active type)

if (this.$root.$refs.mediaLibrary) this.$root.$refs.mediaLibrary.open()
Expand Down
24 changes: 24 additions & 0 deletions frontend/js/store/modules/media-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ const state = {
* @type {number}
*/
max: 0,
/**
* Define the maximum filesize allowed to attach in a field from the media library
* @type {number}
*/
filesizeMax: 0,
/**
* Define the min image width allowed to attach in a field from the media library
* @type {number}
*/
widthMin: 0,
/**
* Define the min image height allowed to attach in a field from the media library
* @type {number}
*/
heightMin: 0,
/**
* Restrict the media library navigation between type
* @type {Boolean}
Expand Down Expand Up @@ -173,6 +188,15 @@ const mutations = {
[MEDIA_LIBRARY.UPDATE_MEDIA_MAX] (state, newValue) {
state.max = Math.max(0, newValue)
},
[MEDIA_LIBRARY.UPDATE_MEDIA_FILESIZE_MAX] (state, newValue) {
state.filesizeMax = Math.max(0, newValue)
},
[MEDIA_LIBRARY.UPDATE_MEDIA_WIDTH_MIN] (state, newValue) {
state.widthMin = Math.max(0, newValue)
},
[MEDIA_LIBRARY.UPDATE_MEDIA_HEIGHT_MIN] (state, newValue) {
state.heightMin = Math.max(0, newValue)
},
[MEDIA_LIBRARY.SET_MEDIA_METADATAS] (state, metadatas) {
const connector = metadatas.media.context
const medias = state.selected[connector]
Expand Down
6 changes: 6 additions & 0 deletions frontend/js/store/mutations/media-library.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export const DONE_UPLOAD_MEDIA = 'doneUploadMedia'
export const ERROR_UPLOAD_MEDIA = 'errorUploadMedia'
export const DESTROY_SPECIFIC_MEDIA = 'destroyMediasInSelected'
export const UPDATE_MEDIA_MAX = 'updateMediaMax'
export const UPDATE_MEDIA_FILESIZE_MAX = 'updateMediaFilesizeMax'
export const UPDATE_MEDIA_WIDTH_MIN = 'updateMediaWidthMin'
export const UPDATE_MEDIA_HEIGHT_MIN = 'updateMediaHeightMin'
export const UPDATE_MEDIA_TYPE = 'updateMediaType'
export const RESET_MEDIA_TYPE = 'resetMediaType'
export const SET_MEDIA_CROP = 'setMediaCrop'
Expand All @@ -33,6 +36,9 @@ export default {
ERROR_UPLOAD_MEDIA,
DESTROY_SPECIFIC_MEDIA,
UPDATE_MEDIA_MAX,
UPDATE_MEDIA_FILESIZE_MAX,
UPDATE_MEDIA_WIDTH_MIN,
UPDATE_MEDIA_HEIGHT_MIN,
UPDATE_MEDIA_TYPE,
RESET_MEDIA_TYPE,
SET_MEDIA_CROP,
Expand Down
1 change: 1 addition & 0 deletions src/Models/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public function toCmsArray()
'src' => FileService::getUrl($this->uuid),
'original' => FileService::getUrl($this->uuid),
'size' => $this->size,
'filesizeInMb' => number_format($this->attributes['size'] / 1048576, 2),
];
}

Expand Down
4 changes: 3 additions & 1 deletion views/partials/form/_files.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
$itemLabel = $itemLabel ?? strtolower($label);
$note = $note ?? 'Add' . ($max > 1 ? " up to $max $itemLabel" : ' one ' . Str::singular($itemLabel));
$fieldNote = $fieldNote ?? '';
$filesizeMax = $filesizeMax ?? 0;
@endphp

<a17-locale
Expand All @@ -13,7 +14,8 @@
@include('twill::partials.form.utils._field_name', ['asAttributes' => true])
note: '{{ $note }}',
fieldNote: '{{ $fieldNote }}',
max: {{ $max }}
max: {{ $max }},
filesizeMax: {{ $filesizeMax }}
}"
></a17-locale>

Expand Down
6 changes: 6 additions & 0 deletions views/partials/form/_medias.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
$captionMaxLength = $captionMaxLength ?? false;
$extraMetadatas = $extraMetadatas ?? false;
$multiple = $max > 1 || $max == 0;
$widthMin = $widthMin ?? 0;
$heightMin = $heightMin ?? 0;
@endphp

@if (config('twill.media_library.translated_form_fields', $translated ?? false) && ($translated ?? true))
Expand All @@ -19,6 +21,8 @@
label: '{{ $label }}',
cropContext: '{{ $name }}',
max: {{ $max }},
widthMin: {{ $widthMin }},
heightMin: {{ $heightMin }},
@if ($extraMetadatas) extraMetadatas: {{ json_encode($extraMetadatas) }}, @endif
@if ($altTextMaxLength) altTextMaxLength: {{ $altTextMaxLength }}, @endif
@if ($captionMaxLength) captionMaxLength: {{ $captionMaxLength }}, @endif
Expand All @@ -44,6 +48,8 @@
@if($multiple) <a17-slideshow @else <a17-mediafield @endif
@include('twill::partials.form.utils._field_name')
crop-context="{{ $name }}"
:width-min="{{ $widthMin }}"
:height-min="{{ $heightMin }}"
@if($multiple) :max="{{ $max }}" @endif
@if ($extraMetadatas) :extra-metadatas="{{ json_encode($extraMetadatas) }}" @endif
@if ($required) :required="true" @endif
Expand Down

0 comments on commit c564ecc

Please sign in to comment.