@duetds/components 4.32.0 → 4.34.0
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/hydrate/index.js +2367 -244
- package/lib/cjs/{dom-a28e5c5f.js → dom-52a4f07a.js} +1 -1
- package/lib/cjs/duet-alert.cjs.entry.js +2 -2
- package/lib/cjs/duet-badge.cjs.entry.js +1 -1
- package/lib/cjs/duet-button_2.cjs.entry.js +4 -4
- package/lib/cjs/duet-caption_4.cjs.entry.js +18 -11
- package/lib/cjs/duet-card.cjs.entry.js +3 -3
- package/lib/cjs/duet-checkbox.cjs.entry.js +2 -2
- package/lib/cjs/duet-choice_2.cjs.entry.js +39 -18
- package/lib/cjs/duet-collapsible.cjs.entry.js +5 -450
- package/lib/cjs/duet-cookie-consent.cjs.entry.js +1 -1
- package/lib/cjs/duet-date-picker.cjs.entry.js +7 -7
- package/lib/cjs/duet-divider_2.cjs.entry.js +1 -1
- package/lib/cjs/duet-editable-table-button.cjs.entry.js +96 -0
- package/lib/cjs/duet-editable-table_4.cjs.entry.js +1520 -0
- package/lib/cjs/duet-empty-state.cjs.entry.js +1 -1
- package/lib/cjs/duet-fieldset.cjs.entry.js +1 -1
- package/lib/cjs/duet-footer.cjs.entry.js +3 -3
- package/lib/cjs/duet-grid_2.cjs.entry.js +69 -4
- package/lib/cjs/duet-header_2.cjs.entry.js +216 -49
- package/lib/cjs/duet-hero.cjs.entry.js +2 -2
- package/lib/cjs/duet-icon.cjs.entry.js +8 -6
- package/lib/cjs/duet-input_2.cjs.entry.js +8 -9
- package/lib/cjs/duet-layout.cjs.entry.js +1 -1
- package/lib/cjs/duet-list_2.cjs.entry.js +3 -3
- package/lib/cjs/duet-modal.cjs.entry.js +3 -3
- package/lib/cjs/duet-notification_2.cjs.entry.js +3 -3
- package/lib/cjs/duet-number-input.cjs.entry.js +2 -2
- package/lib/cjs/duet-progress.cjs.entry.js +75 -0
- package/lib/cjs/duet-radio_2.cjs.entry.js +2 -2
- package/lib/cjs/duet-range-slider.cjs.entry.js +2 -2
- package/lib/cjs/duet-select.cjs.entry.js +5 -5
- package/lib/cjs/duet-step_2.cjs.entry.js +1 -1
- package/lib/cjs/duet-tab_2.cjs.entry.js +3 -3
- package/lib/cjs/duet-textarea.cjs.entry.js +5 -5
- package/lib/cjs/duet-toggle.cjs.entry.js +1 -1
- package/lib/cjs/duet-tooltip.cjs.entry.js +2 -2
- package/lib/cjs/duet-tray.cjs.entry.js +3 -3
- package/lib/cjs/duet-upload-aria-status.cjs.entry.js +100 -0
- package/lib/cjs/duet-visually-hidden.cjs.entry.js +1 -1
- package/lib/cjs/duet.cjs.js +4 -4
- package/lib/cjs/{focus-utils-55b5a616.js → focus-utils-480ea4e0.js} +1 -1
- package/lib/cjs/form-search-d61b2843.js +8 -0
- package/lib/cjs/{index-03ed1f55.js → index-6966a494.js} +5 -2
- package/lib/cjs/{language-utils-48b8860b.js → language-utils-aa282901.js} +6 -2
- package/lib/cjs/loader.cjs.js +3 -3
- package/lib/cjs/{shadow-css-6560c90c.js → shadow-css-e1b62a99.js} +9 -10
- package/lib/cjs/token-utils-05bd23b4.js +77 -0
- package/lib/cjs/tokens-8596cece.js +459 -0
- package/lib/cjs/{tokens.module-53b3bd92.js → tokens.module-6b2df1c2.js} +2 -0
- package/lib/cjs/{watch-options-3877c082.js → watch-options-d88afac0.js} +29 -6
- package/lib/collection/collection-manifest.json +17 -3
- package/lib/collection/components/duet-checkbox/duet-checkbox.css +1 -1
- package/lib/collection/components/duet-choice/duet-choice.js +94 -21
- package/lib/collection/components/duet-collapsible/duet-collapsible.js +4 -1
- package/lib/collection/components/duet-date-picker/duet-date-picker.js +9 -9
- package/lib/collection/components/duet-editable-table/duet-editable-table-button.css +32 -0
- package/lib/collection/components/duet-editable-table/duet-editable-table-button.js +225 -0
- package/lib/collection/components/duet-editable-table/duet-editable-table-item.css +36 -0
- package/lib/collection/components/duet-editable-table/duet-editable-table-item.js +225 -0
- package/lib/collection/components/duet-editable-table/duet-editable-table-tabledata.js +13 -0
- package/lib/collection/components/duet-editable-table/duet-editable-table.css +16 -0
- package/lib/collection/components/duet-editable-table/duet-editable-table.js +404 -0
- package/lib/collection/components/duet-footer/duet-footer.css +1 -0
- package/lib/collection/components/duet-grid/duet-grid.js +74 -6
- package/lib/collection/components/duet-header/duet-header-dropdown.js +27 -0
- package/lib/collection/components/duet-header/duet-header-hamburger.js +9 -0
- package/lib/collection/components/duet-header/duet-header-icon.js +9 -0
- package/lib/collection/components/duet-header/duet-header.css +272 -39
- package/lib/collection/components/duet-header/duet-header.js +310 -122
- package/lib/collection/components/duet-heading/duet-heading.css +3 -0
- package/lib/collection/components/duet-heading/duet-heading.js +7 -6
- package/lib/collection/components/duet-icon/duet-icon.js +5 -3
- package/lib/collection/components/duet-input/duet-input.css +15 -0
- package/lib/collection/components/duet-input/duet-input.js +4 -4
- package/lib/collection/components/duet-link/duet-link.js +4 -1
- package/lib/collection/components/duet-list-item/duet-list-item.css +1 -1
- package/lib/collection/components/duet-notification-drawer/duet-notification-drawer.css +4 -3
- package/lib/collection/components/duet-paragraph/duet-paragraph.css +6 -0
- package/lib/collection/components/duet-paragraph/duet-paragraph.js +34 -3
- package/lib/collection/components/duet-progress/duet-progress.css +103 -0
- package/lib/collection/components/duet-progress/duet-progress.js +240 -0
- package/lib/collection/components/duet-select/duet-select.css +15 -0
- package/lib/collection/components/duet-select/duet-select.js +3 -3
- package/lib/collection/components/duet-tab-group/duet-tab-group.css +2 -2
- package/lib/collection/components/duet-table/duet-table.css +42 -17
- package/lib/collection/components/duet-table/duet-table.js +2 -2
- package/lib/collection/components/duet-textarea/duet-textarea.css +19 -0
- package/lib/collection/components/duet-textarea/duet-textarea.js +5 -4
- package/lib/collection/components/duet-upload/duet-upload.css +64 -0
- package/lib/collection/components/duet-upload/duet-upload.js +1885 -0
- package/lib/collection/components/duet-upload/errorcodes.utils.js +32 -0
- package/lib/collection/components/duet-upload/mock.helpers.js +91 -0
- package/lib/collection/components/duet-upload/upload-editable-item-error.js +16 -0
- package/lib/collection/components/duet-upload/upload-editable-item-inprogres.js +8 -0
- package/lib/collection/components/duet-upload/upload-editable-item-success.js +30 -0
- package/lib/collection/components/duet-upload/upload-validators.js +93 -0
- package/lib/collection/components/duet-upload/upload.helpers.js +13 -0
- package/lib/collection/components/duet-upload/xhr.helpers.js +30 -0
- package/lib/collection/components/duet-upload-aria-status/duet-upload-aria-status.js +217 -0
- package/lib/collection/utils/js-utils.js +12 -0
- package/lib/collection/utils/language-utils.js +6 -3
- package/lib/collection/utils/template-utils.js +33 -0
- package/lib/collection/utils/token-utils.js +67 -14
- package/lib/collection/utils/watch-options.js +35 -6
- package/lib/custom-elements-bundle/index.d.ts +36 -0
- package/lib/custom-elements-bundle/index.js +2309 -334
- package/lib/duet/duet.esm.js +1 -1
- package/lib/duet/duet.js +1 -1
- package/lib/duet/{p-92103298.system.entry.js → p-07f43530.system.entry.js} +1 -1
- package/lib/duet/{p-cc0bd28f.system.entry.js → p-093bca2f.system.entry.js} +1 -1
- package/lib/duet/{p-a678da8c.entry.js → p-0aaf86ba.entry.js} +1 -1
- package/lib/duet/{p-94a5fd74.system.entry.js → p-0b0a05ed.system.entry.js} +1 -1
- package/lib/duet/{p-00eac879.system.entry.js → p-0be1c660.system.entry.js} +1 -1
- package/lib/duet/{p-3b3bac3f.system.entry.js → p-0d66e11b.system.entry.js} +1 -1
- package/lib/duet/{p-7331f2fe.system.entry.js → p-0de430e1.system.entry.js} +1 -1
- package/lib/duet/{p-3618aaee.entry.js → p-0ef8d711.entry.js} +1 -1
- package/lib/duet/p-12721178.js +4 -0
- package/lib/duet/{p-c19094dd.entry.js → p-12a08d77.entry.js} +1 -1
- package/lib/duet/p-15c9a17c.entry.js +4 -0
- package/lib/duet/{p-9cdd361e.js → p-183726f7.js} +0 -0
- package/lib/duet/{p-b75c5f13.entry.js → p-18c3eb54.entry.js} +1 -1
- package/lib/duet/{p-9542c540.entry.js → p-1b591fa4.entry.js} +1 -1
- package/lib/duet/{p-f364ce8b.system.entry.js → p-1bd0f4eb.system.entry.js} +1 -1
- package/lib/duet/p-2764f081.js +4 -0
- package/lib/duet/p-27bd8744.system.entry.js +4 -0
- package/lib/duet/p-289a31cb.entry.js +4 -0
- package/lib/duet/{p-8c511832.system.entry.js → p-29b352db.system.entry.js} +1 -1
- package/lib/duet/p-2a00f231.system.entry.js +4 -0
- package/lib/duet/p-3215e07e.system.entry.js +4 -0
- package/lib/duet/{p-ed479d09.system.entry.js → p-338b9955.system.entry.js} +1 -1
- package/lib/duet/{p-8740fa38.entry.js → p-33de1029.entry.js} +1 -1
- package/lib/duet/p-34ebff3b.entry.js +4 -0
- package/lib/duet/{p-b6a0caf8.system.entry.js → p-379d416f.system.entry.js} +1 -1
- package/lib/duet/{p-0b9b6393.entry.js → p-39a12eb9.entry.js} +1 -1
- package/lib/duet/{p-8652a7ab.system.entry.js → p-39fd8b43.system.entry.js} +1 -1
- package/lib/duet/{p-ffc2ffff.entry.js → p-3bafdf7c.entry.js} +1 -1
- package/lib/duet/{p-4fcbcecd.system.entry.js → p-3c1ce7e2.system.entry.js} +1 -1
- package/lib/duet/p-3da6b84e.entry.js +4 -0
- package/lib/duet/p-43c49a72.entry.js +4 -0
- package/lib/duet/{p-9f0f5674.entry.js → p-44f4b8ff.entry.js} +1 -1
- package/lib/duet/{p-b0bbbdba.system.entry.js → p-4c5ac0c2.system.entry.js} +1 -1
- package/lib/duet/p-50b4fb2c.js +4 -0
- package/lib/duet/p-51f7ae72.entry.js +4 -0
- package/lib/duet/p-52621211.js +15 -0
- package/lib/duet/{p-2a3411b5.system.entry.js → p-5443c9ca.system.entry.js} +1 -1
- package/lib/duet/{p-abd3bfb4.system.entry.js → p-5610db77.system.entry.js} +1 -1
- package/lib/duet/{p-2c0dd9ba.system.entry.js → p-5b409bfb.system.entry.js} +1 -1
- package/lib/duet/{p-807b2087.entry.js → p-6353407f.entry.js} +1 -1
- package/lib/duet/{p-a89e88a3.js → p-64bf94ee.js} +1 -1
- package/lib/duet/{p-2c679963.entry.js → p-64e915ae.entry.js} +1 -1
- package/lib/duet/{p-432ba72e.system.entry.js → p-6c237f21.system.entry.js} +1 -1
- package/lib/duet/p-6c8521f6.system.entry.js +4 -0
- package/lib/duet/{p-a962c8c1.system.js → p-6e4fd6ba.system.js} +0 -0
- package/lib/duet/p-70fafc98.system.js +4 -0
- package/lib/duet/{p-8002a095.entry.js → p-7347f4ac.entry.js} +1 -1
- package/lib/duet/{p-d13874cb.entry.js → p-781bd6db.entry.js} +1 -1
- package/lib/duet/{p-5a817929.system.entry.js → p-78e8a689.system.entry.js} +1 -1
- package/lib/duet/p-8143f3de.js +4 -0
- package/lib/duet/p-81e855e4.system.js +4 -0
- package/lib/duet/{p-84ece735.entry.js → p-8224d768.entry.js} +1 -1
- package/lib/duet/{p-43dde575.system.entry.js → p-848bb1c2.system.entry.js} +1 -1
- package/lib/duet/{p-1391ec53.entry.js → p-880a4afe.entry.js} +1 -1
- package/lib/duet/p-8c375429.entry.js +4 -0
- package/lib/duet/p-8cb71174.system.entry.js +4 -0
- package/lib/duet/p-8d7b68c4.entry.js +4 -0
- package/lib/duet/p-8f477bd6.system.js +4 -0
- package/lib/duet/p-969c6395.system.entry.js +4 -0
- package/lib/duet/p-9c234242.system.entry.js +4 -0
- package/lib/duet/{p-f13a0883.entry.js → p-9d7b9084.entry.js} +1 -1
- package/lib/duet/p-a0544097.system.entry.js +4 -0
- package/lib/duet/p-a16a58c1.system.js +4 -0
- package/lib/duet/{p-fb898d94.system.entry.js → p-a4a16d03.system.entry.js} +1 -1
- package/lib/duet/p-a4e3b44b.entry.js +4 -0
- package/lib/duet/{p-977f2826.entry.js → p-a91673cf.entry.js} +1 -1
- package/lib/duet/p-a926944f.entry.js +4 -0
- package/lib/duet/{p-2826f987.js → p-ad07f399.js} +1 -1
- package/lib/duet/p-b08bce4c.entry.js +4 -0
- package/lib/duet/{p-ec3eef3a.entry.js → p-b48a5f80.entry.js} +1 -1
- package/lib/duet/p-bb3e3777.entry.js +4 -0
- package/lib/duet/{p-fbb7d194.entry.js → p-bbe33d02.entry.js} +1 -1
- package/lib/duet/p-be8e1c48.system.entry.js +4 -0
- package/lib/duet/{p-68d09837.system.entry.js → p-c56c73ee.system.entry.js} +1 -1
- package/lib/duet/p-c63bdc6a.system.entry.js +4 -0
- package/lib/duet/{p-c723d36e.system.js → p-c83685a6.system.js} +1 -1
- package/lib/duet/p-c8dfc958.system.entry.js +4 -0
- package/lib/duet/{p-6cf41bfe.system.entry.js → p-c92f601f.system.entry.js} +1 -1
- package/lib/duet/p-d004da5f.js +4 -0
- package/lib/duet/p-d49416f8.entry.js +4 -0
- package/lib/duet/{p-7a868085.entry.js → p-d581d82d.entry.js} +1 -1
- package/lib/duet/p-d6bb4301.entry.js +4 -0
- package/lib/duet/p-d9aadc15.entry.js +4 -0
- package/lib/duet/p-ddb6344c.system.js +4 -0
- package/lib/duet/{p-3040debf.entry.js → p-dde63979.entry.js} +1 -1
- package/lib/duet/p-e15ccddc.system.entry.js +4 -0
- package/lib/duet/{p-0f2a478e.entry.js → p-e1be37a6.entry.js} +1 -1
- package/lib/duet/p-e5c1751e.system.js +16 -0
- package/lib/duet/{p-b9683731.entry.js → p-e9209e9f.entry.js} +1 -1
- package/lib/duet/p-eb55ccd2.system.js +4 -0
- package/lib/duet/{p-b374d7c2.system.js → p-ee1ba0d4.system.js} +1 -1
- package/lib/duet/{p-57cb58d4.system.entry.js → p-f4a29a8a.system.entry.js} +2 -2
- package/lib/duet/p-f8a0bd32.system.entry.js +4 -0
- package/lib/duet/p-f9599dd9.system.entry.js +4 -0
- package/lib/duet/p-fa99eaa4.system.js +4 -0
- package/lib/duet/p-fd7018e9.js +4 -0
- package/lib/duet/{p-19c28d99.system.entry.js → p-fe0cca67.system.entry.js} +1 -1
- package/lib/esm/{dom-8516b24e.js → dom-5d060ace.js} +1 -1
- package/lib/esm/duet-alert.entry.js +2 -2
- package/lib/esm/duet-badge.entry.js +1 -1
- package/lib/esm/duet-button_2.entry.js +4 -4
- package/lib/esm/duet-caption_4.entry.js +18 -11
- package/lib/esm/duet-card.entry.js +3 -3
- package/lib/esm/duet-checkbox.entry.js +2 -2
- package/lib/esm/duet-choice_2.entry.js +40 -19
- package/lib/esm/duet-collapsible.entry.js +4 -449
- package/lib/esm/duet-cookie-consent.entry.js +1 -1
- package/lib/esm/duet-date-picker.entry.js +7 -7
- package/lib/esm/duet-divider_2.entry.js +1 -1
- package/lib/esm/duet-editable-table-button.entry.js +92 -0
- package/lib/esm/duet-editable-table_4.entry.js +1513 -0
- package/lib/esm/duet-empty-state.entry.js +1 -1
- package/lib/esm/duet-fieldset.entry.js +1 -1
- package/lib/esm/duet-footer.entry.js +3 -3
- package/lib/esm/duet-grid_2.entry.js +69 -4
- package/lib/esm/duet-header_2.entry.js +216 -49
- package/lib/esm/duet-hero.entry.js +2 -2
- package/lib/esm/duet-icon.entry.js +8 -6
- package/lib/esm/duet-input_2.entry.js +7 -8
- package/lib/esm/duet-layout.entry.js +1 -1
- package/lib/esm/duet-list_2.entry.js +3 -3
- package/lib/esm/duet-modal.entry.js +3 -3
- package/lib/esm/duet-notification_2.entry.js +3 -3
- package/lib/esm/duet-number-input.entry.js +2 -2
- package/lib/esm/duet-progress.entry.js +71 -0
- package/lib/esm/duet-radio_2.entry.js +2 -2
- package/lib/esm/duet-range-slider.entry.js +2 -2
- package/lib/esm/duet-select.entry.js +5 -5
- package/lib/esm/duet-step_2.entry.js +1 -1
- package/lib/esm/duet-tab_2.entry.js +3 -3
- package/lib/esm/duet-textarea.entry.js +5 -5
- package/lib/esm/duet-toggle.entry.js +1 -1
- package/lib/esm/duet-tooltip.entry.js +2 -2
- package/lib/esm/duet-tray.entry.js +3 -3
- package/lib/esm/duet-upload-aria-status.entry.js +96 -0
- package/lib/esm/duet-visually-hidden.entry.js +1 -1
- package/lib/esm/duet.js +4 -4
- package/lib/esm/{focus-utils-6a282066.js → focus-utils-48837cfa.js} +1 -1
- package/lib/esm/form-search-ea8e19ae.js +6 -0
- package/lib/esm/{index-3a265449.js → index-80be4170.js} +5 -2
- package/lib/esm/{language-utils-d5c38f65.js → language-utils-344d894c.js} +6 -3
- package/lib/esm/loader.js +3 -3
- package/lib/esm/{shadow-css-9178c864.js → shadow-css-13d024f4.js} +9 -10
- package/lib/esm/token-utils-75f78ca4.js +75 -0
- package/lib/esm/tokens-e110dc89.js +453 -0
- package/lib/esm/{tokens.module-edb66c04.js → tokens.module-49cbf963.js} +3 -1
- package/lib/esm/watch-options-dd55bce8.js +57 -0
- package/lib/esm-es5/{dom-8516b24e.js → dom-5d060ace.js} +0 -0
- package/lib/esm-es5/duet-alert.entry.js +1 -1
- package/lib/esm-es5/duet-badge.entry.js +1 -1
- package/lib/esm-es5/duet-button_2.entry.js +1 -1
- package/lib/esm-es5/duet-caption_4.entry.js +2 -2
- package/lib/esm-es5/duet-card.entry.js +1 -1
- package/lib/esm-es5/duet-checkbox.entry.js +1 -1
- package/lib/esm-es5/duet-choice_2.entry.js +2 -2
- package/lib/esm-es5/duet-collapsible.entry.js +2 -2
- package/lib/esm-es5/duet-cookie-consent.entry.js +1 -1
- package/lib/esm-es5/duet-date-picker.entry.js +1 -1
- package/lib/esm-es5/duet-divider_2.entry.js +1 -1
- package/lib/esm-es5/duet-editable-table-button.entry.js +4 -0
- package/lib/esm-es5/duet-editable-table_4.entry.js +4 -0
- package/lib/esm-es5/duet-empty-state.entry.js +1 -1
- package/lib/esm-es5/duet-fieldset.entry.js +1 -1
- package/lib/esm-es5/duet-footer.entry.js +1 -1
- package/lib/esm-es5/duet-grid_2.entry.js +2 -2
- package/lib/esm-es5/duet-header_2.entry.js +2 -2
- package/lib/esm-es5/duet-hero.entry.js +1 -1
- package/lib/esm-es5/duet-icon.entry.js +1 -1
- package/lib/esm-es5/duet-input_2.entry.js +1 -1
- package/lib/esm-es5/duet-layout.entry.js +1 -1
- package/lib/esm-es5/duet-list_2.entry.js +1 -1
- package/lib/esm-es5/duet-modal.entry.js +1 -1
- package/lib/esm-es5/duet-notification_2.entry.js +1 -1
- package/lib/esm-es5/duet-number-input.entry.js +1 -1
- package/lib/esm-es5/duet-progress.entry.js +4 -0
- package/lib/esm-es5/duet-radio_2.entry.js +1 -1
- package/lib/esm-es5/duet-range-slider.entry.js +1 -1
- package/lib/esm-es5/duet-select.entry.js +1 -1
- package/lib/esm-es5/duet-step_2.entry.js +1 -1
- package/lib/esm-es5/duet-tab_2.entry.js +2 -2
- package/lib/esm-es5/duet-textarea.entry.js +1 -1
- package/lib/esm-es5/duet-toggle.entry.js +1 -1
- package/lib/esm-es5/duet-tooltip.entry.js +1 -1
- package/lib/esm-es5/duet-tray.entry.js +1 -1
- package/lib/esm-es5/duet-upload-aria-status.entry.js +4 -0
- package/lib/esm-es5/duet-visually-hidden.entry.js +1 -1
- package/lib/esm-es5/duet.js +1 -1
- package/lib/esm-es5/focus-utils-48837cfa.js +4 -0
- package/lib/esm-es5/form-search-ea8e19ae.js +4 -0
- package/lib/esm-es5/index-80be4170.js +4 -0
- package/lib/esm-es5/{language-utils-d5c38f65.js → language-utils-344d894c.js} +1 -1
- package/lib/esm-es5/loader.js +1 -1
- package/lib/esm-es5/shadow-css-13d024f4.js +15 -0
- package/lib/esm-es5/token-utils-75f78ca4.js +4 -0
- package/lib/esm-es5/tokens-e110dc89.js +4 -0
- package/lib/esm-es5/tokens.module-49cbf963.js +4 -0
- package/lib/esm-es5/watch-options-dd55bce8.js +4 -0
- package/lib/types/common-types.d.ts +0 -1
- package/lib/types/components/duet-choice/duet-choice.d.ts +20 -1
- package/lib/types/components/duet-collapsible/duet-collapsible.d.ts +3 -0
- package/lib/types/components/duet-date-picker/duet-date-picker.d.ts +5 -5
- package/lib/types/components/duet-editable-table/duet-editable-table-button.d.ts +73 -0
- package/lib/types/components/duet-editable-table/duet-editable-table-item.d.ts +76 -0
- package/lib/types/components/duet-editable-table/duet-editable-table-tabledata.d.ts +8 -0
- package/lib/types/components/duet-editable-table/duet-editable-table.d.ts +94 -0
- package/lib/types/components/duet-grid/duet-grid.d.ts +17 -2
- package/lib/types/components/duet-header/duet-header-dropdown.d.ts +16 -0
- package/lib/types/components/duet-header/duet-header-hamburger.d.ts +2 -0
- package/lib/types/components/duet-header/duet-header-icon.d.ts +8 -0
- package/lib/types/components/duet-header/duet-header.d.ts +41 -4
- package/lib/types/components/duet-heading/duet-heading.d.ts +2 -2
- package/lib/types/components/duet-link/duet-link.d.ts +3 -0
- package/lib/types/components/duet-paragraph/duet-paragraph.d.ts +9 -1
- package/lib/types/components/duet-progress/duet-progress.d.ts +64 -0
- package/lib/types/components/duet-table/duet-table.d.ts +1 -1
- package/lib/types/components/duet-upload/duet-upload.d.ts +408 -0
- package/lib/types/components/duet-upload/errorcodes.utils.d.ts +8 -0
- package/lib/types/components/duet-upload/mock.helpers.d.ts +2 -0
- package/lib/types/components/duet-upload/upload-editable-item-error.d.ts +7 -0
- package/lib/types/components/duet-upload/upload-editable-item-inprogres.d.ts +7 -0
- package/lib/types/components/duet-upload/upload-editable-item-success.d.ts +8 -0
- package/lib/types/components/duet-upload/upload-validators.d.ts +12 -0
- package/lib/types/components/duet-upload/upload.helpers.d.ts +1 -0
- package/lib/types/components/duet-upload/xhr.helpers.d.ts +18 -0
- package/lib/types/components/duet-upload-aria-status/duet-upload-aria-status.d.ts +49 -0
- package/lib/types/components.d.ts +835 -29
- package/lib/types/stencil-public-runtime.d.ts +6 -4
- package/lib/types/utils/js-utils.d.ts +1 -0
- package/lib/types/utils/language-utils.d.ts +5 -1
- package/lib/types/utils/template-utils.d.ts +13 -0
- package/lib/types/utils/token-utils.d.ts +8 -2
- package/lib/types/utils/watch-options.d.ts +2 -0
- package/package.json +13 -13
- package/lib/cjs/duet-table.cjs.entry.js +0 -132
- package/lib/cjs/token-utils-13e5d13e.js +0 -30
- package/lib/duet/p-0058512b.js +0 -4
- package/lib/duet/p-08729381.entry.js +0 -4
- package/lib/duet/p-0b00e8d6.system.js +0 -16
- package/lib/duet/p-15922601.system.js +0 -4
- package/lib/duet/p-194e25ce.system.entry.js +0 -4
- package/lib/duet/p-1d87ea02.system.entry.js +0 -4
- package/lib/duet/p-2d1e2b23.system.entry.js +0 -4
- package/lib/duet/p-322d1c38.js +0 -4
- package/lib/duet/p-40d68321.entry.js +0 -4
- package/lib/duet/p-418b2ce7.system.js +0 -4
- package/lib/duet/p-43e39d98.system.js +0 -4
- package/lib/duet/p-4603830b.entry.js +0 -4
- package/lib/duet/p-52d7fbec.entry.js +0 -4
- package/lib/duet/p-60478325.system.entry.js +0 -4
- package/lib/duet/p-64ed7add.entry.js +0 -4
- package/lib/duet/p-6a356ab1.system.js +0 -4
- package/lib/duet/p-72fd384a.entry.js +0 -4
- package/lib/duet/p-753b406c.entry.js +0 -4
- package/lib/duet/p-76c00d0c.entry.js +0 -4
- package/lib/duet/p-85fe1132.js +0 -4
- package/lib/duet/p-8c8e82aa.system.js +0 -4
- package/lib/duet/p-9a89ec39.js +0 -4
- package/lib/duet/p-a11df1b6.js +0 -15
- package/lib/duet/p-a1eccee1.system.entry.js +0 -4
- package/lib/duet/p-ade33230.entry.js +0 -4
- package/lib/duet/p-b04d738f.system.entry.js +0 -4
- package/lib/duet/p-cb827bb7.entry.js +0 -4
- package/lib/duet/p-d85fba2c.system.entry.js +0 -4
- package/lib/duet/p-dfa90f8a.system.entry.js +0 -4
- package/lib/duet/p-e6b9bd1d.entry.js +0 -4
- package/lib/duet/p-ee64d6be.system.entry.js +0 -4
- package/lib/duet/p-f113671b.system.entry.js +0 -4
- package/lib/duet/p-f2f04396.entry.js +0 -4
- package/lib/duet/p-fc6624fe.system.entry.js +0 -4
- package/lib/esm/duet-table.entry.js +0 -128
- package/lib/esm/token-utils-5a35377f.js +0 -28
- package/lib/esm/watch-options-de55ea78.js +0 -35
- package/lib/esm-es5/duet-table.entry.js +0 -4
- package/lib/esm-es5/focus-utils-6a282066.js +0 -4
- package/lib/esm-es5/index-3a265449.js +0 -4
- package/lib/esm-es5/shadow-css-9178c864.js +0 -15
- package/lib/esm-es5/token-utils-5a35377f.js +0 -4
- package/lib/esm-es5/tokens.module-edb66c04.js +0 -4
- package/lib/esm-es5/watch-options-de55ea78.js +0 -4
|
@@ -0,0 +1,1520 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Built with Duet Design System
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
7
|
+
|
|
8
|
+
const index = require('./index-6966a494.js');
|
|
9
|
+
const languageUtils = require('./language-utils-aa282901.js');
|
|
10
|
+
const themeableComponent = require('./themeable-component-0c1be552.js');
|
|
11
|
+
const tokens_module = require('./tokens.module-6b2df1c2.js');
|
|
12
|
+
const createId = require('./create-id-c3b984b1.js');
|
|
13
|
+
require('./string-utils-267e3dbb.js');
|
|
14
|
+
|
|
15
|
+
const debounce = (func, timeout = 50) => {
|
|
16
|
+
let timer;
|
|
17
|
+
return (...args) => {
|
|
18
|
+
clearTimeout(timer);
|
|
19
|
+
timer = setTimeout(() => {
|
|
20
|
+
func.apply(undefined, args);
|
|
21
|
+
}, timeout);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Produces a function which uses template strings to do simple interpolation from objects.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* var makeMeKing = generateTemplateFn('${name} is now the king of ${country}!');
|
|
30
|
+
*
|
|
31
|
+
* console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
|
|
32
|
+
* // Logs 'Bryan is now the king of Scotland!'
|
|
33
|
+
*/
|
|
34
|
+
const generateTemplateFn = (function () {
|
|
35
|
+
const cache = {};
|
|
36
|
+
function generateTemplate(template) {
|
|
37
|
+
if (typeof template !== "string") {
|
|
38
|
+
template = template.outerHTML;
|
|
39
|
+
}
|
|
40
|
+
let fn = cache[template];
|
|
41
|
+
if (!fn) {
|
|
42
|
+
// Replace ${expressions} (etc) with ${map.expressions}.
|
|
43
|
+
const sanitized = template
|
|
44
|
+
.replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function (_, match) {
|
|
45
|
+
return `\$\{map.${match.trim()}\}`;
|
|
46
|
+
})
|
|
47
|
+
// Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
|
|
48
|
+
.replace(/(\$\{(?!map\.)[^}]+\})/g, "");
|
|
49
|
+
fn = Function("map", `return \`${sanitized}\``);
|
|
50
|
+
}
|
|
51
|
+
return fn;
|
|
52
|
+
}
|
|
53
|
+
return generateTemplate;
|
|
54
|
+
})();
|
|
55
|
+
|
|
56
|
+
const duetEditableTableCss = "duet-editable-table{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none}.duet-editable-table-header tr .duet-editable-table-header-hidden{padding:0 !important;font-size:0;border-bottom:0}";
|
|
57
|
+
|
|
58
|
+
let DuetEditableTable = class {
|
|
59
|
+
constructor(hostRef) {
|
|
60
|
+
index.registerInstance(this, hostRef);
|
|
61
|
+
this.template = undefined;
|
|
62
|
+
/**
|
|
63
|
+
* State() variables
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
this.tick = Date.now();
|
|
67
|
+
/**
|
|
68
|
+
* Map of items that contain list of things.
|
|
69
|
+
*/
|
|
70
|
+
this.items = new Map();
|
|
71
|
+
/**
|
|
72
|
+
* Key used to set vertical alignment of action buttons
|
|
73
|
+
*/
|
|
74
|
+
this.alignment = "middle";
|
|
75
|
+
/**
|
|
76
|
+
* Array of internationalized defaults for the default groups labels.
|
|
77
|
+
*/
|
|
78
|
+
this.groupsLabelDefaults = {
|
|
79
|
+
fi: "Kaikki",
|
|
80
|
+
en: "All items",
|
|
81
|
+
sv: "Alla objekt",
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Array of internationalized defaults for the default action labels.
|
|
85
|
+
*/
|
|
86
|
+
this.actionLabelDefaults = {
|
|
87
|
+
fi: "Toiminnot",
|
|
88
|
+
en: "Actions",
|
|
89
|
+
sv: "Handlingar",
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Array of group names that you want the editable table to display (can be used to hide or show groups depending on conditions).
|
|
93
|
+
* @default { id: "all", label: this.groupsLabelDefaults, actionLabel: this.actionLabelDefaults }.
|
|
94
|
+
* @example [{ id: "success", label: {fi: "Onnistunut", en: "Success", sv: "Alt klart", }}].
|
|
95
|
+
*/
|
|
96
|
+
this.groups = [
|
|
97
|
+
{ id: "all", label: this.groupsLabelDefaults, actionLabel: this.actionLabelDefaults },
|
|
98
|
+
];
|
|
99
|
+
/**
|
|
100
|
+
* Array of actions that are mapped via the map variable to the various groups defined in group.
|
|
101
|
+
* @default undefined
|
|
102
|
+
* @example [{
|
|
103
|
+
variation: "default",
|
|
104
|
+
icon: "action-edit-2",
|
|
105
|
+
id: "edit",
|
|
106
|
+
map: ["success"],
|
|
107
|
+
label: {
|
|
108
|
+
fi: " Label",
|
|
109
|
+
en: " Label",
|
|
110
|
+
sv: " Label",
|
|
111
|
+
}
|
|
112
|
+
}]
|
|
113
|
+
*/
|
|
114
|
+
this.actions = undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Shows or hides the table labels.
|
|
117
|
+
*/
|
|
118
|
+
this.hideGroups = false;
|
|
119
|
+
/**
|
|
120
|
+
* Exposes the aria role for optimizing accessibility.
|
|
121
|
+
*/
|
|
122
|
+
this.accessibleRole = undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Theme of the table.
|
|
125
|
+
*/
|
|
126
|
+
this.theme = "";
|
|
127
|
+
/**
|
|
128
|
+
* Private methods.
|
|
129
|
+
*/
|
|
130
|
+
this.kick = debounce(() => {
|
|
131
|
+
this.tick = Date.now();
|
|
132
|
+
}, 100); // will trigger re-render
|
|
133
|
+
/**
|
|
134
|
+
* If a user defines a template section within editable table, try to read an use it.
|
|
135
|
+
*/
|
|
136
|
+
this.getTemplate = () => {
|
|
137
|
+
const templateDom = this.element.getElementsByTagName("template");
|
|
138
|
+
if (templateDom === null || templateDom === void 0 ? void 0 : templateDom.length) {
|
|
139
|
+
const templateString = templateDom[0].content.firstElementChild.outerHTML;
|
|
140
|
+
return generateTemplateFn(templateString);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
this.getItemData = (data) => {
|
|
147
|
+
const { item, group, uid } = data;
|
|
148
|
+
if (this.template) {
|
|
149
|
+
return {
|
|
150
|
+
group,
|
|
151
|
+
uid,
|
|
152
|
+
item: this.template(item),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return { item, group, uid };
|
|
156
|
+
};
|
|
157
|
+
this.filterMap = needle => {
|
|
158
|
+
if (needle === "all") {
|
|
159
|
+
return Array.from(this.items);
|
|
160
|
+
}
|
|
161
|
+
return Array.from(this.items).filter(item => needle === item[1].group);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Component lifecycle events.
|
|
166
|
+
*/
|
|
167
|
+
componentWillLoad() {
|
|
168
|
+
// look for a <template> region in the duet-editable-table
|
|
169
|
+
this.template = this.getTemplate();
|
|
170
|
+
// take care of the case where groups and actions are defined as html properties instead of javascript objects
|
|
171
|
+
if (typeof this.groups === "string") {
|
|
172
|
+
this.internalGroupArray = languageUtils.sanitizeString(this.groups);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
this.internalGroupArray = this.groups;
|
|
176
|
+
}
|
|
177
|
+
if (typeof this.actions === "string") {
|
|
178
|
+
this.internalActionsArray = languageUtils.sanitizeString(this.actions);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.internalActionsArray = this.actions;
|
|
182
|
+
}
|
|
183
|
+
themeableComponent.inheritGlobalTheme(this);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Method to force an update of a tabular data array.
|
|
187
|
+
* when called the method will rerender the entire tabular structure.
|
|
188
|
+
*/
|
|
189
|
+
async updateTable(passedItems = undefined) {
|
|
190
|
+
this.items = new Map(passedItems || this.items);
|
|
191
|
+
this.kick();
|
|
192
|
+
}
|
|
193
|
+
render() {
|
|
194
|
+
return (index.h(index.Host, { class: {
|
|
195
|
+
"duet-theme-turva": this.theme === "turva",
|
|
196
|
+
} }, this.internalGroupArray.map(group => {
|
|
197
|
+
const currentGroup = this.filterMap(group.id);
|
|
198
|
+
if (!currentGroup.length) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
return (index.h("duet-table", { variation: "plain", breakpoint: "none", role: "", margin: this.hideGroups ? "none" : "auto" }, index.h("table", { class: "duet-editable-table", "aria-role": this.accessibleRole }, index.h("thead", { class: "duet-editable-table-header" }, index.h("tr", null, index.h("th", { class: {
|
|
202
|
+
"duet-editable-table-header-hidden": this.hideGroups,
|
|
203
|
+
} }, !this.hideGroups ? (languageUtils.getLocaleString(group.label)) : (index.h("duet-visually-hidden", null, languageUtils.getLocaleString(group.label)))), index.h("th", { class: {
|
|
204
|
+
"duet-editable-table-header-hidden": this.hideGroups,
|
|
205
|
+
} }, index.h("duet-visually-hidden", null, group.actionLabel
|
|
206
|
+
? languageUtils.getLocaleString(group.actionLabel)
|
|
207
|
+
: languageUtils.getLocaleString(this.actionLabelDefaults))))), index.h("tbody", null, currentGroup.map(dataAsArray => {
|
|
208
|
+
const [key, value] = dataAsArray;
|
|
209
|
+
return (index.h("duet-editable-table-item", { theme: this.theme, keyName: key, data: this.getItemData(value), groupId: group.id, part: group.id, alignment: this.alignment, actions: this.internalActionsArray }));
|
|
210
|
+
})))));
|
|
211
|
+
})));
|
|
212
|
+
}
|
|
213
|
+
get element() { return index.getElement(this); }
|
|
214
|
+
};
|
|
215
|
+
DuetEditableTable.style = duetEditableTableCss;
|
|
216
|
+
|
|
217
|
+
//simple functional component that renders the data in the table
|
|
218
|
+
const TableData = ({ data, groupId, alignment }, _children) => {
|
|
219
|
+
if (typeof data === "string") {
|
|
220
|
+
return (index.h("td", { innerHTML: data, class: "duet-editable-table-content", part: `${groupId}content`, style: { verticalAlign: alignment } }));
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
return (index.h("td", { class: "duet-editable-table-content", part: `${groupId}content`, style: { verticalAlign: alignment } }, data));
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const duetEditableTableItemCss = "*,*::after,*::before{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none}:host{display:table-row;height:32px}.duet-editable-table-content,.duet-editable-table-actions{height:32px;padding:12px 0;vertical-align:middle;break-word:break-all;border-bottom:1px solid #e1e3e6}.duet-editable-table-actions-items{display:flex;justify-content:flex-end}.duet-editable-table-actions-items duet-editable-table-button{padding-left:8px}.duet-editable-table .editable-item-small{font-size:0.75rem;font-weight:400}";
|
|
228
|
+
|
|
229
|
+
let DuetEditableTableItem = class {
|
|
230
|
+
constructor(hostRef) {
|
|
231
|
+
index.registerInstance(this, hostRef);
|
|
232
|
+
this.duetEditableItemAction = index.createEvent(this, "duetEditableItemAction", 7);
|
|
233
|
+
this.isHovering = false;
|
|
234
|
+
/**
|
|
235
|
+
* Theme of the empty state component.
|
|
236
|
+
*/
|
|
237
|
+
this.theme = "";
|
|
238
|
+
/**
|
|
239
|
+
* Actions that can be performed on the element
|
|
240
|
+
*/
|
|
241
|
+
this.actions = undefined;
|
|
242
|
+
/**
|
|
243
|
+
* GroupId used to pierce the shadowdom - gets concatenated with "content & actions" and used as part="groupIDcontent/actions" to pierce the content/Action item
|
|
244
|
+
* @internal
|
|
245
|
+
*/
|
|
246
|
+
this.groupId = "";
|
|
247
|
+
/**
|
|
248
|
+
* Key used to set vertical alignment of action buttons
|
|
249
|
+
*/
|
|
250
|
+
this.alignment = "middle";
|
|
251
|
+
/**
|
|
252
|
+
* Key used to identify item, when running actions
|
|
253
|
+
*/
|
|
254
|
+
this.keyName = "";
|
|
255
|
+
/**
|
|
256
|
+
* Object of data itemsused to render the entire row
|
|
257
|
+
*/
|
|
258
|
+
this.data = undefined;
|
|
259
|
+
}
|
|
260
|
+
watchPropHandler(_newValue, _oldValue) {
|
|
261
|
+
// console.log("The new value of activated is: ", _newValue)
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
/**
|
|
265
|
+
* Component lifecycle events.
|
|
266
|
+
*/
|
|
267
|
+
componentWillLoad() {
|
|
268
|
+
themeableComponent.inheritGlobalTheme(this);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
/**
|
|
272
|
+
* private functions
|
|
273
|
+
*/
|
|
274
|
+
/**
|
|
275
|
+
* render() function
|
|
276
|
+
* Always the last one in the class.
|
|
277
|
+
*/
|
|
278
|
+
render() {
|
|
279
|
+
return (index.h(index.Host, { role: "row" }, index.h(TableData, { data: this.data.item, alignment: this.alignment, groupId: this.groupId }), index.h("td", { class: "duet-editable-table-actions", style: { verticalAlign: this.alignment } }, index.h("div", { class: "duet-editable-table-actions-items", part: `${this.groupId}actions` }, this.actions.map(result => {
|
|
280
|
+
const { map = undefined } = result;
|
|
281
|
+
// if map has been specified, only show the current action if groupID matches the map array
|
|
282
|
+
if (map && !map.includes(this.groupId)) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
return (index.h("duet-editable-table-button", { keyName: this.keyName, group: this.data.group, uid: this.data.uid, actions: result, theme: this.theme }));
|
|
286
|
+
})))));
|
|
287
|
+
}
|
|
288
|
+
get el() { return index.getElement(this); }
|
|
289
|
+
static get watchers() { return {
|
|
290
|
+
"data": ["watchPropHandler"]
|
|
291
|
+
}; }
|
|
292
|
+
};
|
|
293
|
+
DuetEditableTableItem.style = duetEditableTableItemCss;
|
|
294
|
+
|
|
295
|
+
const duetTableCss = "duet-table{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none;margin-bottom:20px !important;display:block;font-variant-numeric:tabular-nums}duet-table table,duet-table thead,duet-table tbody,duet-table tfoot,duet-table th,duet-table td,duet-table tr{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none}duet-table.duet-m-0{margin:0 !important}duet-table table{width:100%;font-family:\"localtapiola-sans\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";font-size:1rem;text-align:left;border-spacing:0;border-collapse:separate}duet-table.duet-theme-turva table{font-family:\"turva-sans\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\"}duet-table td{-webkit-hyphens:auto;hyphens:auto;color:#00294d}duet-table.duet-theme-turva td{color:#171c3a}duet-table th{font-weight:600;line-height:1.25;color:#657787;text-align:left}duet-table.duet-theme-turva th{color:#747475}duet-table tbody th{font-weight:600;color:#00294d}duet-table.duet-theme-turva tbody th{color:#171c3a}.duet-table-flattened table,.duet-table-flattened thead,.duet-table-flattened tbody,.duet-table-flattened tfoot,.duet-table-flattened th,.duet-table-flattened td,.duet-table-flattened tr{display:block}.duet-table-flattened thead tr{position:absolute !important;top:0;width:1px !important;height:1px !important;padding:0 !important;overflow:hidden !important;clip:rect(1px, 1px, 1px, 1px) !important;border:0 !important}.duet-table-flattened td{line-height:1.25}.duet-table-flattened td:not(:last-child){margin-bottom:16px !important}.duet-table-flattened tbody td,.duet-table-flattened tbody th,.duet-table-flattened tfoot td{padding:0 !important;text-align:left !important}.duet-table-flattened tbody th{font-weight:600;line-height:1.25;color:#657787;text-align:left}.duet-table-flattened td[data-heading]::before{margin-bottom:4px !important;display:block;font-size:1rem;font-weight:600;color:#00294d;content:attr(data-heading)}.duet-table-flattened.duet-theme-turva td[data-heading]::before{color:#171c3a}.duet-table-sticky thead th{position:sticky;top:0;background:white}.duet-table-striped td,.duet-table-striped th{padding:20px !important}@media (max-width: 35.9375em){.duet-table-striped td,.duet-table-striped th{padding:20px 12px !important}}.duet-table-striped tbody th{background:white}.duet-table-striped.duet-table-sticky thead th{border-bottom:1px solid #e1e3e6}.duet-table-striped.duet-table-sticky.duet-theme-turva thead th{border-bottom-color:#e4e4e6}.duet-table-striped tbody:not(:first-of-type) th{padding-top:40px !important}.duet-table-striped tbody:only-of-type tr:nth-of-type(odd){background:rgba(0, 80, 128, 0.04)}.duet-table-striped.duet-theme-turva tbody:only-of-type tr:nth-of-type(odd){background:rgba(23, 28, 58, 0.04)}.duet-table-striped tbody:not(:only-of-type) tr:nth-of-type(even){background:rgba(0, 80, 128, 0.04)}.duet-table-striped.duet-theme-turva tbody:not(:only-of-type) tr:nth-of-type(even){background:rgba(23, 28, 58, 0.04)}.duet-table-striped tfoot td{border-top:1px solid #e1e3e6}.duet-table-striped.duet-theme-turva tfoot td{border-top-color:#e4e4e6}.duet-table-striped.duet-table-flattened tbody:not(:first-of-type) th{padding-top:20px !important}.duet-table-striped.duet-table-flattened tr{padding:20px !important}.duet-table-striped.duet-table-flattened tfoot td{border-top:0}.duet-table-striped.duet-table-flattened tfoot tr{border-top:1px solid #e1e3e6}.duet-table-striped.duet-table-flattened.duet-theme-turva tfoot tr{border-top-color:#e4e4e6}.duet-table-fixed th,.duet-table-minimal th,.duet-table-plain th{padding:16px !important;border-bottom:1px solid #657787}.duet-table-fixed th:first-child,.duet-table-minimal th:first-child,.duet-table-plain th:first-child{padding-left:0 !important}.duet-table-fixed th:last-child,.duet-table-minimal th:last-child,.duet-table-plain th:last-child{padding-right:0 !important}.duet-theme-turva.duet-table-fixed th,.duet-theme-turva.duet-table-minimal th,.duet-theme-turva.duet-table-plain th{border-bottom-color:#444445}.duet-table-fixed tbody th,.duet-table-minimal tbody th,.duet-table-plain tbody th{padding-top:40px !important;border-bottom-color:#e1e3e6}.duet-theme-turva.duet-table-fixed tbody th,.duet-theme-turva.duet-table-minimal tbody th,.duet-theme-turva.duet-table-plain tbody th{border-bottom-color:#e4e4e6}.duet-table-fixed td,.duet-table-minimal td,.duet-table-plain td{padding:16px !important}.duet-table-fixed td:first-child,.duet-table-minimal td:first-child,.duet-table-plain td:first-child{padding-left:0 !important}.duet-table-fixed td:last-child,.duet-table-minimal td:last-child,.duet-table-plain td:last-child{padding-right:0 !important}.duet-table-fixed tbody td,.duet-table-minimal tbody td,.duet-table-plain tbody td{border-bottom:1px solid #e1e3e6}.duet-theme-turva.duet-table-fixed tbody td,.duet-theme-turva.duet-table-minimal tbody td,.duet-theme-turva.duet-table-plain tbody td{border-bottom-color:#e4e4e6}.duet-table-flattened.duet-table-fixed tbody:first-of-type th,.duet-table-flattened.duet-table-minimal tbody:first-of-type th,.duet-table-flattened.duet-table-plain tbody:first-of-type th{padding-top:0 !important}.duet-table-flattened.duet-table-fixed td,.duet-table-flattened.duet-table-minimal td,.duet-table-flattened.duet-table-plain td,.duet-table-flattened.duet-table-fixed tbody th,.duet-table-flattened.duet-table-minimal tbody th,.duet-table-flattened.duet-table-plain tbody th{border-bottom:0}.duet-table-flattened.duet-table-fixed tr,.duet-table-flattened.duet-table-minimal tr,.duet-table-flattened.duet-table-plain tr{padding:20px 0 !important}.duet-table-flattened.duet-table-fixed tbody th,.duet-table-flattened.duet-table-minimal tbody th,.duet-table-flattened.duet-table-plain tbody th{padding-top:20px !important}.duet-table-flattened.duet-table-fixed tfoot td,.duet-table-flattened.duet-table-minimal tfoot td,.duet-table-flattened.duet-table-plain tfoot td{margin-bottom:4px !important}.duet-table-flattened.duet-table-fixed tbody:not(:only-of-type) tr:first-child,.duet-table-flattened.duet-table-minimal tbody:not(:only-of-type) tr:first-child,.duet-table-flattened.duet-table-plain tbody:not(:only-of-type) tr:first-child{border-bottom:0}.duet-table-plain.duet-table-flattened tbody tr{border-bottom:1px solid #e1e3e6}.duet-table-plain.duet-table-flattened.duet-theme-turva tbody tr{border-bottom-color:#e4e4e6}.duet-table-minimal tbody tr,.duet-table-minimal tbody tr td{vertical-align:top;border-bottom:0 none}.duet-table-minimal tbody tr:last-of-type,.duet-table-minimal tbody tr:last-of-type td{border-bottom:1px solid #e1e3e6}.duet-table-minimal.duet-table-flattened tbody tr,.duet-table-minimal.duet-table-flattened tbody tr td{border-bottom:0 none}.duet-table-minimal.duet-table-flattened tbody tr td[data-heading]::before{display:none}.duet-table-minimal.duet-table-flattened tfoot{border-top:1px solid #e1e3e6}.duet-table-minimal.duet-table-flattened.duet-theme-turva tfoot{border-top-color:#e4e4e6}.duet-table-fixed table{table-layout:fixed}.duet-table-fixed tbody tr,.duet-table-fixed tbody tr td,.duet-table-fixed tbody tr td:first-child{padding:4px !important;vertical-align:text-bottom;border-bottom:0 none}.duet-table-fixed thead{display:none}.duet-table-fixed tbody tr,.duet-table-fixed tbody tr td{border-bottom:0 none}.duet-table-fixed:not(.duet-table-flattened) tfoot{border-top:1px solid #e1e3e6}.duet-table-fixed:not(.duet-table-flattened).duet-theme-turva tfoot{border-top-color:#e4e4e6}.duet-table-scrollable{position:relative;width:100%;overflow-x:auto;background:linear-gradient(90deg, #fff 0%, rgba(255, 255, 255, 0)), linear-gradient(-90deg, #fff 0%, rgba(255, 255, 255, 0)) 100% 0, radial-gradient(farthest-side at 0% 50%, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0)), radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0)) 100% 0%;background-repeat:no-repeat;background-attachment:local, local, scroll, scroll;background-size:100px 100%, 100px 100%, 12px 100%, 12px 100%}.duet-table-selected-column{background:rgba(0, 119, 179, 0.08)}.duet-theme-turva .duet-table-selected-column{background:rgba(68, 68, 69, 0.08)}";
|
|
296
|
+
|
|
297
|
+
// remove wrapping speech marks.
|
|
298
|
+
// media query tokens are wrapped in speech marks,
|
|
299
|
+
// which need to be removed before use with matchMedia.
|
|
300
|
+
const unwrap = (str) => str.substring(1, str.length - 1);
|
|
301
|
+
const breakpointToToken = {
|
|
302
|
+
none: "all",
|
|
303
|
+
"none-scrollable": "all",
|
|
304
|
+
small: unwrap(tokens_module.mediaQuerySmall),
|
|
305
|
+
medium: unwrap(tokens_module.mediaQueryMedium),
|
|
306
|
+
large: unwrap(tokens_module.mediaQueryLarge),
|
|
307
|
+
"x-large": unwrap(tokens_module.mediaQueryXLarge),
|
|
308
|
+
"xx-large": unwrap(tokens_module.mediaQueryXxLarge),
|
|
309
|
+
"xxx-large": unwrap(tokens_module.mediaQueryXxxLarge),
|
|
310
|
+
};
|
|
311
|
+
const stickyTopValues = {
|
|
312
|
+
none: 0,
|
|
313
|
+
"with-links": parseFloat(tokens_module.sizeNavigation) * 16,
|
|
314
|
+
"without-links": parseFloat(tokens_module.sizeHeader) * 16,
|
|
315
|
+
};
|
|
316
|
+
let DuetTable = class {
|
|
317
|
+
constructor(hostRef) {
|
|
318
|
+
index.registerInstance(this, hostRef);
|
|
319
|
+
/**
|
|
320
|
+
* Tracks whether the breakpoint is matched. This is set to true by default so that JavaScript disabled in SSR mode we get accessible table data first.
|
|
321
|
+
*/
|
|
322
|
+
this.matchesBreakpoint = true;
|
|
323
|
+
/**
|
|
324
|
+
* Controls the margin of the component.
|
|
325
|
+
*/
|
|
326
|
+
this.margin = "auto";
|
|
327
|
+
/**
|
|
328
|
+
* Style variation of the table.
|
|
329
|
+
*/
|
|
330
|
+
this.variation = "striped";
|
|
331
|
+
/**
|
|
332
|
+
* Controls whether the table has a sticky header.
|
|
333
|
+
* Sticky headers are not compatible with breakpoint="none-scrollable".
|
|
334
|
+
*/
|
|
335
|
+
this.sticky = false;
|
|
336
|
+
/**
|
|
337
|
+
* Adjust the distance from top of the viewport (in pixels) when the
|
|
338
|
+
* table header becomes sticky.
|
|
339
|
+
*/
|
|
340
|
+
this.stickyDistance = "with-links";
|
|
341
|
+
/**
|
|
342
|
+
* By default the table is responsive - it will be flattened at narrow viewport widths.
|
|
343
|
+
* This prop controls the breakpoint at which the table should be rendered as a _regular_ table.
|
|
344
|
+
* Set to "none" to disable the responsive functionality.
|
|
345
|
+
* Set to "none-scrollable" to disable responsive functionality _and_ allow horizontal scrolling -
|
|
346
|
+
* this is useful for comparison tables where it's important to maintain column and row layout.
|
|
347
|
+
*/
|
|
348
|
+
this.breakpoint = "small";
|
|
349
|
+
this.handleMediaQueryChange = (mq) => {
|
|
350
|
+
this.matchesBreakpoint = mq.matches;
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
connectedCallback() {
|
|
354
|
+
this.mq = matchMedia(breakpointToToken[this.breakpoint]);
|
|
355
|
+
this.mq.addEventListener("change", this.handleMediaQueryChange);
|
|
356
|
+
this.handleMediaQueryChange(this.mq);
|
|
357
|
+
this.observer = new MutationObserver(() => this.copyHeadingsToCells());
|
|
358
|
+
this.observer.observe(this.element, {
|
|
359
|
+
childList: true,
|
|
360
|
+
subtree: true,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
componentWillLoad() {
|
|
364
|
+
themeableComponent.inheritGlobalTheme(this);
|
|
365
|
+
this.copyHeadingsToCells();
|
|
366
|
+
if (this.sticky && this.breakpoint === "none-scrollable") {
|
|
367
|
+
console.warn(`[DUET WARNING]: sticky and breakpoint="none-scrollable" are incompatible. Scrollable takes precedence`);
|
|
368
|
+
}
|
|
369
|
+
if (this.sticky) {
|
|
370
|
+
const stickyTop = stickyTopValues[this.stickyDistance];
|
|
371
|
+
const headingElements = this.element.querySelectorAll("thead th");
|
|
372
|
+
headingElements.forEach(th => (th.style.top = `${stickyTop}px`));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
componentDidLoad() {
|
|
376
|
+
// this clears all pending mutations,
|
|
377
|
+
// that way we avoid dealing with any initial changes
|
|
378
|
+
// and only get genuine mutations as rows are added/removed
|
|
379
|
+
this.observer.takeRecords();
|
|
380
|
+
}
|
|
381
|
+
disconnectedCallback() {
|
|
382
|
+
this.observer.disconnect();
|
|
383
|
+
this.observer = null;
|
|
384
|
+
this.mq.removeListener(this.handleMediaQueryChange);
|
|
385
|
+
this.mq = null;
|
|
386
|
+
this.matchesBreakpoint = true;
|
|
387
|
+
}
|
|
388
|
+
copyHeadingsToCells() {
|
|
389
|
+
const headingElements = this.element.querySelectorAll("thead th");
|
|
390
|
+
const rowElements = this.element.querySelectorAll("tbody tr");
|
|
391
|
+
const headings = Array.from(headingElements).map(th => th.textContent.trim());
|
|
392
|
+
rowElements.forEach(tr => {
|
|
393
|
+
tr.querySelectorAll("td").forEach((td, i) => {
|
|
394
|
+
if (headings[i]) {
|
|
395
|
+
td.dataset.heading = headings[i];
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
render() {
|
|
401
|
+
return (index.h(index.Host, { class: {
|
|
402
|
+
[`duet-table-${this.variation}`]: true,
|
|
403
|
+
"duet-table-flattened": !this.matchesBreakpoint,
|
|
404
|
+
// sticky only valid when in regular table layout
|
|
405
|
+
"duet-table-sticky": this.matchesBreakpoint && this.sticky,
|
|
406
|
+
"duet-table-scrollable": this.breakpoint === "none-scrollable",
|
|
407
|
+
"duet-m-0": this.margin === "none",
|
|
408
|
+
"duet-theme-turva": this.theme === "turva",
|
|
409
|
+
} }, index.h("slot", null)));
|
|
410
|
+
}
|
|
411
|
+
get element() { return index.getElement(this); }
|
|
412
|
+
};
|
|
413
|
+
DuetTable.style = duetTableCss;
|
|
414
|
+
|
|
415
|
+
const errorCodes = [
|
|
416
|
+
{
|
|
417
|
+
type: "default",
|
|
418
|
+
system_message: "unknown error",
|
|
419
|
+
message: {
|
|
420
|
+
fi: "Tapahtui tuntematon virhe, ole hyvä ja yritä uudelleen.",
|
|
421
|
+
sv: "Ett okänt fel uppstod, försök igen.",
|
|
422
|
+
en: "An unknown error occured, please try again."
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
type: "400",
|
|
427
|
+
system_message: "Bad Request: The server could not understand the request due to invalid syntax.",
|
|
428
|
+
message: {
|
|
429
|
+
fi: "Tiedostoa ei hyväksytty.",
|
|
430
|
+
sv: "Servern avvisade din fil.",
|
|
431
|
+
en: "The server rejected your file."
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
type: "401",
|
|
436
|
+
system_message: "Not Authenticated: The client must authenticate itself to get the requested response...",
|
|
437
|
+
message: {
|
|
438
|
+
fi: "Vain kirjautunut käyttäjä voi lähettää tiedostoja.",
|
|
439
|
+
sv: "Du måste vara inloggad för att ladda upp filer.",
|
|
440
|
+
en: "You need to be logged in to upload files."
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
type: "403",
|
|
445
|
+
system_message: "No Access: The client does not have access rights to the content.",
|
|
446
|
+
message: {
|
|
447
|
+
fi: "Ei oikeuksia lähettää tiedostoja.",
|
|
448
|
+
sv: "Du har inte rätt åtkomsträttigheter för att ladda upp filer.",
|
|
449
|
+
en: "You do not have the correct access rights to upload files."
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
type: "413",
|
|
454
|
+
system_message: "Payload too large",
|
|
455
|
+
message: {
|
|
456
|
+
fi: "Tiedosto oli liian vastaanotettavaksi.",
|
|
457
|
+
sv: "Filen var för stor för servern att hantera.",
|
|
458
|
+
en: "The file was to large for the server to handle."
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
type: "415",
|
|
463
|
+
system_message: "Unsupported media type",
|
|
464
|
+
message: {
|
|
465
|
+
fi: "Tiedoston tyyppi oli väärä.",
|
|
466
|
+
sv: "Servern avvisade filen eftersom den hade fel typ.",
|
|
467
|
+
en: "The server rejected the file because it had the wrong type."
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
type: "429",
|
|
472
|
+
system_message: "Too many request from same address",
|
|
473
|
+
message: {
|
|
474
|
+
fi: "Liian monta yritystä, ole hyvä ja yritä myöhemmin uudelleen.",
|
|
475
|
+
sv: "Servern har fått många förfrågningar från dig, försök igen senare.",
|
|
476
|
+
en: "The server has received to many request from you, please try again later."
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
type: "500",
|
|
481
|
+
system_message: "Internal Server Error",
|
|
482
|
+
message: {
|
|
483
|
+
fi: "Palvelin ilmoitti tuntemattomasta virheestä ja lataus epäonnistui.",
|
|
484
|
+
sv: "Servern rapporterade ett okänt fel och uppladdningen misslyckades.",
|
|
485
|
+
en: "The server reported an unknown error and the upload failed."
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
type: "duet-upload-100",
|
|
490
|
+
system_message: "File extension not allowed",
|
|
491
|
+
message: {
|
|
492
|
+
fi: "Tiedoston tyyppi ei ole sallittu.",
|
|
493
|
+
sv: "Du kan inte ladda upp filer av den type.",
|
|
494
|
+
en: "You cannot upload files with that extension."
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
type: "duet-upload-001",
|
|
499
|
+
system_message: "File transfer failed",
|
|
500
|
+
message: {
|
|
501
|
+
fi: "Tiedoston lähetys keskeytyi, ole hyvä ja yritä uudelleen.",
|
|
502
|
+
sv: "Din anslutning till servern avbröts, försök igen.",
|
|
503
|
+
en: "Your connection to the server was interrupted, try again."
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
type: "duet-upload-101",
|
|
508
|
+
system_message: "File mimetype not allowed",
|
|
509
|
+
message: {
|
|
510
|
+
fi: "Tiedoston tyyppi ei ole sallittu.",
|
|
511
|
+
sv: "Du kan inte ladda upp filer av den typ.",
|
|
512
|
+
en: "You cannot upload files of that type."
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
type: "duet-upload-201",
|
|
517
|
+
system_message: "File is too large",
|
|
518
|
+
message: {
|
|
519
|
+
fi: "Tiedosto on liian iso.",
|
|
520
|
+
sv: "Filen är större än tillåtet.",
|
|
521
|
+
en: "The file is larger than permitted."
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
type: "duet-upload-202",
|
|
526
|
+
system_message: "The combined size of all files is too large",
|
|
527
|
+
message: {
|
|
528
|
+
fi: "Tiedostojen yhteenlaskettu koko on liian iso.",
|
|
529
|
+
sv: "Du har nått den maximala kombinerade filstorleken.",
|
|
530
|
+
en: "You have reached the maximum combined filesize."
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
type: "duet-upload-301",
|
|
535
|
+
system_message: "The maximum file limit has been reached",
|
|
536
|
+
message: {
|
|
537
|
+
fi: "Liitteiden maksimimäärä saavutettu.",
|
|
538
|
+
sv: "Maximalt antal bilagor har uppnåtts.",
|
|
539
|
+
en: "Maximum number of attachments reached."
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
];
|
|
543
|
+
|
|
544
|
+
const getError = (code) => {
|
|
545
|
+
let error = {
|
|
546
|
+
type: undefined,
|
|
547
|
+
system_message: undefined,
|
|
548
|
+
message: undefined,
|
|
549
|
+
};
|
|
550
|
+
error = errorCodes.filter(errorItem => {
|
|
551
|
+
// the == is intentional we may be comparing numbers to strings - and that is ok here
|
|
552
|
+
return errorItem.type == code;
|
|
553
|
+
})[0];
|
|
554
|
+
if (!error) {
|
|
555
|
+
error = errorCodes.filter(errorItem => {
|
|
556
|
+
return errorItem.type === "default";
|
|
557
|
+
})[0];
|
|
558
|
+
}
|
|
559
|
+
return error;
|
|
560
|
+
};
|
|
561
|
+
const getI18nError = (errorCode) => {
|
|
562
|
+
const errorFromJson = getError(errorCode);
|
|
563
|
+
const i18String = languageUtils.getLocaleString(errorFromJson.message);
|
|
564
|
+
if (i18String === "" || !i18String) {
|
|
565
|
+
return errorFromJson.system_message;
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
return i18String;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const ErrorItem = ({ data }) => {
|
|
573
|
+
const { item, error } = data;
|
|
574
|
+
const { name } = item;
|
|
575
|
+
const { type } = error;
|
|
576
|
+
return (index.h("span", { class: "duet-upload-item-error", role: "status" },
|
|
577
|
+
index.h("duet-paragraph", { class: "duet-upload-item-name", color: "danger", margin: "none", weight: "semi-bold" },
|
|
578
|
+
index.h("duet-icon", { margin: "none", size: "xx-small", name: "messaging-attachment" }),
|
|
579
|
+
" ",
|
|
580
|
+
name),
|
|
581
|
+
index.h("duet-paragraph", { class: "duet-upload-item-error-label", size: "small", margin: "none", color: "danger" }, getI18nError(type))));
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
const ProgressItem = ({ progress, name }) => (index.h("span", null,
|
|
585
|
+
index.h("duet-paragraph", { color: "secondary", margin: "none", size: "small" }, name),
|
|
586
|
+
index.h("duet-spacer", { size: "xx-small" }),
|
|
587
|
+
index.h("duet-progress", { progress: Math.ceil(progress), "aria-hidden": true })));
|
|
588
|
+
|
|
589
|
+
const formatBytes = (bytes, decimals = 2) => {
|
|
590
|
+
if (bytes === 0) {
|
|
591
|
+
return "0 Bytes";
|
|
592
|
+
}
|
|
593
|
+
const k = 1024;
|
|
594
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
595
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
596
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
597
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const SuccessItem = ({ data, showLinks }) => {
|
|
601
|
+
const { item, size, uploaded, url, meta } = data;
|
|
602
|
+
const { name } = item;
|
|
603
|
+
const ContentName = (index.h("span", { class: "duet-upload-item-name" },
|
|
604
|
+
index.h("duet-icon", { margin: "none", size: "xx-small", name: "messaging-attachment" }),
|
|
605
|
+
index.h("duet-spacer", { size: "xx-small", direction: "horizontal" }),
|
|
606
|
+
name));
|
|
607
|
+
const SizeText = (index.h("span", { class: "duet-upload-item-size", style: { fontSize: "14px", fontWeight: "400" } },
|
|
608
|
+
"(",
|
|
609
|
+
formatBytes(size),
|
|
610
|
+
")"));
|
|
611
|
+
const FilenameLine = uploaded && url && showLinks ? (index.h("duet-paragraph", { color: "secondary", margin: "none", weight: "semi-bold" },
|
|
612
|
+
index.h("duet-link", { url: url, external: true }, ContentName),
|
|
613
|
+
index.h("duet-spacer", { size: "xx-small", direction: "horizontal" }),
|
|
614
|
+
SizeText)) : (index.h("duet-paragraph", { color: "secondary", margin: "none", weight: "semi-bold" },
|
|
615
|
+
ContentName,
|
|
616
|
+
index.h("duet-spacer", { size: "xx-small", direction: "horizontal" }),
|
|
617
|
+
SizeText));
|
|
618
|
+
const Badges = meta && meta.badges ? (index.h("span", null,
|
|
619
|
+
index.h("duet-spacer", { size: "xx-small" }),
|
|
620
|
+
meta.badges.map(badgeText => (index.h("duet-badge", { color: "primary" }, badgeText))))) : undefined;
|
|
621
|
+
return (index.h("span", { class: "duet-upload-item-success" },
|
|
622
|
+
index.h("div", null, FilenameLine),
|
|
623
|
+
Badges));
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
const validateFileExtension = (name, allowedExtensions) => {
|
|
627
|
+
if (!allowedExtensions) {
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
const ext = name.split(".");
|
|
631
|
+
const validExtension = allowedExtensions.split(",");
|
|
632
|
+
const extension = ext[ext.length - 1];
|
|
633
|
+
return validExtension.includes(extension);
|
|
634
|
+
};
|
|
635
|
+
const validateFileMime = (type, allowedMimetypes) => {
|
|
636
|
+
if (!allowedMimetypes || !type) {
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
const validMimeTypes = allowedMimetypes.split(",");
|
|
640
|
+
let valid = false;
|
|
641
|
+
validMimeTypes.forEach(mimeType => {
|
|
642
|
+
const allowedTypes = mimeType.split("/");
|
|
643
|
+
const fileType = type.split("/");
|
|
644
|
+
if (allowedTypes[0] === fileType[0] && (allowedTypes[1] === fileType[1] || allowedTypes[1] === "*")) {
|
|
645
|
+
valid = true;
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
return valid;
|
|
649
|
+
};
|
|
650
|
+
const validateFileSize = (size, maxBytes) => {
|
|
651
|
+
if (!maxBytes || !size) {
|
|
652
|
+
return true;
|
|
653
|
+
}
|
|
654
|
+
return maxBytes >= size;
|
|
655
|
+
};
|
|
656
|
+
const validateFile = (item, validators) => {
|
|
657
|
+
const { allowedMimetypes, allowedExtensions, maxBytes } = validators;
|
|
658
|
+
let valid = false;
|
|
659
|
+
let errorMessage = getError("default");
|
|
660
|
+
if (item) {
|
|
661
|
+
const { name, type, size } = item;
|
|
662
|
+
const mime = validateFileMime(type, allowedMimetypes);
|
|
663
|
+
const ext = validateFileExtension(name, allowedExtensions);
|
|
664
|
+
const bytes = validateFileSize(size, maxBytes);
|
|
665
|
+
if (!mime) {
|
|
666
|
+
errorMessage = getError("duet-upload-101");
|
|
667
|
+
}
|
|
668
|
+
if (!ext) {
|
|
669
|
+
errorMessage = getError("duet-upload-100");
|
|
670
|
+
}
|
|
671
|
+
if (!bytes) {
|
|
672
|
+
errorMessage = getError("duet-upload-201");
|
|
673
|
+
}
|
|
674
|
+
valid = mime && ext && bytes;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
valid = false;
|
|
678
|
+
}
|
|
679
|
+
return {
|
|
680
|
+
valid,
|
|
681
|
+
errorMessage: valid ? undefined : languageUtils.getLocaleString(errorMessage.message),
|
|
682
|
+
errorSystem: valid ? undefined : errorMessage.system_message,
|
|
683
|
+
errorType: valid ? undefined : errorMessage.type,
|
|
684
|
+
};
|
|
685
|
+
};
|
|
686
|
+
const validateTotalSizeIsAboveMax = (filelist, maxTotalBytes) => {
|
|
687
|
+
let total = 0;
|
|
688
|
+
if (maxTotalBytes) {
|
|
689
|
+
filelist.forEach(item => {
|
|
690
|
+
if (item.valid && item.size) {
|
|
691
|
+
total += item.size;
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
if (total < maxTotalBytes) {
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return false;
|
|
699
|
+
};
|
|
700
|
+
const validateTotalAmountIsAboveMax = (filelist, maxFiles) => {
|
|
701
|
+
let total = 0;
|
|
702
|
+
if (maxFiles) {
|
|
703
|
+
filelist.forEach(item => {
|
|
704
|
+
if (item.valid) {
|
|
705
|
+
total++;
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
if (total > maxFiles) {
|
|
709
|
+
return true;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return false;
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
const makeXhrRequest = ({ payload, options, onFailure, onSuccess, onProgress }) => {
|
|
716
|
+
const { type = "POST", xhr, uri, argument = null, headers = null } = options;
|
|
717
|
+
xhr.open(type, `${uri}${argument || ""}`, true);
|
|
718
|
+
const { data, name } = payload;
|
|
719
|
+
// headers must be added after open
|
|
720
|
+
if (headers) {
|
|
721
|
+
Object.keys(headers).forEach(key => {
|
|
722
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
if (type === "POST") {
|
|
726
|
+
xhr.onreadystatechange = () => {
|
|
727
|
+
// Call a function when the state changes.
|
|
728
|
+
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status >= 200 && xhr.status < 300) {
|
|
729
|
+
// Request finished without errors
|
|
730
|
+
onSuccess(xhr, name, xhr.status);
|
|
731
|
+
}
|
|
732
|
+
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status >= 300 && xhr.status < 999) {
|
|
733
|
+
// Request finished with errors
|
|
734
|
+
onFailure(xhr, name, xhr.status);
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
onProgress(name);
|
|
738
|
+
}
|
|
739
|
+
xhr.send(data);
|
|
740
|
+
return xhr;
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
const duetUploadCss = "*,*::after,*::before{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none}:host{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none}::slotted([slot=header]){margin-bottom:16px}::slotted([slot=fileheader]){margin:16px 0 0 0}::slotted([slot=filefooter]){margin-top:16px}.duet-upload{box-sizing:border-box;padding:0;margin:0;background:transparent;border:0;-moz-appearance:none;-webkit-appearance:none;appearance:none}.duet-upload-item-size{font-size:0.75rem;font-weight:400}.duet-upload-filelist{margin-bottom:25px}.duet-upload-filelist-empty{display:flex;align-items:center;justify-content:center;width:100%;height:75px;margin:0 auto;font-size:1rem;font-weight:400;background-color:#f5f8fa}";
|
|
744
|
+
|
|
745
|
+
let DuetUpload = class {
|
|
746
|
+
constructor(hostRef) {
|
|
747
|
+
index.registerInstance(this, hostRef);
|
|
748
|
+
this.duetChange = index.createEvent(this, "duetChange", 3);
|
|
749
|
+
this.duetBlur = index.createEvent(this, "duetBlur", 7);
|
|
750
|
+
this.duetFocus = index.createEvent(this, "duetFocus", 7);
|
|
751
|
+
this.duetDone = index.createEvent(this, "duetDone", 3);
|
|
752
|
+
this.duetState = index.createEvent(this, "duetState", 3);
|
|
753
|
+
this.duetDelete = index.createEvent(this, "duetDelete", 3);
|
|
754
|
+
this.duetCancel = index.createEvent(this, "duetCancel", 3);
|
|
755
|
+
this.duetProgress = index.createEvent(this, "duetProgress", 3);
|
|
756
|
+
this.duetUpload = index.createEvent(this, "duetUpload", 3);
|
|
757
|
+
/**
|
|
758
|
+
* Own Properties
|
|
759
|
+
*/
|
|
760
|
+
this.buttonId = createId.createID("DuetButton");
|
|
761
|
+
this.labelId = createId.createID("DuetLabel");
|
|
762
|
+
this.uploadId = createId.createID("DuetUpload");
|
|
763
|
+
this.editableTableId = createId.createID("DuetEditableTable");
|
|
764
|
+
this.filesInProgress = new Map();
|
|
765
|
+
this.fileMaxReached = false;
|
|
766
|
+
this.bytesMaxReached = false;
|
|
767
|
+
this.internalStatusMessageLabel = undefined;
|
|
768
|
+
/**
|
|
769
|
+
* Properties
|
|
770
|
+
*/
|
|
771
|
+
this.DefaultGroups = {
|
|
772
|
+
inprogress: "inprogress",
|
|
773
|
+
success: "success",
|
|
774
|
+
failure: "failure",
|
|
775
|
+
};
|
|
776
|
+
/**
|
|
777
|
+
* State() variables
|
|
778
|
+
*/
|
|
779
|
+
this.tick = Date.now();
|
|
780
|
+
/**
|
|
781
|
+
* If external is set to true, the upload component will not actually upload the files, but only keep states
|
|
782
|
+
* it will be up to you to handle the upload and return progress information to the upload-component
|
|
783
|
+
*/
|
|
784
|
+
this.external = false;
|
|
785
|
+
/**
|
|
786
|
+
* If set the upload component will not display an upload button, you will have to create one yourself
|
|
787
|
+
* and call the exposed method startUpload
|
|
788
|
+
*/
|
|
789
|
+
this.hideButton = false;
|
|
790
|
+
/**
|
|
791
|
+
* Default actions added to the internally used duet-editable-table
|
|
792
|
+
*/
|
|
793
|
+
this.actions = [
|
|
794
|
+
{
|
|
795
|
+
icon: "action-delete",
|
|
796
|
+
color: "color-danger",
|
|
797
|
+
color_hover: "primary-dark",
|
|
798
|
+
id: "delete",
|
|
799
|
+
map: ["success", "failure"],
|
|
800
|
+
label: {
|
|
801
|
+
fi: "Poista tiedosto",
|
|
802
|
+
en: "Poista tiedosto",
|
|
803
|
+
sv: "Ta bort filen",
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
icon: "navigation-close",
|
|
808
|
+
color: "primary",
|
|
809
|
+
color_hover: "primary-dark",
|
|
810
|
+
id: "cancel",
|
|
811
|
+
map: ["inprogress"],
|
|
812
|
+
label: {
|
|
813
|
+
fi: "Keskeytä lähetys",
|
|
814
|
+
en: "Cancel the upload",
|
|
815
|
+
sv: "Stop överföringen",
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
];
|
|
819
|
+
/**
|
|
820
|
+
* If enabled the editable-table will display links on successfully uploaded items,
|
|
821
|
+
* this requires the server can respond with link URIs in the correct format
|
|
822
|
+
* and that the files are accessible to the user
|
|
823
|
+
*/
|
|
824
|
+
this.showLinks = false;
|
|
825
|
+
/**
|
|
826
|
+
* Property to change the aria upload progress text read aloud by screenreaders
|
|
827
|
+
* @default {
|
|
828
|
+
* fi: {
|
|
829
|
+
* inProgress: "Lähetetään {filesUploaded} lähetettävästä {filesTotal} tiedostosta",
|
|
830
|
+
* inProgressWithErrors:
|
|
831
|
+
* "Lähetetään {filesInProgress} tiedostoa, lähetetty {filesUploaded} lähetettävästä {filesTotal} tiedostosta, {filesWithErrors} tiedostossa on virheitä",
|
|
832
|
+
* done: "Kaikki {filesTotal} tiedostoa lähetetty onnistuneesti",
|
|
833
|
+
* doneWithErrors:
|
|
834
|
+
* "Lähetys valmis, {filesUploaded} tiedostoa on lähetetty onnistuneesti, {filesWithErrors} tiedostossa oli virheitä",
|
|
835
|
+
* files: "tiedostot",
|
|
836
|
+
* file: "tiedosto",
|
|
837
|
+
* },
|
|
838
|
+
* sv: {
|
|
839
|
+
* inProgress: "Adding {filesUploaded} of {filesTotal}",
|
|
840
|
+
* inProgressWithErrors:
|
|
841
|
+
* "Laddar upp {filesInProgress}, {filesUploaded} uppladdad av {filesTotal}, {filesWithErrors} misslyckades",
|
|
842
|
+
* done: "Alla {filesTotal} har lagts till",
|
|
843
|
+
* doneWithErrors: "Handling slutförd, {filesUploaded} har lagts till, {filesWithErrors} misslyckades",
|
|
844
|
+
* files: "filer",
|
|
845
|
+
* file: "fil",
|
|
846
|
+
* },
|
|
847
|
+
* en: {
|
|
848
|
+
* inProgress: "Adding {filesUploaded} of {filesTotal}",
|
|
849
|
+
* inProgressWithErrors:
|
|
850
|
+
* "Uploading {filesInProgress}, {filesUploaded} uploaded of {filesTotal}, {filesWithErrors} failed",
|
|
851
|
+
* done: "All {filesTotal} added successfully",
|
|
852
|
+
* doneWithErrors: "Action completed, {filesUploaded} has been added successfully, {filesWithErrors} had errors",
|
|
853
|
+
* files: "tiedostoa",
|
|
854
|
+
* file: "tiedosto",
|
|
855
|
+
* },
|
|
856
|
+
* }
|
|
857
|
+
*/
|
|
858
|
+
this.statusLabelDefaults = {
|
|
859
|
+
fi: {
|
|
860
|
+
inProgress: "Lähetetään {filesUploaded} lähetettävästä {filesTotal} tiedostosta",
|
|
861
|
+
inProgressWithErrors: "Lähetetään {filesInProgress} tiedostoa, lähetetty {filesUploaded} lähetettävästä {filesTotal} tiedostosta, {filesWithErrors} tiedostossa on virheitä",
|
|
862
|
+
done: "Kaikki {filesTotal} tiedostoa lähetetty onnistuneesti",
|
|
863
|
+
doneWithErrors: "Lähetys valmis, {filesUploaded} tiedostoa on lähetetty onnistuneesti, {filesWithErrors} tiedostossa oli virheitä",
|
|
864
|
+
files: "tiedostot",
|
|
865
|
+
file: "tiedosto",
|
|
866
|
+
},
|
|
867
|
+
sv: {
|
|
868
|
+
inProgress: "Adding {filesUploaded} of {filesTotal}",
|
|
869
|
+
inProgressWithErrors: "Laddar upp {filesInProgress}, {filesUploaded} uppladdad av {filesTotal}, {filesWithErrors} misslyckades",
|
|
870
|
+
done: "Alla {filesTotal} har lagts till",
|
|
871
|
+
doneWithErrors: "Handling slutförd, {filesUploaded} har lagts till, {filesWithErrors} misslyckades",
|
|
872
|
+
files: "filer",
|
|
873
|
+
file: "fil",
|
|
874
|
+
},
|
|
875
|
+
en: {
|
|
876
|
+
inProgress: "Adding {filesUploaded} of {filesTotal}",
|
|
877
|
+
inProgressWithErrors: "Uploading {filesInProgress}, {filesUploaded} uploaded of {filesTotal}, {filesWithErrors} failed",
|
|
878
|
+
done: "All {filesTotal} added successfully",
|
|
879
|
+
doneWithErrors: "Action completed, {filesUploaded} has been added successfully, {filesWithErrors} had errors",
|
|
880
|
+
files: "tiedostoa",
|
|
881
|
+
file: "tiedosto",
|
|
882
|
+
},
|
|
883
|
+
};
|
|
884
|
+
/**
|
|
885
|
+
* Strings used for the status aria-label
|
|
886
|
+
*/
|
|
887
|
+
this.statusMessageLabel = languageUtils.getLocaleString(this.statusLabelDefaults);
|
|
888
|
+
/**
|
|
889
|
+
* Property to change button label defaults on the component.
|
|
890
|
+
* @default {
|
|
891
|
+
fi: "Lisää liite",
|
|
892
|
+
sv: "Lägg till en bilaga",
|
|
893
|
+
en: "Add an attachment",
|
|
894
|
+
}
|
|
895
|
+
*/
|
|
896
|
+
this.buttonLabelDefaults = {
|
|
897
|
+
fi: "Lisää liite",
|
|
898
|
+
sv: "Lägg till en bilaga",
|
|
899
|
+
en: "Add an attachment",
|
|
900
|
+
};
|
|
901
|
+
/**
|
|
902
|
+
* Label of button
|
|
903
|
+
* @default { fi: "Lisää liite", sv: "Lägg till en bilaga", en: "Add an attachment" }
|
|
904
|
+
*/
|
|
905
|
+
this.buttonLabel = languageUtils.getLocaleString(this.buttonLabelDefaults);
|
|
906
|
+
/**
|
|
907
|
+
* accessible aria-Label of button
|
|
908
|
+
*/
|
|
909
|
+
this.accessibleButtonLabel = undefined;
|
|
910
|
+
/**
|
|
911
|
+
* Theme of the input.
|
|
912
|
+
*/
|
|
913
|
+
this.theme = "";
|
|
914
|
+
/**
|
|
915
|
+
* Makes the input component disabled. This prevents users from being able to
|
|
916
|
+
* interact with the upload component, and conveys its inactive state to assistive technologies.
|
|
917
|
+
*/
|
|
918
|
+
this.disabled = false;
|
|
919
|
+
/**
|
|
920
|
+
* Controls the margin of the component.
|
|
921
|
+
*/
|
|
922
|
+
this.margin = "auto";
|
|
923
|
+
/**
|
|
924
|
+
* Set whether the input is required or not. Please note that this is necessary for
|
|
925
|
+
* accessible inputs when the user is required to fill them. When using this property
|
|
926
|
+
* you need to also set “novalidate” attribute to your form element to prevent
|
|
927
|
+
* browser from displaying its own validation errors.
|
|
928
|
+
*/
|
|
929
|
+
this.required = false;
|
|
930
|
+
/**
|
|
931
|
+
* Key used to set vertical alignment of action buttons
|
|
932
|
+
*/
|
|
933
|
+
this.alignment = "middle";
|
|
934
|
+
/**
|
|
935
|
+
* Visually hides the groups labels in the editable table list used to display the list of files
|
|
936
|
+
*/
|
|
937
|
+
this.hideGroups = false;
|
|
938
|
+
/**
|
|
939
|
+
* Map of string that contain list of uploaded files.
|
|
940
|
+
*/
|
|
941
|
+
this.files = new Map();
|
|
942
|
+
/**
|
|
943
|
+
* Property to read if the internally used editable-table contains errors or not
|
|
944
|
+
*/
|
|
945
|
+
this.valid = !this.required;
|
|
946
|
+
/**
|
|
947
|
+
* Property to change labelDefaults defaults on the component.
|
|
948
|
+
* normally you would handle these strings on an application level and override @label when needed
|
|
949
|
+
* @default { fi: "Lisää liite",sv: "Lägg till en bilaga",en: "Add attachments"}
|
|
950
|
+
*/
|
|
951
|
+
this.labelDefaults = {
|
|
952
|
+
fi: "Lisää liite",
|
|
953
|
+
sv: "Lägg till en bilaga",
|
|
954
|
+
en: "Add attachments",
|
|
955
|
+
};
|
|
956
|
+
/**
|
|
957
|
+
* Label for the input.
|
|
958
|
+
* @default { fi: "Lisää liite",sv: "Lägg till en bilaga",en: "Add attachments"}
|
|
959
|
+
*/
|
|
960
|
+
this.label = languageUtils.getLocaleString(this.labelDefaults);
|
|
961
|
+
/**
|
|
962
|
+
* Property to change descriptionDefaults defaults on the component.
|
|
963
|
+
* @default {
|
|
964
|
+
fi: "Voit liittää {filetypes}-muotoisia tiedostoja sekä yleisimpiä videotiedostoja. Voit lähettää {maxbytes} verran tiedostoja yhdellä kertaa, ja lisätä enintään {maxfiles} liitettä kerrallaan.",
|
|
965
|
+
sv: "Du kan bifoga filer i flg. formater {filetypes} samt de vanligaste videofilerna. Du kan ladda upp {maxbytes} filer åt gången och lägga till upp till {maxfiles} bilagor åt gången.",
|
|
966
|
+
en: "You may attach the following filetypes: {filetypes} - as well as the most common video files. You can upload {maxbytes} of files at a time, and add up to {maxfiles} attachments at a time.",
|
|
967
|
+
}
|
|
968
|
+
*/
|
|
969
|
+
this.descriptionDefaults = {
|
|
970
|
+
fi: "Voit liittää {filetypes}-muotoisia tiedostoja sekä yleisimpiä videotiedostoja. Voit lähettää {maxbytes} verran tiedostoja yhdellä kertaa, ja lisätä enintään {maxfiles} liitettä kerrallaan.",
|
|
971
|
+
sv: "Du kan bifoga filer i flg. formater {filetypes} samt de vanligaste videofilerna. Du kan ladda upp {maxbytes} filer åt gången och lägga till upp till {maxfiles} bilagor åt gången.",
|
|
972
|
+
en: "You may attach the following filetypes: {filetypes} - as well as the most common video files. You can upload {maxbytes} of files at a time, and add up to {maxfiles} attachments at a time.",
|
|
973
|
+
};
|
|
974
|
+
/**
|
|
975
|
+
* Description for the upload component.
|
|
976
|
+
* @default {
|
|
977
|
+
fi: "Voit liittää {filetypes}-muotoisia tiedostoja sekä yleisimpiä videotiedostoja. Voit lähettää {maxbytes} verran tiedostoja yhdellä kertaa, ja lisätä enintään {maxfiles} liitettä kerrallaan.",
|
|
978
|
+
sv: "Du kan bifoga filer i flg. formater {filetypes} samt de vanligaste videofilerna. Du kan ladda upp {maxbytes} filer åt gången och lägga till upp till {maxfiles} bilagor åt gången.",
|
|
979
|
+
en: "You may attach the following filetypes: {filetypes} - as well as the most common video files. You can upload {maxbytes} of files at a time, and add up to {maxfiles} attachments at a time.",
|
|
980
|
+
}
|
|
981
|
+
*/
|
|
982
|
+
this.description = languageUtils.getLocaleString(this.descriptionDefaults);
|
|
983
|
+
/**
|
|
984
|
+
* Defaults for the filelist's empty state.
|
|
985
|
+
* @default {
|
|
986
|
+
fi: "Ei vielä lisättyjä tiedostoja.",
|
|
987
|
+
sv: "Inga filer har lagts till ännu.",
|
|
988
|
+
en: "No files added yet.",
|
|
989
|
+
}
|
|
990
|
+
*/
|
|
991
|
+
this.fileListEmptyDefaults = {
|
|
992
|
+
fi: "Ei vielä lisättyjä tiedostoja.",
|
|
993
|
+
sv: "Inga filer har lagts till ännu.",
|
|
994
|
+
en: "No files added yet.",
|
|
995
|
+
};
|
|
996
|
+
/**
|
|
997
|
+
* Label for the filelist's empty state.
|
|
998
|
+
* @default { fi: "Ei vielä lisättyjä tiedostoja.",sv: "Inga filer har lagts till ännu.",en: "No files added yet."}
|
|
999
|
+
*/
|
|
1000
|
+
this.fileListEmpty = languageUtils.getLocaleString(this.fileListEmptyDefaults);
|
|
1001
|
+
/**
|
|
1002
|
+
* Display the input in error state along with an error message.
|
|
1003
|
+
*/
|
|
1004
|
+
this.error = "";
|
|
1005
|
+
/**
|
|
1006
|
+
* Use maxBytes to specify the maximum size in Bytes of a file that can be uploaded.
|
|
1007
|
+
*/
|
|
1008
|
+
this.maxBytes = 200000000;
|
|
1009
|
+
/**
|
|
1010
|
+
* Use maxBytesTotal to specify the maximum size in Bytes of All files combined that can be uploaded.
|
|
1011
|
+
*/
|
|
1012
|
+
this.maxBytesTotal = undefined;
|
|
1013
|
+
/**
|
|
1014
|
+
* Use maxFiles to specify the maximum amount of files that can be uploaded
|
|
1015
|
+
*/
|
|
1016
|
+
this.maxFiles = 99;
|
|
1017
|
+
/**
|
|
1018
|
+
* A string of commaseperated file type values that are allowed
|
|
1019
|
+
* @example: .pdf,.doc,.docx
|
|
1020
|
+
*/
|
|
1021
|
+
this.allowedExtensions = "all";
|
|
1022
|
+
/**
|
|
1023
|
+
* A string of commaseperated mime type values that are allowed
|
|
1024
|
+
* @example: image/*,application/msword,
|
|
1025
|
+
*/
|
|
1026
|
+
this.allowedMimetypes = "*";
|
|
1027
|
+
/**
|
|
1028
|
+
* Use multiple to allow the user to select multiple files when uploading
|
|
1029
|
+
*/
|
|
1030
|
+
this.multiple = true;
|
|
1031
|
+
/**
|
|
1032
|
+
* Use limitSelection to enforce the value in allowedExtension & allowedMimetypes when selecting files,
|
|
1033
|
+
* by default this is off, setting this to true will limit the users choices to what has been explicitly set
|
|
1034
|
+
*/
|
|
1035
|
+
this.limitSelection = false;
|
|
1036
|
+
/**
|
|
1037
|
+
* Private functions
|
|
1038
|
+
*/
|
|
1039
|
+
this.listenForActionEvents = () => {
|
|
1040
|
+
this.element.addEventListener("duetEditableItemAction", (e) => {
|
|
1041
|
+
const detail = e.detail;
|
|
1042
|
+
const { action, keyName, originalEvent } = detail;
|
|
1043
|
+
switch (action) {
|
|
1044
|
+
case "delete":
|
|
1045
|
+
this.onDelete(keyName, originalEvent);
|
|
1046
|
+
break;
|
|
1047
|
+
case "cancel":
|
|
1048
|
+
this.onCancel(keyName, originalEvent);
|
|
1049
|
+
break;
|
|
1050
|
+
// code block
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
};
|
|
1054
|
+
this.verifyValidity = () => {
|
|
1055
|
+
const { invalid, valid } = this.getFilesAsArray();
|
|
1056
|
+
const oldValid = this.valid;
|
|
1057
|
+
this.valid = invalid.length === 0 && valid.length !== 0;
|
|
1058
|
+
if (this.valid !== oldValid) {
|
|
1059
|
+
this.duetState.emit({
|
|
1060
|
+
originalEvent: undefined,
|
|
1061
|
+
data: { valid: this.valid, from: "componentWillRender" },
|
|
1062
|
+
component: "duet-upload",
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
this.getGroupFromItemData = (item) => {
|
|
1067
|
+
if (item.valid && item.progress === 100) {
|
|
1068
|
+
// if the item has a group, move the file to that group instead
|
|
1069
|
+
// of into the standard success group
|
|
1070
|
+
if (item.group) {
|
|
1071
|
+
return item.group;
|
|
1072
|
+
}
|
|
1073
|
+
return this.DefaultGroups.success;
|
|
1074
|
+
}
|
|
1075
|
+
else if (item.progress > 0 && item.progress !== 100) {
|
|
1076
|
+
return this.DefaultGroups.inprogress;
|
|
1077
|
+
}
|
|
1078
|
+
else if (!item.valid) {
|
|
1079
|
+
return this.DefaultGroups.failure;
|
|
1080
|
+
}
|
|
1081
|
+
else if (item.group) {
|
|
1082
|
+
return item.group;
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
return "none";
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
this.getItemHTMLFromItemData = (data, group) => {
|
|
1089
|
+
if (group === this.DefaultGroups.success) {
|
|
1090
|
+
return index.h(SuccessItem, { data: data, showLinks: this.showLinks });
|
|
1091
|
+
}
|
|
1092
|
+
else if (group === this.DefaultGroups.inprogress) {
|
|
1093
|
+
return index.h(ProgressItem, { progress: data.progress, name: data.item.name });
|
|
1094
|
+
}
|
|
1095
|
+
else if (group === this.DefaultGroups.failure) {
|
|
1096
|
+
return index.h(ErrorItem, { data: data });
|
|
1097
|
+
}
|
|
1098
|
+
else if (data.group) {
|
|
1099
|
+
return data.html;
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
return "none";
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
this.convertToDuetEditableTableItems = () => {
|
|
1106
|
+
// we're always recreating the map - in order to force an update down stream.
|
|
1107
|
+
const itemData = new Map();
|
|
1108
|
+
//walk the files Map and convert to DuetEditableTableItemData
|
|
1109
|
+
this.files.forEach((data, key, _originalMap) => {
|
|
1110
|
+
const group = this.getGroupFromItemData(data);
|
|
1111
|
+
const item = this.getItemHTMLFromItemData(data, group);
|
|
1112
|
+
itemData.set(key, {
|
|
1113
|
+
uid: data.uid,
|
|
1114
|
+
item,
|
|
1115
|
+
group,
|
|
1116
|
+
});
|
|
1117
|
+
});
|
|
1118
|
+
return itemData;
|
|
1119
|
+
};
|
|
1120
|
+
this.kick = debounce(() => {
|
|
1121
|
+
this.tick = Date.now();
|
|
1122
|
+
}, 30); // will trigger re-render
|
|
1123
|
+
this.genHashName = () => Date.now().toString(36) + Math.random();
|
|
1124
|
+
this.updateValueInMap = (item, key, value, kick = true) => {
|
|
1125
|
+
const fileItem = this.files.get(item);
|
|
1126
|
+
fileItem[key] = value;
|
|
1127
|
+
this.files.set(item, fileItem);
|
|
1128
|
+
if (kick) {
|
|
1129
|
+
this.kick();
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
this.updateProgress = (ev, name) => {
|
|
1133
|
+
const updateProgressHelper = percentComplete => {
|
|
1134
|
+
this.updateValueInMap(name, "progress", percentComplete);
|
|
1135
|
+
this.onProgress(name, percentComplete, ev);
|
|
1136
|
+
};
|
|
1137
|
+
if (ev.lengthComputable) {
|
|
1138
|
+
const percentComplete = (ev.loaded / ev.total) * 100;
|
|
1139
|
+
updateProgressHelper(percentComplete);
|
|
1140
|
+
}
|
|
1141
|
+
else {
|
|
1142
|
+
console.log("cant read progress");
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
this.trackProgress = (name, remove = false) => {
|
|
1146
|
+
if (remove) {
|
|
1147
|
+
this.filesInProgress.delete(name);
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
this.filesInProgress.set(name, "inprogress");
|
|
1151
|
+
}
|
|
1152
|
+
if (this.filesInProgress.size === 0) {
|
|
1153
|
+
this.onDone();
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
this.getFilesAsArray = () => {
|
|
1157
|
+
const filesInQueue = [];
|
|
1158
|
+
const filesInError = [];
|
|
1159
|
+
this.files.forEach(value => {
|
|
1160
|
+
if (value.valid && !value.deleted) {
|
|
1161
|
+
filesInQueue.push(value);
|
|
1162
|
+
}
|
|
1163
|
+
else if (!value.valid && !value.deleted) {
|
|
1164
|
+
filesInError.push(value);
|
|
1165
|
+
}
|
|
1166
|
+
});
|
|
1167
|
+
return { valid: filesInQueue, invalid: filesInError };
|
|
1168
|
+
};
|
|
1169
|
+
this.resetFormFields = () => {
|
|
1170
|
+
/**
|
|
1171
|
+
* You cannot modify a FileList, nor remove single items from it
|
|
1172
|
+
* This completely removes all items in the FileList
|
|
1173
|
+
* We reset the form fields to always be able to re-upload files
|
|
1174
|
+
* and because we handle all uploads and states internally in the component (not relying on native form elements)
|
|
1175
|
+
*/
|
|
1176
|
+
/* TODO: it may be a good idea to just update the list so that this always matches what is in the files map,
|
|
1177
|
+
* TODO: this would remove the capability of Re-uploading, unless we can catch and remove the user file from the form filelist before the upload is canceled by the browser
|
|
1178
|
+
* TODO: but for now we'll just reset the form fields
|
|
1179
|
+
*/
|
|
1180
|
+
this.nativeInput.value = "";
|
|
1181
|
+
};
|
|
1182
|
+
this.startUpload = async (ev, metaData = undefined) => {
|
|
1183
|
+
await this.setFocus();
|
|
1184
|
+
this.metaData = metaData;
|
|
1185
|
+
this.nativeInput.click();
|
|
1186
|
+
this.onUpload(ev, metaData);
|
|
1187
|
+
ev.stopPropagation();
|
|
1188
|
+
ev.preventDefault();
|
|
1189
|
+
return;
|
|
1190
|
+
};
|
|
1191
|
+
/**
|
|
1192
|
+
* Eventlisteners for the XHR requests
|
|
1193
|
+
*/
|
|
1194
|
+
this.transferComplete = name => {
|
|
1195
|
+
this.updateValueInMap(name, "progress", 100, false);
|
|
1196
|
+
this.trackProgress(name, true);
|
|
1197
|
+
};
|
|
1198
|
+
this.transferDone = (xhr, name, status) => {
|
|
1199
|
+
this.updateValueInMap(name, "status", status, false);
|
|
1200
|
+
this.updateValueInMap(name, "uploaded", true, false);
|
|
1201
|
+
try {
|
|
1202
|
+
const response = JSON.parse(xhr.response);
|
|
1203
|
+
this.updateValueInMap(name, "url", response.url);
|
|
1204
|
+
}
|
|
1205
|
+
catch (e) {
|
|
1206
|
+
this.updateValueInMap(name, "url", null);
|
|
1207
|
+
console.error("Server did not respond with expected response {url: string}");
|
|
1208
|
+
}
|
|
1209
|
+
return;
|
|
1210
|
+
};
|
|
1211
|
+
this.transferDoneWithFailure = (xhr, name, status) => {
|
|
1212
|
+
try {
|
|
1213
|
+
const { error } = JSON.parse(xhr.response);
|
|
1214
|
+
this.updateValueInMap(name, "error", { message: error.message, type: error.type }, false);
|
|
1215
|
+
}
|
|
1216
|
+
catch (e) {
|
|
1217
|
+
console.error("Server did not respond with expected response error:{message: string, type: int}");
|
|
1218
|
+
this.updateValueInMap(name, "error", { type: status }, false);
|
|
1219
|
+
}
|
|
1220
|
+
this.updateValueInMap(name, "valid", false, true);
|
|
1221
|
+
};
|
|
1222
|
+
this.transferFailed = name => {
|
|
1223
|
+
this.updateValueInMap(name, "error", getError("duet-upload-001"));
|
|
1224
|
+
};
|
|
1225
|
+
this.transferCanceled = name => {
|
|
1226
|
+
this.files.delete(name);
|
|
1227
|
+
this.validateTotals(name);
|
|
1228
|
+
this.kick();
|
|
1229
|
+
};
|
|
1230
|
+
this.validateTotals = (name) => {
|
|
1231
|
+
const isTotalSizeOverMaxSize = validateTotalSizeIsAboveMax(this.files, this.maxBytesTotal);
|
|
1232
|
+
const isTotalFileAmountAboveMax = validateTotalAmountIsAboveMax(this.files, this.maxFiles);
|
|
1233
|
+
if (isTotalSizeOverMaxSize && name) {
|
|
1234
|
+
this.updateValueInMap(name, "error", getError("duet-upload-202"), false);
|
|
1235
|
+
}
|
|
1236
|
+
if (isTotalFileAmountAboveMax && name) {
|
|
1237
|
+
this.updateValueInMap(name, "error", getError("duet-upload-301"), false);
|
|
1238
|
+
}
|
|
1239
|
+
this.bytesMaxReached = isTotalSizeOverMaxSize;
|
|
1240
|
+
this.fileMaxReached = isTotalFileAmountAboveMax;
|
|
1241
|
+
return {
|
|
1242
|
+
bytesMaxReached: isTotalSizeOverMaxSize,
|
|
1243
|
+
fileMaxReached: isTotalFileAmountAboveMax,
|
|
1244
|
+
};
|
|
1245
|
+
};
|
|
1246
|
+
this.onDelete = (key, ev) => {
|
|
1247
|
+
const deletedItem = this.files.get(key);
|
|
1248
|
+
this.files.delete(key);
|
|
1249
|
+
this.validateTotals();
|
|
1250
|
+
this.kick();
|
|
1251
|
+
this.duetDelete.emit({
|
|
1252
|
+
originalEvent: ev,
|
|
1253
|
+
data: { deletion: deletedItem },
|
|
1254
|
+
component: "duet-upload",
|
|
1255
|
+
});
|
|
1256
|
+
if (!this.external) {
|
|
1257
|
+
this.makeXHRDeleteRequest(deletedItem);
|
|
1258
|
+
}
|
|
1259
|
+
this.resetFormFields();
|
|
1260
|
+
};
|
|
1261
|
+
this.onCancel = (key, ev) => {
|
|
1262
|
+
const cancelledItem = this.files.get(key);
|
|
1263
|
+
this.files.delete(key);
|
|
1264
|
+
if (!this.external) {
|
|
1265
|
+
const { xhr } = cancelledItem;
|
|
1266
|
+
xhr.abort();
|
|
1267
|
+
}
|
|
1268
|
+
else {
|
|
1269
|
+
this.kick();
|
|
1270
|
+
}
|
|
1271
|
+
this.resetFormFields();
|
|
1272
|
+
this.duetCancel.emit({
|
|
1273
|
+
originalEvent: ev,
|
|
1274
|
+
data: { cancelled: cancelledItem },
|
|
1275
|
+
component: "duet-upload",
|
|
1276
|
+
});
|
|
1277
|
+
};
|
|
1278
|
+
this.onUpload = (ev, metaData) => {
|
|
1279
|
+
this.duetUpload.emit({
|
|
1280
|
+
originalEvent: ev,
|
|
1281
|
+
metaData,
|
|
1282
|
+
component: "duet-upload",
|
|
1283
|
+
});
|
|
1284
|
+
};
|
|
1285
|
+
this.onBlur = (ev) => {
|
|
1286
|
+
this.duetBlur.emit({
|
|
1287
|
+
originalEvent: ev,
|
|
1288
|
+
component: "duet-upload",
|
|
1289
|
+
});
|
|
1290
|
+
};
|
|
1291
|
+
this.onProgress = (key, percentComplete, ev) => {
|
|
1292
|
+
this.duetChange.emit({
|
|
1293
|
+
originalEvent: ev,
|
|
1294
|
+
data: {
|
|
1295
|
+
key,
|
|
1296
|
+
percentComplete,
|
|
1297
|
+
},
|
|
1298
|
+
component: "duet-upload",
|
|
1299
|
+
});
|
|
1300
|
+
};
|
|
1301
|
+
this.onFocus = (ev) => {
|
|
1302
|
+
this.duetFocus.emit({
|
|
1303
|
+
originalEvent: ev,
|
|
1304
|
+
component: "duet-upload",
|
|
1305
|
+
});
|
|
1306
|
+
};
|
|
1307
|
+
this.onDone = () => {
|
|
1308
|
+
this.duetDone.emit({
|
|
1309
|
+
component: "duet-upload",
|
|
1310
|
+
data: { files: this.files },
|
|
1311
|
+
});
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
watchValidHandler(newValue, oldValue) {
|
|
1315
|
+
if (newValue !== oldValue) {
|
|
1316
|
+
this.kick();
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Component lifecycle events.
|
|
1321
|
+
*/
|
|
1322
|
+
componentWillLoad() {
|
|
1323
|
+
if (typeof this.statusMessageLabel === "string") {
|
|
1324
|
+
this.internalStatusMessageLabel = languageUtils.sanitizeString(this.groups);
|
|
1325
|
+
}
|
|
1326
|
+
else {
|
|
1327
|
+
this.internalStatusMessageLabel = this.statusMessageLabel;
|
|
1328
|
+
}
|
|
1329
|
+
themeableComponent.inheritGlobalTheme(this);
|
|
1330
|
+
this.listenForActionEvents();
|
|
1331
|
+
}
|
|
1332
|
+
componentWillRender() {
|
|
1333
|
+
// listen to the events from the component
|
|
1334
|
+
this.verifyValidity();
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* XHR request utilities
|
|
1338
|
+
*/
|
|
1339
|
+
makeXHRPostRequest(data) {
|
|
1340
|
+
const xhr = new XMLHttpRequest();
|
|
1341
|
+
const name = data.get("name");
|
|
1342
|
+
xhr.upload.addEventListener("progress", ev => {
|
|
1343
|
+
this.updateProgress(ev, name);
|
|
1344
|
+
});
|
|
1345
|
+
xhr.upload.addEventListener("load", () => {
|
|
1346
|
+
this.transferComplete(name);
|
|
1347
|
+
});
|
|
1348
|
+
xhr.upload.addEventListener("error", () => {
|
|
1349
|
+
this.transferFailed(name);
|
|
1350
|
+
});
|
|
1351
|
+
xhr.upload.addEventListener("abort", () => {
|
|
1352
|
+
this.transferCanceled(name);
|
|
1353
|
+
});
|
|
1354
|
+
return makeXhrRequest({
|
|
1355
|
+
payload: { data, name },
|
|
1356
|
+
options: { type: "POST", uri: this.uri, xhr, argument: null, headers: null },
|
|
1357
|
+
onFailure: this.transferDoneWithFailure,
|
|
1358
|
+
onSuccess: this.transferDone,
|
|
1359
|
+
onProgress: this.trackProgress,
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
makeXHRDeleteRequest(data) {
|
|
1363
|
+
const { uid, item } = data;
|
|
1364
|
+
const xhr = new XMLHttpRequest();
|
|
1365
|
+
// don't present server issues to user on deletes, just remove them from the visible list
|
|
1366
|
+
return makeXhrRequest({
|
|
1367
|
+
payload: { data: null, name },
|
|
1368
|
+
options: {
|
|
1369
|
+
type: "DELETE",
|
|
1370
|
+
xhr,
|
|
1371
|
+
uri: this.uri,
|
|
1372
|
+
arguments: `?key=${uid}&name=${item.name}`,
|
|
1373
|
+
headers: {
|
|
1374
|
+
"x-fileuid": uid,
|
|
1375
|
+
"x-filename": item.name,
|
|
1376
|
+
},
|
|
1377
|
+
},
|
|
1378
|
+
onFailure: this.transferDoneWithFailure,
|
|
1379
|
+
onSuccess: this.transferDone,
|
|
1380
|
+
onProgress: this.trackProgress,
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Component event handling.
|
|
1385
|
+
*/
|
|
1386
|
+
async onChange(ev) {
|
|
1387
|
+
var _a;
|
|
1388
|
+
const selectedFiles = Array.from((_a = this.nativeInput) === null || _a === void 0 ? void 0 : _a.files);
|
|
1389
|
+
// FileList is a nice array like structure but
|
|
1390
|
+
// to ensure uniqueness of files we use a mapping structure and
|
|
1391
|
+
// key to the name (makes it easier to delete as well)
|
|
1392
|
+
if (selectedFiles) {
|
|
1393
|
+
for (const item of selectedFiles) {
|
|
1394
|
+
const { valid, errorMessage, errorType, errorSystem } = validateFile(item, {
|
|
1395
|
+
maxBytes: this.maxBytes,
|
|
1396
|
+
allowedExtensions: this.allowedExtensions,
|
|
1397
|
+
allowedMimetypes: this.allowedMimetypes,
|
|
1398
|
+
});
|
|
1399
|
+
const uid = this.genHashName();
|
|
1400
|
+
const fileListItem = {
|
|
1401
|
+
uid,
|
|
1402
|
+
item: item,
|
|
1403
|
+
size: item.size,
|
|
1404
|
+
meta: this.metaData,
|
|
1405
|
+
uploaded: false,
|
|
1406
|
+
valid,
|
|
1407
|
+
error: {
|
|
1408
|
+
type: valid ? undefined : errorType,
|
|
1409
|
+
message: valid ? undefined : errorMessage,
|
|
1410
|
+
system_message: valid ? undefined : errorSystem,
|
|
1411
|
+
},
|
|
1412
|
+
progress: 0,
|
|
1413
|
+
deleted: false,
|
|
1414
|
+
xhr: false,
|
|
1415
|
+
url: false,
|
|
1416
|
+
};
|
|
1417
|
+
this.files.set(item.name, fileListItem);
|
|
1418
|
+
// validate that we haven't hit any maxfiles or maxbytes limits before we upload
|
|
1419
|
+
const { bytesMaxReached, fileMaxReached } = this.validateTotals(item.name);
|
|
1420
|
+
if (bytesMaxReached) {
|
|
1421
|
+
// in case one of the global maxes have been reached, invalidate the file
|
|
1422
|
+
this.updateValueInMap(item.name, "valid", false, false);
|
|
1423
|
+
}
|
|
1424
|
+
else if (fileMaxReached) {
|
|
1425
|
+
// in case one of the global maxes have been reached, invalidate the file
|
|
1426
|
+
this.updateValueInMap(item.name, "valid", false, false);
|
|
1427
|
+
}
|
|
1428
|
+
else if (valid && !this.external) {
|
|
1429
|
+
// if all is well AND external file upload handling has not been set, start upload
|
|
1430
|
+
const data = new FormData();
|
|
1431
|
+
data.append("file", item);
|
|
1432
|
+
data.append("uid", uid);
|
|
1433
|
+
data.append("name", item.name);
|
|
1434
|
+
data.append("metadata", JSON.stringify({ uid, url: this.uri, size: item.size, meta: fileListItem.meta }));
|
|
1435
|
+
try {
|
|
1436
|
+
fileListItem.xhr = await this.makeXHRPostRequest(data);
|
|
1437
|
+
}
|
|
1438
|
+
catch (e) {
|
|
1439
|
+
// in case one of the global maxes have been reached, invalidate the file
|
|
1440
|
+
this.updateValueInMap(item.name, "valid", false, false);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
// kick the stat to force update
|
|
1444
|
+
this.kick();
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
// reset the form, so that a user may upload a file again (with the same name)
|
|
1448
|
+
this.resetFormFields();
|
|
1449
|
+
// reset the internal metaData state
|
|
1450
|
+
this.metaData = undefined;
|
|
1451
|
+
this.duetChange.emit({
|
|
1452
|
+
originalEvent: ev,
|
|
1453
|
+
data: { files: this.files },
|
|
1454
|
+
component: "duet-upload",
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Sets focus on the specified `duet-input`. Use this method instead of the global
|
|
1459
|
+
* `input.focus()`.
|
|
1460
|
+
*/
|
|
1461
|
+
async setFocus(options) {
|
|
1462
|
+
if (this.nativeInput) {
|
|
1463
|
+
this.nativeInput.focus(options);
|
|
1464
|
+
}
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Method for invoking the upload sequence
|
|
1469
|
+
*/
|
|
1470
|
+
async upload(metaData = undefined) {
|
|
1471
|
+
await this.setFocus();
|
|
1472
|
+
this.metaData = metaData;
|
|
1473
|
+
this.nativeInput.click();
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Get list of files, divided in errors and valid sections
|
|
1478
|
+
*/
|
|
1479
|
+
async getFiles() {
|
|
1480
|
+
if (!this.files || this.files.size === 0) {
|
|
1481
|
+
return false;
|
|
1482
|
+
}
|
|
1483
|
+
return this.getFilesAsArray();
|
|
1484
|
+
}
|
|
1485
|
+
/**
|
|
1486
|
+
* Convenience method for updating the value of a key:value inside an item in the files attribute
|
|
1487
|
+
*/
|
|
1488
|
+
async updateValue(item, key, value) {
|
|
1489
|
+
this.updateValueInMap(item, key, value);
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* render() function
|
|
1493
|
+
* Always the last one in the class.
|
|
1494
|
+
*/
|
|
1495
|
+
render() {
|
|
1496
|
+
const identifier = this.identifier || this.uploadId;
|
|
1497
|
+
let caption = this.description.replace(/{maxfiles}/g, this.maxFiles.toString());
|
|
1498
|
+
caption = caption.replace(/{maxbytes}/g, `${Math.floor(this.maxBytes / 1024 / 1024)} MB`);
|
|
1499
|
+
caption = caption.replace(/{filetypes}/g, this.allowedExtensions.split(",").join(", "));
|
|
1500
|
+
return (index.h(index.Host, { class: { "duet-m-0": this.margin === "none" } }, index.h("duet-fieldset", { label: this.label, caption: caption }, index.h("slot", { name: "header" }), !this.files.size && (index.h("duet-label", { theme: this.theme === "turva" ? "turva" : "default", size: "small", class: {
|
|
1501
|
+
"duet-upload-filelist-empty": !this.files.size,
|
|
1502
|
+
"duet-upload-filelist": true,
|
|
1503
|
+
"duet-upload-filelist-filled": this.files.size,
|
|
1504
|
+
}, id: this.labelId, for: identifier }, this.fileListEmpty)), !!this.files.size && index.h("slot", { name: "fileheader" }), !!this.files.size && (index.h("duet-upload-aria-status", { invalid: this.getFilesAsArray().invalid.length, valid: this.getFilesAsArray().valid.length, inprogress: this.filesInProgress.size, total: this.files.size, statusMessageLabel: this.internalStatusMessageLabel })), !!this.files.size && (index.h("duet-editable-table", { "aria-live": "polite", "aria-relevant": "removals", accessibleRole: "log", id: this.editableTableId, groups: this.groups, actions: this.actions, hideGroups: this.hideGroups, alignment: this.alignment, items: this.convertToDuetEditableTableItems() })), !!this.files.size && index.h("slot", { name: "filefooter" }), index.h("duet-spacer", { size: "large" }), !this.hideButton && (index.h("duet-button", { id: this.buttonId, onClick: this.startUpload, "accessible-controls": identifier, disabled: this.fileMaxReached, "accessible-label": this.accessibleButtonLabel, "accessible-owns": identifier, size: "small", variation: "secondary", fixed: true, icon: "action-add-circle" }, this.buttonLabel)), index.h("duet-spacer", { size: "medium" }), (this.fileMaxReached || this.bytesMaxReached) && (index.h("duet-alert", null, this.fileMaxReached && getI18nError("duet-upload-301"), this.bytesMaxReached && getI18nError("duet-upload-202"))), index.h("duet-spacer", { size: "medium" }), index.h("duet-visually-hidden", null, index.h("input", { ref: input => {
|
|
1505
|
+
this.nativeInput = input;
|
|
1506
|
+
}, accept: !this.limitSelection ? undefined : `${this.allowedMimetypes},${this.allowedExtensions}`, onBlur: this.onBlur, onFocus: this.onFocus, onChange: e => this.onChange(e), type: "file", class: {
|
|
1507
|
+
"duet-upload": true,
|
|
1508
|
+
}, disabled: this.disabled, "aria-hidden": "true", required: this.required, name: this.name, id: this.identifier, multiple: this.multiple, capture: "user" })))));
|
|
1509
|
+
}
|
|
1510
|
+
get element() { return index.getElement(this); }
|
|
1511
|
+
static get watchers() { return {
|
|
1512
|
+
"valid": ["watchValidHandler"]
|
|
1513
|
+
}; }
|
|
1514
|
+
};
|
|
1515
|
+
DuetUpload.style = duetUploadCss;
|
|
1516
|
+
|
|
1517
|
+
exports.duet_editable_table = DuetEditableTable;
|
|
1518
|
+
exports.duet_editable_table_item = DuetEditableTableItem;
|
|
1519
|
+
exports.duet_table = DuetTable;
|
|
1520
|
+
exports.duet_upload = DuetUpload;
|