@salla.sa/twilight-components 2.14.540 → 2.14.541
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/dist/cjs/{filepond-U8F_iDbp.js → filepond-CNdvfaMJ.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-poster-CAJAmCHU.js → filepond-plugin-file-poster-Di_D3w89.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-validate-size-Dxgl8Gdz.js → filepond-plugin-file-validate-size-BiRa98qd.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-validate-type-BPhw8zXs.js → filepond-plugin-file-validate-type-Bolv-kyJ.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-edit-DNKfSuCy.js → filepond-plugin-image-edit-AN6huMV9.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-exif-orientation-NCmUtKOd.js → filepond-plugin-image-exif-orientation-Bwa8QtGo.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-preview-jRCd9jSG.js → filepond-plugin-image-preview-CaVYLAvG.js} +1 -1
- package/dist/cjs/helpers-ClOJIAG8.js +89 -0
- package/dist/cjs/{index-F_FURF-0.js → index-DX2EKTCE.js} +18 -14
- package/dist/cjs/{intlTelInput-yt9noy9U.js → intlTelInput-DnwdGAiP.js} +1 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/salla-accordion-body_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-accordion_6.cjs.entry.js +1 -1
- package/dist/cjs/salla-add-product-button_5.cjs.entry.js +1 -1
- package/dist/cjs/salla-advertisement.cjs.entry.js +1 -1
- package/dist/cjs/salla-alert_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-app-install-alert.cjs.entry.js +1 -1
- package/dist/cjs/salla-apps-icons.cjs.entry.js +1 -1
- package/dist/cjs/{salla-booking-field_7.cjs.entry.js → salla-attachment-view_9.cjs.entry.js} +1003 -40
- package/dist/cjs/salla-badge.cjs.entry.js +1 -1
- package/dist/cjs/salla-basket-gap.cjs.entry.js +1 -1
- package/dist/cjs/salla-bullet-delivery_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-cart-coupons.cjs.entry.js +1 -1
- package/dist/cjs/salla-cart-item-offers_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-cart-summary-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-cashback-banner.cjs.entry.js +1 -1
- package/dist/cjs/salla-comment-factors.cjs.entry.js +2 -2
- package/dist/cjs/salla-comment-form_8.cjs.entry.js +14 -5
- package/dist/cjs/salla-conditional-offer.cjs.entry.js +1 -1
- package/dist/cjs/salla-contacts.cjs.entry.js +1 -1
- package/dist/cjs/salla-cookies-bar.cjs.entry.js +1 -1
- package/dist/cjs/salla-count-down.cjs.entry.js +1 -1
- package/dist/cjs/salla-custom-fields.cjs.entry.js +1 -1
- package/dist/cjs/salla-delivery-promise.cjs.entry.js +1 -1
- package/dist/cjs/salla-edit-order-button.cjs.entry.js +1 -1
- package/dist/cjs/salla-filters-widget.cjs.entry.js +1 -1
- package/dist/cjs/salla-filters.cjs.entry.js +1 -1
- package/dist/cjs/salla-fulfillment-methods.cjs.entry.js +1 -1
- package/dist/cjs/salla-gifting.cjs.entry.js +1 -1
- package/dist/cjs/salla-hook.cjs.entry.js +1 -1
- package/dist/cjs/salla-infinite-scroll.cjs.entry.js +1 -1
- package/dist/cjs/salla-installment.cjs.entry.js +1 -1
- package/dist/cjs/salla-list-tile.cjs.entry.js +1 -1
- package/dist/cjs/salla-localization-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-login-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-banner_10.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-exchange-product-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-points-banner.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-points-history.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-prize-item.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty.cjs.entry.js +1 -1
- package/dist/cjs/salla-maintenance-alert.cjs.entry.js +1 -1
- package/dist/cjs/salla-map_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-menu.cjs.entry.js +1 -1
- package/dist/cjs/salla-metadata.cjs.entry.js +1 -1
- package/dist/cjs/salla-multiple-bundle-product-cart_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-multiple-bundle-product-options-modal_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-multiple-bundle-product.cjs.entry.js +1 -1
- package/dist/cjs/salla-next-order-coupon.cjs.entry.js +1 -1
- package/dist/cjs/salla-notification-item_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-offer-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-offer.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-branch.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-cancel.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-details-multiple-bundle-product.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-details-options.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-details.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-edit-item.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-edit-product-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-edit.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-options-modal_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-shipments.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-summary.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-totals-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-orders.cjs.entry.js +1 -1
- package/dist/cjs/salla-payments.cjs.entry.js +1 -1
- package/dist/cjs/salla-placeholder.cjs.entry.js +1 -1
- package/dist/cjs/salla-price-range.cjs.entry.js +1 -1
- package/dist/cjs/salla-product-card-embed.cjs.entry.js +1 -1
- package/dist/cjs/salla-product-size-guide.cjs.entry.js +1 -1
- package/dist/cjs/salla-products-list.cjs.entry.js +1 -1
- package/dist/cjs/salla-products-slider.cjs.entry.js +1 -1
- package/dist/cjs/salla-quick-order.cjs.entry.js +1 -1
- package/dist/cjs/salla-rating-modal-v2.cjs.entry.js +420 -84
- package/dist/cjs/salla-rating-modal.cjs.entry.js +3 -5
- package/dist/cjs/salla-review-factors-tags.cjs.entry.js +4 -83
- package/dist/cjs/salla-review-order-item.cjs.entry.js +125 -0
- package/dist/cjs/salla-scopes.cjs.entry.js +1 -1
- package/dist/cjs/salla-search.cjs.entry.js +1 -1
- package/dist/cjs/salla-skeleton.cjs.entry.js +1 -1
- package/dist/cjs/salla-slider.cjs.entry.js +1 -1
- package/dist/cjs/salla-social-share.cjs.entry.js +1 -1
- package/dist/cjs/salla-social.cjs.entry.js +1 -1
- package/dist/cjs/salla-tab-content_3.cjs.entry.js +1 -1
- package/dist/cjs/salla-tiered-offer.cjs.entry.js +1 -1
- package/dist/cjs/salla-tooltip.cjs.entry.js +1 -1
- package/dist/cjs/salla-trust-badges.cjs.entry.js +1 -1
- package/dist/cjs/salla-user-menu.cjs.entry.js +1 -1
- package/dist/cjs/salla-user-profile.cjs.entry.js +1 -1
- package/dist/cjs/salla-user-settings.cjs.entry.js +1 -1
- package/dist/cjs/salla-verify.cjs.entry.js +1 -1
- package/dist/cjs/salla-wallet.cjs.entry.js +1 -1
- package/dist/cjs/salla-wishlist-actions.cjs.entry.js +1 -1
- package/dist/cjs/twilight.cjs.js +2 -2
- package/dist/cjs/upload-limits-C3RarAPN.js +136 -0
- package/dist/cjs/{vanilla-picker-DXgSpklI.js → vanilla-picker-BUFYPi-_.js} +1 -1
- package/dist/collection/collection-manifest.json +16 -11
- package/dist/collection/components/salla-attachment-view/salla-attachment-view.css +164 -0
- package/dist/collection/components/salla-attachment-view/salla-attachment-view.js +250 -0
- package/dist/collection/components/salla-attachments/salla-attachments.css +69 -0
- package/dist/collection/components/salla-attachments/salla-attachments.js +375 -0
- package/dist/collection/components/salla-comments/salla-comment-item.js +13 -3
- package/dist/collection/components/salla-comments/salla-comments.css +7 -0
- package/dist/collection/components/salla-datetime-picker/salla-datetime-picker.js +1 -1
- package/dist/collection/components/salla-file-upload/salla-file-upload.css +149 -0
- package/dist/collection/components/salla-file-upload/salla-file-upload.js +784 -42
- package/dist/collection/components/salla-file-upload/upload-limits.js +127 -0
- package/dist/collection/components/salla-products-slider/salla-products-slider.js +1 -1
- package/dist/collection/components/salla-rating-modal/rating-modal-media.js +85 -0
- package/dist/collection/components/salla-rating-modal/salla-rating-modal-v2.js +348 -85
- package/dist/collection/components/salla-rating-modal/salla-rating-modal.css +17 -7
- package/dist/collection/components/salla-rating-modal/salla-rating-modal.js +1 -3
- package/dist/collection/components/salla-review-factors-tags/helpers.js +8 -7
- package/dist/collection/components/salla-review-order-item/interfaces.js +1 -0
- package/dist/collection/components/salla-review-order-item/salla-review-order-item.js +154 -0
- package/dist/components/index.js +2 -2
- package/dist/components/salla-add-product-button2.js +40 -28
- package/dist/components/salla-attachment-view.d.ts +11 -0
- package/dist/components/salla-attachment-view.js +9 -0
- package/dist/components/salla-attachment-view2.js +323 -0
- package/dist/components/salla-attachments.d.ts +11 -0
- package/dist/components/salla-attachments.js +9 -0
- package/dist/components/salla-attachments2.js +232 -0
- package/dist/components/salla-basket-gap.js +46 -34
- package/dist/components/salla-breadcrumb.js +1 -1
- package/dist/components/salla-comment-factors2.js +1 -1
- package/dist/components/salla-comment-item2.js +26 -4
- package/dist/components/salla-comments.js +14 -2
- package/dist/components/salla-custom-fields.js +28 -4
- package/dist/components/salla-file-upload2.js +703 -31
- package/dist/components/salla-gifting.js +7 -1
- package/dist/components/salla-loyalty-exchange-product-card2.js +46 -34
- package/dist/components/salla-loyalty-panel.js +8 -2
- package/dist/components/salla-loyalty-program.js +8 -2
- package/dist/components/salla-multiple-bundle-product-cart2.js +40 -28
- package/dist/components/salla-multiple-bundle-product-details2.js +12 -6
- package/dist/components/salla-multiple-bundle-product-options-modal2.js +7 -1
- package/dist/components/salla-multiple-bundle-product-slider2.js +1 -1
- package/dist/components/salla-multiple-bundle-product.js +12 -6
- package/dist/components/salla-offer-modal.js +8 -2
- package/dist/components/salla-order-edit-item2.js +36 -24
- package/dist/components/salla-order-edit.js +42 -30
- package/dist/components/salla-order-options-modal2.js +34 -22
- package/dist/components/salla-product-card2.js +44 -32
- package/dist/components/salla-product-options2.js +32 -20
- package/dist/components/salla-products-slider2.js +8 -2
- package/dist/components/salla-quick-buy2.js +36 -24
- package/dist/components/salla-rating-modal-v22.js +449 -97
- package/dist/components/salla-rating-modal.js +30 -20
- package/dist/components/salla-review-factors-tags2.js +9 -8
- package/dist/components/salla-review-order-item.d.ts +11 -0
- package/dist/components/salla-review-order-item.js +196 -0
- package/dist/components/salla-reward-details2.js +8 -2
- package/dist/components/salla-slider2.js +1 -1
- package/dist/esm/{filepond-Bxzb6RRZ.js → filepond-CKsbRWmS.js} +1 -1
- package/dist/esm/{filepond-plugin-file-poster-CZfrjnEX.js → filepond-plugin-file-poster-B_gYCESq.js} +1 -1
- package/dist/esm/{filepond-plugin-file-validate-size-Dqa69lX7.js → filepond-plugin-file-validate-size-Bep6fNi3.js} +1 -1
- package/dist/esm/{filepond-plugin-file-validate-type-C_76nxDb.js → filepond-plugin-file-validate-type-r3uRmGIr.js} +1 -1
- package/dist/esm/{filepond-plugin-image-edit-BvzVMeMY.js → filepond-plugin-image-edit-BJcOlOFL.js} +1 -1
- package/dist/esm/{filepond-plugin-image-exif-orientation-Br4ANTi7.js → filepond-plugin-image-exif-orientation-DJoDaRwQ.js} +1 -1
- package/dist/esm/{filepond-plugin-image-preview-e54xZ08P.js → filepond-plugin-image-preview-BsuTLPS0.js} +1 -1
- package/dist/esm/helpers-DqXpn47Z.js +85 -0
- package/dist/esm/{index-5UtJVEzd.js → index-BVqCTDsV.js} +18 -14
- package/dist/esm/{intlTelInput-BQXch__5.js → intlTelInput-CD2FA0nI.js} +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/salla-accordion-body_2.entry.js +1 -1
- package/dist/esm/salla-accordion_6.entry.js +1 -1
- package/dist/esm/salla-add-product-button_5.entry.js +1 -1
- package/dist/esm/salla-advertisement.entry.js +1 -1
- package/dist/esm/salla-alert_2.entry.js +1 -1
- package/dist/esm/salla-app-install-alert.entry.js +1 -1
- package/dist/esm/salla-apps-icons.entry.js +1 -1
- package/dist/esm/{salla-booking-field_7.entry.js → salla-attachment-view_9.entry.js} +1002 -41
- package/dist/esm/salla-badge.entry.js +1 -1
- package/dist/esm/salla-basket-gap.entry.js +1 -1
- package/dist/esm/salla-bullet-delivery_2.entry.js +1 -1
- package/dist/esm/salla-cart-coupons.entry.js +1 -1
- package/dist/esm/salla-cart-item-offers_2.entry.js +1 -1
- package/dist/esm/salla-cart-summary-card.entry.js +1 -1
- package/dist/esm/salla-cashback-banner.entry.js +1 -1
- package/dist/esm/salla-comment-factors.entry.js +2 -2
- package/dist/esm/salla-comment-form_8.entry.js +14 -5
- package/dist/esm/salla-conditional-offer.entry.js +1 -1
- package/dist/esm/salla-contacts.entry.js +1 -1
- package/dist/esm/salla-cookies-bar.entry.js +1 -1
- package/dist/esm/salla-count-down.entry.js +1 -1
- package/dist/esm/salla-custom-fields.entry.js +1 -1
- package/dist/esm/salla-delivery-promise.entry.js +1 -1
- package/dist/esm/salla-edit-order-button.entry.js +1 -1
- package/dist/esm/salla-filters-widget.entry.js +1 -1
- package/dist/esm/salla-filters.entry.js +1 -1
- package/dist/esm/salla-fulfillment-methods.entry.js +1 -1
- package/dist/esm/salla-gifting.entry.js +1 -1
- package/dist/esm/salla-hook.entry.js +1 -1
- package/dist/esm/salla-infinite-scroll.entry.js +1 -1
- package/dist/esm/salla-installment.entry.js +1 -1
- package/dist/esm/salla-list-tile.entry.js +1 -1
- package/dist/esm/salla-localization-modal.entry.js +1 -1
- package/dist/esm/salla-login-modal.entry.js +1 -1
- package/dist/esm/salla-loyalty-banner_10.entry.js +1 -1
- package/dist/esm/salla-loyalty-exchange-product-card.entry.js +1 -1
- package/dist/esm/salla-loyalty-points-banner.entry.js +1 -1
- package/dist/esm/salla-loyalty-points-history.entry.js +1 -1
- package/dist/esm/salla-loyalty-prize-item.entry.js +1 -1
- package/dist/esm/salla-loyalty.entry.js +1 -1
- package/dist/esm/salla-maintenance-alert.entry.js +1 -1
- package/dist/esm/salla-map_2.entry.js +1 -1
- package/dist/esm/salla-menu.entry.js +1 -1
- package/dist/esm/salla-metadata.entry.js +1 -1
- package/dist/esm/salla-multiple-bundle-product-cart_2.entry.js +1 -1
- package/dist/esm/salla-multiple-bundle-product-options-modal_2.entry.js +1 -1
- package/dist/esm/salla-multiple-bundle-product.entry.js +1 -1
- package/dist/esm/salla-next-order-coupon.entry.js +1 -1
- package/dist/esm/salla-notification-item_2.entry.js +1 -1
- package/dist/esm/salla-offer-modal.entry.js +1 -1
- package/dist/esm/salla-offer.entry.js +1 -1
- package/dist/esm/salla-order-branch.entry.js +1 -1
- package/dist/esm/salla-order-cancel.entry.js +1 -1
- package/dist/esm/salla-order-details-multiple-bundle-product.entry.js +1 -1
- package/dist/esm/salla-order-details-options.entry.js +1 -1
- package/dist/esm/salla-order-details.entry.js +1 -1
- package/dist/esm/salla-order-edit-item.entry.js +1 -1
- package/dist/esm/salla-order-edit-product-card.entry.js +1 -1
- package/dist/esm/salla-order-edit.entry.js +1 -1
- package/dist/esm/salla-order-options-modal_2.entry.js +1 -1
- package/dist/esm/salla-order-shipments.entry.js +1 -1
- package/dist/esm/salla-order-summary.entry.js +1 -1
- package/dist/esm/salla-order-totals-card.entry.js +1 -1
- package/dist/esm/salla-orders.entry.js +1 -1
- package/dist/esm/salla-payments.entry.js +1 -1
- package/dist/esm/salla-placeholder.entry.js +1 -1
- package/dist/esm/salla-price-range.entry.js +1 -1
- package/dist/esm/salla-product-card-embed.entry.js +1 -1
- package/dist/esm/salla-product-size-guide.entry.js +1 -1
- package/dist/esm/salla-products-list.entry.js +1 -1
- package/dist/esm/salla-products-slider.entry.js +1 -1
- package/dist/esm/salla-quick-order.entry.js +1 -1
- package/dist/esm/salla-rating-modal-v2.entry.js +420 -84
- package/dist/esm/salla-rating-modal.entry.js +3 -5
- package/dist/esm/salla-review-factors-tags.entry.js +2 -81
- package/dist/esm/salla-review-order-item.entry.js +123 -0
- package/dist/esm/salla-scopes.entry.js +1 -1
- package/dist/esm/salla-search.entry.js +1 -1
- package/dist/esm/salla-skeleton.entry.js +1 -1
- package/dist/esm/salla-slider.entry.js +1 -1
- package/dist/esm/salla-social-share.entry.js +1 -1
- package/dist/esm/salla-social.entry.js +1 -1
- package/dist/esm/salla-tab-content_3.entry.js +1 -1
- package/dist/esm/salla-tiered-offer.entry.js +1 -1
- package/dist/esm/salla-tooltip.entry.js +1 -1
- package/dist/esm/salla-trust-badges.entry.js +1 -1
- package/dist/esm/salla-user-menu.entry.js +1 -1
- package/dist/esm/salla-user-profile.entry.js +1 -1
- package/dist/esm/salla-user-settings.entry.js +1 -1
- package/dist/esm/salla-verify.entry.js +1 -1
- package/dist/esm/salla-wallet.entry.js +1 -1
- package/dist/esm/salla-wishlist-actions.entry.js +1 -1
- package/dist/esm/twilight.js +3 -3
- package/dist/esm/upload-limits-DrXX8XG8.js +121 -0
- package/dist/esm/{vanilla-picker-lLULIehu.js → vanilla-picker-Ba_za9Iy.js} +1 -1
- package/dist/twilight/{p-1c66fdb3.entry.js → p-003499a8.entry.js} +1 -1
- package/dist/twilight/{p-0bc1c246.entry.js → p-0974f6c6.entry.js} +1 -1
- package/dist/twilight/{p-1578cbe5.entry.js → p-0a9093f1.entry.js} +1 -1
- package/dist/twilight/{p-ad54610c.entry.js → p-0ce2c41f.entry.js} +1 -1
- package/dist/twilight/{p-acd1a9d8.entry.js → p-0ea8365b.entry.js} +1 -1
- package/dist/twilight/p-1174e53e.entry.js +4 -0
- package/dist/twilight/{p-d8a69feb.entry.js → p-11ef8b82.entry.js} +1 -1
- package/dist/twilight/{p-5cbbf472.entry.js → p-13244c52.entry.js} +1 -1
- package/dist/twilight/{p-9af31040.entry.js → p-14689252.entry.js} +1 -1
- package/dist/twilight/{p-397acd73.entry.js → p-17940d8a.entry.js} +1 -1
- package/dist/twilight/{p-40a0baa7.entry.js → p-1974f6da.entry.js} +1 -1
- package/dist/twilight/{p-02e821a0.entry.js → p-1a191989.entry.js} +1 -1
- package/dist/twilight/{p-900ee42a.entry.js → p-1ec6e0fe.entry.js} +1 -1
- package/dist/twilight/{p-3af52c82.entry.js → p-1fcebaad.entry.js} +1 -1
- package/dist/twilight/{p-6c4cef7a.entry.js → p-2b0cf190.entry.js} +1 -1
- package/dist/twilight/{p-7e9d67f2.entry.js → p-333ea76b.entry.js} +1 -1
- package/dist/twilight/{p-d6b6f984.entry.js → p-337cc9f6.entry.js} +1 -1
- package/dist/twilight/{p-71731e63.entry.js → p-34d5c7bf.entry.js} +1 -1
- package/dist/twilight/{p-49c2e935.entry.js → p-36abc50f.entry.js} +1 -1
- package/dist/twilight/{p-e6007706.entry.js → p-37d9f762.entry.js} +1 -1
- package/dist/twilight/{p-891009e2.entry.js → p-3961522a.entry.js} +1 -1
- package/dist/twilight/{p-b5c90151.entry.js → p-39d9e02f.entry.js} +1 -1
- package/dist/twilight/{p-088c1ab3.entry.js → p-3a4bb8de.entry.js} +1 -1
- package/dist/twilight/{p-538a1642.entry.js → p-409f95a8.entry.js} +1 -1
- package/dist/twilight/{p-fb2c863d.entry.js → p-42952fac.entry.js} +1 -1
- package/dist/twilight/{p-913d4965.entry.js → p-436dfe93.entry.js} +1 -1
- package/dist/twilight/{p-ed9899c0.entry.js → p-50c90e0a.entry.js} +1 -1
- package/dist/twilight/{p-ce941081.entry.js → p-5115117b.entry.js} +1 -1
- package/dist/twilight/{p-693d012f.entry.js → p-56647774.entry.js} +1 -1
- package/dist/twilight/{p-18d7763b.entry.js → p-598cadf4.entry.js} +1 -1
- package/dist/twilight/{p-66313db6.entry.js → p-635265d1.entry.js} +1 -1
- package/dist/twilight/{p-95224232.entry.js → p-659e2280.entry.js} +1 -1
- package/dist/twilight/{p-6757a647.entry.js → p-6a3487de.entry.js} +1 -1
- package/dist/twilight/{p-582247b3.entry.js → p-6d07d195.entry.js} +1 -1
- package/dist/twilight/{p-8dab94d8.entry.js → p-6ee096e8.entry.js} +1 -1
- package/dist/twilight/{p-c138132c.entry.js → p-723aeda4.entry.js} +1 -1
- package/dist/twilight/{p-c8c36233.entry.js → p-743b79ae.entry.js} +1 -1
- package/dist/twilight/{p-5f1b8510.entry.js → p-75e692d1.entry.js} +1 -1
- package/dist/twilight/{p-0895958b.entry.js → p-79444897.entry.js} +1 -1
- package/dist/twilight/{p-4e2e4e92.entry.js → p-7b23dec7.entry.js} +1 -1
- package/dist/twilight/p-7bb24ad6.entry.js +4 -0
- package/dist/twilight/{p-4c34e1fd.entry.js → p-7d9288b0.entry.js} +1 -1
- package/dist/twilight/{p-0ecbe43b.entry.js → p-85f95a58.entry.js} +1 -1
- package/dist/twilight/{p-2a9a4e12.entry.js → p-86a1f616.entry.js} +1 -1
- package/dist/twilight/{p-1bc7ab28.entry.js → p-87115499.entry.js} +1 -1
- package/dist/twilight/{p-497cc3a6.entry.js → p-878c2be2.entry.js} +1 -1
- package/dist/twilight/{p-524aabd2.entry.js → p-89e9a91f.entry.js} +1 -1
- package/dist/twilight/{p-f3771ebc.entry.js → p-90ee37c7.entry.js} +1 -1
- package/dist/twilight/{p-e4cb5ee8.entry.js → p-96584590.entry.js} +1 -1
- package/dist/twilight/{p-3136d942.entry.js → p-96a57e9c.entry.js} +1 -1
- package/dist/twilight/{p-7a17138f.entry.js → p-978e4164.entry.js} +1 -1
- package/dist/twilight/{p-b9b32feb.entry.js → p-97fc57c1.entry.js} +1 -1
- package/dist/twilight/p-98b1ff35.entry.js +4 -0
- package/dist/twilight/{p-5a26fb06.entry.js → p-9d18525b.entry.js} +1 -1
- package/dist/twilight/p-B83s3cRn.js +9 -0
- package/dist/twilight/{p-5UtJVEzd.js → p-BVqCTDsV.js} +1 -1
- package/dist/twilight/{p-5njrWPq2.js → p-CP29f7RQ.js} +2 -2
- package/dist/twilight/{p-CXv4fDWa.js → p-CS-t4QAX.js} +1 -1
- package/dist/twilight/{p-1YJa6YaH.js → p-Cluq3aDa.js} +1 -1
- package/dist/twilight/{p-yEKxvrPt.js → p-D-zqM6k8.js} +1 -1
- package/dist/twilight/{p-Dke2dnYe.js → p-DJmqmO68.js} +1 -1
- package/dist/twilight/{p-CkJpLPBM.js → p-DgwK96eP.js} +1 -1
- package/dist/twilight/p-DqXpn47Z.js +4 -0
- package/dist/twilight/p-DrXX8XG8.js +4 -0
- package/dist/twilight/{p-Cf5WZwC9.js → p-DzW3U8TR.js} +1 -1
- package/dist/twilight/{p-Dso9PQdO.js → p-JKh0XFIn.js} +1 -1
- package/dist/twilight/{p-64ee420e.entry.js → p-a347e701.entry.js} +1 -1
- package/dist/twilight/{p-271a2d55.entry.js → p-a5d08af6.entry.js} +1 -1
- package/dist/twilight/{p-fbb156e8.entry.js → p-a774f6f0.entry.js} +7 -7
- package/dist/twilight/p-afaa0fbe.entry.js +4 -0
- package/dist/twilight/p-b389b1d3.entry.js +4 -0
- package/dist/twilight/{p-3b0032e4.entry.js → p-b6d5ae9b.entry.js} +1 -1
- package/dist/twilight/{p-2d62c356.entry.js → p-b862c670.entry.js} +1 -1
- package/dist/twilight/{p-4e71dacc.entry.js → p-bab59319.entry.js} +1 -1
- package/dist/twilight/{p-16c09de9.entry.js → p-bf4c2184.entry.js} +1 -1
- package/dist/twilight/{p-b9477568.entry.js → p-c19cf93c.entry.js} +1 -1
- package/dist/twilight/{p-b16c1eac.entry.js → p-c34f8c08.entry.js} +1 -1
- package/dist/twilight/{p-d4e1a8f7.entry.js → p-c47ecca7.entry.js} +1 -1
- package/dist/twilight/{p-46d2375b.entry.js → p-c48f5c6b.entry.js} +1 -1
- package/dist/twilight/{p-1c049149.entry.js → p-c53c2f59.entry.js} +1 -1
- package/dist/twilight/{p-f5747d3c.entry.js → p-cd805a38.entry.js} +1 -1
- package/dist/twilight/{p-ac9a54cc.entry.js → p-cdd8ed7f.entry.js} +1 -1
- package/dist/twilight/{p-02df1c31.entry.js → p-ced4b7ac.entry.js} +1 -1
- package/dist/twilight/{p-21e9a475.entry.js → p-cf3365e2.entry.js} +1 -1
- package/dist/twilight/p-d78998b7.entry.js +4 -0
- package/dist/twilight/{p-bb7bc52f.entry.js → p-daea3207.entry.js} +1 -1
- package/dist/twilight/{p-6e766b2a.entry.js → p-dff6d623.entry.js} +1 -1
- package/dist/twilight/p-e04221de.entry.js +4 -0
- package/dist/twilight/{p-66448f0f.entry.js → p-e2934193.entry.js} +1 -1
- package/dist/twilight/{p-a9e276fa.entry.js → p-e3dab961.entry.js} +1 -1
- package/dist/twilight/{p-73607393.entry.js → p-e41e5fc7.entry.js} +1 -1
- package/dist/twilight/{p-fe222cbe.entry.js → p-e4c9cef4.entry.js} +1 -1
- package/dist/twilight/{p-a5afb821.entry.js → p-eaf9d536.entry.js} +1 -1
- package/dist/twilight/{p-c05513ae.entry.js → p-ee2b16d7.entry.js} +1 -1
- package/dist/twilight/{p-c224fa3a.entry.js → p-ee3ddc23.entry.js} +1 -1
- package/dist/twilight/{p-963d34af.entry.js → p-f0a14b18.entry.js} +1 -1
- package/dist/twilight/{p-4cff8533.entry.js → p-f195a63d.entry.js} +1 -1
- package/dist/twilight/{p-200a9c11.entry.js → p-f2c688d6.entry.js} +1 -1
- package/dist/twilight/{p-b7f1bad9.entry.js → p-f4ac8cae.entry.js} +1 -1
- package/dist/twilight/{p-1ee008c3.entry.js → p-f58d14ed.entry.js} +1 -1
- package/dist/twilight/{p-d505caaf.entry.js → p-f82cee0c.entry.js} +1 -1
- package/dist/twilight/{p-b639f062.entry.js → p-fa17989b.entry.js} +1 -1
- package/dist/twilight/{p-575b3b4c.entry.js → p-fbc075fe.entry.js} +1 -1
- package/dist/twilight/{p-f27472f4.entry.js → p-fc5d5473.entry.js} +1 -1
- package/dist/twilight/twilight.esm.js +1 -1
- package/dist/types/components/salla-attachment-view/salla-attachment-view.d.ts +47 -0
- package/dist/types/components/salla-attachments/salla-attachments.d.ts +73 -0
- package/dist/types/components/salla-comments/interfaces.d.ts +1 -0
- package/dist/types/components/salla-comments/salla-comment-item.d.ts +3 -1
- package/dist/types/components/salla-file-upload/salla-file-upload.d.ts +127 -4
- package/dist/types/components/salla-file-upload/upload-limits.d.ts +49 -0
- package/dist/types/components/salla-rating-modal/rating-modal-media.d.ts +38 -0
- package/dist/types/components/salla-rating-modal/salla-rating-modal-v2.d.ts +30 -7
- package/dist/types/components/salla-review-factors-tags/helpers.d.ts +1 -1
- package/dist/types/components/salla-review-factors-tags/interfaces.d.ts +7 -0
- package/dist/types/components/salla-review-order-item/interfaces.d.ts +30 -0
- package/dist/types/components/salla-review-order-item/salla-review-order-item.d.ts +30 -0
- package/dist/types/components.d.ts +282 -7
- package/package.json +5 -5
- package/dist/twilight/p-3024f859.entry.js +0 -4
- package/dist/twilight/p-3b821dc9.entry.js +0 -4
- package/dist/twilight/p-4dabd999.entry.js +0 -4
- package/dist/twilight/p-WDLGvEaR.js +0 -9
- package/dist/twilight/p-aaa37ca1.entry.js +0 -4
- package/dist/twilight/p-dcf53c45.entry.js +0 -4
- package/dist/twilight/p-f17fa83f.entry.js +0 -4
- package/dist/components/{keyboard_arrow_right.js → keyboard_arrow_left.js} +6 -6
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Crafted with ❤ by Salla
|
|
3
3
|
*/
|
|
4
4
|
import { h, Host } from "@stencil/core";
|
|
5
|
+
import { formatDuration, formatBytesAsSize, getFilePondMaxFileSize, getMaxImagesCount, getMaxVideosCount, getTotalMaxFiles, getUploadErrorMessage, isImageMimeType, isVideoMimeType, parseSizeToBytes, shouldCountGalleryFile, shouldCountGalleryLimit, usesSplitCountLimits, } from "./upload-limits";
|
|
6
|
+
import CancelIcon from "../../assets/svg/cancel.svg";
|
|
7
|
+
import PlayIcon from "../../assets/svg/play-circle.svg";
|
|
8
|
+
const VIDEO_METADATA_TIMEOUT_MS = 10000;
|
|
5
9
|
export class SallaFileUpload {
|
|
6
10
|
/**
|
|
7
11
|
* Lazy load FilePond and all plugins
|
|
@@ -34,10 +38,29 @@ export class SallaFileUpload {
|
|
|
34
38
|
constructor() {
|
|
35
39
|
this.filePondLoaded = false;
|
|
36
40
|
this.max_images_count = (count) => salla.lang.get('common.uploader.max_images_count', { count });
|
|
41
|
+
this.max_videos_count = (count) => salla.lang.get('common.uploader.max_videos_count', { count });
|
|
37
42
|
this.max_count_hint = (count) => salla.lang.get('common.uploader.max_count_hint', { count });
|
|
43
|
+
this.video_too_large = (size) => salla.lang.get('common.uploader.video_too_large', { size });
|
|
44
|
+
this.video_too_long = (duration) => salla.lang.get('common.uploader.video_too_long', { duration });
|
|
38
45
|
this.uploadedFiles = [];
|
|
39
46
|
this.isListScrollerListenerAdded = false;
|
|
40
47
|
this.showMaxCountHint = false;
|
|
48
|
+
this.previewFiles = [];
|
|
49
|
+
this.maxFilesNotified = false;
|
|
50
|
+
this.validationRejectedFileIds = new Set();
|
|
51
|
+
this.previewFilesSyncRaf = null;
|
|
52
|
+
/**
|
|
53
|
+
* Transient reservations for files currently passing add-validation, keyed by
|
|
54
|
+
* FilePond file id. FilePond runs beforeAddFile async and only inserts a file
|
|
55
|
+
* into `getFiles()` after validation resolves, so a batch of parallel picks
|
|
56
|
+
* would race if we counted the pond alone. We reserve a slot here synchronously
|
|
57
|
+
* for the in-flight window and always release it in `onaddfile` (once the file
|
|
58
|
+
* is committed to the pond and counted from there). Because committed files are
|
|
59
|
+
* always counted from `getFiles()` — never from this map — it cannot drift and
|
|
60
|
+
* "stick" the uploader at its limit across delete/re-upload cycles.
|
|
61
|
+
*/
|
|
62
|
+
this.inFlightFiles = new Map();
|
|
63
|
+
this.previewObjectUrls = new Map();
|
|
41
64
|
/**
|
|
42
65
|
* Set the component to be profile image uploader with a preview and a circular shape
|
|
43
66
|
*/
|
|
@@ -66,6 +89,10 @@ export class SallaFileUpload {
|
|
|
66
89
|
* Enable or disable file browser
|
|
67
90
|
*/
|
|
68
91
|
this.allowBrowse = true;
|
|
92
|
+
/**
|
|
93
|
+
* Enable the custom gallery preview instead of FilePond thumbnails.
|
|
94
|
+
*/
|
|
95
|
+
this.enableGallery = false;
|
|
69
96
|
/**
|
|
70
97
|
* Allow drop to replace a file, only works when allowMultiple is false
|
|
71
98
|
*/
|
|
@@ -83,7 +110,8 @@ export class SallaFileUpload {
|
|
|
83
110
|
*/
|
|
84
111
|
this.allowImagePreview = true;
|
|
85
112
|
/**
|
|
86
|
-
* Fixed image preview height, overrides min and max preview height
|
|
113
|
+
* Fixed image preview height, overrides min and max preview height.
|
|
114
|
+
* Also sets the gallery thumbnail size when using the swiper preview (default: 75px).
|
|
87
115
|
*/
|
|
88
116
|
this.imagePreviewHeight = null;
|
|
89
117
|
/**
|
|
@@ -151,8 +179,9 @@ export class SallaFileUpload {
|
|
|
151
179
|
*/
|
|
152
180
|
this.iconUndo = '<svg>...</svg>';
|
|
153
181
|
this.openFileBrowser = () => {
|
|
154
|
-
this.filepond
|
|
182
|
+
this.filepond?.browse();
|
|
155
183
|
};
|
|
184
|
+
this.usesGalleryPreview = () => this.enableGallery;
|
|
156
185
|
//if cartItemIdIsPassed, we need to set the url
|
|
157
186
|
if (!this.url && this.cartItemId) {
|
|
158
187
|
this.url = salla.cart.getUploadImageEndpoint();
|
|
@@ -192,13 +221,22 @@ export class SallaFileUpload {
|
|
|
192
221
|
});
|
|
193
222
|
};
|
|
194
223
|
const setTranslations = async () => {
|
|
195
|
-
await setNestedAsync('ar.trans', 'common.uploader.max_images_count', '
|
|
224
|
+
await setNestedAsync('ar.trans', 'common.uploader.max_images_count', 'أضف :count صور كحد أقصى');
|
|
196
225
|
await setNestedAsync('en.trans', 'common.uploader.max_images_count', 'Add up to :count images maximum.');
|
|
197
226
|
await setNestedAsync('ar.trans', 'common.uploader.max_count_hint', 'يمكنك رفع حتى :count صور');
|
|
198
227
|
await setNestedAsync('en.trans', 'common.uploader.max_count_hint', 'You can upload up to :count images.');
|
|
228
|
+
await setNestedAsync('ar.trans', 'common.uploader.max_videos_count', 'أضف :count فيديوهات كحد أقصى');
|
|
229
|
+
await setNestedAsync('en.trans', 'common.uploader.max_videos_count', 'Add up to :count videos maximum.');
|
|
230
|
+
await setNestedAsync('ar.trans', 'common.uploader.video_too_large', 'حجم الفيديو يتجاوز الحد المسموح (:size)');
|
|
231
|
+
await setNestedAsync('en.trans', 'common.uploader.video_too_large', 'Video size exceeds the allowed limit (:size)');
|
|
232
|
+
await setNestedAsync('ar.trans', 'common.uploader.video_too_long', 'مدة الفيديو تتجاوز الحد المسموح (:duration)');
|
|
233
|
+
await setNestedAsync('en.trans', 'common.uploader.video_too_long', 'Video duration exceeds the allowed limit (:duration)');
|
|
199
234
|
};
|
|
200
235
|
this.max_count_hint = (count) => salla.lang.get('common.uploader.max_count_hint', { count });
|
|
201
236
|
this.max_images_count = (count) => salla.lang.get('common.uploader.max_images_count', { count });
|
|
237
|
+
this.max_videos_count = (count) => salla.lang.get('common.uploader.max_videos_count', { count });
|
|
238
|
+
this.video_too_large = (size) => salla.lang.get('common.uploader.video_too_large', { size });
|
|
239
|
+
this.video_too_long = (duration) => salla.lang.get('common.uploader.video_too_long', { duration });
|
|
202
240
|
setTranslations();
|
|
203
241
|
});
|
|
204
242
|
}
|
|
@@ -220,13 +258,23 @@ export class SallaFileUpload {
|
|
|
220
258
|
}
|
|
221
259
|
uploadedHandler() {
|
|
222
260
|
let fileInput = this.getFormDataFileInput();
|
|
261
|
+
const hiddenValue = this.getHiddenInputValue();
|
|
223
262
|
fileInput.type = 'hidden';
|
|
224
|
-
fileInput.value =
|
|
225
|
-
this.hiddenInput.value =
|
|
263
|
+
fileInput.value = hiddenValue;
|
|
264
|
+
this.hiddenInput.value = hiddenValue;
|
|
226
265
|
fileInput.dispatchEvent(new window.Event('change', { bubbles: true }));
|
|
227
266
|
return this.uploaded.emit(this.value);
|
|
228
267
|
}
|
|
229
|
-
|
|
268
|
+
emitRemovedFile(deletedFile) {
|
|
269
|
+
const removedId = deletedFile.getMetadata('id') ||
|
|
270
|
+
deletedFile.getMetadata('url') ||
|
|
271
|
+
deletedFile.serverId ||
|
|
272
|
+
deletedFile.id;
|
|
273
|
+
return this.removed.emit(removedId);
|
|
274
|
+
}
|
|
275
|
+
removedHandler(deletedFile, options = {}) {
|
|
276
|
+
this.releaseAcceptedFile(deletedFile.id);
|
|
277
|
+
this.releasePreviewObjectUrl(deletedFile.id);
|
|
230
278
|
let fileInput = this.getFormDataFileInput();
|
|
231
279
|
fileInput.type = 'hidden';
|
|
232
280
|
fileInput.value = '';
|
|
@@ -237,10 +285,13 @@ export class SallaFileUpload {
|
|
|
237
285
|
if (this.height) {
|
|
238
286
|
setTimeout(() => this.host.querySelector('.filepond--root').style.height = this.height, 1000);
|
|
239
287
|
}
|
|
240
|
-
this.
|
|
288
|
+
if (!this.usesGalleryPreview()) {
|
|
289
|
+
this.hiddenInput.value = '';
|
|
290
|
+
}
|
|
241
291
|
fileInput.dispatchEvent(new window.Event('change', { bubbles: true }));
|
|
242
|
-
|
|
243
|
-
|
|
292
|
+
if (!options.skipEmit) {
|
|
293
|
+
this.emitRemovedFile(deletedFile);
|
|
294
|
+
}
|
|
244
295
|
}
|
|
245
296
|
/**
|
|
246
297
|
* Method to set option for filepond
|
|
@@ -248,6 +299,12 @@ export class SallaFileUpload {
|
|
|
248
299
|
async setOption(key, value) {
|
|
249
300
|
this.filepond[key] = value;
|
|
250
301
|
}
|
|
302
|
+
generateUploadFileId() {
|
|
303
|
+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
304
|
+
return `${this.host.id}-${crypto.randomUUID()}`;
|
|
305
|
+
}
|
|
306
|
+
return `${this.host.id}-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
307
|
+
}
|
|
251
308
|
getLabel() {
|
|
252
309
|
if (this.labelIdle) {
|
|
253
310
|
//some times we are passing label before translations is loaded, so here we will make sure that all translations are translated
|
|
@@ -270,6 +327,514 @@ export class SallaFileUpload {
|
|
|
270
327
|
getFormDataFileInput() {
|
|
271
328
|
return this.host.querySelector('.filepond--data input');
|
|
272
329
|
}
|
|
330
|
+
isValidPreviewUrl(url) {
|
|
331
|
+
return typeof url === 'string' && (url.startsWith('http') ||
|
|
332
|
+
url.startsWith('blob:') ||
|
|
333
|
+
url.startsWith('data:') ||
|
|
334
|
+
url.startsWith('/'));
|
|
335
|
+
}
|
|
336
|
+
getHiddenInputValue() {
|
|
337
|
+
if (this.usesGalleryPreview()) {
|
|
338
|
+
return this.previewFiles.map(file => file.url).join(',');
|
|
339
|
+
}
|
|
340
|
+
if (typeof this.value === 'object' && this.value?.url) {
|
|
341
|
+
return this.value.url;
|
|
342
|
+
}
|
|
343
|
+
return this.value || '';
|
|
344
|
+
}
|
|
345
|
+
usesSplitCountLimits() {
|
|
346
|
+
return usesSplitCountLimits(this.maxImagesCount, this.maxVideosCount);
|
|
347
|
+
}
|
|
348
|
+
hasImageLimit() {
|
|
349
|
+
return this.maxImagesCount != null;
|
|
350
|
+
}
|
|
351
|
+
hasVideoLimit() {
|
|
352
|
+
return this.maxVideosCount != null;
|
|
353
|
+
}
|
|
354
|
+
getMaxImagesCount() {
|
|
355
|
+
return getMaxImagesCount(this.maxImagesCount);
|
|
356
|
+
}
|
|
357
|
+
getMaxVideosCount() {
|
|
358
|
+
return getMaxVideosCount(this.maxVideosCount);
|
|
359
|
+
}
|
|
360
|
+
getTotalMaxFiles() {
|
|
361
|
+
return getTotalMaxFiles(this.maxFilesCount, this.maxImagesCount, this.maxVideosCount);
|
|
362
|
+
}
|
|
363
|
+
getImageMaxFileSizeString() {
|
|
364
|
+
const storeSize = salla.config.get('store.settings.upload_size');
|
|
365
|
+
if (storeSize)
|
|
366
|
+
return `${storeSize}KB`;
|
|
367
|
+
return this.maxFileSize;
|
|
368
|
+
}
|
|
369
|
+
getImageMaxFileSizeBytes() {
|
|
370
|
+
const size = this.getImageMaxFileSizeString();
|
|
371
|
+
return size ? parseSizeToBytes(size) : null;
|
|
372
|
+
}
|
|
373
|
+
getVideoMaxFileSizeBytes() {
|
|
374
|
+
if (this.maxVideoFileSize)
|
|
375
|
+
return parseSizeToBytes(this.maxVideoFileSize);
|
|
376
|
+
return this.getImageMaxFileSizeBytes();
|
|
377
|
+
}
|
|
378
|
+
getFilePondMaxFileSizeValue() {
|
|
379
|
+
return getFilePondMaxFileSize(this.maxFileSize, salla.config.get('store.settings.upload_size'), this.maxVideoFileSize);
|
|
380
|
+
}
|
|
381
|
+
getFileMimeType(file) {
|
|
382
|
+
if (file instanceof File) {
|
|
383
|
+
return file.type;
|
|
384
|
+
}
|
|
385
|
+
return file.mimeType;
|
|
386
|
+
}
|
|
387
|
+
getFileUrlOrName(file) {
|
|
388
|
+
if (file instanceof File) {
|
|
389
|
+
return file.name;
|
|
390
|
+
}
|
|
391
|
+
return file.url;
|
|
392
|
+
}
|
|
393
|
+
isVideoFile(file) {
|
|
394
|
+
return isVideoMimeType(this.getFileMimeType(file), this.getFileUrlOrName(file));
|
|
395
|
+
}
|
|
396
|
+
getPondItemNameOrUrl(item) {
|
|
397
|
+
const file = item.file;
|
|
398
|
+
// Pre-loaded (local) files may not have a populated File object yet, so fall
|
|
399
|
+
// back to metadata url/name for reliable type detection.
|
|
400
|
+
return (file?.name ||
|
|
401
|
+
item.getMetadata?.('url') ||
|
|
402
|
+
item.getMetadata?.('name') ||
|
|
403
|
+
item.getMetadata?.('poster'));
|
|
404
|
+
}
|
|
405
|
+
isVideoFileFromPond(item) {
|
|
406
|
+
const file = item.file;
|
|
407
|
+
return isVideoMimeType(file?.type || item.fileType, this.getPondItemNameOrUrl(item));
|
|
408
|
+
}
|
|
409
|
+
isImageFileFromPond(item) {
|
|
410
|
+
const file = item.file;
|
|
411
|
+
return isImageMimeType(file?.type || item.fileType, this.getPondItemNameOrUrl(item));
|
|
412
|
+
}
|
|
413
|
+
getFileTypeCategory(item) {
|
|
414
|
+
if (this.isVideoFileFromPond(item))
|
|
415
|
+
return 'video';
|
|
416
|
+
if (this.isImageFileFromPond(item))
|
|
417
|
+
return 'image';
|
|
418
|
+
return 'other';
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Effective count for a type = files committed to the pond + still-in-flight
|
|
422
|
+
* reservations that are not yet in the pond. Committed files come straight from
|
|
423
|
+
* `getFiles()` (the source of truth), so this self-heals after deletes and can
|
|
424
|
+
* never leave the uploader stuck at its limit.
|
|
425
|
+
*/
|
|
426
|
+
countAcceptedByType(type, excludeId) {
|
|
427
|
+
const pondItems = this.getCountableGalleryItems();
|
|
428
|
+
const pondIds = new Set(pondItems.map(item => item.id));
|
|
429
|
+
let count = pondItems.filter(item => item.id !== excludeId && this.getFileTypeCategory(item) === type).length;
|
|
430
|
+
this.inFlightFiles.forEach((value, id) => {
|
|
431
|
+
if (value === type && id !== excludeId && !pondIds.has(id))
|
|
432
|
+
count += 1;
|
|
433
|
+
});
|
|
434
|
+
return count;
|
|
435
|
+
}
|
|
436
|
+
/** Effective total across all types (committed pond files + in-flight reservations). */
|
|
437
|
+
countAcceptedTotal(excludeId) {
|
|
438
|
+
const pondItems = this.getCountableGalleryItems().filter(item => item.id !== excludeId);
|
|
439
|
+
const pondIds = new Set(pondItems.map(item => item.id));
|
|
440
|
+
let count = pondItems.length;
|
|
441
|
+
this.inFlightFiles.forEach((_value, id) => {
|
|
442
|
+
if (id !== excludeId && !pondIds.has(id))
|
|
443
|
+
count += 1;
|
|
444
|
+
});
|
|
445
|
+
return count;
|
|
446
|
+
}
|
|
447
|
+
reserveAcceptedFile(id, type) {
|
|
448
|
+
this.inFlightFiles.set(id, type);
|
|
449
|
+
}
|
|
450
|
+
releaseAcceptedFile(id) {
|
|
451
|
+
this.inFlightFiles.delete(id);
|
|
452
|
+
}
|
|
453
|
+
getVideoDuration(file) {
|
|
454
|
+
return new Promise((resolve, reject) => {
|
|
455
|
+
const video = document.createElement('video');
|
|
456
|
+
video.preload = 'metadata';
|
|
457
|
+
const url = URL.createObjectURL(file);
|
|
458
|
+
let settled = false;
|
|
459
|
+
const cleanup = () => {
|
|
460
|
+
clearTimeout(timeoutId);
|
|
461
|
+
video.onloadedmetadata = null;
|
|
462
|
+
video.onerror = null;
|
|
463
|
+
video.removeAttribute('src');
|
|
464
|
+
video.load();
|
|
465
|
+
URL.revokeObjectURL(url);
|
|
466
|
+
};
|
|
467
|
+
const finish = (duration, error) => {
|
|
468
|
+
if (settled) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
settled = true;
|
|
472
|
+
cleanup();
|
|
473
|
+
if (error) {
|
|
474
|
+
reject(error);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
resolve(duration ?? 0);
|
|
478
|
+
};
|
|
479
|
+
const timeoutId = window.setTimeout(() => {
|
|
480
|
+
finish(undefined, new Error('Timed out loading video metadata'));
|
|
481
|
+
}, VIDEO_METADATA_TIMEOUT_MS);
|
|
482
|
+
video.onloadedmetadata = () => {
|
|
483
|
+
finish(video.duration);
|
|
484
|
+
};
|
|
485
|
+
video.onerror = () => {
|
|
486
|
+
finish(undefined, new Error('Failed to load video metadata'));
|
|
487
|
+
};
|
|
488
|
+
video.src = url;
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
notifyMaxImagesLimit() {
|
|
492
|
+
if (this.maxFilesNotified)
|
|
493
|
+
return;
|
|
494
|
+
this.maxFilesNotified = true;
|
|
495
|
+
salla.notify.error(this.max_images_count(this.getMaxImagesCount()));
|
|
496
|
+
setTimeout(() => {
|
|
497
|
+
this.maxFilesNotified = false;
|
|
498
|
+
}, 500);
|
|
499
|
+
}
|
|
500
|
+
notifyMaxVideosLimit() {
|
|
501
|
+
if (this.maxFilesNotified)
|
|
502
|
+
return;
|
|
503
|
+
this.maxFilesNotified = true;
|
|
504
|
+
salla.notify.error(this.max_videos_count(this.getMaxVideosCount()));
|
|
505
|
+
setTimeout(() => {
|
|
506
|
+
this.maxFilesNotified = false;
|
|
507
|
+
}, 500);
|
|
508
|
+
}
|
|
509
|
+
notifyMaxFilesLimit() {
|
|
510
|
+
if (this.maxFilesNotified)
|
|
511
|
+
return;
|
|
512
|
+
this.maxFilesNotified = true;
|
|
513
|
+
if (this.usesSplitCountLimits() && this.hasImageLimit()) {
|
|
514
|
+
salla.notify.error(this.max_images_count(this.getMaxImagesCount()));
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
salla.notify.error(this.max_images_count(this.maxFilesCount));
|
|
518
|
+
}
|
|
519
|
+
setTimeout(() => {
|
|
520
|
+
this.maxFilesNotified = false;
|
|
521
|
+
}, 500);
|
|
522
|
+
}
|
|
523
|
+
markValidationRejected(fileId) {
|
|
524
|
+
this.validationRejectedFileIds.add(fileId);
|
|
525
|
+
window.setTimeout(() => this.validationRejectedFileIds.delete(fileId), 1000);
|
|
526
|
+
}
|
|
527
|
+
getUploadErrorMessageForFile(error, file) {
|
|
528
|
+
const fileType = file ? this.getFileTypeCategory(file) : 'other';
|
|
529
|
+
const maxVideoBytes = this.getVideoMaxFileSizeBytes();
|
|
530
|
+
return getUploadErrorMessage(error, {
|
|
531
|
+
isVideo: fileType === 'video',
|
|
532
|
+
maxVideoFileSizeLabel: this.maxVideoFileSize,
|
|
533
|
+
maxVideoBytes: maxVideoBytes,
|
|
534
|
+
tooLargeLabel: salla.lang.get('common.uploader.too_large'),
|
|
535
|
+
invalidTypeLabel: salla.lang.get('common.uploader.invalid_type'),
|
|
536
|
+
genericErrorLabel: salla.lang.get('common.errors.error_occurred'),
|
|
537
|
+
videoTooLarge: (size) => this.video_too_large(size || formatBytesAsSize(maxVideoBytes || 0)),
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
notifyUploadError(error, file) {
|
|
541
|
+
salla.notify?.error?.(this.getUploadErrorMessageForFile(error, file));
|
|
542
|
+
}
|
|
543
|
+
removeFailedFile(file) {
|
|
544
|
+
if (!this.filepond?.getFiles().some(pondFile => pondFile.id === file.id)) {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
this.filepond.removeFile(file.id, { revert: false });
|
|
548
|
+
}
|
|
549
|
+
async validateBeforeAddFile(item) {
|
|
550
|
+
const file = item.file instanceof Blob ? item.file : undefined;
|
|
551
|
+
const fileType = this.getFileTypeCategory(item);
|
|
552
|
+
if (this.usesSplitCountLimits()) {
|
|
553
|
+
if (fileType === 'other') {
|
|
554
|
+
salla.notify.error(salla.lang.get('common.uploader.invalid_type'));
|
|
555
|
+
this.markValidationRejected(item.id);
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
if (fileType === 'image' && !this.hasImageLimit()) {
|
|
559
|
+
salla.notify.error(salla.lang.get('common.uploader.invalid_type'));
|
|
560
|
+
this.markValidationRejected(item.id);
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
if (fileType === 'video' && !this.hasVideoLimit()) {
|
|
564
|
+
salla.notify.error(salla.lang.get('common.uploader.invalid_type'));
|
|
565
|
+
this.markValidationRejected(item.id);
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
const maxForType = fileType === 'video' ? this.getMaxVideosCount() : this.getMaxImagesCount();
|
|
569
|
+
if (this.countAcceptedByType(fileType, item.id) >= maxForType) {
|
|
570
|
+
if (fileType === 'video') {
|
|
571
|
+
this.notifyMaxVideosLimit();
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
this.notifyMaxImagesLimit();
|
|
575
|
+
}
|
|
576
|
+
this.markValidationRejected(item.id);
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
if (this.countAcceptedTotal(item.id) >= this.maxFilesCount) {
|
|
582
|
+
this.notifyMaxFilesLimit();
|
|
583
|
+
this.markValidationRejected(item.id);
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
// Reserve the slot synchronously so parallel batch adds can't exceed the limit.
|
|
588
|
+
this.reserveAcceptedFile(item.id, fileType);
|
|
589
|
+
// Pre-loaded local files (edit mode) may not have a Blob yet; metadata is enough.
|
|
590
|
+
if (!file) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
if (fileType === 'video') {
|
|
594
|
+
const maxSize = this.getVideoMaxFileSizeBytes();
|
|
595
|
+
if (maxSize && file.size > maxSize) {
|
|
596
|
+
salla.notify.error(this.video_too_large(this.maxVideoFileSize || formatBytesAsSize(maxSize)));
|
|
597
|
+
this.releaseAcceptedFile(item.id);
|
|
598
|
+
this.markValidationRejected(item.id);
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
if (this.maxVideoDuration) {
|
|
602
|
+
try {
|
|
603
|
+
const duration = await this.getVideoDuration(file);
|
|
604
|
+
if (duration > this.maxVideoDuration) {
|
|
605
|
+
salla.notify.error(this.video_too_long(formatDuration(this.maxVideoDuration)));
|
|
606
|
+
this.releaseAcceptedFile(item.id);
|
|
607
|
+
this.markValidationRejected(item.id);
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
catch {
|
|
612
|
+
salla.notify.error(salla.lang.get('common.uploader.failed_to_load'));
|
|
613
|
+
this.releaseAcceptedFile(item.id);
|
|
614
|
+
this.markValidationRejected(item.id);
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
else if (fileType === 'image') {
|
|
620
|
+
const maxSize = this.getImageMaxFileSizeBytes();
|
|
621
|
+
if (maxSize && file.size > maxSize) {
|
|
622
|
+
salla.notify.error(salla.lang.get('common.uploader.too_large'));
|
|
623
|
+
this.releaseAcceptedFile(item.id);
|
|
624
|
+
this.markValidationRejected(item.id);
|
|
625
|
+
return false;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
else if (this.usesSplitCountLimits()) {
|
|
629
|
+
salla.notify.error(salla.lang.get('common.uploader.invalid_type'));
|
|
630
|
+
this.releaseAcceptedFile(item.id);
|
|
631
|
+
this.markValidationRejected(item.id);
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
renderGalleryThumb(file) {
|
|
637
|
+
if (this.isVideoFile(file)) {
|
|
638
|
+
return [
|
|
639
|
+
h("video", { class: "s-file-upload-gallery-video-thumb", src: file.url, muted: true, playsInline: true, preload: "metadata" }),
|
|
640
|
+
h("span", { class: "s-file-upload-gallery-video-icon", innerHTML: PlayIcon }),
|
|
641
|
+
];
|
|
642
|
+
}
|
|
643
|
+
return h("img", { src: file.url, alt: "", loading: "lazy" });
|
|
644
|
+
}
|
|
645
|
+
releasePreviewObjectUrl(fileId) {
|
|
646
|
+
const url = this.previewObjectUrls.get(fileId);
|
|
647
|
+
if (!url)
|
|
648
|
+
return;
|
|
649
|
+
URL.revokeObjectURL(url);
|
|
650
|
+
this.previewObjectUrls.delete(fileId);
|
|
651
|
+
}
|
|
652
|
+
prunePreviewObjectUrls(activeFileIds) {
|
|
653
|
+
[...this.previewObjectUrls.keys()].forEach(id => {
|
|
654
|
+
if (!activeFileIds.has(id)) {
|
|
655
|
+
this.releasePreviewObjectUrl(id);
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
revokeAllPreviewObjectUrls() {
|
|
660
|
+
[...this.previewObjectUrls.keys()].forEach(id => this.releasePreviewObjectUrl(id));
|
|
661
|
+
}
|
|
662
|
+
getFilePreviewUrl(item) {
|
|
663
|
+
const fromMeta = item.getMetadata('url') || item.getMetadata('poster');
|
|
664
|
+
if (this.isValidPreviewUrl(fromMeta)) {
|
|
665
|
+
this.releasePreviewObjectUrl(item.id);
|
|
666
|
+
return fromMeta;
|
|
667
|
+
}
|
|
668
|
+
const uploaded = this.uploadedFiles.find(file => file.id === item.serverId || file.id === item.getMetadata('id'));
|
|
669
|
+
if (uploaded?.url) {
|
|
670
|
+
this.releasePreviewObjectUrl(item.id);
|
|
671
|
+
return uploaded.url;
|
|
672
|
+
}
|
|
673
|
+
const file = item.file;
|
|
674
|
+
if (file instanceof Blob) {
|
|
675
|
+
const existing = this.previewObjectUrls.get(item.id);
|
|
676
|
+
if (existing)
|
|
677
|
+
return existing;
|
|
678
|
+
const url = URL.createObjectURL(file);
|
|
679
|
+
this.previewObjectUrls.set(item.id, url);
|
|
680
|
+
return url;
|
|
681
|
+
}
|
|
682
|
+
return '';
|
|
683
|
+
}
|
|
684
|
+
isFileUploading(item) {
|
|
685
|
+
return item.status === 3 || item.status === 7 || item.status === 9;
|
|
686
|
+
}
|
|
687
|
+
getPreviewGalleryItems() {
|
|
688
|
+
return (this.filepond?.getFiles() || []).filter(item => shouldCountGalleryFile(item.status));
|
|
689
|
+
}
|
|
690
|
+
getCountableGalleryItems() {
|
|
691
|
+
return (this.filepond?.getFiles() || []).filter(item => shouldCountGalleryLimit(item.status));
|
|
692
|
+
}
|
|
693
|
+
schedulePreviewFilesSync() {
|
|
694
|
+
if (!this.usesGalleryPreview())
|
|
695
|
+
return;
|
|
696
|
+
if (this.previewFilesSyncRaf != null) {
|
|
697
|
+
cancelAnimationFrame(this.previewFilesSyncRaf);
|
|
698
|
+
}
|
|
699
|
+
this.previewFilesSyncRaf = requestAnimationFrame(() => {
|
|
700
|
+
this.previewFilesSyncRaf = requestAnimationFrame(() => {
|
|
701
|
+
this.previewFilesSyncRaf = null;
|
|
702
|
+
this.syncPreviewFiles();
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
mapItemsToPreviewFiles(items) {
|
|
707
|
+
return items.map(item => ({
|
|
708
|
+
id: String(item.getMetadata('id') || item.serverId || item.id),
|
|
709
|
+
url: this.getFilePreviewUrl(item),
|
|
710
|
+
mimeType: item.file?.type || item.fileType,
|
|
711
|
+
processing: this.isFileUploading(item),
|
|
712
|
+
})).filter(file => file.url);
|
|
713
|
+
}
|
|
714
|
+
emitGalleryCounts(items) {
|
|
715
|
+
// Derive display counts from the settled pond items. This runs deferred
|
|
716
|
+
// (schedulePreviewFilesSync), so batch-rejected/over-limit files are already
|
|
717
|
+
// gone and the numbers always match what is actually on screen. Admission is
|
|
718
|
+
// guarded synchronously by the in-flight reservations in validateBeforeAddFile,
|
|
719
|
+
// so the pond never exceeds the configured limits — counting it here always
|
|
720
|
+
// reflects the real state (e.g. after deletes) instead of a stale number.
|
|
721
|
+
let imageCount = 0;
|
|
722
|
+
let videoCount = 0;
|
|
723
|
+
items.forEach(item => {
|
|
724
|
+
const type = this.getFileTypeCategory(item);
|
|
725
|
+
if (type === 'video')
|
|
726
|
+
videoCount += 1;
|
|
727
|
+
else if (type === 'image')
|
|
728
|
+
imageCount += 1;
|
|
729
|
+
});
|
|
730
|
+
let count = items.length;
|
|
731
|
+
if (this.hasImageLimit()) {
|
|
732
|
+
imageCount = Math.min(imageCount, this.getMaxImagesCount());
|
|
733
|
+
}
|
|
734
|
+
if (this.hasVideoLimit()) {
|
|
735
|
+
videoCount = Math.min(videoCount, this.getMaxVideosCount());
|
|
736
|
+
}
|
|
737
|
+
if (this.usesSplitCountLimits()) {
|
|
738
|
+
count = Math.min(count, this.getTotalMaxFiles());
|
|
739
|
+
}
|
|
740
|
+
const uploading = items.some(item => this.isFileUploading(item));
|
|
741
|
+
this.galleryUpdated.emit({
|
|
742
|
+
count,
|
|
743
|
+
imageCount,
|
|
744
|
+
videoCount,
|
|
745
|
+
uploading,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
syncPreviewFiles() {
|
|
749
|
+
if (!this.usesGalleryPreview())
|
|
750
|
+
return;
|
|
751
|
+
const previewItems = this.getPreviewGalleryItems();
|
|
752
|
+
this.previewFiles = this.mapItemsToPreviewFiles(previewItems);
|
|
753
|
+
this.prunePreviewObjectUrls(new Set(previewItems.map(item => item.id)));
|
|
754
|
+
this.emitGalleryCounts(this.getCountableGalleryItems());
|
|
755
|
+
if (this.hiddenInput) {
|
|
756
|
+
this.hiddenInput.value = this.getHiddenInputValue();
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
enforceDropLabelVisibility(fileCount) {
|
|
760
|
+
if (!this.usesGalleryPreview())
|
|
761
|
+
return;
|
|
762
|
+
const dropLabel = this.host.querySelector('.filepond--drop-label');
|
|
763
|
+
if (!dropLabel)
|
|
764
|
+
return;
|
|
765
|
+
const imageCount = this.countAcceptedByType('image');
|
|
766
|
+
const videoCount = this.countAcceptedByType('video');
|
|
767
|
+
let isMaxReached = false;
|
|
768
|
+
if (this.usesSplitCountLimits()) {
|
|
769
|
+
const imagesBlocked = this.hasImageLimit() && imageCount >= this.getMaxImagesCount();
|
|
770
|
+
const videosBlocked = this.hasVideoLimit() && videoCount >= this.getMaxVideosCount();
|
|
771
|
+
if (this.hasImageLimit() && this.hasVideoLimit()) {
|
|
772
|
+
isMaxReached = imagesBlocked && videosBlocked;
|
|
773
|
+
}
|
|
774
|
+
else if (this.hasImageLimit()) {
|
|
775
|
+
isMaxReached = imagesBlocked;
|
|
776
|
+
}
|
|
777
|
+
else if (this.hasVideoLimit()) {
|
|
778
|
+
isMaxReached = videosBlocked;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
isMaxReached = (fileCount ?? this.countAcceptedTotal()) >= this.maxFilesCount;
|
|
783
|
+
}
|
|
784
|
+
this.host.classList.toggle('s-file-upload-at-max', isMaxReached);
|
|
785
|
+
dropLabel.classList.toggle('s-file-upload-drop-label-disabled', isMaxReached);
|
|
786
|
+
dropLabel.classList.remove('s-hidden');
|
|
787
|
+
if (isMaxReached) {
|
|
788
|
+
dropLabel.style.setProperty('opacity', '0.55', 'important');
|
|
789
|
+
dropLabel.style.setProperty('visibility', 'visible', 'important');
|
|
790
|
+
dropLabel.style.setProperty('transform', 'none', 'important');
|
|
791
|
+
dropLabel.style.setProperty('height', 'auto', 'important');
|
|
792
|
+
dropLabel.style.setProperty('min-height', '4.75em', 'important');
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
['opacity', 'visibility', 'transform', 'height', 'min-height'].forEach(prop => {
|
|
796
|
+
dropLabel.style.removeProperty(prop);
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
scheduleDropLabelVisibilityEnforcement(fileCount) {
|
|
800
|
+
this.enforceDropLabelVisibility(fileCount);
|
|
801
|
+
requestAnimationFrame(() => this.enforceDropLabelVisibility(fileCount));
|
|
802
|
+
setTimeout(() => this.enforceDropLabelVisibility(fileCount), 200);
|
|
803
|
+
}
|
|
804
|
+
removePreviewFile(event, fileId) {
|
|
805
|
+
event.stopPropagation();
|
|
806
|
+
const pondFile = this.filepond?.getFiles().find(file => String(file.getMetadata('id')) === String(fileId) || file.id === fileId);
|
|
807
|
+
if (pondFile) {
|
|
808
|
+
this.filepond.removeFile(pondFile.id);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
openPreview(index) {
|
|
812
|
+
const file = this.previewFiles[index];
|
|
813
|
+
if (!file || file.processing)
|
|
814
|
+
return;
|
|
815
|
+
this.attachmentView?.open(index);
|
|
816
|
+
}
|
|
817
|
+
getGalleryThumbSize() {
|
|
818
|
+
return this.imagePreviewHeight || 75;
|
|
819
|
+
}
|
|
820
|
+
getGalleryStyles() {
|
|
821
|
+
const size = this.getGalleryThumbSize();
|
|
822
|
+
return {
|
|
823
|
+
'--s-file-upload-preview-size': `${size}px`,
|
|
824
|
+
'--s-file-upload-remove-size': `${Math.max(18, Math.round(size * 0.24))}px`,
|
|
825
|
+
'--s-file-upload-remove-icon-size': `${Math.max(10, Math.round(size * 0.13))}px`,
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
renderPreviewGallery() {
|
|
829
|
+
if (!this.usesGalleryPreview() || !this.previewFiles.length)
|
|
830
|
+
return null;
|
|
831
|
+
const galleryThumbSize = this.getGalleryThumbSize();
|
|
832
|
+
return (h("div", { class: "s-file-upload-gallery", style: this.getGalleryStyles() }, h("div", { class: "s-file-upload-gallery-track s-scrollbar ps-2" }, this.previewFiles.map((file, index) => (h("div", { class: "s-file-upload-gallery-item", key: file.id }, this.allowRemove && (h("button", { type: "button", class: "s-file-upload-gallery-remove", "aria-label": salla.lang.get('common.elements.remove'), onClick: (event) => this.removePreviewFile(event, file.id) }, h("span", { innerHTML: CancelIcon }))), h("div", { class: {
|
|
833
|
+
's-file-upload-gallery-thumb': true,
|
|
834
|
+
'is-processing': file.processing,
|
|
835
|
+
'is-video': this.isVideoFile(file),
|
|
836
|
+
}, onClick: () => this.openPreview(index) }, this.renderGalleryThumb(file), file.processing && h("salla-loading", { size: Math.max(16, Math.round(galleryThumbSize * 0.22)) })))))), this.previewFiles.length > 0 && (h("salla-attachment-view", { ref: el => (this.attachmentView = el), attachments: this.previewFiles }))));
|
|
837
|
+
}
|
|
273
838
|
getFiles() {
|
|
274
839
|
if (!this.value && !this.files) {
|
|
275
840
|
return [];
|
|
@@ -306,12 +871,20 @@ export class SallaFileUpload {
|
|
|
306
871
|
this.host.innerHTML = '';
|
|
307
872
|
}
|
|
308
873
|
}
|
|
874
|
+
disconnectedCallback() {
|
|
875
|
+
if (this.previewFilesSyncRaf != null) {
|
|
876
|
+
cancelAnimationFrame(this.previewFilesSyncRaf);
|
|
877
|
+
this.previewFilesSyncRaf = null;
|
|
878
|
+
}
|
|
879
|
+
this.revokeAllPreviewObjectUrls();
|
|
880
|
+
}
|
|
309
881
|
render() {
|
|
310
|
-
return (h(Host, { key: '
|
|
882
|
+
return (h(Host, { key: '9c9bb99746270f2511bd86344a135d05f9b3cf29', class: {
|
|
311
883
|
"s-file-upload": true,
|
|
312
884
|
"s-file-upload-profile-image": this.profileImage,
|
|
313
885
|
"s-file-upload-multiple": this.allowMultiple,
|
|
314
|
-
|
|
886
|
+
"s-file-upload-has-gallery": this.usesGalleryPreview(),
|
|
887
|
+
} }, h("input", { key: 'd033124b1829ee4b9f0c4d44041a525e73769b77', type: "file", name: this.name, ref: ele => this.fileUploader = ele, required: this.required, class: "s-file-upload-wrapper s-file-upload-input", accept: this.accept }), this.allowMultiple && this.showMaxCountHint ? h("div", { class: "s-file-upload-hint s-hidden" }, this.max_count_hint(this.getTotalMaxFiles())) : '', h("input", { key: '95608637f6b52dabbad4a7374d329549cb6d3862', class: "s-hidden", name: 'hidden-' + this.name, required: this.required, value: this.getHiddenInputValue(), ref: input => this.hiddenInput = input }), this.renderPreviewGallery()));
|
|
315
888
|
}
|
|
316
889
|
async componentDidLoad() {
|
|
317
890
|
await Salla.onReady();
|
|
@@ -320,6 +893,7 @@ export class SallaFileUpload {
|
|
|
320
893
|
this.value = Salla.config.get('user.avatar');
|
|
321
894
|
}
|
|
322
895
|
let files = this.getFiles();
|
|
896
|
+
const filePondMaxFileSize = this.getFilePondMaxFileSizeValue();
|
|
323
897
|
this.filepond = this.FilePond.create(this.fileUploader, {
|
|
324
898
|
name: this.payloadName || this.name,
|
|
325
899
|
//@ts-ignore
|
|
@@ -336,10 +910,13 @@ export class SallaFileUpload {
|
|
|
336
910
|
allowReorder: this.allowReorder,
|
|
337
911
|
storeAsFile: this.storeAsFile,
|
|
338
912
|
forceRevert: this.forceRevert,
|
|
339
|
-
maxFiles
|
|
913
|
+
// FilePond hides the drop label (opacity 0 + height 0) when maxFiles is reached.
|
|
914
|
+
// In gallery mode we enforce the limit ourselves so labels stay visible, dimmed at max.
|
|
915
|
+
maxFiles: this.usesGalleryPreview() ? null : this.getTotalMaxFiles(),
|
|
916
|
+
beforeAddFile: (item) => this.validateBeforeAddFile(item),
|
|
340
917
|
imagePreviewHeight: this.imagePreviewHeight,
|
|
341
918
|
filePosterHeight: this.filePosterHeight,
|
|
342
|
-
allowImagePreview: this.allowImagePreview,
|
|
919
|
+
allowImagePreview: this.usesGalleryPreview() ? false : this.allowImagePreview,
|
|
343
920
|
maxParallelUploads: this.maxParallelUploads,
|
|
344
921
|
checkValidity: this.checkValidity,
|
|
345
922
|
itemInsertLocation: this.itemInsertLocation,
|
|
@@ -349,36 +926,80 @@ export class SallaFileUpload {
|
|
|
349
926
|
dropOnElement: this.dropOnElement,
|
|
350
927
|
dropValidation: this.dropValidation,
|
|
351
928
|
ignoredFiles: this.ignoredFiles,
|
|
352
|
-
onaddfile: (error, file) =>
|
|
929
|
+
onaddfile: (error, file) => {
|
|
930
|
+
// The file is now committed to the pond (or errored out), so it is
|
|
931
|
+
// counted from getFiles() from here on — drop the in-flight reservation
|
|
932
|
+
// either way to keep the map transient and drift-free.
|
|
933
|
+
this.releaseAcceptedFile(file.id);
|
|
934
|
+
if (error) {
|
|
935
|
+
if (!this.validationRejectedFileIds.has(file.id)) {
|
|
936
|
+
this.notifyUploadError(error, file);
|
|
937
|
+
}
|
|
938
|
+
this.validationRejectedFileIds.delete(file.id);
|
|
939
|
+
}
|
|
940
|
+
this.addedHandler(error, file);
|
|
941
|
+
if (this.usesGalleryPreview()) {
|
|
942
|
+
this.schedulePreviewFilesSync();
|
|
943
|
+
}
|
|
944
|
+
},
|
|
353
945
|
onwarning: (error, _file, _status) => {
|
|
354
946
|
if (error.body === "Max files") {
|
|
355
|
-
|
|
947
|
+
this.notifyMaxFilesLimit();
|
|
356
948
|
}
|
|
357
949
|
},
|
|
358
950
|
onprocessfile: (error, file) => {
|
|
951
|
+
if (error) {
|
|
952
|
+
this.notifyUploadError(error, file);
|
|
953
|
+
this.removeFailedFile(file);
|
|
954
|
+
if (this.usesGalleryPreview()) {
|
|
955
|
+
this.schedulePreviewFilesSync();
|
|
956
|
+
}
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
let syncedGallery = false;
|
|
359
960
|
if (this.allowMultiple && !error) {
|
|
360
961
|
// Find the uploaded file data using the serverId returned from onload
|
|
361
962
|
const serverId = file.serverId;
|
|
362
963
|
const uploadedFile = this.uploadedFiles.find(f => f.id === serverId);
|
|
363
964
|
if (uploadedFile) {
|
|
364
|
-
// Set metadata on the file
|
|
365
965
|
file.setMetadata('id', uploadedFile.id, true);
|
|
366
966
|
file.setMetadata('url', uploadedFile.url, true);
|
|
367
967
|
this.value = {
|
|
368
968
|
id: uploadedFile.id,
|
|
369
969
|
url: uploadedFile.url
|
|
370
970
|
};
|
|
971
|
+
if (this.usesGalleryPreview()) {
|
|
972
|
+
this.syncPreviewFiles();
|
|
973
|
+
syncedGallery = true;
|
|
974
|
+
}
|
|
371
975
|
this.uploadedHandler();
|
|
372
976
|
}
|
|
373
977
|
}
|
|
978
|
+
if (this.usesGalleryPreview() && !syncedGallery) {
|
|
979
|
+
this.schedulePreviewFilesSync();
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
onremovefile: (_error, file) => {
|
|
983
|
+
if (this.usesGalleryPreview()) {
|
|
984
|
+
if (file) {
|
|
985
|
+
this.emitRemovedFile(file);
|
|
986
|
+
}
|
|
987
|
+
this.schedulePreviewFilesSync();
|
|
988
|
+
}
|
|
374
989
|
},
|
|
375
990
|
onupdatefiles: (fileItems) => {
|
|
376
991
|
const dropLabel = this.host.querySelector('.filepond--drop-label');
|
|
377
992
|
const listScroller = this.host.querySelector('.filepond--list-scroller');
|
|
993
|
+
if (this.usesGalleryPreview()) {
|
|
994
|
+
listScroller?.classList.add('s-hidden');
|
|
995
|
+
this.scheduleDropLabelVisibilityEnforcement();
|
|
996
|
+
this.schedulePreviewFilesSync();
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
378
999
|
if (this.allowMultiple) {
|
|
379
1000
|
if (fileItems.length > 0) {
|
|
380
1001
|
dropLabel.classList.add('s-hidden');
|
|
381
|
-
if (!this.isListScrollerListenerAdded && fileItems.length < this.
|
|
1002
|
+
if (!this.isListScrollerListenerAdded && fileItems.length < this.getTotalMaxFiles()) {
|
|
382
1003
|
this.showMaxCountHint = true;
|
|
383
1004
|
listScroller.addEventListener('click', this.openFileBrowser);
|
|
384
1005
|
this.isListScrollerListenerAdded = true;
|
|
@@ -391,8 +1012,7 @@ export class SallaFileUpload {
|
|
|
391
1012
|
this.isListScrollerListenerAdded = false;
|
|
392
1013
|
}
|
|
393
1014
|
}
|
|
394
|
-
|
|
395
|
-
if (fileItems.length === this.maxFilesCount && this.isListScrollerListenerAdded) {
|
|
1015
|
+
if (fileItems.length === this.getTotalMaxFiles() && this.isListScrollerListenerAdded) {
|
|
396
1016
|
listScroller.removeEventListener('click', this.openFileBrowser);
|
|
397
1017
|
this.isListScrollerListenerAdded = false;
|
|
398
1018
|
this.showMaxCountHint = false;
|
|
@@ -408,21 +1028,28 @@ export class SallaFileUpload {
|
|
|
408
1028
|
onload: (response) => {
|
|
409
1029
|
let responseData = JSON.parse(response).data;
|
|
410
1030
|
if ((this.instantUpload || this.allowMultiple) && Array.isArray(responseData) && responseData.length > 0) {
|
|
411
|
-
const
|
|
412
|
-
const fileUrl =
|
|
1031
|
+
const item = responseData[0];
|
|
1032
|
+
const fileUrl = typeof item === 'object' && item !== null ? item.filePath || item.url : item;
|
|
1033
|
+
const fileId = this.generateUploadFileId();
|
|
413
1034
|
// Store the upload result to be picked up by onprocessfile
|
|
414
|
-
this.uploadedFiles
|
|
415
|
-
|
|
416
|
-
url: fileUrl
|
|
417
|
-
|
|
1035
|
+
this.uploadedFiles = [
|
|
1036
|
+
...this.uploadedFiles,
|
|
1037
|
+
{ id: fileId, url: fileUrl }
|
|
1038
|
+
];
|
|
418
1039
|
// Return the serverId that FilePond will use to identify this file
|
|
419
1040
|
// We'll use the fileId as the serverId
|
|
420
1041
|
return fileId;
|
|
421
1042
|
}
|
|
422
1043
|
else {
|
|
423
|
-
|
|
1044
|
+
const fileUrl = typeof responseData === 'object' && responseData !== null
|
|
1045
|
+
? responseData.filePath || responseData.url
|
|
1046
|
+
: responseData;
|
|
1047
|
+
const fileId = typeof responseData === 'object' && responseData !== null && responseData.id
|
|
1048
|
+
? responseData.id
|
|
1049
|
+
: this.generateUploadFileId();
|
|
1050
|
+
this.value = { id: fileId, url: fileUrl };
|
|
424
1051
|
this.uploadedHandler();
|
|
425
|
-
return
|
|
1052
|
+
return fileUrl;
|
|
426
1053
|
}
|
|
427
1054
|
},
|
|
428
1055
|
headers: salla.api.getHeaders(),
|
|
@@ -487,13 +1114,19 @@ export class SallaFileUpload {
|
|
|
487
1114
|
fileValidateTypeLabelExpectedTypes: '{allButLastType}, {lastType}',
|
|
488
1115
|
labelMaxFileSizeExceeded: salla.lang.get('common.uploader.too_large'),
|
|
489
1116
|
labelMaxFileSize: '{filesize}',
|
|
490
|
-
maxFileSize:
|
|
1117
|
+
...(filePondMaxFileSize ? { maxFileSize: filePondMaxFileSize } : {}),
|
|
491
1118
|
beforeRemoveFile: (deletedFile) => new Promise((resolve) => {
|
|
492
|
-
this.removedHandler(deletedFile);
|
|
1119
|
+
this.removedHandler(deletedFile, { skipEmit: this.usesGalleryPreview() });
|
|
493
1120
|
resolve(true);
|
|
494
1121
|
}),
|
|
495
1122
|
});
|
|
496
|
-
|
|
1123
|
+
this.syncPreviewFiles();
|
|
1124
|
+
if (this.usesGalleryPreview()) {
|
|
1125
|
+
this.filepond.on('updatefiles', () => {
|
|
1126
|
+
this.scheduleDropLabelVisibilityEnforcement();
|
|
1127
|
+
});
|
|
1128
|
+
this.scheduleDropLabelVisibilityEnforcement();
|
|
1129
|
+
}
|
|
497
1130
|
this.hiddenInput.addEventListener('invalid', e => {
|
|
498
1131
|
this.invalidInput.emit(e);
|
|
499
1132
|
});
|
|
@@ -925,6 +1558,26 @@ export class SallaFileUpload {
|
|
|
925
1558
|
"setter": false,
|
|
926
1559
|
"reflect": false
|
|
927
1560
|
},
|
|
1561
|
+
"enableGallery": {
|
|
1562
|
+
"type": "boolean",
|
|
1563
|
+
"attribute": "enable-gallery",
|
|
1564
|
+
"mutable": false,
|
|
1565
|
+
"complexType": {
|
|
1566
|
+
"original": "boolean",
|
|
1567
|
+
"resolved": "boolean",
|
|
1568
|
+
"references": {}
|
|
1569
|
+
},
|
|
1570
|
+
"required": false,
|
|
1571
|
+
"optional": false,
|
|
1572
|
+
"docs": {
|
|
1573
|
+
"tags": [],
|
|
1574
|
+
"text": "Enable the custom gallery preview instead of FilePond thumbnails."
|
|
1575
|
+
},
|
|
1576
|
+
"getter": false,
|
|
1577
|
+
"setter": false,
|
|
1578
|
+
"reflect": true,
|
|
1579
|
+
"defaultValue": "false"
|
|
1580
|
+
},
|
|
928
1581
|
"allowReplace": {
|
|
929
1582
|
"type": "boolean",
|
|
930
1583
|
"attribute": "allow-replace",
|
|
@@ -1056,7 +1709,7 @@ export class SallaFileUpload {
|
|
|
1056
1709
|
"optional": false,
|
|
1057
1710
|
"docs": {
|
|
1058
1711
|
"tags": [],
|
|
1059
|
-
"text": "Fixed image preview height, overrides min and max preview height"
|
|
1712
|
+
"text": "Fixed image preview height, overrides min and max preview height.\nAlso sets the gallery thumbnail size when using the swiper preview (default: 75px)."
|
|
1060
1713
|
},
|
|
1061
1714
|
"getter": false,
|
|
1062
1715
|
"setter": false,
|
|
@@ -1161,6 +1814,82 @@ export class SallaFileUpload {
|
|
|
1161
1814
|
"reflect": false,
|
|
1162
1815
|
"defaultValue": "3"
|
|
1163
1816
|
},
|
|
1817
|
+
"maxImagesCount": {
|
|
1818
|
+
"type": "number",
|
|
1819
|
+
"attribute": "max-images-count",
|
|
1820
|
+
"mutable": false,
|
|
1821
|
+
"complexType": {
|
|
1822
|
+
"original": "number",
|
|
1823
|
+
"resolved": "number",
|
|
1824
|
+
"references": {}
|
|
1825
|
+
},
|
|
1826
|
+
"required": false,
|
|
1827
|
+
"optional": false,
|
|
1828
|
+
"docs": {
|
|
1829
|
+
"tags": [],
|
|
1830
|
+
"text": "Primary: maximum number of image files (split count mode).\nWhen set with or without maxVideosCount, maxFilesCount is ignored for count limits."
|
|
1831
|
+
},
|
|
1832
|
+
"getter": false,
|
|
1833
|
+
"setter": false,
|
|
1834
|
+
"reflect": false
|
|
1835
|
+
},
|
|
1836
|
+
"maxVideosCount": {
|
|
1837
|
+
"type": "number",
|
|
1838
|
+
"attribute": "max-videos-count",
|
|
1839
|
+
"mutable": false,
|
|
1840
|
+
"complexType": {
|
|
1841
|
+
"original": "number",
|
|
1842
|
+
"resolved": "number",
|
|
1843
|
+
"references": {}
|
|
1844
|
+
},
|
|
1845
|
+
"required": false,
|
|
1846
|
+
"optional": false,
|
|
1847
|
+
"docs": {
|
|
1848
|
+
"tags": [],
|
|
1849
|
+
"text": "Primary: maximum number of video files (split count mode).\nWhen set with or without maxImagesCount, maxFilesCount is ignored for count limits."
|
|
1850
|
+
},
|
|
1851
|
+
"getter": false,
|
|
1852
|
+
"setter": false,
|
|
1853
|
+
"reflect": false
|
|
1854
|
+
},
|
|
1855
|
+
"maxVideoFileSize": {
|
|
1856
|
+
"type": "string",
|
|
1857
|
+
"attribute": "max-video-file-size",
|
|
1858
|
+
"mutable": false,
|
|
1859
|
+
"complexType": {
|
|
1860
|
+
"original": "`${number}MB` | `${number}KB`",
|
|
1861
|
+
"resolved": "`${number}KB` | `${number}MB`",
|
|
1862
|
+
"references": {}
|
|
1863
|
+
},
|
|
1864
|
+
"required": false,
|
|
1865
|
+
"optional": false,
|
|
1866
|
+
"docs": {
|
|
1867
|
+
"tags": [],
|
|
1868
|
+
"text": "Maximum size for video files only, e.g. 50MB or 750KB"
|
|
1869
|
+
},
|
|
1870
|
+
"getter": false,
|
|
1871
|
+
"setter": false,
|
|
1872
|
+
"reflect": false
|
|
1873
|
+
},
|
|
1874
|
+
"maxVideoDuration": {
|
|
1875
|
+
"type": "number",
|
|
1876
|
+
"attribute": "max-video-duration",
|
|
1877
|
+
"mutable": false,
|
|
1878
|
+
"complexType": {
|
|
1879
|
+
"original": "number",
|
|
1880
|
+
"resolved": "number",
|
|
1881
|
+
"references": {}
|
|
1882
|
+
},
|
|
1883
|
+
"required": false,
|
|
1884
|
+
"optional": false,
|
|
1885
|
+
"docs": {
|
|
1886
|
+
"tags": [],
|
|
1887
|
+
"text": "Maximum video duration in seconds"
|
|
1888
|
+
},
|
|
1889
|
+
"getter": false,
|
|
1890
|
+
"setter": false,
|
|
1891
|
+
"reflect": false
|
|
1892
|
+
},
|
|
1164
1893
|
"checkValidity": {
|
|
1165
1894
|
"type": "boolean",
|
|
1166
1895
|
"attribute": "check-validity",
|
|
@@ -1575,10 +2304,14 @@ export class SallaFileUpload {
|
|
|
1575
2304
|
static get states() {
|
|
1576
2305
|
return {
|
|
1577
2306
|
"max_images_count": {},
|
|
2307
|
+
"max_videos_count": {},
|
|
1578
2308
|
"max_count_hint": {},
|
|
2309
|
+
"video_too_large": {},
|
|
2310
|
+
"video_too_long": {},
|
|
1579
2311
|
"uploadedFiles": {},
|
|
1580
2312
|
"isListScrollerListenerAdded": {},
|
|
1581
|
-
"showMaxCountHint": {}
|
|
2313
|
+
"showMaxCountHint": {},
|
|
2314
|
+
"previewFiles": {}
|
|
1582
2315
|
};
|
|
1583
2316
|
}
|
|
1584
2317
|
static get events() {
|
|
@@ -1646,18 +2379,27 @@ export class SallaFileUpload {
|
|
|
1646
2379
|
"composed": true,
|
|
1647
2380
|
"docs": {
|
|
1648
2381
|
"tags": [],
|
|
1649
|
-
"text": "Event emitted when the file is about to be removed. Returns
|
|
2382
|
+
"text": "Event emitted when the file is about to be removed. Returns the removed file id when available."
|
|
1650
2383
|
},
|
|
1651
2384
|
"complexType": {
|
|
1652
|
-
"original": "
|
|
1653
|
-
"resolved": "
|
|
1654
|
-
"references": {
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
2385
|
+
"original": "string | number",
|
|
2386
|
+
"resolved": "number | string",
|
|
2387
|
+
"references": {}
|
|
2388
|
+
}
|
|
2389
|
+
}, {
|
|
2390
|
+
"method": "galleryUpdated",
|
|
2391
|
+
"name": "galleryUpdated",
|
|
2392
|
+
"bubbles": true,
|
|
2393
|
+
"cancelable": true,
|
|
2394
|
+
"composed": true,
|
|
2395
|
+
"docs": {
|
|
2396
|
+
"tags": [],
|
|
2397
|
+
"text": "Event emitted when the gallery preview list changes (upload/remove)."
|
|
2398
|
+
},
|
|
2399
|
+
"complexType": {
|
|
2400
|
+
"original": "{\n count: number;\n imageCount?: number;\n videoCount?: number;\n uploading?: boolean;\n }",
|
|
2401
|
+
"resolved": "{ count: number; imageCount?: number; videoCount?: number; uploading?: boolean; }",
|
|
2402
|
+
"references": {}
|
|
1661
2403
|
}
|
|
1662
2404
|
}];
|
|
1663
2405
|
}
|