├── .babelrc ├── .gitattributes ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── banner-cli.js ├── banner.js ├── dist ├── filepond.css ├── filepond.esm.js ├── filepond.esm.min.js ├── filepond.js ├── filepond.min.css └── filepond.min.js ├── index.html ├── jest.config.js ├── jest.stubs.js ├── locale ├── am-et.js ├── ar-ar.js ├── az-az.js ├── ca-ca.js ├── cs-cz.js ├── da-dk.js ├── de-de.js ├── el-el.js ├── en-en.js ├── es-es.js ├── et-ee.js ├── fa_ir.js ├── fi-fi.js ├── fr-fr.js ├── he-he.js ├── hr-hr.js ├── hu-hu.js ├── id-id.js ├── it-it.js ├── ja-ja.js ├── km-km.js ├── ko-kr.js ├── ku-ckb.js ├── lt-lt.js ├── lv-lv.js ├── nl-nl.js ├── no_nb.js ├── pl-pl.js ├── pt-br.js ├── pt-pt.js ├── ro-ro.js ├── ru-ru.js ├── sk-sk.js ├── sl-si.js ├── sv_se.js ├── tr-tr.js ├── uk-ua.js ├── vi-vi.js ├── zh-cn.js └── zh-tw.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── rollup.scripts.js ├── src ├── css │ ├── assistant.css │ ├── browser.css │ ├── data.css │ ├── drip.css │ ├── drop-label.css │ ├── file-action-button.css │ ├── file-info.css │ ├── file-status.css │ ├── file-wrapper.css │ ├── file.css │ ├── hopper.css │ ├── item-order.css │ ├── item.css │ ├── list-scroller.css │ ├── list.css │ ├── modifiers.css │ ├── panel-root.css │ ├── panel.css │ ├── progress-indicator.css │ ├── root-order.css │ ├── root.css │ └── styles.css └── js │ ├── __tests__ │ ├── addFile.test.js │ ├── callbacks.test.js │ ├── contentDisposition.test.js │ ├── createInstance.test.js │ ├── removeFile.test.js │ ├── revertUploadOnRemove.test.js │ ├── server.test.js │ ├── setFiles.test.js │ └── windowMatchMedia.mock │ ├── app │ ├── actions.js │ ├── enum │ │ ├── ChunkStatus.js │ │ ├── FileOrigin.js │ │ ├── InteractionMethod.js │ │ ├── ItemStatus.js │ │ ├── Key.js │ │ ├── Status.js │ │ └── Type.js │ ├── frame │ │ ├── createPainter.js │ │ ├── createRoute.js │ │ ├── createStore.js │ │ ├── createView.js │ │ ├── index.js │ │ ├── mixins │ │ │ ├── animations.js │ │ │ ├── apis.js │ │ │ ├── index.js │ │ │ ├── listeners.js │ │ │ ├── styles.js │ │ │ └── utils │ │ │ │ └── addGetSet.js │ │ └── utils │ │ │ ├── AxisEnum.js │ │ │ ├── addEvent.js │ │ │ ├── animators │ │ │ ├── easing.js │ │ │ ├── spring.js │ │ │ └── tween.js │ │ │ ├── appendChild.js │ │ │ ├── appendChildView.js │ │ │ ├── createAnimator.js │ │ │ ├── createElement.js │ │ │ ├── getChildCount.js │ │ │ ├── getViewRect.js │ │ │ ├── removeChildView.js │ │ │ ├── removeEvent.js │ │ │ └── updateRect.js │ ├── index.js │ ├── options.js │ ├── queries.js │ ├── utils │ │ ├── buildURL.js │ │ ├── convertTo.js │ │ ├── createDragHelper.js │ │ ├── createFetchFunction.js │ │ ├── createFileLoader.js │ │ ├── createFileProcessor.js │ │ ├── createFileProcessorFunction.js │ │ ├── createFileStub.js │ │ ├── createHopper.js │ │ ├── createInitialState.js │ │ ├── createItem.js │ │ ├── createItemAPI.js │ │ ├── createOption.js │ │ ├── createOptionAPI.js │ │ ├── createOptionActions.js │ │ ├── createOptionQueries.js │ │ ├── createOptions.js │ │ ├── createPaster.js │ │ ├── createPerceivedPerformanceUpdater.js │ │ ├── createProcessorFunction.js │ │ ├── createRevertFunction.js │ │ ├── createServerAPI.js │ │ ├── dnd.js │ │ ├── dropAreaDimensions.js │ │ ├── dynamicLabel.js │ │ ├── fetchBlob.js │ │ ├── getActiveItems.js │ │ ├── getItemById.js │ │ ├── getItemByQuery.js │ │ ├── getItemIndexByPosition.js │ │ ├── getItemIndexByQuery.js │ │ ├── getItemsPerRow.js │ │ ├── getType.js │ │ ├── getValueByType.js │ │ ├── hasRoomForItem.js │ │ ├── insertItem.js │ │ ├── isAPI.js │ │ ├── mergeOptionObject.js │ │ ├── on.js │ │ ├── processFileChunked.js │ │ ├── removeReleasedItems.js │ │ ├── requestDataTransferItems.js │ │ └── toServerAPI.js │ └── view │ │ ├── assistant.js │ │ ├── blob.js │ │ ├── browser.js │ │ ├── data.js │ │ ├── drip.js │ │ ├── dropLabel.js │ │ ├── file.js │ │ ├── fileActionButton.js │ │ ├── fileInfo.js │ │ ├── fileStatus.js │ │ ├── fileWrapper.js │ │ ├── item.js │ │ ├── list.js │ │ ├── listScroller.js │ │ ├── panel.js │ │ ├── progressIndicator.js │ │ └── root.js │ ├── createApp.js │ ├── createAppAPI.js │ ├── createAppAtElement.js │ ├── createAppObject.js │ ├── createAppPlugin.js │ ├── filter.js │ ├── index.js │ └── utils │ ├── arrayInsert.js │ ├── arrayRemove.js │ ├── arrayReverse.js │ ├── attr.js │ ├── attrToggle.js │ ├── canUpdateFileInput.js │ ├── capitalizeFirstLetter.js │ ├── composeObject.js │ ├── copyFile.js │ ├── copyObjectPropertiesToObject.js │ ├── createBlob.js │ ├── createDefaultResponse.js │ ├── createElement.js │ ├── createObject.js │ ├── createResponse.js │ ├── createWorker.js │ ├── debounce.js │ ├── deepCloneObject.js │ ├── defineProperty.js │ ├── describeArc.js │ ├── forEachDelayed.js │ ├── forin.js │ ├── formatFilename.js │ ├── fromCamels.js │ ├── getAttributesAsObject.js │ ├── getBase64DataFromBase64DataURI.js │ ├── getBlobBuilder.js │ ├── getBlobFromBase64DataURI.js │ ├── getBlobFromByteStringWithMimeType.js │ ├── getByteStringFromBase64DataURI.js │ ├── getDateString.js │ ├── getDecimalSeparator.js │ ├── getDomainFromURL.js │ ├── getExtensionFromFilename.js │ ├── getFileFromBase64DataURI.js │ ├── getFileFromBlob.js │ ├── getFileInfoFromHeaders.js │ ├── getFilenameFromURL.js │ ├── getFilenameWithoutExtension.js │ ├── getMimeTypeFromBase64DataURI.js │ ├── getNonNumeric.js │ ├── getNumericAspectRatioFromString.js │ ├── getParameters.js │ ├── getRandomNumber.js │ ├── getRootNode.js │ ├── getThousandsSeparator.js │ ├── getUniqueId.js │ ├── guesstimateExtension.js │ ├── guesstimateMimeType.js │ ├── hasQueryString.js │ ├── insertAfter.js │ ├── insertBefore.js │ ├── isArray.js │ ├── isBase64DataURI.js │ ├── isBoolean.js │ ├── isBrowser.js │ ├── isDefined.js │ ├── isEmpty.js │ ├── isExternalURL.js │ ├── isFile.js │ ├── isFunction.js │ ├── isIOS.js │ ├── isInt.js │ ├── isNode.js │ ├── isNull.js │ ├── isNumber.js │ ├── isObject.js │ ├── isString.js │ ├── leftPad.js │ ├── limit.js │ ├── loadImage.js │ ├── lowerCaseFirstLetter.js │ ├── percentageArc.js │ ├── polarToCartesian.js │ ├── renameFile.js │ ├── replaceInString.js │ ├── resetFileInput.js │ ├── sendRequest.js │ ├── setInputFiles.js │ ├── text.js │ ├── toArray.js │ ├── toBoolean.js │ ├── toBytes.js │ ├── toCamels.js │ ├── toFloat.js │ ├── toFunctionReference.js │ ├── toInt.js │ ├── toNaturalFileSize.js │ ├── toNumber.js │ ├── toPercentage.js │ ├── toString.js │ └── trim.js └── types ├── index.d.ts └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "retainLines": true, 3 | "presets": [ 4 | ["@babel/preset-env", { 5 | "exclude": ["transform-typeof-symbol"], 6 | "modules": false 7 | }] 8 | ], 9 | "plugins": [ 10 | ["@babel/plugin-proposal-object-rest-spread", { 11 | "loose": true, 12 | "useBuiltIns": true 13 | }], 14 | ["@babel/plugin-transform-template-literals", { 15 | "loose": true 16 | }] 17 | ], 18 | "env": { 19 | "test": { 20 | "presets": [ 21 | ["@babel/preset-env", { 22 | "targets": { 23 | "node": "current" 24 | } 25 | }] 26 | ] 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/* linguist-vendored=false 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ['https://www.buymeacoffee.com/rikschennink'] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | title: "[Bug] " 3 | description: Report an issue with FilePond 4 | labels: bug 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out this bug report! 10 | - type: checkboxes 11 | attributes: 12 | label: Is there an existing issue for this? 13 | description: Please search to see if an issue already exists for the bug you encountered. 14 | options: 15 | - label: I have searched the existing issues 16 | required: true 17 | - type: checkboxes 18 | attributes: 19 | label: Have you updated FilePond and its plugins? 20 | description: Please update both FilePond and its plugins to the most recent version. 21 | options: 22 | - label: I have updated FilePond and its plugins 23 | required: true 24 | - type: textarea 25 | attributes: 26 | label: Describe the bug 27 | description: A concise description of what the bug is. 28 | placeholder: Bug description 29 | validations: 30 | required: true 31 | - type: textarea 32 | attributes: 33 | label: Reproduction 34 | description: Provide clear steps to reproduce the bug. Please take the time to create a reproduction of the bug by [forking this project on codesandbox.io](https://codesandbox.io/s/filepond-plain-javascript-24i1m) 35 | placeholder: Reproduction 36 | validations: 37 | required: true 38 | - type: textarea 39 | attributes: 40 | label: Environment 41 | description: | 42 | examples: 43 | - **Device**: Samsung Galaxy s20, iPhone 12 Mini, Macbook Pro (2020), etc. 44 | - **OS**: Android 8, iOS 12, Windows 10, etc. 45 | - **Browser**: Firefox 93, Chrome 94, etc. 46 | value: | 47 | - Device: 48 | - OS: 49 | - Browser: 50 | render: markdown 51 | validations: 52 | required: true 53 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Stack Overflow 4 | url: https://stackoverflow.com/questions/tagged/filepond 5 | about: Ask questions on Stack Overflow and tag with "filepond" 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | title: "[Feature] " 3 | description: Suggest an idea for this project 4 | labels: new feature 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out this feature request! 10 | - type: checkboxes 11 | attributes: 12 | label: Is there an existing issue for this? 13 | description: Please search to see if an issue already exists for the feature request you want to submit. 14 | options: 15 | - label: I have searched the existing issues 16 | required: true 17 | - type: textarea 18 | attributes: 19 | label: Is your feature request related to a problem? Please describe. 20 | description: A clear and concise description of what the problem is you want to solve. 21 | placeholder: I'm always frustrated when... 22 | validations: 23 | required: true 24 | - type: textarea 25 | attributes: 26 | label: Describe the solution you'd like 27 | description: A clear and concise description of what you want to happen. 28 | validations: 29 | required: true 30 | - type: textarea 31 | attributes: 32 | label: Describe alternatives you've considered 33 | description: A clear and concise description of any alternative solutions or features you've considered. 34 | validations: 35 | required: true 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules/ 3 | coverage/ 4 | .idea 5 | .vscode/ 6 | upload/ 7 | test*.html 8 | _TODO.md -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v10.15.3 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/* -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "svelteSortOrder": "scripts-markup-styles", 3 | "trailingComma": "es5", 4 | "tabWidth": 4, 5 | "printWidth": 100, 6 | "singleQuote": true, 7 | "semi": true 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 PQINA | Rik Schennink 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /banner-cli.js: -------------------------------------------------------------------------------- 1 | const banner = require('./banner'); 2 | const pkg = require('./package.json'); 3 | const args = process.argv.slice(2); 4 | process.stdin.resume(); 5 | process.stdin.setEncoding('utf8'); 6 | process.stdin.on('data', function(data) { 7 | process.stdout.write(banner({ id: args[0], ...pkg }) + data); 8 | }); -------------------------------------------------------------------------------- /banner.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ id, version, license, homepage }) => `/*! 2 | * ${ id } ${ version } 3 | * Licensed under ${ license }, https://opensource.org/licenses/${ license }/ 4 | * Please visit ${ homepage } for details. 5 | */ 6 | 7 | /* eslint-disable */ 8 | `; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FilePond Demo 7 | 8 | 9 | 10 | 11 | 12 | 25 | 26 | 27 | 28 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bail: true, 3 | verbose: true, 4 | setupFiles: ['/jest.stubs.js'], 5 | roots: ['/src/js'] 6 | }; -------------------------------------------------------------------------------- /jest.stubs.js: -------------------------------------------------------------------------------- 1 | const uuid = require('uuid/v4'); 2 | 3 | // needed because jest doesn't have CSS on window 4 | if (!window.CSS) window.CSS = {}; 5 | window.CSS.supports = () => true; 6 | 7 | window.URL.createObjectURL = blob => { 8 | return `blob:${serializeURL(location.origin)}/${uuid()}`; 9 | }; 10 | 11 | window.URL.revokeObjectURL = url => {}; 12 | -------------------------------------------------------------------------------- /locale/am-et.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'ፋይሎች ስበው እዚህ ጋር ይልቀቁት ወይም ፋይሉን ይምረጡ ', 3 | labelInvalidField: 'መስኩ ልክ ያልሆኑ ፋይሎችን ይዟል', 4 | labelFileWaitingForSize: 'የፋይሉን መጠን በመጠባበቅ ላይ', 5 | labelFileSizeNotAvailable: 'የፋይሉን መጠን ሊገኝ አልቻለም', 6 | labelFileLoading: 'በማንበብ ላይ', 7 | labelFileLoadError: 'በማንበብ ላይ ችግር ተፈጥሯል', 8 | labelFileProcessing: 'ፋይሉን በመጫን ላይ', 9 | labelFileProcessingComplete: 'ፋይሉን መጫን ተጠናቅቋል', 10 | labelFileProcessingAborted: 'ፋይሉን መጫን ተቋርጧል', 11 | labelFileProcessingError: 'ፋይሉን በመጫን ላይ ችግር ተፈጥሯል', 12 | labelFileProcessingRevertError: 'ፈይሉን በመቀልበስ ላይ ችግር ተፈጥሯል', 13 | labelFileRemoveError: 'በማጥፋት ላይ ችግር ተፈጥሯል', 14 | labelTapToCancel: 'ለማቋረጥ ነካ ያድርጉ', 15 | labelTapToRetry: 'ደግሞ ለመሞከር ነካ ያድርጉ', 16 | labelTapToUndo: 'ወደነበረበት ለመመለስ ነካ ያድርጉ', 17 | labelButtonRemoveItem: 'ላጥፋ', 18 | labelButtonAbortItemLoad: 'ላቋርጥ', 19 | labelButtonRetryItemLoad: 'ደግሜ ልሞክር', 20 | labelButtonAbortItemProcessing: 'ይቅር', 21 | labelButtonUndoItemProcessing: 'ወደነበረበት ልመልስ', 22 | labelButtonRetryItemProcessing: 'ደግሜ ልሞክር', 23 | labelButtonProcessItem: 'ልጫን', 24 | labelMaxFileSizeExceeded: 'ፋይሉ ተልቋል', 25 | labelMaxFileSize: 'የፋይል መጠን ከ {filesize} መብለጥ አይፈቀድም', 26 | labelMaxTotalFileSizeExceeded: 'የሚፈቀደውን ጠቅላላ የፋይል መጠን አልፈዋል', 27 | labelMaxTotalFileSize: 'ጠቅላላ የፋይል መጠን ከ {filesize} መብለጥ አይፈቀድም', 28 | labelFileTypeNotAllowed: 'የተሳሳተ የፋይል አይነት ነው', 29 | fileValidateTypeLabelExpectedTypes: 'የፋይል አይነቱ መሆን የሚገባው {allButLastType} እና {lastType} ነው', 30 | imageValidateSizeLabelFormatError: 'የምስል አይነቱ ለመጫን አይሆንም', 31 | imageValidateSizeLabelImageSizeTooSmall: 'ምስሉ በጣም አንሷል', 32 | imageValidateSizeLabelImageSizeTooBig: 'ምስሉ በጣም ተልቋል', 33 | imageValidateSizeLabelExpectedMinSize: 'ዝቅተኛው የምስል ልኬት {minWidth} × {minHeight} ነው', 34 | imageValidateSizeLabelExpectedMaxSize: 'ከፍተኛው የምስል ልኬት {maxWidth} × {maxHeight} ነው', 35 | imageValidateSizeLabelImageResolutionTooLow: 'የምስሉ ጥራት በጣም ዝቅተኛ ነው', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'የምስሉ ጥራት በጣም ከፍተኛ ነው', 37 | imageValidateSizeLabelExpectedMinResolution: 'ዝቅተኛው የምስል ጥራት {minResolution} ነው', 38 | imageValidateSizeLabelExpectedMaxResolution: 'ከፍተኛው የምስል ጥራት {maxResolution} ነው' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/ar-ar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'اسحب و ادرج ملفاتك أو تصفح ', 3 | labelInvalidField: 'الحقل يحتوي على ملفات غير صالحة', 4 | labelFileWaitingForSize: 'بانتظار الحجم', 5 | labelFileSizeNotAvailable: 'الحجم غير متاح', 6 | labelFileLoading: 'بالإنتظار', 7 | labelFileLoadError: 'حدث خطأ أثناء التحميل', 8 | labelFileProcessing: 'يتم الرفع', 9 | labelFileProcessingComplete: 'تم الرفع', 10 | labelFileProcessingAborted: 'تم إلغاء الرفع', 11 | labelFileProcessingError: 'حدث خطأ أثناء الرفع', 12 | labelFileProcessingRevertError: 'حدث خطأ أثناء التراجع', 13 | labelFileRemoveError: 'حدث خطأ أثناء الحذف', 14 | labelTapToCancel: 'انقر للإلغاء', 15 | labelTapToRetry: 'انقر لإعادة المحاولة', 16 | labelTapToUndo: 'انقر للتراجع', 17 | labelButtonRemoveItem: 'مسح', 18 | labelButtonAbortItemLoad: 'إلغاء', 19 | labelButtonRetryItemLoad: 'إعادة', 20 | labelButtonAbortItemProcessing: 'إلغاء', 21 | labelButtonUndoItemProcessing: 'تراجع', 22 | labelButtonRetryItemProcessing: 'إعادة', 23 | labelButtonProcessItem: 'رفع', 24 | labelMaxFileSizeExceeded: 'الملف كبير جدا', 25 | labelMaxFileSize: 'حجم الملف الأقصى: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'تم تجاوز الحد الأقصى للحجم الإجمالي', 27 | labelMaxTotalFileSize: 'الحد الأقصى لحجم الملف: {filesize}', 28 | labelFileTypeNotAllowed: 'ملف من نوع غير صالح', 29 | fileValidateTypeLabelExpectedTypes: 'تتوقع {allButLastType} من {lastType}', 30 | imageValidateSizeLabelFormatError: 'نوع الصورة غير مدعوم', 31 | imageValidateSizeLabelImageSizeTooSmall: 'الصورة صغير جدا', 32 | imageValidateSizeLabelImageSizeTooBig: 'الصورة كبيرة جدا', 33 | imageValidateSizeLabelExpectedMinSize: 'الحد الأدنى للأبعاد هو: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'الحد الأقصى للأبعاد هو: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'الدقة ضعيفة جدا', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'الدقة مرتفعة جدا', 37 | imageValidateSizeLabelExpectedMinResolution: 'أقل دقة: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'أقصى دقة: {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/az-az.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Faylınızı Sürüşdürün & Buraxın ya da Seçin ', 3 | labelInvalidField: 'Sahədə etibarsız fayllar var', 4 | labelFileWaitingForSize: 'Ölçü hesablanır', 5 | labelFileSizeNotAvailable: 'Ölçü mövcud deyil', 6 | labelFileLoading: 'Yüklənir', 7 | labelFileLoadError: 'Yükləmə əsnasında xəta baş verdi', 8 | labelFileProcessing: 'Yüklənir', 9 | labelFileProcessingComplete: 'Yükləmə tamamlandı', 10 | labelFileProcessingAborted: 'Yükləmə ləğv edildi', 11 | labelFileProcessingError: 'Yükəyərkən xəta baş verdi', 12 | labelFileProcessingRevertError: 'Geri çəkərkən xəta baş verdi', 13 | labelFileRemoveError: 'Çıxararkən xəta baş verdi', 14 | labelTapToCancel: 'İmtina etmək üçün klikləyin', 15 | labelTapToRetry: 'Təkrar yoxlamaq üçün klikləyin', 16 | labelTapToUndo: 'Geri almaq üçün klikləyin', 17 | labelButtonRemoveItem: 'Çıxar', 18 | labelButtonAbortItemLoad: 'İmtina Et', 19 | labelButtonRetryItemLoad: 'Təkrar yoxla', 20 | labelButtonAbortItemProcessing: 'İmtina et', 21 | labelButtonUndoItemProcessing: 'Geri Al', 22 | labelButtonRetryItemProcessing: 'Təkrar yoxla', 23 | labelButtonProcessItem: 'Yüklə', 24 | labelMaxFileSizeExceeded: 'Fayl çox böyükdür', 25 | labelMaxFileSize: 'Ən böyük fayl ölçüsü: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maksimum ölçü keçildi', 27 | labelMaxTotalFileSize: 'Maksimum fayl ölçüsü :{filesize}', 28 | labelFileTypeNotAllowed: 'Etibarsız fayl tipi', 29 | fileValidateTypeLabelExpectedTypes: 'Bu {allButLastType} ya da bu fayl olması lazımdır: {lastType}', 30 | imageValidateSizeLabelFormatError: 'Şəkil tipi dəstəklənmir', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Şəkil çox kiçik', 32 | imageValidateSizeLabelImageSizeTooBig: 'Şəkil çox böyük', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimum ölçü {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksimum ölçü {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Görüntü imkanı çox aşağı', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Görüntü imkanı çox yüksək', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimum görüntü imkanı {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximum görüntü imkanı {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/ca-ca.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: `Arrossega i deixa anar els teus fitxers o Navega `, 3 | labelInvalidField: `El camp conté fitxers invàlids`, 4 | labelFileWaitingForSize: `Esperant mida`, 5 | labelFileSizeNotAvailable: `Mida no disponible`, 6 | labelFileLoading: `Carregant`, 7 | labelFileLoadError: `Error durant la càrrega`, 8 | labelFileProcessing: `Pujant`, 9 | labelFileProcessingComplete: `Pujada completada`, 10 | labelFileProcessingAborted: `Pujada cancel·lada`, 11 | labelFileProcessingError: `Error durant la pujada`, 12 | labelFileProcessingRevertError: `Error durant la reversió`, 13 | labelFileRemoveError: `Error durant l'eliminació`, 14 | labelTapToCancel: `toca per cancel·lar`, 15 | labelTapToRetry: `toca per reintentar`, 16 | labelTapToUndo: `toca per desfer`, 17 | labelButtonRemoveItem: `Eliminar`, 18 | labelButtonAbortItemLoad: `Cancel·lar`, 19 | labelButtonRetryItemLoad: `Reintentar`, 20 | labelButtonAbortItemProcessing: `Cancel·lar`, 21 | labelButtonUndoItemProcessing: `Desfer`, 22 | labelButtonRetryItemProcessing: `Reintentar`, 23 | labelButtonProcessItem: `Pujar`, 24 | labelMaxFileSizeExceeded: `El fitxer és massa gran`, 25 | labelMaxFileSize: `La mida màxima del fitxer és {filesize}`, 26 | labelMaxTotalFileSizeExceeded: `Mida màxima total excedida`, 27 | labelMaxTotalFileSize: `La mida màxima total del fitxer és {filesize}`, 28 | labelFileTypeNotAllowed: `Fitxer de tipus invàlid`, 29 | fileValidateTypeLabelExpectedTypes: `Espera {allButLastType} o {lastType}`, 30 | imageValidateSizeLabelFormatError: `Tipus d'imatge no suportada`, 31 | imageValidateSizeLabelImageSizeTooSmall: `La imatge és massa petita`, 32 | imageValidateSizeLabelImageSizeTooBig: `La imatge és massa gran`, 33 | imageValidateSizeLabelExpectedMinSize: `La mida mínima és {minWidth} x {minHeight}`, 34 | imageValidateSizeLabelExpectedMaxSize: `La mida màxima és {maxWidth} x {maxHeight}`, 35 | imageValidateSizeLabelImageResolutionTooLow: `La resolució és massa baixa`, 36 | imageValidateSizeLabelImageResolutionTooHigh: `La resolució és massa alta`, 37 | imageValidateSizeLabelExpectedMinResolution: `La resolució mínima és {minResolution}`, 38 | imageValidateSizeLabelExpectedMaxResolution: `La resolució màxima és {maxResolution}`, 39 | } 40 | -------------------------------------------------------------------------------- /locale/cs-cz.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Přetáhněte soubor sem (drag&drop) nebo Vyhledat ', 3 | labelInvalidField: 'Pole obsahuje chybné soubory', 4 | labelFileWaitingForSize: 'Zjišťuje se velikost', 5 | labelFileSizeNotAvailable: 'Velikost není známá', 6 | labelFileLoading: 'Přenáší se', 7 | labelFileLoadError: 'Chyba při přenosu', 8 | labelFileProcessing: 'Probíhá upload', 9 | labelFileProcessingComplete: 'Upload dokončen', 10 | labelFileProcessingAborted: 'Upload stornován', 11 | labelFileProcessingError: 'Chyba při uploadu', 12 | labelFileProcessingRevertError: 'Chyba při obnově', 13 | labelFileRemoveError: 'Chyba při odstranění', 14 | labelTapToCancel: 'klepněte pro storno', 15 | labelTapToRetry: 'klepněte pro opakování', 16 | labelTapToUndo: 'klepněte pro vrácení', 17 | labelButtonRemoveItem: 'Odstranit', 18 | labelButtonAbortItemLoad: 'Storno', 19 | labelButtonRetryItemLoad: 'Opakovat', 20 | labelButtonAbortItemProcessing: 'Zpět', 21 | labelButtonUndoItemProcessing: 'Vrátit', 22 | labelButtonRetryItemProcessing: 'Opakovat', 23 | labelButtonProcessItem: 'Upload', 24 | labelMaxFileSizeExceeded: 'Soubor je příliš velký', 25 | labelMaxFileSize: 'Největší velikost souboru je {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Překročena maximální celková velikost souboru', 27 | labelMaxTotalFileSize: 'Maximální celková velikost souboru je {filesize}', 28 | labelFileTypeNotAllowed: 'Soubor je nesprávného typu', 29 | fileValidateTypeLabelExpectedTypes: 'Očekává se {allButLastType} nebo {lastType}', 30 | imageValidateSizeLabelFormatError: 'Obrázek tohoto typu není podporován', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Obrázek je příliš malý', 32 | imageValidateSizeLabelImageSizeTooBig: 'Obrázek je příliš velký', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimální rozměr je {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximální rozměr je {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Rozlišení je příliš malé', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Rozlišení je příliš velké', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimální rozlišení je {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximální rozlišení je {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/da-dk.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 3 | 'Træk & slip filer eller Gennemse ', 4 | labelInvalidField: 'Felt indeholder ugyldige filer', 5 | labelFileWaitingForSize: 'Venter på størrelse', 6 | labelFileSizeNotAvailable: 'Størrelse ikke tilgængelig', 7 | labelFileLoading: 'Loader', 8 | labelFileLoadError: 'Load fejlede', 9 | labelFileProcessing: 'Uploader', 10 | labelFileProcessingComplete: 'Upload færdig', 11 | labelFileProcessingAborted: 'Upload annulleret', 12 | labelFileProcessingError: 'Upload fejlede', 13 | labelFileProcessingRevertError: 'Fortryd fejlede', 14 | labelFileRemoveError: 'Fjern fejlede', 15 | labelTapToCancel: 'tryk for at annullere', 16 | labelTapToRetry: 'tryk for at prøve igen', 17 | labelTapToUndo: 'tryk for at fortryde', 18 | labelButtonRemoveItem: 'Fjern', 19 | labelButtonAbortItemLoad: 'Annuller', 20 | labelButtonRetryItemLoad: 'Forsøg igen', 21 | labelButtonAbortItemProcessing: 'Annuller', 22 | labelButtonUndoItemProcessing: 'Fortryd', 23 | labelButtonRetryItemProcessing: 'Prøv igen', 24 | labelButtonProcessItem: 'Upload', 25 | labelMaxFileSizeExceeded: 'Filen er for stor', 26 | labelMaxFileSize: 'Maksimal filstørrelse er {filesize}', 27 | labelMaxTotalFileSizeExceeded: 'Maksimal totalstørrelse overskredet', 28 | labelMaxTotalFileSize: 'Maksimal total filstørrelse er {filesize}', 29 | labelFileTypeNotAllowed: 'Ugyldig filtype', 30 | fileValidateTypeLabelExpectedTypes: 'Forventer {allButLastType} eller {lastType}', 31 | imageValidateSizeLabelFormatError: 'Ugyldigt format', 32 | imageValidateSizeLabelImageSizeTooSmall: 'Billedet er for lille', 33 | imageValidateSizeLabelImageSizeTooBig: 'Billedet er for stort', 34 | imageValidateSizeLabelExpectedMinSize: 'Minimum størrelse er {minBredde} × {minHøjde}', 35 | imageValidateSizeLabelExpectedMaxSize: 'Maksimal størrelse er {maxWidth} × {maxHeight}', 36 | imageValidateSizeLabelImageResolutionTooLow: 'For lav opløsning', 37 | imageValidateSizeLabelImageResolutionTooHigh: 'For høj opløsning', 38 | imageValidateSizeLabelExpectedMinResolution: 'Minimum opløsning er {minResolution}', 39 | imageValidateSizeLabelExpectedMaxResolution: 'Maksimal opløsning er {maxResolution}', 40 | }; 41 | -------------------------------------------------------------------------------- /locale/de-de.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Dateien ablegen oder auswählen ', 3 | labelInvalidField: 'Feld beinhaltet ungültige Dateien', 4 | labelFileWaitingForSize: 'Dateigröße berechnen', 5 | labelFileSizeNotAvailable: 'Dateigröße nicht verfügbar', 6 | labelFileLoading: 'Laden', 7 | labelFileLoadError: 'Fehler beim Laden', 8 | labelFileProcessing: 'Upload läuft', 9 | labelFileProcessingComplete: 'Upload abgeschlossen', 10 | labelFileProcessingAborted: 'Upload abgebrochen', 11 | labelFileProcessingError: 'Fehler beim Upload', 12 | labelFileProcessingRevertError: 'Fehler beim Wiederherstellen', 13 | labelFileRemoveError: 'Fehler beim Löschen', 14 | labelTapToCancel: 'abbrechen', 15 | labelTapToRetry: 'erneut versuchen', 16 | labelTapToUndo: 'rückgängig', 17 | labelButtonRemoveItem: 'Entfernen', 18 | labelButtonAbortItemLoad: 'Verwerfen', 19 | labelButtonRetryItemLoad: 'Erneut versuchen', 20 | labelButtonAbortItemProcessing: 'Abbrechen', 21 | labelButtonUndoItemProcessing: 'Rückgängig', 22 | labelButtonRetryItemProcessing: 'Erneut versuchen', 23 | labelButtonProcessItem: 'Upload', 24 | labelMaxFileSizeExceeded: 'Datei ist zu groß', 25 | labelMaxFileSize: 'Maximale Dateigröße: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maximale gesamte Dateigröße überschritten', 27 | labelMaxTotalFileSize: 'Maximale gesamte Dateigröße: {filesize}', 28 | labelFileTypeNotAllowed: 'Dateityp ungültig', 29 | fileValidateTypeLabelExpectedTypes: 'Erwartet {allButLastType} oder {lastType}', 30 | imageValidateSizeLabelFormatError: 'Bildtyp nicht unterstützt', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Bild ist zu klein', 32 | imageValidateSizeLabelImageSizeTooBig: 'Bild ist zu groß', 33 | imageValidateSizeLabelExpectedMinSize: 'Mindestgröße: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximale Größe: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Auflösung ist zu niedrig', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Auflösung ist zu hoch', 37 | imageValidateSizeLabelExpectedMinResolution: 'Mindestauflösung: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximale Auflösung: {maxResolution}' 39 | }; -------------------------------------------------------------------------------- /locale/en-en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Drag & Drop your files or Browse ', 3 | labelInvalidField: 'Field contains invalid files', 4 | labelFileWaitingForSize: 'Waiting for size', 5 | labelFileSizeNotAvailable: 'Size not available', 6 | labelFileLoading: 'Loading', 7 | labelFileLoadError: 'Error during load', 8 | labelFileProcessing: 'Uploading', 9 | labelFileProcessingComplete: 'Upload complete', 10 | labelFileProcessingAborted: 'Upload cancelled', 11 | labelFileProcessingError: 'Error during upload', 12 | labelFileProcessingRevertError: 'Error during revert', 13 | labelFileRemoveError: 'Error during remove', 14 | labelTapToCancel: 'tap to cancel', 15 | labelTapToRetry: 'tap to retry', 16 | labelTapToUndo: 'tap to undo', 17 | labelButtonRemoveItem: 'Remove', 18 | labelButtonAbortItemLoad: 'Abort', 19 | labelButtonRetryItemLoad: 'Retry', 20 | labelButtonAbortItemProcessing: 'Cancel', 21 | labelButtonUndoItemProcessing: 'Undo', 22 | labelButtonRetryItemProcessing: 'Retry', 23 | labelButtonProcessItem: 'Upload', 24 | labelMaxFileSizeExceeded: 'File is too large', 25 | labelMaxFileSize: 'Maximum file size is {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maximum total size exceeded', 27 | labelMaxTotalFileSize: 'Maximum total file size is {filesize}', 28 | labelFileTypeNotAllowed: 'File of invalid type', 29 | fileValidateTypeLabelExpectedTypes: 'Expects {allButLastType} or {lastType}', 30 | imageValidateSizeLabelFormatError: 'Image type not supported', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Image is too small', 32 | imageValidateSizeLabelImageSizeTooBig: 'Image is too big', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimum size is {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximum size is {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Resolution is too low', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Resolution is too high', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimum resolution is {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximum resolution is {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/es-es.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Arrastra y suelta tus archivos o Examina ', 3 | labelInvalidField: "El campo contiene archivos inválidos", 4 | labelFileWaitingForSize: "Esperando tamaño", 5 | labelFileSizeNotAvailable: "Tamaño no disponible", 6 | labelFileLoading: "Cargando", 7 | labelFileLoadError: "Error durante la carga", 8 | labelFileProcessing: "Subiendo", 9 | labelFileProcessingComplete: "Subida completa", 10 | labelFileProcessingAborted: "Subida cancelada", 11 | labelFileProcessingError: "Error durante la subida", 12 | labelFileProcessingRevertError: "Error durante la reversión", 13 | labelFileRemoveError: "Error durante la eliminación", 14 | labelTapToCancel: "toca para cancelar", 15 | labelTapToRetry: "tocar para reintentar", 16 | labelTapToUndo: "tocar para deshacer", 17 | labelButtonRemoveItem: "Eliminar", 18 | labelButtonAbortItemLoad: "Cancelar", 19 | labelButtonRetryItemLoad: "Reintentar", 20 | labelButtonAbortItemProcessing: "Cancelar", 21 | labelButtonUndoItemProcessing: "Deshacer", 22 | labelButtonRetryItemProcessing: "Reintentar", 23 | labelButtonProcessItem: "Subir", 24 | labelMaxFileSizeExceeded: "El archivo es demasiado grande", 25 | labelMaxFileSize: "El tamaño máximo del archivo es {filesize}", 26 | labelMaxTotalFileSizeExceeded: "Tamaño total máximo excedido", 27 | labelMaxTotalFileSize: "El tamaño total máximo del archivo es {filesize}", 28 | labelFileTypeNotAllowed: "Archivo de tipo inválido", 29 | fileValidateTypeLabelExpectedTypes: "Espera {allButLastType} o {lastType}", 30 | imageValidateSizeLabelFormatError: "Tipo de imagen no soportada", 31 | imageValidateSizeLabelImageSizeTooSmall: "La imagen es demasiado pequeña", 32 | imageValidateSizeLabelImageSizeTooBig: "La imagen es demasiado grande", 33 | imageValidateSizeLabelExpectedMinSize: "El tamaño mínimo es {minWidth} x {minHeight}", 34 | imageValidateSizeLabelExpectedMaxSize: "El tamaño máximo es {maxWidth} x {maxHeight}", 35 | imageValidateSizeLabelImageResolutionTooLow: "La resolución es demasiado baja", 36 | imageValidateSizeLabelImageResolutionTooHigh: "La resolución es demasiado alta", 37 | imageValidateSizeLabelExpectedMinResolution: "La resolución mínima es {minResolution}", 38 | imageValidateSizeLabelExpectedMaxResolution: "La resolución máxima es {maxResolution}", 39 | }; 40 | -------------------------------------------------------------------------------- /locale/et-ee.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Lohista oma failid siia või Sirvi ', 3 | labelInvalidField: 'Väli sisaldab kehtetuid faile', 4 | labelFileWaitingForSize: 'Ootab suurust', 5 | labelFileSizeNotAvailable: 'Suurus pole saadaval', 6 | labelFileLoading: 'Laadimine', 7 | labelFileLoadError: 'Viga laadimisel', 8 | labelFileProcessing: 'Üleslaadimine', 9 | labelFileProcessingComplete: 'Üleslaadimine lõpetatud', 10 | labelFileProcessingAborted: 'Üleslaadimine tühistatud', 11 | labelFileProcessingError: 'Viga üleslaadimisel', 12 | labelFileProcessingRevertError: 'Viga tagasivõtmisel', 13 | labelFileRemoveError: 'Viga eemaldamisel', 14 | labelTapToCancel: 'katkesta puudutades', 15 | labelTapToRetry: 'proovi uuesti puudutades', 16 | labelTapToUndo: 'võta tagasi puudutades', 17 | labelButtonRemoveItem: 'Eemalda', 18 | labelButtonAbortItemLoad: 'Katkesta', 19 | labelButtonRetryItemLoad: 'Proovi uuesti', 20 | labelButtonAbortItemProcessing: 'Tühista', 21 | labelButtonUndoItemProcessing: 'Võta tagasi', 22 | labelButtonRetryItemProcessing: 'Proovi uuesti', 23 | labelButtonProcessItem: 'Lae üles', 24 | labelMaxFileSizeExceeded: 'Fail on liiga suur', 25 | labelMaxFileSize: 'Maksimaalne faili suurus on {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maksimaalne kogusuurus ületatud', 27 | labelMaxTotalFileSize: 'Maksimaalne kogu faili suurus on {filesize}', 28 | labelFileTypeNotAllowed: 'Keelatud failitüüp', 29 | fileValidateTypeLabelExpectedTypes: 'Oodatakse {allButLastType} või {lastType}', 30 | imageValidateSizeLabelFormatError: 'Pildi formaat ei ole toetatud', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Pilt on liiga väike', 32 | imageValidateSizeLabelImageSizeTooBig: 'Pilt on liiga suur', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimaalne suurus on {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksimaalne suurus on {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Resolutsioon on liiga madal', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Resolutsioon on liiga kõrge', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimaalne resolutsioon on {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maksimaalne resolutsioon on {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/fa_ir.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'فایل را اینجا بکشید و رها کنید، یا جستجو کنید ', 3 | labelInvalidField: 'فیلد دارای فایل های نامعتبر است', 4 | labelFileWaitingForSize: 'Waiting for size', 5 | labelFileSizeNotAvailable: 'حجم فایل مجاز نیست', 6 | labelFileLoading: 'درحال بارگذاری', 7 | labelFileLoadError: 'خطا در زمان اجرا', 8 | labelFileProcessing: 'درحال بارگذاری', 9 | labelFileProcessingComplete: 'بارگذاری کامل شد', 10 | labelFileProcessingAborted: 'بارگذاری لغو شد', 11 | labelFileProcessingError: 'خطا در زمان بارگذاری', 12 | labelFileProcessingRevertError: 'خطا در زمان حذف', 13 | labelFileRemoveError: 'خطا در زمان حذف', 14 | labelTapToCancel: 'برای لغو ضربه بزنید', 15 | labelTapToRetry: 'برای تکرار کلیک کنید', 16 | labelTapToUndo: 'برای برگشت کلیک کنید', 17 | labelButtonRemoveItem: 'حذف', 18 | labelButtonAbortItemLoad: 'لغو', 19 | labelButtonRetryItemLoad: 'تکرار', 20 | labelButtonAbortItemProcessing: 'لغو', 21 | labelButtonUndoItemProcessing: 'برگشت', 22 | labelButtonRetryItemProcessing: 'تکرار', 23 | labelButtonProcessItem: 'بارگذاری', 24 | labelMaxFileSizeExceeded: 'فایل بسیار حجیم است', 25 | labelMaxFileSize: 'حداکثر مجاز فایل {filesize} است', 26 | labelMaxTotalFileSizeExceeded: 'از حداکثر حجم فایل بیشتر شد', 27 | labelMaxTotalFileSize: 'حداکثر حجم فایل {filesize} است', 28 | labelFileTypeNotAllowed: 'نوع فایل نامعتبر است', 29 | fileValidateTypeLabelExpectedTypes: 'در انتظار {allButLastType} یا {lastType}', 30 | imageValidateSizeLabelFormatError: 'فرمت تصویر پشتیبانی نمی شود', 31 | imageValidateSizeLabelImageSizeTooSmall: 'تصویر بسیار کوچک است', 32 | imageValidateSizeLabelImageSizeTooBig: 'تصویر بسیار بزرگ است', 33 | imageValidateSizeLabelExpectedMinSize: 'حداقل اندازه {minWidth} × {minHeight} است', 34 | imageValidateSizeLabelExpectedMaxSize: 'حداکثر اندازه {maxWidth} × {maxHeight} است', 35 | imageValidateSizeLabelImageResolutionTooLow: 'وضوح تصویر بسیار کم است', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'وضوع تصویر بسیار زیاد است', 37 | imageValidateSizeLabelExpectedMinResolution: 'حداقل وضوح تصویر {minResolution} است', 38 | imageValidateSizeLabelExpectedMaxResolution: 'حداکثر وضوح تصویر {maxResolution} است' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/fi-fi.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Vedä ja pudota tiedostoja tai Selaa ', 3 | labelInvalidField: 'Kentässä on virheellisiä tiedostoja', 4 | labelFileWaitingForSize: 'Odotetaan kokoa', 5 | labelFileSizeNotAvailable: 'Kokoa ei saatavilla', 6 | labelFileLoading: 'Ladataan', 7 | labelFileLoadError: 'Virhe latauksessa', 8 | labelFileProcessing: 'Lähetetään', 9 | labelFileProcessingComplete: 'Lähetys valmis', 10 | labelFileProcessingAborted: 'Lähetys peruttu', 11 | labelFileProcessingError: 'Virhe lähetyksessä', 12 | labelFileProcessingRevertError: 'Virhe palautuksessa', 13 | labelFileRemoveError: 'Virhe poistamisessa', 14 | labelTapToCancel: 'peruuta napauttamalla', 15 | labelTapToRetry: 'yritä uudelleen napauttamalla', 16 | labelTapToUndo: 'kumoa napauttamalla', 17 | labelButtonRemoveItem: 'Poista', 18 | labelButtonAbortItemLoad: 'Keskeytä', 19 | labelButtonRetryItemLoad: 'Yritä uudelleen', 20 | labelButtonAbortItemProcessing: 'Peruuta', 21 | labelButtonUndoItemProcessing: 'Kumoa', 22 | labelButtonRetryItemProcessing: 'Yritä uudelleen', 23 | labelButtonProcessItem: 'Lähetä', 24 | labelMaxFileSizeExceeded: 'Tiedoston koko on liian suuri', 25 | labelMaxFileSize: 'Tiedoston maksimikoko on {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Tiedostojen yhdistetty maksimikoko ylitetty', 27 | labelMaxTotalFileSize: 'Tiedostojen yhdistetty maksimikoko on {filesize}', 28 | labelFileTypeNotAllowed: 'Tiedostotyyppiä ei sallita', 29 | fileValidateTypeLabelExpectedTypes: 'Sallitaan {allButLastType} tai {lastType}', 30 | imageValidateSizeLabelFormatError: 'Kuvatyyppiä ei tueta', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Kuva on liian pieni', 32 | imageValidateSizeLabelImageSizeTooBig: 'Kuva on liian suuri', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimikoko on {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksimikoko on {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Resoluutio on liian pieni', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Resoluutio on liian suuri', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimiresoluutio on {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maksimiresoluutio on {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/he-he.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'גרור ושחרר את הקבצים כאן או לחץ כאן לבחירה ', 3 | labelInvalidField: 'קובץ לא חוקי', 4 | labelFileWaitingForSize: 'מחשב את גודל הקבצים', 5 | labelFileSizeNotAvailable: 'לא ניתן לקבוע את גודל הקבצים', 6 | labelFileLoading: 'טוען...', 7 | labelFileLoadError: 'שגיאה ארעה בעת טעינת הקבצים', 8 | labelFileProcessing: 'מעלה את הקבצים', 9 | labelFileProcessingComplete: 'העלאת הקבצים הסתיימה', 10 | labelFileProcessingAborted: 'העלאת הקבצים בוטלה', 11 | labelFileProcessingError: 'שגיאה ארעה בעת העלאת הקבצים', 12 | labelFileProcessingRevertError: 'שגיאה ארעה בעת שחזור הקבצים', 13 | labelFileRemoveError: 'שגיאה ארעה בעת הסרת הקובץ', 14 | labelTapToCancel: 'הקלק לביטול', 15 | labelTapToRetry: 'הקלק לנסות שנית', 16 | labelTapToUndo: 'הקלק לשחזר', 17 | labelButtonRemoveItem: 'הסר', 18 | labelButtonAbortItemLoad: 'בטל', 19 | labelButtonRetryItemLoad: 'טען שנית', 20 | labelButtonAbortItemProcessing: 'בטל', 21 | labelButtonUndoItemProcessing: 'שחזר', 22 | labelButtonRetryItemProcessing: 'נסה שנית', 23 | labelButtonProcessItem: 'העלה קובץ', 24 | labelMaxFileSizeExceeded: 'הקובץ גדול מדי', 25 | labelMaxFileSize: 'גודל המירבי המותר הוא: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'גודל הקבצים חורג מהכמות המותרת', 27 | labelMaxTotalFileSize: 'הגודל המירבי של סך הקבצים: {filesize}', 28 | labelFileTypeNotAllowed: 'קובץ מסוג זה אינו מותר', 29 | fileValidateTypeLabelExpectedTypes: 'הקבצים המותרים הם {allButLastType} או {lastType}', 30 | imageValidateSizeLabelFormatError: 'תמונה בפורמט זה אינה נתמכת', 31 | imageValidateSizeLabelImageSizeTooSmall: 'תמונה זו קטנה מדי', 32 | imageValidateSizeLabelImageSizeTooBig: 'תמונה זו גדולה מדי', 33 | imageValidateSizeLabelExpectedMinSize: 'הגודל צריך להיות לפחות: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'הגודל המרבי המותר: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'הרזולוציה של תמונה זו נמוכה מדי', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'הרזולוציה של תמונה זו גבוהה מדי', 37 | imageValidateSizeLabelExpectedMinResolution: 'הרזולוציה צריכה להיות לפחות: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'הרזולוציה המירבית המותרת היא: {maxResolution}', 39 | }; 40 | -------------------------------------------------------------------------------- /locale/hr-hr.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Ovdje "ispusti" datoteku ili Pretraži ', 3 | labelInvalidField: 'Polje sadrži neispravne datoteke', 4 | labelFileWaitingForSize: 'Čekanje na veličinu datoteke', 5 | labelFileSizeNotAvailable: 'Veličina datoteke nije dostupna', 6 | labelFileLoading: 'Učitavanje', 7 | labelFileLoadError: 'Greška tijekom učitavanja', 8 | labelFileProcessing: 'Prijenos', 9 | labelFileProcessingComplete: 'Prijenos završen', 10 | labelFileProcessingAborted: 'Prijenos otkazan', 11 | labelFileProcessingError: 'Greška tijekom prijenosa', 12 | labelFileProcessingRevertError: 'Greška tijekom vraćanja', 13 | labelFileRemoveError: 'Greška tijekom uklananja datoteke', 14 | labelTapToCancel: 'Dodirni za prekid', 15 | labelTapToRetry: 'Dodirni za ponovno', 16 | labelTapToUndo: 'Dodirni za vraćanje', 17 | labelButtonRemoveItem: 'Ukloni', 18 | labelButtonAbortItemLoad: 'Odbaci', 19 | labelButtonRetryItemLoad: 'Ponovi', 20 | labelButtonAbortItemProcessing: 'Prekini', 21 | labelButtonUndoItemProcessing: 'Vrati', 22 | labelButtonRetryItemProcessing: 'Ponovi', 23 | labelButtonProcessItem: 'Prijenos', 24 | labelMaxFileSizeExceeded: 'Datoteka je prevelika', 25 | labelMaxFileSize: 'Maksimalna veličina datoteke je {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maksimalna ukupna veličina datoteke prekoračena', 27 | labelMaxTotalFileSize: 'Maksimalna ukupna veličina datoteke je {filesize}', 28 | labelFileTypeNotAllowed: 'Tip datoteke nije podržan', 29 | fileValidateTypeLabelExpectedTypes: 'Očekivan {allButLastType} ili {lastType}', 30 | imageValidateSizeLabelFormatError: 'Tip slike nije podržan', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Slika je premala', 32 | imageValidateSizeLabelImageSizeTooBig: 'Slika je prevelika', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimalna veličina je {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksimalna veličina je {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Rezolucija je preniska', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Rezolucija je previsoka', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimalna rezolucija je {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maksimalna rezolucija je {maxResolution}' 39 | }; -------------------------------------------------------------------------------- /locale/hu-hu.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Mozgasd ide a fájlt a feltöltéshez, vagy tallózás ', 3 | labelInvalidField: 'A mező érvénytelen fájlokat tartalmaz', 4 | labelFileWaitingForSize: 'Fáljméret kiszámolása', 5 | labelFileSizeNotAvailable: 'A fájlméret nem elérhető', 6 | labelFileLoading: 'Töltés', 7 | labelFileLoadError: 'Hiba a betöltés során', 8 | labelFileProcessing: 'Feltöltés', 9 | labelFileProcessingComplete: 'Sikeres feltöltés', 10 | labelFileProcessingAborted: 'A feltöltés megszakítva', 11 | labelFileProcessingError: 'Hiba történt a feltöltés során', 12 | labelFileProcessingRevertError: 'Hiba a visszaállítás során', 13 | labelFileRemoveError: 'Hiba történt az eltávolítás során', 14 | labelTapToCancel: 'koppints a törléshez', 15 | labelTapToRetry: 'koppints az újrakezdéshez', 16 | labelTapToUndo: 'koppints a visszavonáshoz', 17 | labelButtonRemoveItem: 'Eltávolítás', 18 | labelButtonAbortItemLoad: 'Megszakítás', 19 | labelButtonRetryItemLoad: 'Újrapróbálkozás', 20 | labelButtonAbortItemProcessing: 'Megszakítás', 21 | labelButtonUndoItemProcessing: 'Visszavonás', 22 | labelButtonRetryItemProcessing: 'Újrapróbálkozás', 23 | labelButtonProcessItem: 'Feltöltés', 24 | labelMaxFileSizeExceeded: 'A fájl túllépte a maximális méretet', 25 | labelMaxFileSize: 'Maximális fájlméret: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Túllépte a maximális teljes méretet', 27 | labelMaxTotalFileSize: 'A maximáis teljes fájlméret: {filesize}', 28 | labelFileTypeNotAllowed: 'Érvénytelen típusú fájl', 29 | fileValidateTypeLabelExpectedTypes: 'Engedélyezett típusok {allButLastType} vagy {lastType}', 30 | imageValidateSizeLabelFormatError: 'A képtípus nem támogatott', 31 | imageValidateSizeLabelImageSizeTooSmall: 'A kép túl kicsi', 32 | imageValidateSizeLabelImageSizeTooBig: 'A kép túl nagy', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimum méret: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximum méret: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'A felbontás túl alacsony', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'A felbontás túl magas', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimáis felbontás: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximális felbontás: {maxResolution}' 39 | }; -------------------------------------------------------------------------------- /locale/id-id.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Seret & Jatuhkan berkas Anda atau Jelajahi', 3 | labelInvalidField: 'Isian berisi berkas yang tidak valid', 4 | labelFileWaitingForSize: 'Menunggu ukuran berkas', 5 | labelFileSizeNotAvailable: 'Ukuran berkas tidak tersedia', 6 | labelFileLoading: 'Memuat', 7 | labelFileLoadError: 'Kesalahan saat memuat', 8 | labelFileProcessing: 'Mengunggah', 9 | labelFileProcessingComplete: 'Pengunggahan selesai', 10 | labelFileProcessingAborted: 'Pengunggahan dibatalkan', 11 | labelFileProcessingError: 'Kesalahan saat pengunggahan', 12 | labelFileProcessingRevertError: 'Kesalahan saat pemulihan', 13 | labelFileRemoveError: 'Kesalahan saat penghapusan', 14 | labelTapToCancel: 'ketuk untuk membatalkan', 15 | labelTapToRetry: 'ketuk untuk mencoba lagi', 16 | labelTapToUndo: 'ketuk untuk mengurungkan', 17 | labelButtonRemoveItem: 'Hapus', 18 | labelButtonAbortItemLoad: 'Batalkan', 19 | labelButtonRetryItemLoad: 'Coba Kembali', 20 | labelButtonAbortItemProcessing: 'Batalkan', 21 | labelButtonUndoItemProcessing: 'Urungkan', 22 | labelButtonRetryItemProcessing: 'Coba Kembali', 23 | labelButtonProcessItem: 'Unggah', 24 | labelMaxFileSizeExceeded: 'Berkas terlalu besar', 25 | labelMaxFileSize: 'Ukuran berkas maksimum adalah {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Jumlah berkas maksimum terlampaui', 27 | labelMaxTotalFileSize: 'Jumlah berkas maksimum adalah {filesize}', 28 | labelFileTypeNotAllowed: 'Jenis berkas tidak valid', 29 | fileValidateTypeLabelExpectedTypes: 'Mengharapkan {allButLastType} atau {lastType}', 30 | imageValidateSizeLabelFormatError: 'Jenis citra tidak didukung', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Citra terlalu kecil', 32 | imageValidateSizeLabelImageSizeTooBig: 'Citra terlalu besar', 33 | imageValidateSizeLabelExpectedMinSize: 'Ukuran minimum adalah {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Ukuran maksimum adalah {minWidth} × {minHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Resolusi terlalu rendah', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Resolusi terlalu tinggi', 37 | imageValidateSizeLabelExpectedMinResolution: 'Resolusi minimum adalah {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Resolusi maksimum adalah {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/km-km.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'ទាញ&ដាក់ហ្វាល់ឯកសាររបស់អ្នក ឬ ស្វែងរក ', 3 | labelInvalidField: 'ចន្លោះមានឯកសារមិនត្រឹមត្រូវ', 4 | labelFileWaitingForSize: 'កំពុងរង់ចាំទំហំ', 5 | labelFileSizeNotAvailable: 'ទំហំមិនអាចប្រើបាន', 6 | labelFileLoading: 'កំពុងដំណើរការ', 7 | labelFileLoadError: 'មានបញ្ហាកំឡុងពេលដំណើរការ', 8 | labelFileProcessing: 'កំពុងផ្ទុកឡើង', 9 | labelFileProcessingComplete: 'ការផ្ទុកឡើងពេញលេញ', 10 | labelFileProcessingAborted: 'ការបង្ហោះត្រូវបានបោះបង់', 11 | labelFileProcessingError: 'មានបញ្ហាកំឡុងពេលកំពុងផ្ទុកឡើង', 12 | labelFileProcessingRevertError: 'មានបញ្ហាកំឡុងពេលត្រឡប់', 13 | labelFileRemoveError: 'មានបញ្ហាកំឡុងពេលដកចេញ', 14 | labelTapToCancel: 'ចុចដើម្បីបោះបង់', 15 | labelTapToRetry: 'ចុចដើម្បីព្យាយាមម្តងទៀត', 16 | labelTapToUndo: 'ចុចដើម្បីមិនធ្វើវិញ', 17 | labelButtonRemoveItem: 'យកចេញ', 18 | labelButtonAbortItemLoad: 'បោះបង់', 19 | labelButtonRetryItemLoad: 'ព្យាយាមម្តងទៀត', 20 | labelButtonAbortItemProcessing: 'បោះបង់', 21 | labelButtonUndoItemProcessing: 'មិនធ្វើវិញ', 22 | labelButtonRetryItemProcessing: 'ព្យាយាមម្តងទៀត', 23 | labelButtonProcessItem: 'ផ្ទុកឡើង', 24 | labelMaxFileSizeExceeded: 'ឯកសារធំពេក', 25 | labelMaxFileSize: 'ទំហំឯកសារអតិបរមាគឺ {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'លើសទំហំសរុបអតិបរមា', 27 | labelMaxTotalFileSize: 'ទំហំឯកសារសរុបអតិបរមាគឺ {filesize}', 28 | labelFileTypeNotAllowed: 'ប្រភេទឯកសារមិនត្រឹមត្រូវ', 29 | fileValidateTypeLabelExpectedTypes: 'រំពឹងថា {allButLastType} ឬ {lastType}', 30 | imageValidateSizeLabelFormatError: 'ប្រភេទរូបភាពមិនត្រឹមត្រូវ', 31 | imageValidateSizeLabelImageSizeTooSmall: 'រូបភាពតូចពេក', 32 | imageValidateSizeLabelImageSizeTooBig: 'រូបភាពធំពេក', 33 | imageValidateSizeLabelExpectedMinSize: 'ទំហំអប្បបរមាគឺ {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'ទំហំអតិបរមាគឺ {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'គុណភាពបង្ហាញទាបពេក', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'គុណភាពបង្ហាញខ្ពស់ពេក', 37 | imageValidateSizeLabelExpectedMinResolution: 'គុណភាពបង្ហាញអប្បបរមាគឺ {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'គុណភាពបង្ហាញអតិបរមាគឺ {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/ko-kr.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: '파일을 드래그 하거나 찾아보기 ', 3 | labelInvalidField: '필드에 유효하지 않은 파일이 있습니다.', 4 | labelFileWaitingForSize: '용량 확인중', 5 | labelFileSizeNotAvailable: '사용할 수 없는 용량', 6 | labelFileLoading: '불러오는 중', 7 | labelFileLoadError: '파일 불러오기 실패', 8 | labelFileProcessing: '업로드 중', 9 | labelFileProcessingComplete: '업로드 성공', 10 | labelFileProcessingAborted: '업로드 취소됨', 11 | labelFileProcessingError: '파일 업로드 실패', 12 | labelFileProcessingRevertError: '되돌리기 실패', 13 | labelFileRemoveError: '제거 실패', 14 | labelTapToCancel: '탭하여 취소', 15 | labelTapToRetry: '탭하여 재시작', 16 | labelTapToUndo: '탭하여 실행 취소', 17 | labelButtonRemoveItem: '제거', 18 | labelButtonAbortItemLoad: '중단', 19 | labelButtonRetryItemLoad: '재시작', 20 | labelButtonAbortItemProcessing: '취소', 21 | labelButtonUndoItemProcessing: '실행 취소', 22 | labelButtonRetryItemProcessing: '재시작', 23 | labelButtonProcessItem: '업로드', 24 | labelMaxFileSizeExceeded: '파일이 너무 큽니다.', 25 | labelMaxFileSize: '최대 파일 용량은 {filesize} 입니다.', 26 | labelMaxTotalFileSizeExceeded: '최대 전체 파일 용량 초과하였습니다.', 27 | labelMaxTotalFileSize: '최대 전체 파일 용량은 {filesize} 입니다.', 28 | labelFileTypeNotAllowed: '잘못된 형식의 파일', 29 | fileValidateTypeLabelExpectedTypes: '{allButLastType} 또는 {lastType}', 30 | imageValidateSizeLabelFormatError: '지원되지 않는 이미지 유형', 31 | imageValidateSizeLabelImageSizeTooSmall: '이미지가 너무 작습니다.', 32 | imageValidateSizeLabelImageSizeTooBig: '이미지가 너무 큽니다.', 33 | imageValidateSizeLabelExpectedMinSize: '이미지 최소 크기는 {minWidth} × {minHeight} 입니다', 34 | imageValidateSizeLabelExpectedMaxSize: '이미지 최대 크기는 {maxWidth} × {maxHeight} 입니다', 35 | imageValidateSizeLabelImageResolutionTooLow: '해상도가 너무 낮습니다.', 36 | imageValidateSizeLabelImageResolutionTooHigh: '해상도가 너무 높습니다.', 37 | imageValidateSizeLabelExpectedMinResolution: '최소 해상도는 {minResolution} 입니다.', 38 | imageValidateSizeLabelExpectedMaxResolution: '최대 해상도는 {maxResolution} 입니다.' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/ku-ckb.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'پەڕگەکان فڕێ بدە ئێرە بۆ بارکردن یان هەڵبژێرە ', 3 | labelInvalidField: 'پەڕگەی نادروستی تێدایە', 4 | labelFileWaitingForSize: 'چاوەڕوانیی قەبارە', 5 | labelFileSizeNotAvailable: 'قەبارە بەردەست نیە', 6 | labelFileLoading: 'بارکردن', 7 | labelFileLoadError: 'هەڵە لەماوەی بارکردن', 8 | labelFileProcessing: 'بارکردن', 9 | labelFileProcessingComplete: 'بارکردن تەواو بوو', 10 | labelFileProcessingAborted: 'بارکردن هەڵوەشایەوە', 11 | labelFileProcessingError: 'هەڵە لەکاتی بارکردندا', 12 | labelFileProcessingRevertError: 'هەڵە لە کاتی گەڕانەوە', 13 | labelFileRemoveError: 'هەڵە لە کاتی سڕینەوە', 14 | labelTapToCancel: 'بۆ هەڵوەشاندنەوە Tab دابگرە', 15 | labelTapToRetry: 'tap دابگرە بۆ دووبارەکردنەوە', 16 | labelTapToUndo: 'tap دابگرە بۆ گەڕاندنەوە', 17 | labelButtonRemoveItem: 'سڕینەوە', 18 | labelButtonAbortItemLoad: 'هەڵوەشاندنەوە', 19 | labelButtonRetryItemLoad: 'هەوڵدانەوە', 20 | labelButtonAbortItemProcessing: 'پەشیمانبوونەوە', 21 | labelButtonUndoItemProcessing: 'گەڕاندنەوە', 22 | labelButtonRetryItemProcessing: 'هەوڵدانەوە', 23 | labelButtonProcessItem: 'بارکردن', 24 | labelMaxFileSizeExceeded: 'پەڕگە زۆر گەورەیە', 25 | labelMaxFileSize: 'زۆرترین قەبارە {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'زۆرترین قەبارەی کۆی گشتی تێپەڕێندرا', 27 | labelMaxTotalFileSize: 'زۆرترین قەبارەی کۆی پەڕگە {filesize}', 28 | labelFileTypeNotAllowed: 'جۆری پەڕگەکە نادروستە', 29 | fileValidateTypeLabelExpectedTypes: 'جگە لە {allButLastType} یان {lastType}', 30 | imageValidateSizeLabelFormatError: 'جۆری وێنە پاڵپشتیی نەکراوە', 31 | imageValidateSizeLabelImageSizeTooSmall: 'وێنەکە زۆر بچووکە', 32 | imageValidateSizeLabelImageSizeTooBig: 'وێنەکە زۆر گەورەیە', 33 | imageValidateSizeLabelExpectedMinSize: 'کەمترین قەبارە {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'زۆرترین قەبارە {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'وردبینییەکەی زۆر کەمە', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'وردبینییەکەی زۆر بەرزە', 37 | imageValidateSizeLabelExpectedMinResolution: 'کەمترین وردبینیی {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'زۆرترین وردبینی {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/lt-lt.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Įdėkite failus čia arba Ieškokite ', 3 | labelInvalidField: 'Laukelis talpina netinkamus failus', 4 | labelFileWaitingForSize: 'Laukiama dydžio', 5 | labelFileSizeNotAvailable: 'Dydis nežinomas', 6 | labelFileLoading: 'Kraunama', 7 | labelFileLoadError: 'Klaida įkeliant', 8 | labelFileProcessing: 'Įkeliama', 9 | labelFileProcessingComplete: 'Įkėlimas sėkmingas', 10 | labelFileProcessingAborted: 'Įkėlimas atšauktas', 11 | labelFileProcessingError: 'Įkeliant įvyko klaida', 12 | labelFileProcessingRevertError: 'Atšaukiant įvyko klaida', 13 | labelFileRemoveError: 'Ištrinant įvyko klaida', 14 | labelTapToCancel: 'Palieskite norėdami atšaukti', 15 | labelTapToRetry: 'Palieskite norėdami pakartoti', 16 | labelTapToUndo: 'Palieskite norėdami atšaukti', 17 | labelButtonRemoveItem: 'Ištrinti', 18 | labelButtonAbortItemLoad: 'Sustabdyti', 19 | labelButtonRetryItemLoad: 'Pakartoti', 20 | labelButtonAbortItemProcessing: 'Atšaukti', 21 | labelButtonUndoItemProcessing: 'Atšaukti', 22 | labelButtonRetryItemProcessing: 'Pakartoti', 23 | labelButtonProcessItem: 'Įkelti', 24 | labelMaxFileSizeExceeded: 'Failas per didelis', 25 | labelMaxFileSize: 'Maksimalus failo dydis yra {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Viršijote maksimalų leistiną dydį', 27 | labelMaxTotalFileSize: 'Maksimalus leistinas dydis yra {filesize}', 28 | labelFileTypeNotAllowed: 'Netinkamas failas', 29 | fileValidateTypeLabelExpectedTypes: 'Tikisi {allButLastType} arba {lastType}', 30 | imageValidateSizeLabelFormatError: 'Nuotraukos formatas nepalaikomas', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Nuotrauka per maža', 32 | imageValidateSizeLabelImageSizeTooBig: 'Nuotrauka per didelė', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimalus dydis yra {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksimalus dydis yra {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Rezoliucija per maža', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Rezoliucija per didelė', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimali rezoliucija yra {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maksimali rezoliucija yra {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/nl-nl.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Drag & Drop je bestanden of Bladeren ', 3 | labelInvalidField: 'Veld bevat ongeldige bestanden', 4 | labelFileWaitingForSize: 'Wachten op grootte', 5 | labelFileSizeNotAvailable: 'Grootte niet beschikbaar', 6 | labelFileLoading: 'Laden', 7 | labelFileLoadError: 'Fout tijdens laden', 8 | labelFileProcessing: 'Uploaden', 9 | labelFileProcessingComplete: 'Upload afgerond', 10 | labelFileProcessingAborted: 'Upload geannuleerd', 11 | labelFileProcessingError: 'Fout tijdens upload', 12 | labelFileProcessingRevertError: 'Fout bij herstellen', 13 | labelFileRemoveError: 'Fout bij verwijderen', 14 | labelTapToCancel: 'tik om te annuleren', 15 | labelTapToRetry: 'tik om opnieuw te proberen', 16 | labelTapToUndo: 'tik om ongedaan te maken', 17 | labelButtonRemoveItem: 'Verwijderen', 18 | labelButtonAbortItemLoad: 'Afbreken', 19 | labelButtonRetryItemLoad: 'Opnieuw proberen', 20 | labelButtonAbortItemProcessing: 'Annuleren', 21 | labelButtonUndoItemProcessing: 'Ongedaan maken', 22 | labelButtonRetryItemProcessing: 'Opnieuw proberen', 23 | labelButtonProcessItem: 'Upload', 24 | labelMaxFileSizeExceeded: 'Bestand is te groot', 25 | labelMaxFileSize: 'Maximale bestandsgrootte is {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maximale totale grootte overschreden', 27 | labelMaxTotalFileSize: 'Maximale totale bestandsgrootte is {filesize}', 28 | labelFileTypeNotAllowed: 'Ongeldig bestandstype', 29 | fileValidateTypeLabelExpectedTypes: 'Verwacht {allButLastType} of {lastType}', 30 | imageValidateSizeLabelFormatError: 'Afbeeldingstype niet ondersteund', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Afbeelding is te klein', 32 | imageValidateSizeLabelImageSizeTooBig: 'Afbeelding is te groot', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimale afmeting is {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximale afmeting is {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Resolutie is te laag', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Resolution is too high', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimale resolutie is {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximale resolutie is {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/no_nb.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Dra og slipp filene dine, eller Bla gjennom... ', 3 | labelInvalidField: 'Feltet inneholder ugyldige filer', 4 | labelFileWaitingForSize: 'Venter på størrelse', 5 | labelFileSizeNotAvailable: 'Størrelse ikke tilgjengelig', 6 | labelFileLoading: 'Laster', 7 | labelFileLoadError: 'Feil under lasting', 8 | labelFileProcessing: 'Laster opp', 9 | labelFileProcessingComplete: 'Opplasting ferdig', 10 | labelFileProcessingAborted: 'Opplasting avbrutt', 11 | labelFileProcessingError: 'Feil under opplasting', 12 | labelFileProcessingRevertError: 'Feil under reversering', 13 | labelFileRemoveError: 'Feil under flytting', 14 | labelTapToCancel: 'klikk for å avbryte', 15 | labelTapToRetry: 'klikk for å prøve på nytt', 16 | labelTapToUndo: 'klikk for å angre', 17 | labelButtonRemoveItem: 'Fjern', 18 | labelButtonAbortItemLoad: 'Avbryt', 19 | labelButtonRetryItemLoad: 'Prøv på nytt', 20 | labelButtonAbortItemProcessing: 'Avbryt', 21 | labelButtonUndoItemProcessing: 'Angre', 22 | labelButtonRetryItemProcessing: 'Prøv på nytt', 23 | labelButtonProcessItem: 'Last opp', 24 | labelMaxFileSizeExceeded: 'Filen er for stor', 25 | labelMaxFileSize: 'Maksimal filstørrelse er {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maksimal total størrelse oversteget', 27 | labelMaxTotalFileSize: 'Maksimal total størrelse er {filesize}', 28 | labelFileTypeNotAllowed: 'Ugyldig filtype', 29 | fileValidateTypeLabelExpectedTypes: 'Forventer {allButLastType} eller {lastType}', 30 | imageValidateSizeLabelFormatError: 'Bildeformat ikke støttet', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Bildet er for lite', 32 | imageValidateSizeLabelImageSizeTooBig: 'Bildet er for stort', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimumsstørrelse er {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksimumsstørrelse er {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Oppløsningen er for lav', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Oppløsningen er for høy', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimum oppløsning er {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maksimal oppløsning er {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/pl-pl.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Przeciągnij i upuść lub wybierz pliki', 3 | labelInvalidField: 'Nieprawidłowe pliki', 4 | labelFileWaitingForSize: 'Pobieranie rozmiaru', 5 | labelFileSizeNotAvailable: 'Nieznany rozmiar', 6 | labelFileLoading: 'Wczytywanie', 7 | labelFileLoadError: 'Błąd wczytywania', 8 | labelFileProcessing: 'Przesyłanie', 9 | labelFileProcessingComplete: 'Przesłano', 10 | labelFileProcessingAborted: 'Przerwano', 11 | labelFileProcessingError: 'Przesyłanie nie powiodło się', 12 | labelFileProcessingRevertError: 'Coś poszło nie tak', 13 | labelFileRemoveError: 'Nieudane usunięcie', 14 | labelTapToCancel: 'Anuluj', 15 | labelTapToRetry: 'Ponów', 16 | labelTapToUndo: 'Cofnij', 17 | labelButtonRemoveItem: 'Usuń', 18 | labelButtonAbortItemLoad: 'Przerwij', 19 | labelButtonRetryItemLoad: 'Ponów', 20 | labelButtonAbortItemProcessing: 'Anuluj', 21 | labelButtonUndoItemProcessing: 'Cofnij', 22 | labelButtonRetryItemProcessing: 'Ponów', 23 | labelButtonProcessItem: 'Prześlij', 24 | labelMaxFileSizeExceeded: 'Plik jest zbyt duży', 25 | labelMaxFileSize: 'Dopuszczalna wielkość pliku to {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Przekroczono łączny rozmiar plików', 27 | labelMaxTotalFileSize: 'Łączny rozmiar plików nie może przekroczyć {filesize}', 28 | labelFileTypeNotAllowed: 'Niedozwolony rodzaj pliku', 29 | fileValidateTypeLabelExpectedTypes: 'Oczekiwano {allButLastType} lub {lastType}', 30 | imageValidateSizeLabelFormatError: 'Nieobsługiwany format obrazu', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Obraz jest zbyt mały', 32 | imageValidateSizeLabelImageSizeTooBig: 'Obraz jest zbyt duży', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimalne wymiary obrazu to {minWidth}×{minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maksymalna wymiary obrazu to {maxWidth}×{maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Rozdzielczość jest zbyt niska', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Rozdzielczość jest zbyt wysoka', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimalna rozdzielczość to {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maksymalna rozdzielczość to {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/pt-br.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Arraste e solte os arquivos ou Clique aqui ', 3 | labelInvalidField: 'Arquivos inválidos', 4 | labelFileWaitingForSize: 'Calculando o tamanho do arquivo', 5 | labelFileSizeNotAvailable: 'Tamanho do arquivo indisponível', 6 | labelFileLoading: 'Carregando', 7 | labelFileLoadError: 'Erro durante o carregamento', 8 | labelFileProcessing: 'Enviando', 9 | labelFileProcessingComplete: 'Envio finalizado', 10 | labelFileProcessingAborted: 'Envio cancelado', 11 | labelFileProcessingError: 'Erro durante o envio', 12 | labelFileProcessingRevertError: 'Erro ao reverter o envio', 13 | labelFileRemoveError: 'Erro ao remover o arquivo', 14 | labelTapToCancel: 'clique para cancelar', 15 | labelTapToRetry: 'clique para reenviar', 16 | labelTapToUndo: 'clique para desfazer', 17 | labelButtonRemoveItem: 'Remover', 18 | labelButtonAbortItemLoad: 'Abortar', 19 | labelButtonRetryItemLoad: 'Reenviar', 20 | labelButtonAbortItemProcessing: 'Cancelar', 21 | labelButtonUndoItemProcessing: 'Desfazer', 22 | labelButtonRetryItemProcessing: 'Reenviar', 23 | labelButtonProcessItem: 'Enviar', 24 | labelMaxFileSizeExceeded: 'Arquivo é muito grande', 25 | labelMaxFileSize: 'O tamanho máximo permitido: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Tamanho total dos arquivos excedido', 27 | labelMaxTotalFileSize: 'Tamanho total permitido: {filesize}', 28 | labelFileTypeNotAllowed: 'Tipo de arquivo inválido', 29 | fileValidateTypeLabelExpectedTypes: 'Tipos de arquivo suportados são {allButLastType} ou {lastType}', 30 | imageValidateSizeLabelFormatError: 'Tipo de imagem inválida', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Imagem muito pequena', 32 | imageValidateSizeLabelImageSizeTooBig: 'Imagem muito grande', 33 | imageValidateSizeLabelExpectedMinSize: 'Tamanho mínimo permitida: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Tamanho máximo permitido: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Resolução muito baixa', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Resolução muito alta', 37 | imageValidateSizeLabelExpectedMinResolution: 'Resolução mínima permitida: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Resolução máxima permitida: {maxResolution}', 39 | }; 40 | -------------------------------------------------------------------------------- /locale/pt-pt.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Arraste & Largue os ficheiros ou Seleccione ', 3 | labelInvalidField: 'O campo contém ficheiros inválidos', 4 | labelFileWaitingForSize: 'A aguardar tamanho', 5 | labelFileSizeNotAvailable: 'Tamanho não disponível', 6 | labelFileLoading: 'A carregar', 7 | labelFileLoadError: 'Erro ao carregar', 8 | labelFileProcessing: 'A carregar', 9 | labelFileProcessingComplete: 'Carregamento completo', 10 | labelFileProcessingAborted: 'Carregamento cancelado', 11 | labelFileProcessingError: 'Erro ao carregar', 12 | labelFileProcessingRevertError: 'Erro ao reverter', 13 | labelFileRemoveError: 'Erro ao remover', 14 | labelTapToCancel: 'carregue para cancelar', 15 | labelTapToRetry: 'carregue para tentar novamente', 16 | labelTapToUndo: 'carregue para desfazer', 17 | labelButtonRemoveItem: 'Remover', 18 | labelButtonAbortItemLoad: 'Abortar', 19 | labelButtonRetryItemLoad: 'Tentar novamente', 20 | labelButtonAbortItemProcessing: 'Cancelar', 21 | labelButtonUndoItemProcessing: 'Desfazer', 22 | labelButtonRetryItemProcessing: 'Tentar novamente', 23 | labelButtonProcessItem: 'Carregar', 24 | labelMaxFileSizeExceeded: 'Ficheiro demasiado grande', 25 | labelMaxFileSize: 'O tamanho máximo do ficheiro é de {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Tamanho máximo total excedido', 27 | labelMaxTotalFileSize: 'O tamanho máximo total do ficheiro é de {filesize}', 28 | labelFileTypeNotAllowed: 'Tipo de ficheiro inválido', 29 | fileValidateTypeLabelExpectedTypes: 'É esperado {allButLastType} ou {lastType}', 30 | imageValidateSizeLabelFormatError: 'Tipo de imagem não suportada', 31 | imageValidateSizeLabelImageSizeTooSmall: 'A imagem é demasiado pequena', 32 | imageValidateSizeLabelImageSizeTooBig: 'A imagem é demasiado grande', 33 | imageValidateSizeLabelExpectedMinSize: 'O tamanho mínimo é de {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'O tamanho máximo é de {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'A resolução é demasiado baixa', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'A resolução é demasiado grande', 37 | imageValidateSizeLabelExpectedMinResolution: 'A resolução mínima é de {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'A resolução máxima é de {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/ro-ro.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Trage și plasează fișiere sau Caută-le ', 3 | labelInvalidField: 'Câmpul conține fișiere care nu sunt valide', 4 | labelFileWaitingForSize: 'În așteptarea dimensiunii', 5 | labelFileSizeNotAvailable: 'Dimensiunea nu este diponibilă', 6 | labelFileLoading: 'Se încarcă', 7 | labelFileLoadError: 'Eroare la încărcare', 8 | labelFileProcessing: 'Se încarcă', 9 | labelFileProcessingComplete: 'Încărcare finalizată', 10 | labelFileProcessingAborted: 'Încărcare anulată', 11 | labelFileProcessingError: 'Eroare la încărcare', 12 | labelFileProcessingRevertError: 'Eroare la anulare', 13 | labelFileRemoveError: 'Eroare la ştergere', 14 | labelTapToCancel: 'apasă pentru a anula', 15 | labelTapToRetry: 'apasă pentru a reîncerca', 16 | labelTapToUndo: 'apasă pentru a anula', 17 | labelButtonRemoveItem: 'Şterge', 18 | labelButtonAbortItemLoad: 'Anulează', 19 | labelButtonRetryItemLoad: 'Reîncearcă', 20 | labelButtonAbortItemProcessing: 'Anulează', 21 | labelButtonUndoItemProcessing: 'Anulează', 22 | labelButtonRetryItemProcessing: 'Reîncearcă', 23 | labelButtonProcessItem: 'Încarcă', 24 | labelMaxFileSizeExceeded: 'Fișierul este prea mare', 25 | labelMaxFileSize: 'Dimensiunea maximă a unui fișier este de {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Dimensiunea totală maximă a fost depășită', 27 | labelMaxTotalFileSize: 'Dimensiunea totală maximă a fișierelor este de {filesize}', 28 | labelFileTypeNotAllowed: 'Tipul fișierului nu este valid', 29 | fileValidateTypeLabelExpectedTypes: 'Se așteaptă {allButLastType} sau {lastType}', 30 | imageValidateSizeLabelFormatError: 'Formatul imaginii nu este acceptat', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Imaginea este prea mică', 32 | imageValidateSizeLabelImageSizeTooBig: 'Imaginea este prea mare', 33 | imageValidateSizeLabelExpectedMinSize: 'Mărimea minimă este de {maxWidth} x {maxHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Mărimea maximă este de {maxWidth} x {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Rezoluția este prea mică', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Rezoluția este prea mare', 37 | imageValidateSizeLabelExpectedMinResolution: 'Rezoluția minimă este de {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Rezoluția maximă este de {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/ru-ru.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Перетащите файлы или выберите ', 3 | labelInvalidField: 'Поле содержит недопустимые файлы', 4 | labelFileWaitingForSize: 'Укажите размер', 5 | labelFileSizeNotAvailable: 'Размер не поддерживается', 6 | labelFileLoading: 'Ожидание', 7 | labelFileLoadError: 'Ошибка при ожидании', 8 | labelFileProcessing: 'Загрузка', 9 | labelFileProcessingComplete: 'Загрузка завершена', 10 | labelFileProcessingAborted: 'Загрузка отменена', 11 | labelFileProcessingError: 'Ошибка при загрузке', 12 | labelFileProcessingRevertError: 'Ошибка при возврате', 13 | labelFileRemoveError: 'Ошибка при удалении', 14 | labelTapToCancel: 'нажмите для отмены', 15 | labelTapToRetry: 'нажмите, чтобы повторить попытку', 16 | labelTapToUndo: 'нажмите для отмены последнего действия', 17 | labelButtonRemoveItem: 'Удалить', 18 | labelButtonAbortItemLoad: 'Прекращено', 19 | labelButtonRetryItemLoad: 'Повторите попытку', 20 | labelButtonAbortItemProcessing: 'Отмена', 21 | labelButtonUndoItemProcessing: 'Отмена последнего действия', 22 | labelButtonRetryItemProcessing: 'Повторите попытку', 23 | labelButtonProcessItem: 'Загрузка', 24 | labelMaxFileSizeExceeded: 'Файл слишком большой', 25 | labelMaxFileSize: 'Максимальный размер файла: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Превышен максимальный размер', 27 | labelMaxTotalFileSize: 'Максимальный размер файла: {filesize}', 28 | labelFileTypeNotAllowed: 'Файл неверного типа', 29 | fileValidateTypeLabelExpectedTypes: 'Ожидается {allButLastType} или {lastType}', 30 | imageValidateSizeLabelFormatError: 'Тип изображения не поддерживается', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Изображение слишком маленькое', 32 | imageValidateSizeLabelImageSizeTooBig: 'Изображение слишком большое', 33 | imageValidateSizeLabelExpectedMinSize: 'Минимальный размер: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Максимальный размер: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Разрешение слишком низкое', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Разрешение слишком высокое', 37 | imageValidateSizeLabelExpectedMinResolution: 'Минимальное разрешение: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Максимальное разрешение: {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/sk-sk.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Natiahnúť súbor (drag&drop) alebo Vyhľadať ', 3 | labelInvalidField: 'Pole obsahuje chybné súbory', 4 | labelFileWaitingForSize: 'Zisťuje sa veľkosť', 5 | labelFileSizeNotAvailable: 'Neznáma veľkosť', 6 | labelFileLoading: 'Prenáša sa', 7 | labelFileLoadError: 'Chyba pri prenose', 8 | labelFileProcessing: 'Prebieha upload', 9 | labelFileProcessingComplete: 'Upload dokončený', 10 | labelFileProcessingAborted: 'Upload stornovaný', 11 | labelFileProcessingError: 'Chyba pri uploade', 12 | labelFileProcessingRevertError: 'Chyba pri obnove', 13 | labelFileRemoveError: 'Chyba pri odstránení', 14 | labelTapToCancel: 'Kliknite pre storno', 15 | labelTapToRetry: 'Kliknite pre opakovanie', 16 | labelTapToUndo: 'Kliknite pre vrátenie', 17 | labelButtonRemoveItem: 'Odstrániť', 18 | labelButtonAbortItemLoad: 'Storno', 19 | labelButtonRetryItemLoad: 'Opakovať', 20 | labelButtonAbortItemProcessing: 'Späť', 21 | labelButtonUndoItemProcessing: 'Vrátiť', 22 | labelButtonRetryItemProcessing: 'Opakovať', 23 | labelButtonProcessItem: 'Upload', 24 | labelMaxFileSizeExceeded: 'Súbor je príliš veľký', 25 | labelMaxFileSize: 'Najväčšia veľkosť súboru je {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Prekročená maximálna celková veľkosť súboru', 27 | labelMaxTotalFileSize: 'Maximálna celková veľkosť súboru je {filesize}', 28 | labelFileTypeNotAllowed: 'Súbor je nesprávneho typu', 29 | fileValidateTypeLabelExpectedTypes: 'Očakáva sa {allButLastType} alebo {lastType}', 30 | imageValidateSizeLabelFormatError: 'Obrázok tohto typu nie je podporovaný', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Obrázok je príliš malý', 32 | imageValidateSizeLabelImageSizeTooBig: 'Obrázok je príliš veľký', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimálny rozmer je {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximálny rozmer je {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Rozlíšenie je príliš malé', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Rozlišenie je príliš veľké', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimálne rozlíšenie je {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximálne rozlíšenie je {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/sl-si.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Povleci in spusti ali izberi', 3 | labelInvalidField: 'Polje vsebuje neveljavne datoteke', 4 | labelFileWaitingForSize: 'Čakanje na velikost', 5 | labelFileSizeNotAvailable: 'Velikost ni na voljo', 6 | labelFileLoading: 'Nalaganje', 7 | labelFileLoadError: 'Napaka pri nalaganju', 8 | labelFileProcessing: 'Prenašanje', 9 | labelFileProcessingComplete: 'Prenos zaključen', 10 | labelFileProcessingAborted: 'Prenos preklican', 11 | labelFileProcessingError: 'Napaka pri prenosu', 12 | labelFileProcessingRevertError: 'Napaka pri razveljavitvi', 13 | labelFileRemoveError: 'Napaka pri odstranjevanju', 14 | labelTapToCancel: 'kliknite za preklic', 15 | labelTapToRetry: 'kliknite za ponovni poskus', 16 | labelTapToUndo: 'kliknite za razveljavitev', 17 | labelButtonRemoveItem: 'Odstrani', 18 | labelButtonAbortItemLoad: 'Prekini', 19 | labelButtonRetryItemLoad: 'Poskusi znova', 20 | labelButtonAbortItemProcessing: 'Prekliči', 21 | labelButtonUndoItemProcessing: 'Razveljavi', 22 | labelButtonRetryItemProcessing: 'Poskusi znova', 23 | labelButtonProcessItem: 'Prenesi', 24 | labelMaxFileSizeExceeded: 'Datoteka je prevelika', 25 | labelMaxFileSize: 'Največja velikost datoteke je {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Presežena je največja skupna velikost', 27 | labelMaxTotalFileSize: 'Največja skupna velikost datotek je {filesize}', 28 | labelFileTypeNotAllowed: 'Neveljavna vrsta datoteke', 29 | fileValidateTypeLabelExpectedTypes: 'Pričakuje se: {allButLastType} ali {lastType}', 30 | imageValidateSizeLabelFormatError: 'Vrsta slike ni podprta', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Slika je premajhna', 32 | imageValidateSizeLabelImageSizeTooBig: 'Slika je prevelika', 33 | imageValidateSizeLabelExpectedMinSize: 'Najmanjša velikost je {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Največja velikost je {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Ločljivost je prenizka', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Ločljivost je previsoka', 37 | imageValidateSizeLabelExpectedMinResolution: 'Najmanjša ločljivost je {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Največja ločljivost je {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/sv_se.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Drag och släpp dina filer eller Bläddra ', 3 | labelInvalidField: 'Fältet innehåller felaktiga filer', 4 | labelFileWaitingForSize: 'Väntar på storlek', 5 | labelFileSizeNotAvailable: 'Storleken finns inte tillgänglig', 6 | labelFileLoading: 'Laddar', 7 | labelFileLoadError: 'Fel under laddning', 8 | labelFileProcessing: 'Laddar upp', 9 | labelFileProcessingComplete: 'Uppladdning klar', 10 | labelFileProcessingAborted: 'Uppladdning avbruten', 11 | labelFileProcessingError: 'Fel under uppladdning', 12 | labelFileProcessingRevertError: 'Fel under återställning', 13 | labelFileRemoveError: 'Fel under borttagning', 14 | labelTapToCancel: 'tryck för att avbryta', 15 | labelTapToRetry: 'tryck för att försöka igen', 16 | labelTapToUndo: 'tryck för att ångra', 17 | labelButtonRemoveItem: 'Tabort', 18 | labelButtonAbortItemLoad: 'Avbryt', 19 | labelButtonRetryItemLoad: 'Försök igen', 20 | labelButtonAbortItemProcessing: 'Avbryt', 21 | labelButtonUndoItemProcessing: 'Ångra', 22 | labelButtonRetryItemProcessing: 'Försök igen', 23 | labelButtonProcessItem: 'Ladda upp', 24 | labelMaxFileSizeExceeded: 'Filen är för stor', 25 | labelMaxFileSize: 'Största tillåtna filstorlek är {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maximal uppladdningsstorlek uppnåd', 27 | labelMaxTotalFileSize: 'Maximal uppladdningsstorlek är {filesize}', 28 | labelFileTypeNotAllowed: 'Felaktig filtyp', 29 | fileValidateTypeLabelExpectedTypes: 'Godkända filtyper {allButLastType} eller {lastType}', 30 | imageValidateSizeLabelFormatError: 'Bildtypen saknar stöd', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Bilden är för liten', 32 | imageValidateSizeLabelImageSizeTooBig: 'Bilden är för stor', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimal storlek är {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximal storlek är {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Upplösningen är för låg', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Upplösningen är för hög', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minsta tillåtna upplösning är {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Högsta tillåtna upplösning är {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/tr-tr.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Dosyanızı Sürükleyin & Bırakın ya da Seçin ', 3 | labelInvalidField: 'Alan geçersiz dosyalar içeriyor', 4 | labelFileWaitingForSize: 'Boyut hesaplanıyor', 5 | labelFileSizeNotAvailable: 'Boyut mevcut değil', 6 | labelFileLoading: 'Yükleniyor', 7 | labelFileLoadError: 'Yükleme sırasında hata oluştu', 8 | labelFileProcessing: 'Yükleniyor', 9 | labelFileProcessingComplete: 'Yükleme tamamlandı', 10 | labelFileProcessingAborted: 'Yükleme iptal edildi', 11 | labelFileProcessingError: 'Yüklerken hata oluştu', 12 | labelFileProcessingRevertError: 'Geri çekerken hata oluştu', 13 | labelFileRemoveError: 'Kaldırırken hata oluştu', 14 | labelTapToCancel: 'İptal etmek için tıklayın', 15 | labelTapToRetry: 'Tekrar denemek için tıklayın', 16 | labelTapToUndo: 'Geri almak için tıklayın', 17 | labelButtonRemoveItem: 'Kaldır', 18 | labelButtonAbortItemLoad: 'İptal Et', 19 | labelButtonRetryItemLoad: 'Tekrar dene', 20 | labelButtonAbortItemProcessing: 'İptal et', 21 | labelButtonUndoItemProcessing: 'Geri Al', 22 | labelButtonRetryItemProcessing: 'Tekrar dene', 23 | labelButtonProcessItem: 'Yükle', 24 | labelMaxFileSizeExceeded: 'Dosya çok büyük', 25 | labelMaxFileSize: 'En fazla dosya boyutu: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Maximum boyut aşıldı', 27 | labelMaxTotalFileSize: 'Maximum dosya boyutu :{filesize}', 28 | labelFileTypeNotAllowed: 'Geçersiz dosya tipi', 29 | fileValidateTypeLabelExpectedTypes: 'Şu {allButLastType} ya da şu dosya olması gerekir: {lastType}', 30 | imageValidateSizeLabelFormatError: 'Resim tipi desteklenmiyor', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Resim çok küçük', 32 | imageValidateSizeLabelImageSizeTooBig: 'Resim çok büyük', 33 | imageValidateSizeLabelExpectedMinSize: 'Minimum boyut {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Maximum boyut {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Çözünürlük çok düşük', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Çözünürlük çok yüksek', 37 | imageValidateSizeLabelExpectedMinResolution: 'Minimum çözünürlük {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Maximum çözünürlük {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/uk-ua.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Перетягніть файли або виберіть ', 3 | labelInvalidField: 'Поле містить недопустимі файли', 4 | labelFileWaitingForSize: 'Вкажіть розмір', 5 | labelFileSizeNotAvailable: 'Розмір не доступний', 6 | labelFileLoading: 'Очікування', 7 | labelFileLoadError: 'Помилка при очікуванні', 8 | labelFileProcessing: 'Завантаження', 9 | labelFileProcessingComplete: 'Завантаження завершено', 10 | labelFileProcessingAborted: 'Завантаження скасовано', 11 | labelFileProcessingError: 'Помилка при завантаженні', 12 | labelFileProcessingRevertError: 'Помилка при відновленні', 13 | labelFileRemoveError: 'Помилка при видаленні', 14 | labelTapToCancel: 'Відмінити', 15 | labelTapToRetry: 'Натисніть, щоб повторити спробу', 16 | labelTapToUndo: 'Натисніть, щоб відмінити останню дію', 17 | labelButtonRemoveItem: 'Видалити', 18 | labelButtonAbortItemLoad: 'Відмінити', 19 | labelButtonRetryItemLoad: 'Повторити спробу', 20 | labelButtonAbortItemProcessing: 'Відмінити', 21 | labelButtonUndoItemProcessing: 'Відмінити останню дію', 22 | labelButtonRetryItemProcessing: 'Повторити спробу', 23 | labelButtonProcessItem: 'Завантаження', 24 | labelMaxFileSizeExceeded: 'Файл занадто великий', 25 | labelMaxFileSize: 'Максимальний розмір файлу: {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Перевищено максимальний загальний розмір', 27 | labelMaxTotalFileSize: 'Максимальний загальний розмір: {filesize}', 28 | labelFileTypeNotAllowed: 'Формат файлу не підтримується', 29 | fileValidateTypeLabelExpectedTypes: 'Очікується {allButLastType} або {lastType}', 30 | imageValidateSizeLabelFormatError: 'Формат зображення не підтримується', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Зображення занадто маленьке', 32 | imageValidateSizeLabelImageSizeTooBig: 'Зображення занадто велике', 33 | imageValidateSizeLabelExpectedMinSize: 'Мінімальний розмір: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Максимальний розмір: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Розміри зображення занадто маленькі', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Розміри зображення занадто великі', 37 | imageValidateSizeLabelExpectedMinResolution: 'Мінімальні розміри: {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Максимальні розміри: {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/vi-vi.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: 'Kéo thả tệp của bạn hoặc Tìm kiếm ', 3 | labelInvalidField: 'Trường chứa các tệp không hợp lệ', 4 | labelFileWaitingForSize: 'Đang chờ kích thước', 5 | labelFileSizeNotAvailable: 'Kích thước không có sẵn', 6 | labelFileLoading: 'Đang tải', 7 | labelFileLoadError: 'Lỗi khi tải', 8 | labelFileProcessing: 'Đang tải lên', 9 | labelFileProcessingComplete: 'Tải lên thành công', 10 | labelFileProcessingAborted: 'Đã huỷ tải lên', 11 | labelFileProcessingError: 'Lỗi khi tải lên', 12 | labelFileProcessingRevertError: 'Lỗi khi hoàn nguyên', 13 | labelFileRemoveError: 'Lỗi khi xóa', 14 | labelTapToCancel: 'nhấn để hủy', 15 | labelTapToRetry: 'nhấn để thử lại', 16 | labelTapToUndo: 'nhấn để hoàn tác', 17 | labelButtonRemoveItem: 'Xoá', 18 | labelButtonAbortItemLoad: 'Huỷ bỏ', 19 | labelButtonRetryItemLoad: 'Thử lại', 20 | labelButtonAbortItemProcessing: 'Hủy bỏ', 21 | labelButtonUndoItemProcessing: 'Hoàn tác', 22 | labelButtonRetryItemProcessing: 'Thử lại', 23 | labelButtonProcessItem: 'Tải lên', 24 | labelMaxFileSizeExceeded: 'Tập tin quá lớn', 25 | labelMaxFileSize: 'Kích thước tệp tối đa là {filesize}', 26 | labelMaxTotalFileSizeExceeded: 'Đã vượt quá tổng kích thước tối đa', 27 | labelMaxTotalFileSize: 'Tổng kích thước tệp tối đa là {filesize}', 28 | labelFileTypeNotAllowed: 'Tệp thuộc loại không hợp lệ', 29 | fileValidateTypeLabelExpectedTypes: 'Kiểu tệp hợp lệ là {allButLastType} hoặc {lastType}', 30 | imageValidateSizeLabelFormatError: 'Loại hình ảnh không được hỗ trợ', 31 | imageValidateSizeLabelImageSizeTooSmall: 'Hình ảnh quá nhỏ', 32 | imageValidateSizeLabelImageSizeTooBig: 'Hình ảnh quá lớn', 33 | imageValidateSizeLabelExpectedMinSize: 'Kích thước tối thiểu là {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: 'Kích thước tối đa là {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: 'Độ phân giải quá thấp', 36 | imageValidateSizeLabelImageResolutionTooHigh: 'Độ phân giải quá cao', 37 | imageValidateSizeLabelExpectedMinResolution: 'Độ phân giải tối thiểu là {minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: 'Độ phân giải tối đa là {maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/zh-cn.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: '拖放文件,或者 浏览 ', 3 | labelInvalidField: '字段包含无效文件', 4 | labelFileWaitingForSize: '计算文件大小', 5 | labelFileSizeNotAvailable: '文件大小不可用', 6 | labelFileLoading: '加载', 7 | labelFileLoadError: '加载错误', 8 | labelFileProcessing: '上传', 9 | labelFileProcessingComplete: '已上传', 10 | labelFileProcessingAborted: '上传已取消', 11 | labelFileProcessingError: '上传出错', 12 | labelFileProcessingRevertError: '还原出错', 13 | labelFileRemoveError: '删除出错', 14 | labelTapToCancel: '点击取消', 15 | labelTapToRetry: '点击重试', 16 | labelTapToUndo: '点击撤消', 17 | labelButtonRemoveItem: '删除', 18 | labelButtonAbortItemLoad: '中止', 19 | labelButtonRetryItemLoad: '重试', 20 | labelButtonAbortItemProcessing: '取消', 21 | labelButtonUndoItemProcessing: '撤消', 22 | labelButtonRetryItemProcessing: '重试', 23 | labelButtonProcessItem: '上传', 24 | labelMaxFileSizeExceeded: '文件太大', 25 | labelMaxFileSize: '最大值: {filesize}', 26 | labelMaxTotalFileSizeExceeded: '超过最大文件大小', 27 | labelMaxTotalFileSize: '最大文件大小:{filesize}', 28 | labelFileTypeNotAllowed: '文件类型无效', 29 | fileValidateTypeLabelExpectedTypes: '应为 {allButLastType} 或 {lastType}', 30 | imageValidateSizeLabelFormatError: '不支持图像类型', 31 | imageValidateSizeLabelImageSizeTooSmall: '图像太小', 32 | imageValidateSizeLabelImageSizeTooBig: '图像太大', 33 | imageValidateSizeLabelExpectedMinSize: '最小值: {minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: '最大值: {maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: '分辨率太低', 36 | imageValidateSizeLabelImageResolutionTooHigh: '分辨率太高', 37 | imageValidateSizeLabelExpectedMinResolution: '最小分辨率:{minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: '最大分辨率:{maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /locale/zh-tw.js: -------------------------------------------------------------------------------- 1 | export default { 2 | labelIdle: '拖放檔案,或者 瀏覽 ', 3 | labelInvalidField: '不支援此檔案', 4 | labelFileWaitingForSize: '正在計算檔案大小', 5 | labelFileSizeNotAvailable: '檔案大小不符', 6 | labelFileLoading: '讀取中', 7 | labelFileLoadError: '讀取錯誤', 8 | labelFileProcessing: '上傳', 9 | labelFileProcessingComplete: '已上傳', 10 | labelFileProcessingAborted: '上傳已取消', 11 | labelFileProcessingError: '上傳發生錯誤', 12 | labelFileProcessingRevertError: '還原錯誤', 13 | labelFileRemoveError: '刪除錯誤', 14 | labelTapToCancel: '點擊取消', 15 | labelTapToRetry: '點擊重試', 16 | labelTapToUndo: '點擊還原', 17 | labelButtonRemoveItem: '刪除', 18 | labelButtonAbortItemLoad: '停止', 19 | labelButtonRetryItemLoad: '重試', 20 | labelButtonAbortItemProcessing: '取消', 21 | labelButtonUndoItemProcessing: '取消', 22 | labelButtonRetryItemProcessing: '重試', 23 | labelButtonProcessItem: '上傳', 24 | labelMaxFileSizeExceeded: '檔案過大', 25 | labelMaxFileSize: '最大值:{filesize}', 26 | labelMaxTotalFileSizeExceeded: '超過最大可上傳大小', 27 | labelMaxTotalFileSize: '最大可上傳大小:{filesize}', 28 | labelFileTypeNotAllowed: '不支援此類型檔案', 29 | fileValidateTypeLabelExpectedTypes: '應為 {allButLastType} 或 {lastType}', 30 | imageValidateSizeLabelFormatError: '不支持此類圖片類型', 31 | imageValidateSizeLabelImageSizeTooSmall: '圖片過小', 32 | imageValidateSizeLabelImageSizeTooBig: '圖片過大', 33 | imageValidateSizeLabelExpectedMinSize: '最小尺寸:{minWidth} × {minHeight}', 34 | imageValidateSizeLabelExpectedMaxSize: '最大尺寸:{maxWidth} × {maxHeight}', 35 | imageValidateSizeLabelImageResolutionTooLow: '解析度過低', 36 | imageValidateSizeLabelImageResolutionTooHigh: '解析度過高', 37 | imageValidateSizeLabelExpectedMinResolution: '最低解析度:{minResolution}', 38 | imageValidateSizeLabelExpectedMaxResolution: '最高解析度:{maxResolution}' 39 | }; 40 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import * as pkg from './package.json'; 2 | import build from './rollup.scripts'; 3 | 4 | export default build( 5 | { 6 | id: 'FilePond', 7 | ...pkg 8 | }, 9 | [ 10 | { 11 | format: 'umd', 12 | transpile: true 13 | }, 14 | { 15 | format: 'umd', 16 | transpile: true, 17 | minify: true 18 | }, 19 | { 20 | format: 'es' 21 | }, 22 | { 23 | format: 'es', 24 | minify: true 25 | } 26 | ] 27 | ); -------------------------------------------------------------------------------- /rollup.scripts.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import license from 'rollup-plugin-license'; 3 | import { terser } from 'rollup-plugin-terser'; 4 | import prettier from 'rollup-plugin-prettier'; 5 | const banner = require('./banner'); 6 | 7 | const createBuild = (options) => { 8 | const { format, id, name, minify = false, transpile = false } = options; 9 | 10 | // get filename 11 | const filename = ['dist/', name]; 12 | if (format === 'es') { 13 | filename.push('.esm'); 14 | } 15 | if (minify) { 16 | filename.push('.min'); 17 | } 18 | filename.push('.js'); 19 | 20 | // collect plugins 21 | const plugins = []; 22 | if (transpile) { 23 | plugins.push(babel({ 24 | exclude: ['node_modules/**'] 25 | })); 26 | } 27 | if (minify) { 28 | plugins.push(terser()); 29 | } 30 | else { 31 | plugins.push(prettier({ 32 | singleQuote: true, 33 | parser: 'babel' 34 | })); 35 | } 36 | plugins.push(license({banner: banner(options)})); 37 | 38 | // return Rollup config 39 | return { 40 | input: 'src/js/index.js', 41 | treeshake: false, 42 | output: [ 43 | { 44 | format, 45 | name: id, 46 | file: filename.join('') 47 | } 48 | ], 49 | plugins 50 | } 51 | }; 52 | 53 | export default (metadata, configs) => configs.map(config => createBuild({ ...metadata, ...config })); -------------------------------------------------------------------------------- /src/css/assistant.css: -------------------------------------------------------------------------------- 1 | .filepond--assistant { 2 | position: absolute; 3 | overflow: hidden; 4 | height: 1px; 5 | width: 1px; 6 | padding: 0; 7 | border: 0; 8 | clip: rect(1px, 1px, 1px, 1px); 9 | clip-path: inset(50%); 10 | white-space: nowrap; 11 | } 12 | -------------------------------------------------------------------------------- /src/css/browser.css: -------------------------------------------------------------------------------- 1 | /* Hard to override styles */ 2 | .filepond--browser.filepond--browser { 3 | /* is positioned absolute so it is focusable for form validation errors */ 4 | position: absolute; 5 | margin: 0; 6 | padding: 0; 7 | 8 | /* is positioned ~behind drop label */ 9 | left: 1em; 10 | top: 1.75em; 11 | width: calc(100% - 2em); 12 | 13 | /* hide visually */ 14 | opacity: 0; 15 | font-size: 0; /* removes text cursor in Internet Explorer 11 */ 16 | } 17 | -------------------------------------------------------------------------------- /src/css/data.css: -------------------------------------------------------------------------------- 1 | .filepond--data { 2 | position: absolute; 3 | width: 0; 4 | height: 0; 5 | padding: 0; 6 | margin: 0; 7 | border: none; 8 | visibility: hidden; 9 | pointer-events: none; 10 | contain: strict; 11 | } 12 | -------------------------------------------------------------------------------- /src/css/drip.css: -------------------------------------------------------------------------------- 1 | .filepond--drip { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | right: 0; 6 | bottom: 0; 7 | overflow: hidden; 8 | opacity: 0.1; 9 | 10 | /* can't interact with this element */ 11 | pointer-events: none; 12 | 13 | /* inherit border radius from parent (needed for drip-blob cut of) */ 14 | border-radius: 0.5em; 15 | 16 | /* this seems to prevent Chrome from redrawing this layer constantly */ 17 | background: rgba(0, 0, 0, 0.01); 18 | } 19 | 20 | .filepond--drip-blob { 21 | position: absolute; 22 | transform-origin: center center; 23 | top: 0; 24 | left: 0; 25 | width: 8em; 26 | height: 8em; 27 | margin-left: -4em; 28 | margin-top: -4em; 29 | background: #292625; 30 | border-radius: 50%; 31 | 32 | /* will be animated */ 33 | will-change: transform, opacity; 34 | } 35 | -------------------------------------------------------------------------------- /src/css/drop-label.css: -------------------------------------------------------------------------------- 1 | .filepond--drop-label { 2 | position: absolute; 3 | left: 0; 4 | right: 0; 5 | top: 0; 6 | margin: 0; 7 | color: #4f4f4f; 8 | 9 | /* center contents */ 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | 14 | /* fixes IE11 centering problems (is overruled by label min-height) */ 15 | height: 0px; 16 | 17 | /* dont allow selection */ 18 | user-select: none; 19 | 20 | /* will be animated */ 21 | will-change: transform, opacity; 22 | } 23 | 24 | /* Hard to override styles on purpose */ 25 | .filepond--drop-label.filepond--drop-label label { 26 | display: block; 27 | margin: 0; 28 | padding: 0.5em; /* use padding instead of margin so click area is not impacted */ 29 | } 30 | 31 | .filepond--drop-label label { 32 | cursor: default; 33 | font-size: 0.875em; 34 | font-weight: normal; 35 | text-align: center; 36 | line-height: 1.5; 37 | } 38 | 39 | .filepond--label-action { 40 | text-decoration: underline; 41 | text-decoration-skip-ink: auto; 42 | text-decoration-color: #a7a4a4; 43 | cursor: pointer; 44 | } 45 | 46 | .filepond--root[data-disabled] { 47 | & .filepond--drop-label label { 48 | opacity: 0.5; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/css/file-info.css: -------------------------------------------------------------------------------- 1 | .filepond--file-info { 2 | position: static; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: flex-start; 6 | flex: 1; 7 | margin: 0 0.5em 0 0; 8 | min-width: 0; 9 | 10 | /* will be animated */ 11 | will-change: transform, opacity; 12 | 13 | /* can't do anything with this info */ 14 | pointer-events: none; 15 | user-select: none; 16 | 17 | /* no margins on children */ 18 | & * { 19 | margin: 0; 20 | } 21 | 22 | /* we don't want to have these overrules so these selectors are a bit more specific */ 23 | & .filepond--file-info-main { 24 | font-size: 0.75em; 25 | line-height: 1.2; 26 | 27 | /* we want ellipsis if this bar gets too wide */ 28 | text-overflow: ellipsis; 29 | overflow: hidden; 30 | white-space: nowrap; 31 | width: 100%; 32 | } 33 | 34 | & .filepond--file-info-sub { 35 | font-size: 0.625em; 36 | opacity: 0.5; 37 | transition: opacity 0.25s ease-in-out; 38 | white-space: nowrap; 39 | } 40 | 41 | & .filepond--file-info-sub:empty { 42 | display: none; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/css/file-status.css: -------------------------------------------------------------------------------- 1 | .filepond--file-status { 2 | position: static; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: flex-end; 6 | flex-grow: 0; 7 | flex-shrink: 0; 8 | 9 | margin: 0; 10 | min-width: 2.25em; 11 | text-align: right; 12 | 13 | /* will be animated */ 14 | will-change: transform, opacity; 15 | 16 | /* can't do anything with this info */ 17 | pointer-events: none; 18 | user-select: none; 19 | 20 | /* no margins on children */ 21 | & * { 22 | margin: 0; 23 | white-space: nowrap; 24 | } 25 | 26 | /* font sizes */ 27 | & .filepond--file-status-main { 28 | font-size: 0.75em; 29 | line-height: 1.2; 30 | } 31 | 32 | & .filepond--file-status-sub { 33 | font-size: 0.625em; 34 | opacity: 0.5; 35 | transition: opacity 0.25s ease-in-out; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/css/file-wrapper.css: -------------------------------------------------------------------------------- 1 | /* Hard to override styles */ 2 | .filepond--file-wrapper.filepond--file-wrapper { 3 | border: none; 4 | margin: 0; 5 | padding: 0; 6 | min-width: 0; 7 | height: 100%; 8 | 9 | /* hide legend for visual users */ 10 | & > legend { 11 | position: absolute; 12 | overflow: hidden; 13 | height: 1px; 14 | width: 1px; 15 | padding: 0; 16 | border: 0; 17 | clip: rect(1px, 1px, 1px, 1px); 18 | clip-path: inset(50%); 19 | white-space: nowrap; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/css/hopper.css: -------------------------------------------------------------------------------- 1 | /* ignore all other interaction elements while dragging a file */ 2 | .filepond--hopper[data-hopper-state='drag-over'] > * { 3 | pointer-events: none; 4 | } 5 | 6 | /* capture all hit tests using a hidden layer, this speeds up the event flow */ 7 | .filepond--hopper[data-hopper-state='drag-over']::after { 8 | content: ''; 9 | position: absolute; 10 | left: 0; 11 | top: 0; 12 | right: 0; 13 | bottom: 0; 14 | z-index: 100; 15 | } 16 | -------------------------------------------------------------------------------- /src/css/item-order.css: -------------------------------------------------------------------------------- 1 | .filepond--progress-indicator { 2 | z-index: 103; 3 | } 4 | 5 | .filepond--file-action-button { 6 | z-index: 102; 7 | } 8 | 9 | .filepond--file-status { 10 | z-index: 101; 11 | } 12 | 13 | .filepond--file-info { 14 | z-index: 100; 15 | } 16 | -------------------------------------------------------------------------------- /src/css/item.css: -------------------------------------------------------------------------------- 1 | .filepond--item { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | right: 0; 6 | z-index: 1; 7 | 8 | padding: 0; 9 | margin: 0.25em; 10 | 11 | will-change: transform, opacity; 12 | 13 | touch-action: auto; 14 | 15 | /* item children order */ 16 | & > .filepond--panel { 17 | z-index: -1; 18 | 19 | /* has a slight shadow */ 20 | .filepond--panel-bottom { 21 | box-shadow: 0 0.0625em 0.125em -0.0625em rgba(0, 0, 0, 0.25); 22 | } 23 | } 24 | 25 | /* drag related */ 26 | & > .filepond--file-wrapper, 27 | & > .filepond--panel { 28 | transition: opacity 0.15s ease-out; 29 | } 30 | 31 | &[data-drag-state] { 32 | cursor: grab; 33 | > .filepond--panel { 34 | transition: box-shadow 0.125s ease-in-out; 35 | box-shadow: 0 0 0 rgba(0, 0, 0, 0); 36 | } 37 | } 38 | 39 | &[data-drag-state='drag'] { 40 | cursor: grabbing; 41 | > .filepond--panel { 42 | box-shadow: 0 0.125em 0.3125em rgba(0, 0, 0, 0.325); 43 | } 44 | } 45 | 46 | &[data-drag-state]:not([data-drag-state='idle']) { 47 | z-index: 2; 48 | } 49 | } 50 | 51 | /* states */ 52 | .filepond--item-panel { 53 | background-color: #64605e; 54 | } 55 | 56 | [data-filepond-item-state='processing-complete'] { 57 | .filepond--item-panel { 58 | background-color: #369763; 59 | } 60 | } 61 | 62 | [data-filepond-item-state*='invalid'], 63 | [data-filepond-item-state*='error'] { 64 | .filepond--item-panel { 65 | background-color: #c44e47; 66 | } 67 | } 68 | 69 | /* style of item panel */ 70 | .filepond--item-panel { 71 | border-radius: 0.5em; 72 | transition: background-color 0.25s; 73 | } 74 | -------------------------------------------------------------------------------- /src/css/list-scroller.css: -------------------------------------------------------------------------------- 1 | /* normal mode */ 2 | .filepond--list-scroller { 3 | position: absolute; 4 | top: 0; 5 | left: 0; 6 | right: 0; 7 | margin: 0; 8 | will-change: transform; 9 | } 10 | 11 | /* scroll mode */ 12 | .filepond--list-scroller[data-state='overflow'] { 13 | & .filepond--list { 14 | bottom: 0; 15 | right: 0; 16 | } 17 | 18 | overflow-y: scroll; 19 | overflow-x: hidden; 20 | -webkit-overflow-scrolling: touch; 21 | mask: linear-gradient(to bottom, #000 calc(100% - 0.5em), transparent 100%); 22 | } 23 | 24 | /* style scrollbar */ 25 | .filepond--list-scroller::-webkit-scrollbar { 26 | background: transparent; 27 | } 28 | 29 | .filepond--list-scroller::-webkit-scrollbar:vertical { 30 | width: 1em; 31 | } 32 | 33 | .filepond--list-scroller::-webkit-scrollbar:horizontal { 34 | height: 0; 35 | } 36 | 37 | .filepond--list-scroller::-webkit-scrollbar-thumb { 38 | background-color: rgba(0, 0, 0, 0.3); 39 | border-radius: 99999px; 40 | border: 0.3125em solid transparent; 41 | background-clip: content-box; 42 | } 43 | -------------------------------------------------------------------------------- /src/css/list.css: -------------------------------------------------------------------------------- 1 | /* hard to overide styles on purpose */ 2 | .filepond--list.filepond--list { 3 | position: absolute; 4 | top: 0; 5 | margin: 0; 6 | padding: 0; 7 | list-style-type: none; 8 | 9 | /* prevents endless paint calls on filepond--list-scroller */ 10 | will-change: transform; 11 | } 12 | 13 | /* used for padding so allowed to be restyled */ 14 | .filepond--list { 15 | left: 0.75em; 16 | right: 0.75em; 17 | } 18 | -------------------------------------------------------------------------------- /src/css/panel-root.css: -------------------------------------------------------------------------------- 1 | .filepond--panel-root { 2 | border-radius: 0.5em; 3 | background-color: #f1f0ef; 4 | } 5 | -------------------------------------------------------------------------------- /src/css/progress-indicator.css: -------------------------------------------------------------------------------- 1 | .filepond--progress-indicator { 2 | position: static; 3 | width: 1.25em; 4 | height: 1.25em; 5 | 6 | color: #fff; 7 | 8 | /* can't have margins */ 9 | margin: 0; 10 | 11 | /* no interaction possible with progress indicator */ 12 | pointer-events: none; 13 | 14 | /* will be animated */ 15 | will-change: transform, opacity; 16 | } 17 | 18 | .filepond--progress-indicator svg { 19 | width: 100%; 20 | height: 100%; 21 | vertical-align: top; 22 | transform-box: fill-box; /* should center the animation correctly when zoomed in */ 23 | } 24 | 25 | .filepond--progress-indicator path { 26 | fill: none; 27 | stroke: currentColor; 28 | } 29 | -------------------------------------------------------------------------------- /src/css/root-order.css: -------------------------------------------------------------------------------- 1 | .filepond--list-scroller { 2 | z-index: 6; 3 | } 4 | 5 | .filepond--drop-label { 6 | z-index: 5; 7 | } 8 | 9 | .filepond--drip { 10 | z-index: 3; 11 | } 12 | 13 | .filepond--root > .filepond--panel { 14 | z-index: 2; 15 | } 16 | 17 | .filepond--browser { 18 | z-index: 1; 19 | } 20 | -------------------------------------------------------------------------------- /src/css/root.css: -------------------------------------------------------------------------------- 1 | .filepond--root { 2 | /* layout*/ 3 | box-sizing: border-box; 4 | position: relative; 5 | margin-bottom: 1em; 6 | 7 | /* base font size for whole component */ 8 | font-size: 1rem; 9 | 10 | /* base line height */ 11 | line-height: normal; 12 | 13 | /* up uses default system font family */ 14 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 15 | 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; 16 | 17 | /* will increase font weight a bit on Safari */ 18 | font-weight: 450; 19 | 20 | /* default text alignment */ 21 | text-align: left; 22 | 23 | /* better text rendering on Safari */ 24 | text-rendering: optimizeLegibility; 25 | 26 | /* text direction is ltr for now */ 27 | direction: ltr; 28 | 29 | /* optimize rendering */ 30 | /* https://developer.mozilla.org/en-US/docs/Web/CSS/contain */ 31 | contain: layout style size; 32 | 33 | /* correct box sizing, line-height and positioning on child elements */ 34 | & * { 35 | box-sizing: inherit; 36 | line-height: inherit; 37 | } 38 | 39 | & *:not(text) { 40 | font-size: inherit; 41 | } 42 | 43 | /* block everything */ 44 | &[data-disabled] { 45 | pointer-events: none; 46 | 47 | .filepond--list-scroller { 48 | pointer-events: all; 49 | } 50 | 51 | .filepond--list { 52 | pointer-events: none; 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * Root element children layout 59 | */ 60 | .filepond--root { 61 | & .filepond--drop-label { 62 | min-height: 4.75em; 63 | } 64 | 65 | & .filepond--list-scroller { 66 | margin-top: 1em; 67 | margin-bottom: 1em; 68 | } 69 | 70 | & .filepond--credits { 71 | position: absolute; 72 | right: 0; 73 | opacity: 0.4; 74 | line-height: 0.85; 75 | font-size: 11px; 76 | color: inherit; 77 | text-decoration: none; 78 | z-index: 3; 79 | bottom: -14px; 80 | } 81 | 82 | & .filepond--credits[style] { 83 | top: 0; 84 | bottom: auto; 85 | margin-top: 14px; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/css/styles.css: -------------------------------------------------------------------------------- 1 | @import 'assistant.css'; 2 | @import 'browser.css'; 3 | @import 'data.css'; 4 | @import 'drip.css'; 5 | @import 'drop-label.css'; 6 | @import 'file-action-button.css'; 7 | @import 'file-info.css'; 8 | @import 'file-status.css'; 9 | @import 'file-wrapper.css'; 10 | @import 'file.css'; 11 | @import 'hopper.css'; 12 | @import 'item-order.css'; 13 | @import 'item.css'; 14 | @import 'list-scroller.css'; 15 | @import 'list.css'; 16 | @import 'modifiers.css'; 17 | @import 'panel-root.css'; 18 | @import 'panel.css'; 19 | @import 'progress-indicator.css'; 20 | @import 'root-order.css'; 21 | @import 'root.css'; 22 | -------------------------------------------------------------------------------- /src/js/__tests__/addFile.test.js: -------------------------------------------------------------------------------- 1 | import './windowMatchMedia.mock'; 2 | import { create } from '../index.js'; 3 | 4 | describe('adding files', () => { 5 | let pond = null; 6 | 7 | beforeEach(() => { 8 | if (pond) { 9 | pond.destroy(); 10 | } 11 | 12 | pond = create(); 13 | 14 | // enables draw loop, else it seems that filepond is hidden 15 | Object.defineProperty(pond.element, 'offsetParent', { 16 | get: jest.fn(() => 1), 17 | }); 18 | }); 19 | 20 | test('add file', done => { 21 | const data = new File(['Hello World!'], 'dummy.txt', { 22 | type: 'text/plain', 23 | lastModified: new Date(), 24 | }); 25 | pond.addFile(data).then(item => { 26 | done(); 27 | }); 28 | }); 29 | 30 | test('add blob', done => { 31 | const data = new Blob(['Hello World!'], { type: 'text/plain' }); 32 | pond.addFile(data).then(item => { 33 | done(); 34 | }); 35 | }); 36 | 37 | test('add base64 string', done => { 38 | const data = 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=='; 39 | pond.addFile(data).then(item => { 40 | done(); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/js/__tests__/contentDisposition.test.js: -------------------------------------------------------------------------------- 1 | import { getFileNameFromHeader } from '../utils/getFileInfoFromHeaders'; 2 | 3 | describe('parse filename', () => { 4 | [ 5 | { value: ``, expected: null }, 6 | { value: `foo-bar`, expected: null }, 7 | { value: `Content-Disposition: attachment;`, expected: null }, 8 | { value: `Content-Disposition: attachment; filename=`, expected: null }, 9 | { value: `Content-Disposition: attachment; filename.jpg`, expected: null }, 10 | { 11 | value: `Content-Disposition: attachment; filename=filename.jpg`, 12 | expected: 'filename.jpg', 13 | }, 14 | { 15 | value: `Content-Disposition: attachment; filename=filename.jpg;`, 16 | expected: 'filename.jpg', 17 | }, 18 | { 19 | value: `Content-Disposition: attachment; filename="filename.jpg"`, 20 | expected: 'filename.jpg', 21 | }, 22 | { 23 | value: `Content-Disposition: attachment; filename="filename.jpg";`, 24 | expected: 'filename.jpg', 25 | }, 26 | { 27 | value: `Content-Disposition: attachment; filename=file name.jpg`, 28 | expected: 'file name.jpg', 29 | }, 30 | { 31 | value: `Content-Disposition: attachment; filename=filename.jpg; filename*=UTF-8''filename.jpg`, 32 | expected: 'filename.jpg', 33 | }, 34 | { 35 | value: `Content-Disposition: attachment; filename="filename.jpg"; filename*=UTF-8''filename.jpg`, 36 | expected: 'filename.jpg', 37 | }, 38 | { 39 | value: `Content-Disposition: attachment; filename="file name.jpg"; filename*=UTF-8''file%20name.jpg`, 40 | expected: 'file name.jpg', 41 | }, 42 | ].forEach(header => { 43 | test(`Can parse: "${header.value}"`, () => { 44 | const name = getFileNameFromHeader(header.value); 45 | expect(name).toBe(header.expected); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/js/__tests__/createInstance.test.js: -------------------------------------------------------------------------------- 1 | import './windowMatchMedia.mock'; 2 | import { create } from '../index.js'; 3 | 4 | describe('create instance', () => { 5 | test('without parameters', () => { 6 | expect(create()).toBeDefined(); 7 | }); 8 | 9 | test('with options object only', () => { 10 | expect( 11 | create({ 12 | instantUpload: false, 13 | }).instantUpload 14 | ).toBe(false); 15 | }); 16 | 17 | test('with element only', () => { 18 | const form = document.createElement('form'); 19 | const input = document.createElement('input'); 20 | input.type = 'file'; 21 | form.appendChild(input); 22 | expect(create(input).element.parentNode).toBe(form); 23 | }); 24 | 25 | test('with element and options object', () => { 26 | const form = document.createElement('form'); 27 | const input = document.createElement('input'); 28 | input.type = 'file'; 29 | input.dataset.dropOnPage = false; 30 | form.appendChild(input); 31 | const pond = create(input, { 32 | dropOnPage: true, 33 | }); 34 | expect(pond.dropOnPage).toBe(false); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/js/__tests__/windowMatchMedia.mock: -------------------------------------------------------------------------------- 1 | // Mocking window.matchMedia as described in the jest docks 2 | // since this is not defined in JSDOM and causes the tests 3 | // to fail. See: "https://jestjs.io/docs/en/manual- 4 | // mocks#mocking-methods-which-are-not-implemented-in-jsdom" 5 | Object.defineProperty(window, 'matchMedia', { 6 | writable: true, 7 | value: jest.fn().mockImplementation(query => ({ 8 | matches: false, 9 | media: query, 10 | onchange: null, 11 | addListener: jest.fn(), // deprecated 12 | removeListener: jest.fn(), // deprecated 13 | addEventListener: jest.fn(), 14 | removeEventListener: jest.fn(), 15 | dispatchEvent: jest.fn(), 16 | })), 17 | }); 18 | -------------------------------------------------------------------------------- /src/js/app/enum/ChunkStatus.js: -------------------------------------------------------------------------------- 1 | export const ChunkStatus = { 2 | QUEUED: 0, 3 | COMPLETE: 1, 4 | PROCESSING: 2, 5 | ERROR: 3, 6 | WAITING: 4 7 | }; -------------------------------------------------------------------------------- /src/js/app/enum/FileOrigin.js: -------------------------------------------------------------------------------- 1 | export const FileOrigin = { 2 | INPUT:1, 3 | LIMBO:2, 4 | LOCAL:3 5 | }; -------------------------------------------------------------------------------- /src/js/app/enum/InteractionMethod.js: -------------------------------------------------------------------------------- 1 | export const InteractionMethod = { 2 | API: 1, 3 | DROP: 2, 4 | BROWSE: 3, 5 | PASTE: 4, 6 | NONE: 5 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/app/enum/ItemStatus.js: -------------------------------------------------------------------------------- 1 | export const ItemStatus = { 2 | INIT: 1, 3 | IDLE: 2, 4 | PROCESSING_QUEUED: 9, 5 | PROCESSING: 3, 6 | PROCESSING_COMPLETE: 5, 7 | PROCESSING_ERROR: 6, 8 | PROCESSING_REVERT_ERROR: 10, 9 | LOADING: 7, 10 | LOAD_ERROR: 8 11 | }; 12 | -------------------------------------------------------------------------------- /src/js/app/enum/Key.js: -------------------------------------------------------------------------------- 1 | export const Key = { 2 | ENTER: 13, 3 | SPACE: 32 4 | }; 5 | -------------------------------------------------------------------------------- /src/js/app/enum/Status.js: -------------------------------------------------------------------------------- 1 | export const Status = { 2 | EMPTY: 0, 3 | IDLE: 1, // waiting 4 | ERROR: 2, // a file is in error state 5 | BUSY: 3, // busy processing or loading 6 | READY: 4 // all files uploaded 7 | }; -------------------------------------------------------------------------------- /src/js/app/enum/Type.js: -------------------------------------------------------------------------------- 1 | export const Type = { 2 | BOOLEAN: 'boolean', 3 | INT: 'int', 4 | NUMBER: 'number', 5 | STRING: 'string', 6 | ARRAY: 'array', 7 | OBJECT: 'object', 8 | FUNCTION: 'function', 9 | ACTION: 'action', 10 | SERVER_API: 'serverapi', 11 | REGEX: 'regex' 12 | }; 13 | -------------------------------------------------------------------------------- /src/js/app/frame/createPainter.js: -------------------------------------------------------------------------------- 1 | export const createPainter = (read, write, fps = 60) => { 2 | 3 | const name = '__framePainter'; 4 | 5 | // set global painter 6 | if (window[name]) { 7 | window[name].readers.push(read); 8 | window[name].writers.push(write); 9 | return; 10 | } 11 | 12 | window[name] = { 13 | readers:[read], 14 | writers:[write] 15 | } 16 | 17 | const painter = window[name]; 18 | 19 | const interval = 1000 / fps; 20 | let last = null; 21 | let id = null; 22 | let requestTick = null; 23 | let cancelTick = null; 24 | 25 | const setTimerType = () => { 26 | if (document.hidden) { 27 | requestTick = () => window.setTimeout(() => tick(performance.now()), interval); 28 | cancelTick = () => window.clearTimeout(id); 29 | } 30 | else { 31 | requestTick = () => window.requestAnimationFrame(tick); 32 | cancelTick = () => window.cancelAnimationFrame(id); 33 | } 34 | } 35 | 36 | document.addEventListener('visibilitychange', () => { 37 | if (cancelTick) cancelTick(); 38 | setTimerType(); 39 | tick(performance.now()); 40 | }); 41 | 42 | const tick = ts => { 43 | 44 | // queue next tick 45 | id = requestTick(tick); 46 | 47 | // limit fps 48 | if (!last) { 49 | last = ts; 50 | } 51 | 52 | const delta = ts - last; 53 | 54 | if (delta <= interval) { 55 | // skip frame 56 | return; 57 | } 58 | 59 | // align next frame 60 | last = ts - delta % interval; 61 | 62 | // update view 63 | painter.readers.forEach(read => read()); 64 | painter.writers.forEach(write => write(ts)); 65 | }; 66 | 67 | setTimerType(); 68 | tick(performance.now()); 69 | 70 | return { 71 | pause: () => { 72 | cancelTick(id); 73 | } 74 | }; 75 | }; 76 | -------------------------------------------------------------------------------- /src/js/app/frame/createRoute.js: -------------------------------------------------------------------------------- 1 | export const createRoute = (routes, fn) => ({ root, props, actions = [], timestamp, shouldOptimize }) => { 2 | actions.filter(action => routes[action.type]) 3 | .forEach(action => 4 | routes[action.type]({ root, props, action: action.data, timestamp, shouldOptimize }) 5 | ); 6 | if (fn) { 7 | fn({ root, props, actions, timestamp, shouldOptimize }); 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /src/js/app/frame/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from './createStore'; 2 | import { createView } from './createView'; 3 | import { createPainter } from './createPainter'; 4 | import { createRoute } from './createRoute'; 5 | 6 | export { createRoute, createPainter, createStore, createView }; -------------------------------------------------------------------------------- /src/js/app/frame/mixins/animations.js: -------------------------------------------------------------------------------- 1 | import { createAnimator } from '../utils/createAnimator'; 2 | import { forin } from '../../../utils/forin'; 3 | import { addGetSet } from './utils/addGetSet'; 4 | 5 | // add to state, 6 | // add getters and setters to internal and external api (if not set) 7 | // setup animators 8 | 9 | export const animations = ({ 10 | mixinConfig, 11 | viewProps, 12 | viewInternalAPI, 13 | viewExternalAPI 14 | }) => { 15 | // initial properties 16 | const initialProps = { ...viewProps }; 17 | 18 | // list of all active animations 19 | const animations = []; 20 | 21 | // setup animators 22 | forin(mixinConfig, (property, animation) => { 23 | const animator = createAnimator(animation); 24 | if (!animator) { 25 | return; 26 | } 27 | 28 | // when the animator updates, update the view state value 29 | animator.onupdate = value => { 30 | viewProps[property] = value; 31 | }; 32 | 33 | // set animator target 34 | animator.target = initialProps[property]; 35 | 36 | // when value is set, set the animator target value 37 | const prop = { 38 | key: property, 39 | setter: value => { 40 | 41 | // if already at target, we done! 42 | if (animator.target === value) { 43 | return; 44 | } 45 | 46 | animator.target = value; 47 | }, 48 | getter: () => viewProps[property] 49 | }; 50 | 51 | // add getters and setters 52 | addGetSet([prop], [viewInternalAPI, viewExternalAPI], viewProps, true); 53 | 54 | // add it to the list for easy updating from the _write method 55 | animations.push(animator); 56 | }); 57 | 58 | // expose internal write api 59 | return { 60 | write: ts => { 61 | let skipToEndState = document.hidden; 62 | let resting = true; 63 | animations.forEach(animation => { 64 | if (!animation.resting) resting = false; 65 | animation.interpolate(ts, skipToEndState); 66 | }); 67 | return resting; 68 | }, 69 | destroy: () => {} 70 | }; 71 | }; 72 | -------------------------------------------------------------------------------- /src/js/app/frame/mixins/apis.js: -------------------------------------------------------------------------------- 1 | import { addGetSet } from './utils/addGetSet'; 2 | 3 | // add to external api and link to props 4 | 5 | export const apis = ({ mixinConfig, viewProps, viewExternalAPI }) => { 6 | addGetSet(mixinConfig, viewExternalAPI, viewProps); 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/app/frame/mixins/index.js: -------------------------------------------------------------------------------- 1 | import { animations } from './animations'; 2 | import { listeners } from './listeners'; 3 | import { apis } from './apis'; 4 | import { styles } from './styles'; 5 | 6 | export const Mixins = { 7 | styles, 8 | listeners, 9 | animations, 10 | apis 11 | }; 12 | -------------------------------------------------------------------------------- /src/js/app/frame/mixins/listeners.js: -------------------------------------------------------------------------------- 1 | import { addEvent } from '../utils/addEvent'; 2 | import { removeEvent } from '../utils/removeEvent'; 3 | 4 | // mixin 5 | export const listeners = ({ 6 | mixinConfig, 7 | viewProps, 8 | viewInternalAPI, 9 | viewExternalAPI, 10 | viewState, 11 | view 12 | }) => { 13 | const events = []; 14 | 15 | const add = addEvent(view.element); 16 | const remove = removeEvent(view.element); 17 | 18 | viewExternalAPI.on = (type, fn) => { 19 | events.push({ 20 | type, 21 | fn 22 | }); 23 | add(type, fn); 24 | }; 25 | 26 | viewExternalAPI.off = (type, fn) => { 27 | events.splice( 28 | events.findIndex(event => event.type === type && event.fn === fn), 29 | 1 30 | ); 31 | remove(type, fn); 32 | }; 33 | 34 | return { 35 | write: () => { 36 | // not busy 37 | return true; 38 | }, 39 | destroy: () => { 40 | events.forEach(event => { 41 | remove(event.type, event.fn); 42 | }); 43 | } 44 | }; 45 | }; 46 | -------------------------------------------------------------------------------- /src/js/app/frame/mixins/utils/addGetSet.js: -------------------------------------------------------------------------------- 1 | export const addGetSet = (keys, obj, props, overwrite = false) => { 2 | obj = Array.isArray(obj) ? obj : [obj]; 3 | obj.forEach(o => { 4 | keys.forEach(key => { 5 | let name = key; 6 | let getter = () => props[key]; 7 | let setter = value => (props[key] = value); 8 | 9 | if (typeof key === 'object') { 10 | name = key.key; 11 | getter = key.getter || getter; 12 | setter = key.setter || setter; 13 | } 14 | 15 | if (o[name] && !overwrite) { 16 | return; 17 | } 18 | 19 | o[name] = { 20 | get: getter, 21 | set: setter 22 | }; 23 | }); 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/AxisEnum.js: -------------------------------------------------------------------------------- 1 | export const AxisEnum = { 2 | X: 0, 3 | Y: 1, 4 | Z: 2 5 | }; 6 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/addEvent.js: -------------------------------------------------------------------------------- 1 | export const addEvent = element => (type, fn) => { 2 | element.addEventListener(type, fn); 3 | }; 4 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/animators/easing.js: -------------------------------------------------------------------------------- 1 | export const easeLinear = t => t; 2 | export const easeInOutQuad = t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t); 3 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/appendChild.js: -------------------------------------------------------------------------------- 1 | export const appendChild = parent => (child, index) => { 2 | if (typeof index !== 'undefined' && parent.children[index]) { 3 | parent.insertBefore(child, parent.children[index]); 4 | } else { 5 | parent.appendChild(child); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/appendChildView.js: -------------------------------------------------------------------------------- 1 | export const appendChildView = (parent, childViews) => (view, index) => { 2 | 3 | if (typeof index !== 'undefined') { 4 | childViews.splice(index, 0, view); 5 | } else { 6 | childViews.push(view); 7 | } 8 | 9 | return view; 10 | }; 11 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/createAnimator.js: -------------------------------------------------------------------------------- 1 | import { spring } from './animators/spring'; 2 | import { tween } from './animators/tween'; 3 | 4 | const animator = { 5 | spring, 6 | tween 7 | }; 8 | 9 | /* 10 | { type: 'spring', stiffness: .5, damping: .75, mass: 10 }; 11 | { translation: { type: 'spring', ... }, ... } 12 | { translation: { x: { type: 'spring', ... } } } 13 | */ 14 | export const createAnimator = (definition, category, property) => { 15 | // default is single definition 16 | // we check if transform is set, if so, we check if property is set 17 | const def = 18 | definition[category] && 19 | typeof definition[category][property] === 'object' 20 | ? definition[category][property] 21 | : definition[category] || definition; 22 | 23 | const type = typeof def === 'string' ? def : def.type; 24 | const props = typeof def === 'object' ? { ...def } : {}; 25 | 26 | return animator[type] ? animator[type](props) : null; 27 | }; 28 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/createElement.js: -------------------------------------------------------------------------------- 1 | import { forin } from '../../../utils/forin'; 2 | import { attr } from '../../../utils/attr'; 3 | 4 | const ns = 'http://www.w3.org/2000/svg'; 5 | const svgElements = ['svg', 'path']; // only svg elements used 6 | 7 | const isSVGElement = tag => svgElements.includes(tag); 8 | 9 | export const createElement = (tag, className, attributes = {}) => { 10 | if (typeof className === 'object') { 11 | attributes = className; 12 | className = null; 13 | } 14 | const element = isSVGElement(tag) 15 | ? document.createElementNS(ns, tag) 16 | : document.createElement(tag); 17 | if (className) { 18 | if (isSVGElement(tag)) { 19 | attr(element, 'class', className); 20 | } else { 21 | element.className = className; 22 | } 23 | } 24 | forin(attributes, (name, value) => { 25 | attr(element, name, value); 26 | }); 27 | return element; 28 | }; 29 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/getChildCount.js: -------------------------------------------------------------------------------- 1 | import { createElement } from './createElement'; 2 | import { isBrowser } from '../../../utils/isBrowser'; 3 | const testElement = isBrowser() ? createElement('svg') : {}; 4 | export const getChildCount = 'children' in testElement ? el => el.children.length : el => el.childNodes.length; -------------------------------------------------------------------------------- /src/js/app/frame/utils/getViewRect.js: -------------------------------------------------------------------------------- 1 | export const getViewRect = (elementRect, childViews, offset, scale) => { 2 | const left = offset[0] || elementRect.left; 3 | const top = offset[1] || elementRect.top; 4 | const right = left + elementRect.width; 5 | const bottom = top + elementRect.height * (scale[1] || 1); 6 | 7 | const rect = { 8 | // the rectangle of the element itself 9 | element: { 10 | ...elementRect 11 | }, 12 | 13 | // the rectangle of the element expanded to contain its children, does not include any margins 14 | inner: { 15 | left: elementRect.left, 16 | top: elementRect.top, 17 | right: elementRect.right, 18 | bottom: elementRect.bottom 19 | }, 20 | 21 | // the rectangle of the element expanded to contain its children including own margin and child margins 22 | // margins will be added after we've recalculated the size 23 | outer: { 24 | left, 25 | top, 26 | right, 27 | bottom 28 | } 29 | }; 30 | 31 | // expand rect to fit all child rectangles 32 | childViews 33 | .filter(childView => !childView.isRectIgnored()) 34 | .map(childView => childView.rect) 35 | .forEach(childViewRect => { 36 | expandRect(rect.inner, { ...childViewRect.inner }); 37 | expandRect(rect.outer, { ...childViewRect.outer }); 38 | }); 39 | 40 | // calculate inner width and height 41 | calculateRectSize(rect.inner); 42 | 43 | // append additional margin (top and left margins are included in top and left automatically) 44 | rect.outer.bottom += rect.element.marginBottom; 45 | rect.outer.right += rect.element.marginRight; 46 | 47 | // calculate outer width and height 48 | calculateRectSize(rect.outer); 49 | 50 | return rect; 51 | }; 52 | 53 | const expandRect = (parent, child) => { 54 | // adjust for parent offset 55 | child.top += parent.top; 56 | child.right += parent.left; 57 | child.bottom += parent.top; 58 | child.left += parent.left; 59 | 60 | if (child.bottom > parent.bottom) { 61 | parent.bottom = child.bottom; 62 | } 63 | 64 | if (child.right > parent.right) { 65 | parent.right = child.right; 66 | } 67 | }; 68 | 69 | const calculateRectSize = rect => { 70 | rect.width = rect.right - rect.left; 71 | rect.height = rect.bottom - rect.top; 72 | }; 73 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/removeChildView.js: -------------------------------------------------------------------------------- 1 | export const removeChildView = (parent, childViews) => view => { 2 | // remove from child views 3 | childViews.splice(childViews.indexOf(view), 1); 4 | 5 | // remove the element 6 | if (view.element.parentNode) { 7 | parent.removeChild(view.element); 8 | } 9 | 10 | return view; 11 | }; 12 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/removeEvent.js: -------------------------------------------------------------------------------- 1 | export const removeEvent = element => (type, fn) => { 2 | element.removeEventListener(type, fn); 3 | }; 4 | -------------------------------------------------------------------------------- /src/js/app/frame/utils/updateRect.js: -------------------------------------------------------------------------------- 1 | export const updateRect = (rect = {}, element = {}, style = {}) => { 2 | 3 | if (!element.layoutCalculated) { 4 | rect.paddingTop = parseInt(style.paddingTop, 10) || 0; 5 | rect.marginTop = parseInt(style.marginTop, 10) || 0; 6 | rect.marginRight = parseInt(style.marginRight, 10) || 0; 7 | rect.marginBottom = parseInt(style.marginBottom, 10) || 0; 8 | rect.marginLeft = parseInt(style.marginLeft, 10) || 0; 9 | element.layoutCalculated = true; 10 | } 11 | 12 | rect.left = element.offsetLeft || 0; 13 | rect.top = element.offsetTop || 0; 14 | rect.width = element.offsetWidth || 0; 15 | rect.height = element.offsetHeight || 0; 16 | 17 | rect.right = rect.left + rect.width; 18 | rect.bottom = rect.top + rect.height; 19 | 20 | rect.scrollTop = element.scrollTop; 21 | 22 | rect.hidden = element.offsetParent === null; 23 | 24 | return rect; 25 | }; 26 | -------------------------------------------------------------------------------- /src/js/app/utils/buildURL.js: -------------------------------------------------------------------------------- 1 | const hasQS = str => /\?/.test(str); 2 | export const buildURL = (...parts) => { 3 | let url = ''; 4 | parts.forEach(part => { 5 | url += hasQS(url) && hasQS(part) ? part.replace(/\?/, '&') : part; 6 | }); 7 | return url; 8 | } -------------------------------------------------------------------------------- /src/js/app/utils/convertTo.js: -------------------------------------------------------------------------------- 1 | import { toArray } from '../../utils/toArray'; 2 | import { toBoolean } from '../../utils/toBoolean'; 3 | import { toInt } from '../../utils/toInt'; 4 | import { toFloat } from '../../utils/toFloat'; 5 | import { toBytes } from '../../utils/toBytes'; 6 | import { toString } from '../../utils/toString'; 7 | import { isFunction } from '../../utils/isFunction'; 8 | import { toFunctionReference } from '../../utils/toFunctionReference'; 9 | import { toServerAPI } from './toServerAPI'; 10 | import { getType } from './getType'; 11 | 12 | const replaceSingleQuotes = (str) => str 13 | .replace(/{\s*'/g,'{"') 14 | .replace(/'\s*}/g,'"}') 15 | .replace(/'\s*:/g,'":') 16 | .replace(/:\s*'/g,':"') 17 | .replace(/,\s*'/g,',"') 18 | .replace(/'\s*,/g,'",') 19 | 20 | const conversionTable = { 21 | array: toArray, 22 | boolean: toBoolean, 23 | int: value => getType(value) === 'bytes' ? toBytes(value) : toInt(value), 24 | number: toFloat, 25 | float: toFloat, 26 | bytes: toBytes, 27 | string: value => isFunction(value) ? value : toString(value), 28 | function: value => toFunctionReference(value), 29 | serverapi: toServerAPI, 30 | object: value => { 31 | try { 32 | return JSON.parse(replaceSingleQuotes(value)) 33 | } 34 | catch(e) { 35 | return null; 36 | } 37 | } 38 | }; 39 | 40 | export const convertTo = (value, type) => conversionTable[type](value); 41 | -------------------------------------------------------------------------------- /src/js/app/utils/createDragHelper.js: -------------------------------------------------------------------------------- 1 | export const createDragHelper = (items) => { 2 | const itemIds = items.map(item => item.id); 3 | let prevIndex = undefined; 4 | return { 5 | setIndex: (index) => { 6 | prevIndex = index; 7 | }, 8 | getIndex: () => prevIndex, 9 | getItemIndex: (item) => itemIds.indexOf(item.id) 10 | } 11 | } -------------------------------------------------------------------------------- /src/js/app/utils/createFileStub.js: -------------------------------------------------------------------------------- 1 | import { getMimeTypeFromBase64DataURI } from '../../utils/getMimeTypeFromBase64DataURI'; 2 | import { getFilenameFromURL } from '../../utils/getFilenameFromURL'; 3 | import { isBase64DataURI } from '../../utils/isBase64DataURI'; 4 | import { isString } from '../../utils/isString'; 5 | import { getDateString } from '../../utils/getDateString'; 6 | 7 | export const createFileStub = source => { 8 | let data = [source.name, source.size, source.type]; 9 | 10 | // is blob or base64, then we need to set the name 11 | if (source instanceof Blob || isBase64DataURI(source)) { 12 | data[0] = source.name || getDateString(); 13 | } else if (isBase64DataURI(source)) { 14 | // if is base64 data uri we need to determine the average size and type 15 | data[1] = source.length; 16 | data[2] = getMimeTypeFromBase64DataURI(source); 17 | } else if (isString(source)) { 18 | // url 19 | data[0] = getFilenameFromURL(source); 20 | data[1] = 0; 21 | data[2] = 'application/octet-stream'; 22 | } 23 | 24 | return { 25 | name: data[0], 26 | size: data[1], 27 | type: data[2] 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /src/js/app/utils/createHopper.js: -------------------------------------------------------------------------------- 1 | import { createDragNDropClient } from '../utils/dnd'; 2 | 3 | export const createHopper = (scope, validateItems, options) => { 4 | // is now hopper scope 5 | scope.classList.add('filepond--hopper'); 6 | 7 | // shortcuts 8 | const { catchesDropsOnPage, requiresDropOnElement, filterItems = items => items } = options; 9 | 10 | // create a dnd client 11 | const client = createDragNDropClient( 12 | scope, 13 | catchesDropsOnPage ? document.documentElement : scope, 14 | requiresDropOnElement 15 | ); 16 | 17 | // current client state 18 | let lastState = ''; 19 | let currentState = ''; 20 | 21 | // determines if a file may be dropped 22 | client.allowdrop = items => { 23 | // TODO: if we can, throw error to indicate the items cannot by dropped 24 | 25 | return validateItems(filterItems(items)); 26 | }; 27 | 28 | client.ondrop = (position, items) => { 29 | 30 | const filteredItems = filterItems(items); 31 | 32 | if (!validateItems(filteredItems)) { 33 | api.ondragend(position); 34 | return; 35 | } 36 | 37 | currentState = 'drag-drop'; 38 | 39 | api.onload(filteredItems, position); 40 | }; 41 | 42 | client.ondrag = position => { 43 | api.ondrag(position); 44 | }; 45 | 46 | client.onenter = position => { 47 | currentState = 'drag-over'; 48 | 49 | api.ondragstart(position); 50 | }; 51 | 52 | client.onexit = position => { 53 | currentState = 'drag-exit'; 54 | 55 | api.ondragend(position); 56 | }; 57 | 58 | const api = { 59 | updateHopperState: () => { 60 | if (lastState !== currentState) { 61 | scope.dataset.hopperState = currentState; 62 | lastState = currentState; 63 | } 64 | }, 65 | onload: () => {}, 66 | ondragstart: () => {}, 67 | ondrag: () => {}, 68 | ondragend: () => {}, 69 | destroy: () => { 70 | // destroy client 71 | client.destroy(); 72 | } 73 | }; 74 | 75 | return api; 76 | }; 77 | -------------------------------------------------------------------------------- /src/js/app/utils/createInitialState.js: -------------------------------------------------------------------------------- 1 | import { createOptions } from './createOptions'; 2 | 3 | export const createInitialState = options => ({ 4 | 5 | // model 6 | items: [], 7 | 8 | // timeout used for calling update items 9 | listUpdateTimeout: null, 10 | 11 | // timeout used for stacking metadata updates 12 | itemUpdateTimeout: null, 13 | 14 | // queue of items waiting to be processed 15 | processingQueue: [], 16 | 17 | // options 18 | options: createOptions(options) 19 | }); 20 | -------------------------------------------------------------------------------- /src/js/app/utils/createItemAPI.js: -------------------------------------------------------------------------------- 1 | import { copyObjectPropertiesToObject } from '../../utils/copyObjectPropertiesToObject'; 2 | 3 | const PRIVATE = [ 4 | 'fire', 5 | 'process', 6 | 'revert', 7 | 'load', 8 | 'on', 9 | 'off', 10 | 'onOnce', 11 | 'retryLoad', 12 | 'extend', 13 | 'archive', 14 | 'archived', 15 | 'release', 16 | 'released', 17 | 'requestProcessing', 18 | 'freeze' 19 | ]; 20 | 21 | export const createItemAPI = item => { 22 | const api = {}; 23 | copyObjectPropertiesToObject(item, api, PRIVATE); 24 | return api; 25 | }; -------------------------------------------------------------------------------- /src/js/app/utils/createOption.js: -------------------------------------------------------------------------------- 1 | import { getValueByType } from './getValueByType'; 2 | 3 | export const createOption = (defaultValue, valueType) => { 4 | let currentValue = defaultValue; 5 | return { 6 | enumerable: true, 7 | get: () => currentValue, 8 | set: newValue => { 9 | currentValue = getValueByType(newValue, defaultValue, valueType); 10 | } 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /src/js/app/utils/createOptionAPI.js: -------------------------------------------------------------------------------- 1 | import { fromCamels } from '../../utils/fromCamels'; 2 | import { forin } from '../../utils/forin'; 3 | 4 | export const createOptionAPI = (store, options) => { 5 | const obj = {}; 6 | forin(options, key => { 7 | obj[key] = { 8 | get: () => store.getState().options[key], 9 | set: value => { 10 | store.dispatch(`SET_${fromCamels(key, '_').toUpperCase()}`, { 11 | value 12 | }); 13 | } 14 | }; 15 | }); 16 | return obj; 17 | }; 18 | -------------------------------------------------------------------------------- /src/js/app/utils/createOptionActions.js: -------------------------------------------------------------------------------- 1 | import { fromCamels } from '../../utils/fromCamels'; 2 | import { forin } from '../../utils/forin'; 3 | 4 | export const createOptionActions = options => (dispatch, query, state) => { 5 | const obj = {}; 6 | forin(options, key => { 7 | const name = fromCamels(key, '_').toUpperCase(); 8 | 9 | obj[`SET_${name}`] = action => { 10 | try { 11 | state.options[key] = action.value; 12 | } catch (e) { 13 | // nope, failed 14 | } 15 | 16 | // we successfully set the value of this option 17 | dispatch(`DID_SET_${name}`, { value: state.options[key] }); 18 | }; 19 | }); 20 | return obj; 21 | }; 22 | -------------------------------------------------------------------------------- /src/js/app/utils/createOptionQueries.js: -------------------------------------------------------------------------------- 1 | import { fromCamels } from '../../utils/fromCamels'; 2 | import { forin } from '../../utils/forin'; 3 | 4 | export const createOptionQueries = options => state => { 5 | const obj = {}; 6 | forin(options, key => { 7 | obj[`GET_${fromCamels(key, '_').toUpperCase()}`] = action => 8 | state.options[key]; 9 | }); 10 | return obj; 11 | }; 12 | -------------------------------------------------------------------------------- /src/js/app/utils/createOptions.js: -------------------------------------------------------------------------------- 1 | import { createObject } from '../../utils/createObject'; 2 | import { createOption } from './createOption'; 3 | import { forin } from '../../utils/forin'; 4 | 5 | export const createOptions = options => { 6 | const obj = {}; 7 | forin(options, prop => { 8 | const optionDefinition = options[prop]; 9 | obj[prop] = createOption( 10 | optionDefinition[0], 11 | optionDefinition[1] 12 | ); 13 | }); 14 | return createObject(obj); 15 | }; 16 | -------------------------------------------------------------------------------- /src/js/app/utils/createPaster.js: -------------------------------------------------------------------------------- 1 | import { arrayRemove } from '../../utils/arrayRemove'; 2 | import { requestDataTransferItems } from './requestDataTransferItems'; 3 | 4 | let listening = false; 5 | const listeners = []; 6 | 7 | const handlePaste = e => { 8 | // if is pasting in input or textarea and the target is outside of a filepond scope, ignore 9 | const activeEl = document.activeElement; 10 | const isActiveElementEditable = 11 | activeEl && 12 | (/textarea|input/i.test(activeEl.nodeName) || 13 | activeEl.getAttribute('contenteditable') === 'true'); 14 | 15 | if (isActiveElementEditable) { 16 | // test textarea or input is contained in filepond root 17 | let inScope = false; 18 | let element = activeEl; 19 | while (element !== document.body) { 20 | if (element.classList.contains('filepond--root')) { 21 | inScope = true; 22 | break; 23 | } 24 | element = element.parentNode; 25 | } 26 | 27 | if (!inScope) return; 28 | } 29 | 30 | requestDataTransferItems(e.clipboardData).then(files => { 31 | // no files received 32 | if (!files.length) { 33 | return; 34 | } 35 | 36 | // notify listeners of received files 37 | listeners.forEach(listener => listener(files)); 38 | }); 39 | }; 40 | 41 | const listen = cb => { 42 | // can't add twice 43 | if (listeners.includes(cb)) { 44 | return; 45 | } 46 | 47 | // add initial listener 48 | listeners.push(cb); 49 | 50 | // setup paste listener for entire page 51 | if (listening) { 52 | return; 53 | } 54 | 55 | listening = true; 56 | document.addEventListener('paste', handlePaste); 57 | }; 58 | 59 | const unlisten = listener => { 60 | arrayRemove(listeners, listeners.indexOf(listener)); 61 | 62 | // clean up 63 | if (listeners.length === 0) { 64 | document.removeEventListener('paste', handlePaste); 65 | listening = false; 66 | } 67 | }; 68 | 69 | export const createPaster = () => { 70 | const cb = files => { 71 | api.onload(files); 72 | }; 73 | 74 | const api = { 75 | destroy: () => { 76 | unlisten(cb); 77 | }, 78 | onload: () => {} 79 | }; 80 | 81 | listen(cb); 82 | 83 | return api; 84 | }; 85 | -------------------------------------------------------------------------------- /src/js/app/utils/createPerceivedPerformanceUpdater.js: -------------------------------------------------------------------------------- 1 | import { getRandomNumber } from '../../utils/getRandomNumber'; 2 | 3 | export const createPerceivedPerformanceUpdater = ( 4 | cb, 5 | duration = 1000, 6 | offset = 0, 7 | tickMin = 25, 8 | tickMax = 250 9 | ) => { 10 | let timeout = null; 11 | const start = Date.now(); 12 | 13 | const tick = () => { 14 | let runtime = Date.now() - start; 15 | let delay = getRandomNumber(tickMin, tickMax); 16 | 17 | if (runtime + delay > duration) { 18 | delay = runtime + delay - duration; 19 | } 20 | 21 | let progress = runtime / duration; 22 | if (progress >= 1 || document.hidden) { 23 | cb(1); 24 | return; 25 | } 26 | 27 | cb(progress); 28 | 29 | timeout = setTimeout(tick, delay); 30 | }; 31 | 32 | if (duration > 0) tick(); 33 | 34 | return { 35 | clear: () => { 36 | clearTimeout(timeout); 37 | }, 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /src/js/app/utils/createProcessorFunction.js: -------------------------------------------------------------------------------- 1 | import { isString } from '../../utils/isString'; 2 | import { createFileProcessorFunction } from './createFileProcessorFunction'; 3 | 4 | export const createProcessorFunction = (apiUrl = '', action, name, options) => { 5 | 6 | // custom handler (should also handle file, load, error, progress and abort) 7 | if (typeof action === 'function') return (...params) => action(name, ...params, options); 8 | 9 | // no action supplied 10 | if (!action || !isString(action.url)) return null; 11 | 12 | // internal handler 13 | return createFileProcessorFunction(apiUrl, action, name, options); 14 | }; -------------------------------------------------------------------------------- /src/js/app/utils/createRevertFunction.js: -------------------------------------------------------------------------------- 1 | import { sendRequest } from '../../utils/sendRequest'; 2 | import { createResponse } from '../../utils/createResponse'; 3 | import { createTimeoutResponse } from '../../utils/createDefaultResponse'; 4 | import { isString } from '../../utils/isString'; 5 | 6 | /* 7 | function signature: 8 | (uniqueFileId, load, error) => { } 9 | */ 10 | export const createRevertFunction = (apiUrl = '', action) => { 11 | // is custom implementation 12 | if (typeof action === 'function') { 13 | return action; 14 | } 15 | 16 | // no action supplied, return stub function, interface will work, but file won't be removed 17 | if (!action || !isString(action.url)) { 18 | return (uniqueFileId, load) => load(); 19 | } 20 | 21 | // set onload hanlder 22 | const onload = action.onload || (res => res); 23 | const onerror = action.onerror || (res => null); 24 | 25 | // internal implementation 26 | return (uniqueFileId, load, error) => { 27 | const request = sendRequest( 28 | uniqueFileId, 29 | apiUrl + action.url, 30 | action // contains method, headers and withCredentials properties 31 | ); 32 | request.onload = (xhr) => { 33 | load( 34 | createResponse( 35 | 'load', 36 | xhr.status, 37 | onload(xhr.response), 38 | xhr.getAllResponseHeaders() 39 | ) 40 | ) 41 | }; 42 | 43 | request.onerror = (xhr) => { 44 | error( 45 | createResponse( 46 | 'error', 47 | xhr.status, 48 | onerror(xhr.response) || xhr.statusText, 49 | xhr.getAllResponseHeaders() 50 | ) 51 | ); 52 | }; 53 | 54 | request.ontimeout = createTimeoutResponse(error); 55 | 56 | return request; 57 | }; 58 | }; 59 | -------------------------------------------------------------------------------- /src/js/app/utils/createServerAPI.js: -------------------------------------------------------------------------------- 1 | import { isString } from '../../utils/isString'; 2 | import { toBoolean } from '../../utils/toBoolean'; 3 | import { forin } from '../../utils/forin'; 4 | 5 | const methods = { 6 | process: 'POST', 7 | patch: 'PATCH', 8 | revert: 'DELETE', 9 | fetch: 'GET', 10 | restore: 'GET', 11 | load: 'GET', 12 | }; 13 | 14 | export const createServerAPI = outline => { 15 | const api = {}; 16 | 17 | api.url = isString(outline) ? outline : outline.url || ''; 18 | api.timeout = outline.timeout ? parseInt(outline.timeout, 10) : 0; 19 | api.headers = outline.headers ? outline.headers : {}; 20 | 21 | forin(methods, key => { 22 | api[key] = createAction(key, outline[key], methods[key], api.timeout, api.headers); 23 | }); 24 | 25 | // remove process if no url or process on outline 26 | api.process = outline.process || isString(outline) || outline.url ? api.process : null; 27 | 28 | // special treatment for remove 29 | api.remove = outline.remove || null; 30 | 31 | // remove generic headers from api object 32 | delete api.headers; 33 | 34 | return api; 35 | }; 36 | 37 | const createAction = (name, outline, method, timeout, headers) => { 38 | // is explicitely set to null so disable 39 | if (outline === null) { 40 | return null; 41 | } 42 | 43 | // if is custom function, done! Dev handles everything. 44 | if (typeof outline === 'function') { 45 | return outline; 46 | } 47 | 48 | // build action object 49 | const action = { 50 | url: method === 'GET' || method === 'PATCH' ? `?${name}=` : '', 51 | method, 52 | headers, 53 | withCredentials: false, 54 | timeout, 55 | onload: null, 56 | ondata: null, 57 | onerror: null, 58 | }; 59 | 60 | // is a single url 61 | if (isString(outline)) { 62 | action.url = outline; 63 | return action; 64 | } 65 | 66 | // overwrite 67 | Object.assign(action, outline); 68 | 69 | // see if should reformat headers; 70 | if (isString(action.headers)) { 71 | const parts = action.headers.split(/:(.+)/); 72 | action.headers = { 73 | header: parts[0], 74 | value: parts[1], 75 | }; 76 | } 77 | 78 | // if is bool withCredentials 79 | action.withCredentials = toBoolean(action.withCredentials); 80 | 81 | return action; 82 | }; 83 | -------------------------------------------------------------------------------- /src/js/app/utils/dropAreaDimensions.js: -------------------------------------------------------------------------------- 1 | export const dropAreaDimensions = { 2 | height: 0, 3 | width: 0, 4 | get getHeight() { 5 | return this.height; 6 | }, 7 | set setHeight(val) { 8 | if (this.height === 0 || val === 0) this.height = val; 9 | }, 10 | get getWidth() { 11 | return this.width; 12 | }, 13 | set setWidth(val) { 14 | if (this.width === 0 || val === 0) this.width = val; 15 | }, 16 | setDimensions: function (height, width) { 17 | if (this.height === 0 || height === 0) this.height = height; 18 | if (this.width === 0 || width === 0) this.width = width; 19 | } 20 | }; -------------------------------------------------------------------------------- /src/js/app/utils/dynamicLabel.js: -------------------------------------------------------------------------------- 1 | import { isFunction } from '../../utils/isFunction'; 2 | 3 | export const dynamicLabel = (label) => (...params) => isFunction(label) ? label(...params) : label; -------------------------------------------------------------------------------- /src/js/app/utils/fetchBlob.js: -------------------------------------------------------------------------------- 1 | import { sendRequest } from '../../utils/sendRequest'; 2 | import { createResponse } from '../../utils/createResponse'; 3 | import { createTimeoutResponse } from '../../utils/createDefaultResponse'; 4 | import { getFileFromBlob } from '../../utils/getFileFromBlob'; 5 | import { getFileInfoFromHeaders } from '../../utils/getFileInfoFromHeaders'; 6 | import { getFilenameFromURL } from '../../utils/getFilenameFromURL'; 7 | 8 | export const fetchBlob = (url, load, error, progress, abort, headers) => { 9 | const request = sendRequest(null, url, { 10 | method: 'GET', 11 | responseType: 'blob' 12 | }); 13 | 14 | request.onload = (xhr) => { 15 | 16 | // get headers 17 | const headers = xhr.getAllResponseHeaders(); 18 | 19 | // get filename 20 | const filename = getFileInfoFromHeaders(headers).name || getFilenameFromURL(url); 21 | 22 | // create response 23 | load( 24 | createResponse( 25 | 'load', 26 | xhr.status, 27 | getFileFromBlob(xhr.response, filename), 28 | headers 29 | ) 30 | ) 31 | }; 32 | 33 | request.onerror = (xhr) => { 34 | error( 35 | createResponse( 36 | 'error', 37 | xhr.status, 38 | xhr.statusText, 39 | xhr.getAllResponseHeaders() 40 | ) 41 | ); 42 | }; 43 | 44 | request.onheaders = (xhr) => { 45 | headers( 46 | createResponse( 47 | 'headers', 48 | xhr.status, 49 | null, 50 | xhr.getAllResponseHeaders() 51 | ) 52 | ) 53 | }; 54 | 55 | request.ontimeout = createTimeoutResponse(error); 56 | request.onprogress = progress; 57 | request.onabort = abort; 58 | 59 | 60 | // should return request 61 | return request; 62 | }; 63 | -------------------------------------------------------------------------------- /src/js/app/utils/getActiveItems.js: -------------------------------------------------------------------------------- 1 | export const getActiveItems = (items) => items.filter(item => !item.archived); -------------------------------------------------------------------------------- /src/js/app/utils/getItemById.js: -------------------------------------------------------------------------------- 1 | import { getItemIndexByQuery } from './getItemIndexByQuery'; 2 | 3 | export const getItemById = (items, itemId) => { 4 | const index = getItemIndexByQuery(items, itemId); 5 | if (index < 0) { 6 | return; 7 | } 8 | return items[index] || null; 9 | }; 10 | -------------------------------------------------------------------------------- /src/js/app/utils/getItemByQuery.js: -------------------------------------------------------------------------------- 1 | import { isEmpty } from '../../utils/isEmpty'; 2 | import { isInt } from '../../utils/isInt'; 3 | 4 | export const getItemByQuery = (items, query) => { 5 | // just return first index 6 | if (isEmpty(query)) { 7 | return items[0] || null; 8 | } 9 | 10 | // query is index 11 | if (isInt(query)) { 12 | return items[query] || null; 13 | } 14 | 15 | // if query is item, get the id 16 | if (typeof query === 'object') { 17 | query = query.id; 18 | } 19 | 20 | // assume query is a string and return item by id 21 | return items.find(item => item.id === query) || null; 22 | }; 23 | -------------------------------------------------------------------------------- /src/js/app/utils/getItemIndexByPosition.js: -------------------------------------------------------------------------------- 1 | import getItemsPerRow from './getItemsPerRow'; 2 | 3 | export const getItemIndexByPosition = (view, children, positionInView) => { 4 | if (!positionInView) return; 5 | 6 | const horizontalSpace = view.rect.element.width; 7 | // const children = view.childViews; 8 | const l = children.length; 9 | let last = null; 10 | 11 | // -1, don't move items to accomodate (either add to top or bottom) 12 | if (l === 0 || positionInView.top < children[0].rect.element.top) return -1; 13 | 14 | // let's get the item width 15 | const item = children[0]; 16 | const itemRect = item.rect.element; 17 | const itemHorizontalMargin = itemRect.marginLeft + itemRect.marginRight; 18 | const itemWidth = itemRect.width + itemHorizontalMargin; 19 | const itemsPerRow = getItemsPerRow(horizontalSpace, itemWidth); 20 | 21 | // stack 22 | if (itemsPerRow === 1) { 23 | for (let index = 0; index < l; index++) { 24 | const child = children[index]; 25 | const childMid = child.rect.outer.top + child.rect.element.height * 0.5; 26 | if (positionInView.top < childMid) { 27 | return index; 28 | } 29 | } 30 | return l; 31 | } 32 | 33 | // grid 34 | const itemVerticalMargin = itemRect.marginTop + itemRect.marginBottom; 35 | const itemHeight = itemRect.height + itemVerticalMargin; 36 | for (let index = 0; index < l; index++) { 37 | const indexX = index % itemsPerRow; 38 | const indexY = Math.floor(index / itemsPerRow); 39 | 40 | const offsetX = indexX * itemWidth; 41 | const offsetY = indexY * itemHeight; 42 | 43 | const itemTop = offsetY - itemRect.marginTop; 44 | const itemRight = offsetX + itemWidth; 45 | const itemBottom = offsetY + itemHeight + itemRect.marginBottom; 46 | 47 | if (positionInView.top < itemBottom && positionInView.top > itemTop) { 48 | if (positionInView.left < itemRight) { 49 | return index; 50 | } else if (index !== l - 1) { 51 | last = index; 52 | } else { 53 | last = null; 54 | } 55 | } 56 | } 57 | 58 | if (last !== null) { 59 | return last; 60 | } 61 | 62 | return l; 63 | }; 64 | -------------------------------------------------------------------------------- /src/js/app/utils/getItemIndexByQuery.js: -------------------------------------------------------------------------------- 1 | import { isEmpty } from '../../utils/isEmpty'; 2 | import { isString } from '../../utils/isString'; 3 | 4 | export const getItemIndexByQuery = (items, query) => { 5 | // just return first index 6 | if (isEmpty(query)) { 7 | return 0; 8 | } 9 | 10 | // invalid queries 11 | if (!isString(query)) { 12 | return -1; 13 | } 14 | 15 | // return item by id (or -1 if not found) 16 | return items.findIndex(item => item.id === query); 17 | }; 18 | -------------------------------------------------------------------------------- /src/js/app/utils/getItemsPerRow.js: -------------------------------------------------------------------------------- 1 | export default (horizontalSpace, itemWidth) => { 2 | // add one pixel leeway, when using percentages for item width total items can be 1.99 per row 3 | 4 | return Math.max(1, Math.floor((horizontalSpace + 1) / itemWidth)); 5 | }; 6 | -------------------------------------------------------------------------------- /src/js/app/utils/getType.js: -------------------------------------------------------------------------------- 1 | import { isArray } from '../../utils/isArray'; 2 | import { isInt } from '../../utils/isInt'; 3 | import { isNull } from '../../utils/isNull'; 4 | import { isAPI } from './isAPI'; 5 | 6 | export const getType = value => { 7 | 8 | if (isArray(value)) { 9 | return 'array'; 10 | } 11 | 12 | if (isNull(value)) { 13 | return 'null'; 14 | } 15 | 16 | if (isInt(value)) { 17 | return 'int'; 18 | } 19 | 20 | if (/^[0-9]+ ?(?:GB|MB|KB)$/gi.test(value)) { 21 | return 'bytes'; 22 | } 23 | 24 | if (isAPI(value)) { 25 | return 'api'; 26 | } 27 | 28 | return typeof value; 29 | }; 30 | -------------------------------------------------------------------------------- /src/js/app/utils/getValueByType.js: -------------------------------------------------------------------------------- 1 | import { convertTo } from './convertTo'; 2 | import { getType } from './getType'; 3 | 4 | export const getValueByType = (newValue, defaultValue, valueType) => { 5 | 6 | // can always assign default value 7 | if (newValue === defaultValue) { 8 | return newValue; 9 | } 10 | 11 | // get the type of the new value 12 | let newValueType = getType(newValue); 13 | 14 | // is valid type? 15 | if (newValueType !== valueType) { 16 | // is string input, let's attempt to convert 17 | const convertedValue = convertTo(newValue, valueType); 18 | 19 | // what is the type now 20 | newValueType = getType(convertedValue); 21 | 22 | // no valid conversions found 23 | if (convertedValue === null) { 24 | throw `Trying to assign value with incorrect type to "${option}", allowed type: "${valueType}"`; 25 | } else { 26 | newValue = convertedValue; 27 | } 28 | } 29 | 30 | // assign new value 31 | return newValue; 32 | } -------------------------------------------------------------------------------- /src/js/app/utils/hasRoomForItem.js: -------------------------------------------------------------------------------- 1 | import { getActiveItems } from './getActiveItems'; 2 | export const hasRoomForItem = state => { 3 | const count = getActiveItems(state.items).length; 4 | 5 | // if cannot have multiple items, to add one item it should currently not contain items 6 | if (!state.options.allowMultiple) { 7 | return count === 0; 8 | } 9 | 10 | // if allows multiple items, we check if a max item count has been set, if not, there's no limit 11 | const maxFileCount = state.options.maxFiles; 12 | if (maxFileCount === null) { 13 | return true; 14 | } 15 | 16 | // we check if the current count is smaller than the max count, if so, another file can still be added 17 | if (count < maxFileCount) { 18 | return true; 19 | } 20 | 21 | // no more room for another file 22 | return false; 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/app/utils/insertItem.js: -------------------------------------------------------------------------------- 1 | import { isEmpty } from '../../utils/isEmpty'; 2 | import { limit } from '../../utils/limit'; 3 | import { arrayInsert } from '../../utils/arrayInsert'; 4 | 5 | export const insertItem = (items, item, index) => { 6 | if (isEmpty(item)) { 7 | return null; 8 | } 9 | 10 | // if index is undefined, append 11 | if (typeof index === 'undefined') { 12 | items.push(item); 13 | return item; 14 | } 15 | 16 | // limit the index to the size of the items array 17 | index = limit(index, 0, items.length); 18 | 19 | // add item to array 20 | arrayInsert(items, index, item); 21 | 22 | // expose 23 | return item; 24 | }; 25 | -------------------------------------------------------------------------------- /src/js/app/utils/isAPI.js: -------------------------------------------------------------------------------- 1 | import { isObject } from '../../utils/isObject'; 2 | import { isString } from '../../utils/isString'; 3 | 4 | export const isAPI = value => { 5 | return ( 6 | isObject(value) && 7 | isString(value.url) && 8 | isObject(value.process) && 9 | isObject(value.revert) && 10 | isObject(value.restore) && 11 | isObject(value.fetch) 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /src/js/app/utils/mergeOptionObject.js: -------------------------------------------------------------------------------- 1 | import { forin } from '../../utils/forin'; 2 | export const mergeOptionObject = (originalObject, newObject) => { 3 | const obj = {}; 4 | forin(originalObject, key => { 5 | obj[key] = newObject[key] || originalObject[key]; 6 | }); 7 | return obj; 8 | }; 9 | -------------------------------------------------------------------------------- /src/js/app/utils/on.js: -------------------------------------------------------------------------------- 1 | import { arrayRemove } from '../../utils/arrayRemove'; 2 | 3 | const run = (cb, sync) => { 4 | if (sync) { 5 | cb(); 6 | } 7 | else if (document.hidden) { 8 | Promise.resolve(1).then(cb); 9 | } 10 | else { 11 | setTimeout(cb, 0); 12 | } 13 | } 14 | 15 | export const on = () => { 16 | const listeners = []; 17 | const off = (event, cb) => { 18 | arrayRemove( 19 | listeners, 20 | listeners.findIndex( 21 | listener => listener.event === event && (listener.cb === cb || !cb) 22 | ) 23 | ); 24 | }; 25 | const fire = (event, args, sync) => { 26 | listeners 27 | .filter(listener => listener.event === event) 28 | .map(listener => listener.cb) 29 | .forEach(cb => run(() => cb(...args), sync)); 30 | } 31 | return { 32 | fireSync: (event, ...args) => { 33 | fire(event, args, true); 34 | }, 35 | fire: (event, ...args) => { 36 | fire(event, args, false); 37 | }, 38 | on: (event, cb) => { 39 | listeners.push({ event, cb }); 40 | }, 41 | onOnce: (event, cb) => { 42 | listeners.push({ 43 | event, 44 | cb: (...args) => { 45 | off(event, cb); 46 | cb(...args); 47 | } 48 | }); 49 | }, 50 | off 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /src/js/app/utils/removeReleasedItems.js: -------------------------------------------------------------------------------- 1 | import { arrayRemove } from '../../utils/arrayRemove'; 2 | 3 | export const removeReleasedItems = (items) => { 4 | items.forEach((item, index) => { 5 | if (item.released) { 6 | arrayRemove(items, index); 7 | } 8 | }); 9 | }; -------------------------------------------------------------------------------- /src/js/app/utils/toServerAPI.js: -------------------------------------------------------------------------------- 1 | import { createServerAPI } from './createServerAPI'; 2 | export const toServerAPI = value => createServerAPI(value); 3 | -------------------------------------------------------------------------------- /src/js/app/view/blob.js: -------------------------------------------------------------------------------- 1 | import { createView } from '../frame/index'; 2 | 3 | export const blob = createView({ 4 | name: 'drip-blob', 5 | ignoreRect: true, 6 | mixins: { 7 | styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'], 8 | animations: { 9 | scaleX: 'spring', 10 | scaleY: 'spring', 11 | translateX: 'spring', 12 | translateY: 'spring', 13 | opacity: { type: 'tween', duration: 250 } 14 | } 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /src/js/app/view/drip.js: -------------------------------------------------------------------------------- 1 | import { createView, createRoute } from '../frame/index'; 2 | import { blob } from './blob'; 3 | 4 | const addBlob = ({ root }) => { 5 | const centerX = root.rect.element.width * 0.5; 6 | const centerY = root.rect.element.height * 0.5; 7 | 8 | root.ref.blob = root.appendChildView( 9 | root.createChildView(blob, { 10 | opacity: 0, 11 | scaleX: 2.5, 12 | scaleY: 2.5, 13 | translateX: centerX, 14 | translateY: centerY 15 | }) 16 | ); 17 | }; 18 | 19 | const moveBlob = ({ root, action }) => { 20 | if (!root.ref.blob) { 21 | addBlob({ root }); 22 | return; 23 | } 24 | 25 | root.ref.blob.translateX = action.position.scopeLeft; 26 | root.ref.blob.translateY = action.position.scopeTop; 27 | root.ref.blob.scaleX = 1; 28 | root.ref.blob.scaleY = 1; 29 | root.ref.blob.opacity = 1; 30 | }; 31 | 32 | const hideBlob = ({ root }) => { 33 | if (!root.ref.blob) { 34 | return; 35 | } 36 | root.ref.blob.opacity = 0; 37 | }; 38 | 39 | const explodeBlob = ({ root }) => { 40 | if (!root.ref.blob) { 41 | return; 42 | } 43 | root.ref.blob.scaleX = 2.5; 44 | root.ref.blob.scaleY = 2.5; 45 | root.ref.blob.opacity = 0; 46 | }; 47 | 48 | const write = ({ root, props, actions }) => { 49 | route({ root, props, actions }); 50 | 51 | const { blob } = root.ref; 52 | 53 | if (actions.length === 0 && blob && blob.opacity === 0) { 54 | root.removeChildView(blob); 55 | root.ref.blob = null; 56 | } 57 | }; 58 | 59 | const route = createRoute({ 60 | DID_DRAG: moveBlob, 61 | DID_DROP: explodeBlob, 62 | DID_END_DRAG: hideBlob 63 | }); 64 | 65 | export const drip = createView({ 66 | ignoreRect: true, 67 | ignoreRectUpdate: true, 68 | name: 'drip', 69 | write 70 | }); 71 | -------------------------------------------------------------------------------- /src/js/app/view/fileActionButton.js: -------------------------------------------------------------------------------- 1 | import { createView } from '../frame/index'; 2 | import { attr } from '../../utils/attr'; 3 | 4 | const create = ({ root, props }) => { 5 | root.element.innerHTML = (props.icon || '') + `${props.label}`; 6 | 7 | props.isDisabled = false; 8 | }; 9 | 10 | const write = ({ root, props }) => { 11 | 12 | const { isDisabled } = props; 13 | const shouldDisable = root.query('GET_DISABLED') || props.opacity === 0; 14 | 15 | if (shouldDisable && !isDisabled) { 16 | props.isDisabled = true; 17 | attr(root.element, 'disabled', 'disabled'); 18 | } 19 | else if (!shouldDisable && isDisabled) { 20 | props.isDisabled = false; 21 | root.element.removeAttribute('disabled'); 22 | } 23 | }; 24 | 25 | export const fileActionButton = createView({ 26 | tag: 'button', 27 | attributes: { 28 | type: 'button' 29 | }, 30 | ignoreRect: true, 31 | ignoreRectUpdate: true, 32 | name: 'file-action-button', 33 | mixins: { 34 | apis: ['label'], 35 | styles: ['translateX', 'translateY', 'scaleX', 'scaleY', 'opacity'], 36 | animations: { 37 | scaleX: 'spring', 38 | scaleY: 'spring', 39 | translateX: 'spring', 40 | translateY: 'spring', 41 | opacity: { type: 'tween', duration: 250 } 42 | }, 43 | listeners: true 44 | }, 45 | create, 46 | write 47 | }); 48 | -------------------------------------------------------------------------------- /src/js/app/view/fileWrapper.js: -------------------------------------------------------------------------------- 1 | import { createView, createRoute } from '../frame/index'; 2 | import { formatFilename } from '../../utils/formatFilename'; 3 | import { createElement } from '../../utils/createElement'; 4 | import { text } from '../../utils/text'; 5 | import { file } from './file'; 6 | import { applyFilters } from '../../filter'; 7 | 8 | /** 9 | * Creates the file view 10 | */ 11 | const create = ({ root, props }) => { 12 | 13 | // filename 14 | root.ref.fileName = createElement('legend'); 15 | root.appendChild(root.ref.fileName); 16 | 17 | // file appended 18 | root.ref.file = root.appendChildView( 19 | root.createChildView(file, { id: props.id }) 20 | ); 21 | 22 | // data has moved to data.js 23 | root.ref.data = false; 24 | }; 25 | 26 | /** 27 | * Data storage 28 | */ 29 | const didLoadItem = ({ root, props }) => { 30 | // updates the legend of the fieldset so screenreaders can better group buttons 31 | text( 32 | root.ref.fileName, 33 | formatFilename(root.query('GET_ITEM_NAME', props.id)) 34 | ); 35 | }; 36 | 37 | export const fileWrapper = createView({ 38 | create, 39 | ignoreRect: true, 40 | write: createRoute({ 41 | DID_LOAD_ITEM: didLoadItem 42 | }), 43 | didCreateView: root => { 44 | applyFilters('CREATE_VIEW', { ...root, view: root }); 45 | }, 46 | tag: 'fieldset', 47 | name: 'file-wrapper' 48 | }); 49 | -------------------------------------------------------------------------------- /src/js/app/view/listScroller.js: -------------------------------------------------------------------------------- 1 | import { createView, createRoute } from '../frame/index'; 2 | import { list } from './list'; 3 | 4 | const create = ({ root, props }) => { 5 | root.ref.list = root.appendChildView(root.createChildView(list)); 6 | props.dragCoordinates = null; 7 | props.overflowing = false; 8 | }; 9 | 10 | const storeDragCoordinates = ({ root, props, action }) => { 11 | if (!root.query('GET_ITEM_INSERT_LOCATION_FREEDOM')) return; 12 | props.dragCoordinates = { 13 | left: action.position.scopeLeft - root.ref.list.rect.element.left, 14 | top: action.position.scopeTop - (root.rect.outer.top + root.rect.element.marginTop + root.rect.element.scrollTop) 15 | }; 16 | }; 17 | 18 | const clearDragCoordinates = ({ props }) => { 19 | props.dragCoordinates = null; 20 | }; 21 | 22 | const route = createRoute({ 23 | DID_DRAG: storeDragCoordinates, 24 | DID_END_DRAG: clearDragCoordinates 25 | }); 26 | 27 | const write = ({ root, props, actions }) => { 28 | 29 | // route actions 30 | route({ root, props, actions }); 31 | 32 | // current drag position 33 | root.ref.list.dragCoordinates = props.dragCoordinates; 34 | 35 | // if currently overflowing but no longer received overflow 36 | if (props.overflowing && !props.overflow) { 37 | props.overflowing = false; 38 | 39 | // reset overflow state 40 | root.element.dataset.state = ''; 41 | root.height = null; 42 | } 43 | 44 | // if is not overflowing currently but does receive overflow value 45 | if (props.overflow) { 46 | const newHeight = Math.round(props.overflow); 47 | if (newHeight !== root.height) { 48 | props.overflowing = true; 49 | root.element.dataset.state = 'overflow'; 50 | root.height = newHeight; 51 | } 52 | } 53 | 54 | }; 55 | 56 | export const listScroller = createView({ 57 | create, 58 | write, 59 | name: 'list-scroller', 60 | mixins: { 61 | apis: ['overflow' , 'dragCoordinates'], 62 | styles: ['height', 'translateY'], 63 | animations: { 64 | translateY: 'spring' 65 | } 66 | } 67 | }); 68 | -------------------------------------------------------------------------------- /src/js/app/view/progressIndicator.js: -------------------------------------------------------------------------------- 1 | import { createView } from '../frame/index'; 2 | import { createElement } from '../frame/utils/createElement'; 3 | import { attr } from '../../utils/attr'; 4 | import { percentageArc } from '../../utils/percentageArc'; 5 | 6 | const create = ({ root, props }) => { 7 | // start at 0 8 | props.spin = false; 9 | props.progress = 0; 10 | props.opacity = 0; 11 | 12 | // svg 13 | const svg = createElement('svg'); 14 | root.ref.path = createElement('path', { 15 | 'stroke-width': 2, 16 | 'stroke-linecap': 'round', 17 | }); 18 | svg.appendChild(root.ref.path); 19 | 20 | root.ref.svg = svg; 21 | 22 | root.appendChild(svg); 23 | }; 24 | 25 | const write = ({ root, props }) => { 26 | if (props.opacity === 0) { 27 | return; 28 | } 29 | 30 | if (props.align) { 31 | root.element.dataset.align = props.align; 32 | } 33 | 34 | // get width of stroke 35 | const ringStrokeWidth = parseInt(attr(root.ref.path, 'stroke-width'), 10); 36 | 37 | // calculate size of ring 38 | const size = root.rect.element.width * 0.5; 39 | 40 | // ring state 41 | let ringFrom = 0; 42 | let ringTo = 0; 43 | 44 | // now in busy mode 45 | if (props.spin) { 46 | ringFrom = 0; 47 | ringTo = 0.5; 48 | } else { 49 | ringFrom = 0; 50 | ringTo = props.progress; 51 | } 52 | 53 | // get arc path 54 | const coordinates = percentageArc(size, size, size - ringStrokeWidth, ringFrom, ringTo); 55 | 56 | // update progress bar 57 | attr(root.ref.path, 'd', coordinates); 58 | 59 | // hide while contains 0 value 60 | attr(root.ref.path, 'stroke-opacity', props.spin || props.progress > 0 ? 1 : 0); 61 | }; 62 | 63 | export const progressIndicator = createView({ 64 | tag: 'div', 65 | name: 'progress-indicator', 66 | ignoreRectUpdate: true, 67 | ignoreRect: true, 68 | create, 69 | write, 70 | mixins: { 71 | apis: ['progress', 'spin', 'align'], 72 | styles: ['opacity'], 73 | animations: { 74 | opacity: { type: 'tween', duration: 500 }, 75 | progress: { 76 | type: 'spring', 77 | stiffness: 0.95, 78 | damping: 0.65, 79 | mass: 10, 80 | }, 81 | }, 82 | }, 83 | }); 84 | -------------------------------------------------------------------------------- /src/js/createApp.js: -------------------------------------------------------------------------------- 1 | import { isNode } from './utils/isNode'; 2 | import { createAppObject } from './createAppObject'; 3 | import { createAppAtElement } from './createAppAtElement'; 4 | 5 | // if an element is passed, we create the instance at that element, if not, we just create an up object 6 | export const createApp = (...args) => 7 | isNode(args[0]) ? createAppAtElement(...args) : createAppObject(...args); 8 | -------------------------------------------------------------------------------- /src/js/createAppAPI.js: -------------------------------------------------------------------------------- 1 | import { copyObjectPropertiesToObject } from './utils/copyObjectPropertiesToObject'; 2 | const PRIVATE_METHODS = ['fire', '_read', '_write']; 3 | 4 | export const createAppAPI = app => { 5 | const api = {}; 6 | 7 | copyObjectPropertiesToObject(app, api, PRIVATE_METHODS); 8 | 9 | return api; 10 | }; 11 | -------------------------------------------------------------------------------- /src/js/createAppObject.js: -------------------------------------------------------------------------------- 1 | import { createApp } from './app/index'; 2 | import { getOptions } from './app/options'; 3 | import { forin } from './utils/forin'; 4 | 5 | export const createAppObject = (customOptions = {}) => { 6 | // default options 7 | const defaultOptions = {}; 8 | forin(getOptions(), (key, value) => { 9 | defaultOptions[key] = value[0]; 10 | }); 11 | 12 | // set app options 13 | const app = createApp({ 14 | // default options 15 | ...defaultOptions, 16 | 17 | // custom options 18 | ...customOptions 19 | }); 20 | 21 | // return the plugin instance 22 | return app; 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/filter.js: -------------------------------------------------------------------------------- 1 | // all registered filters 2 | const filters = []; 3 | 4 | // loops over matching filters and passes options to each filter, returning the mapped results 5 | export const applyFilterChain = (key, value, utils) => 6 | new Promise((resolve, reject) => { 7 | // find matching filters for this key 8 | const matchingFilters = filters 9 | .filter(f => f.key === key) 10 | .map(f => f.cb); 11 | 12 | // resolve now 13 | if (matchingFilters.length === 0) { 14 | resolve(value); 15 | return; 16 | } 17 | 18 | // first filter to kick things of 19 | const initialFilter = matchingFilters.shift(); 20 | 21 | // chain filters 22 | matchingFilters 23 | .reduce( 24 | // loop over promises passing value to next promise 25 | (current, next) => current.then(value => next(value, utils)), 26 | 27 | // call initial filter, will return a promise 28 | initialFilter(value, utils) 29 | 30 | // all executed 31 | ) 32 | .then(value => resolve(value)) 33 | .catch(error => reject(error)); 34 | }); 35 | 36 | export const applyFilters = (key, value, utils) => 37 | filters.filter(f => f.key === key).map(f => f.cb(value, utils)); 38 | 39 | // adds a new filter to the list 40 | export const addFilter = (key, cb) => filters.push({ key, cb }); 41 | -------------------------------------------------------------------------------- /src/js/utils/arrayInsert.js: -------------------------------------------------------------------------------- 1 | export const arrayInsert = (arr, index, item) => arr.splice(index, 0, item); 2 | -------------------------------------------------------------------------------- /src/js/utils/arrayRemove.js: -------------------------------------------------------------------------------- 1 | export const arrayRemove = (arr, index) => arr.splice(index, 1); 2 | -------------------------------------------------------------------------------- /src/js/utils/arrayReverse.js: -------------------------------------------------------------------------------- 1 | export const arrayReverse = arr => arr.reverse(); 2 | -------------------------------------------------------------------------------- /src/js/utils/attr.js: -------------------------------------------------------------------------------- 1 | export const attr = (node, name, value = null) => { 2 | if (value === null) { 3 | return node.getAttribute(name) || node.hasAttribute(name); 4 | } 5 | node.setAttribute(name, value); 6 | }; 7 | -------------------------------------------------------------------------------- /src/js/utils/attrToggle.js: -------------------------------------------------------------------------------- 1 | import { attr } from './attr'; 2 | export const attrToggle = (element, name, state, enabledValue = '') => { 3 | if (state) { 4 | attr(element, name, enabledValue); 5 | } else { 6 | element.removeAttribute(name); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/js/utils/canUpdateFileInput.js: -------------------------------------------------------------------------------- 1 | let res = null; 2 | export const canUpdateFileInput = () => { 3 | if (res === null) { 4 | try { 5 | const dataTransfer = new DataTransfer(); 6 | dataTransfer.items.add(new File(['hello world'], 'This_Works.txt')); 7 | const el = document.createElement('input'); 8 | el.setAttribute('type', 'file'); 9 | el.files = dataTransfer.files; 10 | res = el.files.length === 1; 11 | } catch (err) { 12 | res = false; 13 | } 14 | } 15 | return res; 16 | }; 17 | -------------------------------------------------------------------------------- /src/js/utils/capitalizeFirstLetter.js: -------------------------------------------------------------------------------- 1 | export const capitalizeFirstLetter = string => 2 | string.charAt(0).toUpperCase() + string.slice(1); 3 | -------------------------------------------------------------------------------- /src/js/utils/composeObject.js: -------------------------------------------------------------------------------- 1 | export const composeObject = (...objects) => { 2 | return Object.assign({}, ...objects); 3 | }; 4 | -------------------------------------------------------------------------------- /src/js/utils/copyFile.js: -------------------------------------------------------------------------------- 1 | import { renameFile } from './renameFile'; 2 | export const copyFile = file => renameFile(file, file.name); 3 | -------------------------------------------------------------------------------- /src/js/utils/copyObjectPropertiesToObject.js: -------------------------------------------------------------------------------- 1 | export const copyObjectPropertiesToObject = (src, target, excluded) => { 2 | Object.getOwnPropertyNames(src) 3 | .filter(property => !excluded.includes(property)) 4 | .forEach(key => 5 | Object.defineProperty( 6 | target, 7 | key, 8 | Object.getOwnPropertyDescriptor(src, key) 9 | ) 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/js/utils/createBlob.js: -------------------------------------------------------------------------------- 1 | import { getBlobBuilder } from './getBlobBuilder'; 2 | 3 | export const createBlob = (arrayBuffer, mimeType) => { 4 | const BB = getBlobBuilder(); 5 | 6 | if (BB) { 7 | const bb = new BB(); 8 | bb.append(arrayBuffer); 9 | return bb.getBlob(mimeType); 10 | } 11 | 12 | return new Blob([arrayBuffer], { 13 | type: mimeType 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/js/utils/createDefaultResponse.js: -------------------------------------------------------------------------------- 1 | import { createResponse } from './createResponse'; 2 | 3 | export const createTimeoutResponse = (cb) => (xhr) => { 4 | cb( 5 | createResponse( 6 | 'error', 7 | 0, 8 | 'Timeout', 9 | xhr.getAllResponseHeaders() 10 | ) 11 | ) 12 | } -------------------------------------------------------------------------------- /src/js/utils/createElement.js: -------------------------------------------------------------------------------- 1 | export const createElement = tagName => { 2 | return document.createElement(tagName); 3 | }; 4 | -------------------------------------------------------------------------------- /src/js/utils/createObject.js: -------------------------------------------------------------------------------- 1 | import { defineProperty } from './defineProperty'; 2 | import { forin } from './forin'; 3 | 4 | export const createObject = definition => { 5 | const obj = {}; 6 | forin(definition, property => { 7 | defineProperty(obj, property, definition[property]); 8 | }); 9 | return obj; 10 | }; 11 | -------------------------------------------------------------------------------- /src/js/utils/createResponse.js: -------------------------------------------------------------------------------- 1 | export const createResponse = (type, code, body, headers) => ({ 2 | type, 3 | code, 4 | body, 5 | headers 6 | }); -------------------------------------------------------------------------------- /src/js/utils/createWorker.js: -------------------------------------------------------------------------------- 1 | import { getUniqueId } from './getUniqueId'; 2 | 3 | export const createWorker = fn => { 4 | const workerBlob = new Blob(['(', fn.toString(), ')()'], { 5 | type: 'application/javascript' 6 | }); 7 | const workerURL = URL.createObjectURL(workerBlob); 8 | const worker = new Worker(workerURL); 9 | 10 | return { 11 | transfer: (message, cb) => {}, 12 | post: (message, cb, transferList) => { 13 | const id = getUniqueId(); 14 | 15 | worker.onmessage = e => { 16 | if (e.data.id === id) { 17 | cb(e.data.message); 18 | } 19 | }; 20 | 21 | worker.postMessage( 22 | { 23 | id, 24 | message 25 | }, 26 | transferList 27 | ); 28 | }, 29 | terminate: () => { 30 | worker.terminate(); 31 | URL.revokeObjectURL(workerURL); 32 | } 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /src/js/utils/debounce.js: -------------------------------------------------------------------------------- 1 | export const debounce = (func, interval = 16, immidiateOnly = true) => { 2 | let last = Date.now(); 3 | let timeout = null; 4 | 5 | return (...args) => { 6 | clearTimeout(timeout); 7 | 8 | const dist = Date.now() - last; 9 | 10 | const fn = () => { 11 | last = Date.now(); 12 | func(...args); 13 | }; 14 | 15 | if (dist < interval) { 16 | // we need to delay by the difference between interval and dist 17 | // for example: if distance is 10 ms and interval is 16 ms, 18 | // we need to wait an additional 6ms before calling the function) 19 | if (!immidiateOnly) { 20 | timeout = setTimeout(fn, interval - dist); 21 | } 22 | } else { 23 | // go! 24 | fn(); 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/js/utils/deepCloneObject.js: -------------------------------------------------------------------------------- 1 | import { isObject } from './isObject'; 2 | import { isArray } from './isArray'; 3 | 4 | export const deepCloneObject = (src) => { 5 | if (!isObject(src)) return src; 6 | const target = isArray(src) ? [] : {}; 7 | for (const key in src) { 8 | if (!src.hasOwnProperty(key)) continue; 9 | const v = src[key]; 10 | target[key] = v && isObject(v) ? deepCloneObject(v) : v; 11 | } 12 | return target; 13 | } -------------------------------------------------------------------------------- /src/js/utils/defineProperty.js: -------------------------------------------------------------------------------- 1 | export const defineProperty = (obj, property, definition) => { 2 | if (typeof definition === 'function') { 3 | obj[property] = definition; 4 | return; 5 | } 6 | Object.defineProperty(obj, property, { ...definition }); 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/utils/describeArc.js: -------------------------------------------------------------------------------- 1 | import { polarToCartesian } from './polarToCartesian'; 2 | 3 | export const describeArc = (x, y, radius, startAngle, endAngle, arcSweep) => { 4 | const start = polarToCartesian(x, y, radius, endAngle); 5 | const end = polarToCartesian(x, y, radius, startAngle); 6 | return [ 7 | 'M', 8 | start.x, 9 | start.y, 10 | 'A', 11 | radius, 12 | radius, 13 | 0, 14 | arcSweep, 15 | 0, 16 | end.x, 17 | end.y 18 | ].join(' '); 19 | }; 20 | -------------------------------------------------------------------------------- /src/js/utils/forEachDelayed.js: -------------------------------------------------------------------------------- 1 | export const forEachDelayed = (items, cb, delay = 75) => 2 | items.map( 3 | (item, index) => 4 | new Promise((resolve, reject) => { 5 | setTimeout(() => { 6 | cb(item); 7 | resolve(); 8 | }, delay * index); 9 | }) 10 | ); 11 | -------------------------------------------------------------------------------- /src/js/utils/forin.js: -------------------------------------------------------------------------------- 1 | export const forin = (obj, cb) => { 2 | for (const key in obj) { 3 | if (!obj.hasOwnProperty(key)) { 4 | continue; 5 | } 6 | 7 | cb(key, obj[key]); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/js/utils/formatFilename.js: -------------------------------------------------------------------------------- 1 | export const formatFilename = name => name; 2 | -------------------------------------------------------------------------------- /src/js/utils/fromCamels.js: -------------------------------------------------------------------------------- 1 | export const fromCamels = (string, separator = '-') => 2 | string 3 | .split(/(?=[A-Z])/) 4 | .map(part => part.toLowerCase()) 5 | .join(separator); 6 | -------------------------------------------------------------------------------- /src/js/utils/getBase64DataFromBase64DataURI.js: -------------------------------------------------------------------------------- 1 | export const getBase64DataFromBase64DataURI = dataURI => { 2 | // get data part of string (remove data:image/jpeg...,) 3 | const data = dataURI.split(',')[1]; 4 | 5 | // remove any whitespace as that causes InvalidCharacterError in IE 6 | return data.replace(/\s/g, ''); 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/utils/getBlobBuilder.js: -------------------------------------------------------------------------------- 1 | export const getBlobBuilder = () => { 2 | return (window.BlobBuilder = 3 | window.BlobBuilder || 4 | window.WebKitBlobBuilder || 5 | window.MozBlobBuilder || 6 | window.MSBlobBuilder); 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/utils/getBlobFromBase64DataURI.js: -------------------------------------------------------------------------------- 1 | import { getBlobFromByteStringWithMimeType } from './getBlobFromByteStringWithMimeType'; 2 | import { getMimeTypeFromBase64DataURI } from './getMimeTypeFromBase64DataURI'; 3 | import { getByteStringFromBase64DataURI } from './getByteStringFromBase64DataURI'; 4 | 5 | export const getBlobFromBase64DataURI = dataURI => { 6 | const mimeType = getMimeTypeFromBase64DataURI(dataURI); 7 | const byteString = getByteStringFromBase64DataURI(dataURI); 8 | 9 | return getBlobFromByteStringWithMimeType(byteString, mimeType); 10 | }; 11 | -------------------------------------------------------------------------------- /src/js/utils/getBlobFromByteStringWithMimeType.js: -------------------------------------------------------------------------------- 1 | import { createBlob } from './createBlob'; 2 | 3 | export const getBlobFromByteStringWithMimeType = (byteString, mimeType) => { 4 | const ab = new ArrayBuffer(byteString.length); 5 | const ia = new Uint8Array(ab); 6 | 7 | for (let i = 0; i < byteString.length; i++) { 8 | ia[i] = byteString.charCodeAt(i); 9 | } 10 | 11 | return createBlob(ab, mimeType); 12 | }; 13 | -------------------------------------------------------------------------------- /src/js/utils/getByteStringFromBase64DataURI.js: -------------------------------------------------------------------------------- 1 | import { getBase64DataFromBase64DataURI } from './getBase64DataFromBase64DataURI'; 2 | 3 | export const getByteStringFromBase64DataURI = dataURI => { 4 | return atob(getBase64DataFromBase64DataURI(dataURI)); 5 | }; 6 | -------------------------------------------------------------------------------- /src/js/utils/getDateString.js: -------------------------------------------------------------------------------- 1 | import { leftPad } from './leftPad'; 2 | export const getDateString = (date = new Date()) => 3 | `${date.getFullYear()}-${leftPad(date.getMonth() + 1, '00')}-${leftPad( 4 | date.getDate(), 5 | '00' 6 | )}_${leftPad(date.getHours(), '00')}-${leftPad( 7 | date.getMinutes(), 8 | '00' 9 | )}-${leftPad(date.getSeconds(), '00')}`; 10 | -------------------------------------------------------------------------------- /src/js/utils/getDecimalSeparator.js: -------------------------------------------------------------------------------- 1 | import { getNonNumeric } from './getNonNumeric'; 2 | 3 | export const getDecimalSeparator = () => 4 | getNonNumeric((1.1).toLocaleString())[0]; 5 | -------------------------------------------------------------------------------- /src/js/utils/getDomainFromURL.js: -------------------------------------------------------------------------------- 1 | export const getDomainFromURL = url => { 2 | if (url.indexOf('//') === 0) { 3 | url = location.protocol + url; 4 | } 5 | return url 6 | .toLowerCase() 7 | .replace('blob:', '') 8 | .replace(/([a-z])?:\/\//, '$1') 9 | .split('/')[0]; 10 | }; 11 | -------------------------------------------------------------------------------- /src/js/utils/getExtensionFromFilename.js: -------------------------------------------------------------------------------- 1 | export const getExtensionFromFilename = name => name.split('.').pop(); 2 | -------------------------------------------------------------------------------- /src/js/utils/getFileFromBase64DataURI.js: -------------------------------------------------------------------------------- 1 | import { getFileFromBlob } from './getFileFromBlob'; 2 | import { getBlobFromBase64DataURI } from './getBlobFromBase64DataURI'; 3 | 4 | export const getFileFromBase64DataURI = (dataURI, filename, extension) => { 5 | return getFileFromBlob( 6 | getBlobFromBase64DataURI(dataURI), 7 | filename, 8 | null, 9 | extension 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/js/utils/getFileFromBlob.js: -------------------------------------------------------------------------------- 1 | import { getExtensionFromFilename } from './getExtensionFromFilename'; 2 | import { guesstimateExtension } from './guesstimateExtension'; 3 | import { isString } from './isString'; 4 | import { getDateString } from './getDateString'; 5 | 6 | export const getFileFromBlob = ( 7 | blob, 8 | filename, 9 | type = null, 10 | extension = null 11 | ) => { 12 | const file = 13 | typeof type === 'string' 14 | ? blob.slice(0, blob.size, type) 15 | : blob.slice(0, blob.size, blob.type); 16 | file.lastModifiedDate = new Date(); 17 | 18 | // copy relative path 19 | if (blob._relativePath) file._relativePath = blob._relativePath; 20 | 21 | // if blob has name property, use as filename if no filename supplied 22 | if (!isString(filename)) { 23 | filename = getDateString(); 24 | } 25 | 26 | // if filename supplied but no extension and filename has extension 27 | if (filename && extension === null && getExtensionFromFilename(filename)) { 28 | file.name = filename; 29 | } 30 | else { 31 | extension = extension || guesstimateExtension(file.type); 32 | file.name = filename + (extension ? '.' + extension : ''); 33 | } 34 | 35 | return file; 36 | }; 37 | -------------------------------------------------------------------------------- /src/js/utils/getFileInfoFromHeaders.js: -------------------------------------------------------------------------------- 1 | export const getFileNameFromHeader = header => { 2 | 3 | // test if is content disposition header, if not exit 4 | if (!/^content-disposition:/i.test(header)) return null; 5 | 6 | // get filename parts 7 | const matches = header.split(/filename=|filename\*=.+''/) 8 | .splice(1) 9 | .map(name => name.trim().replace(/^["']|[;"']{0,2}$/g, '')) 10 | .filter(name => name.length) 11 | 12 | return matches.length ? decodeURI(matches[matches.length-1]) : null; 13 | } 14 | 15 | const getFileSizeFromHeader = header => { 16 | if (/content-length:/i.test(header)) { 17 | const size = header.match(/[0-9]+/)[0]; 18 | return size ? parseInt(size, 10) : null; 19 | } 20 | return null; 21 | } 22 | 23 | const getTranfserIdFromHeader = header => { 24 | if (/x-content-transfer-id:/i.test(header)) { 25 | const id = (header.split(':')[1] || '').trim(); 26 | return id || null; 27 | } 28 | return null; 29 | } 30 | 31 | export const getFileInfoFromHeaders = headers => { 32 | 33 | const info = { 34 | source: null, 35 | name: null, 36 | size: null 37 | }; 38 | 39 | const rows = headers.split('\n'); 40 | for (let header of rows) { 41 | 42 | const name = getFileNameFromHeader(header); 43 | if (name) { 44 | info.name = name; 45 | continue; 46 | } 47 | 48 | const size = getFileSizeFromHeader(header); 49 | if (size) { 50 | info.size = size; 51 | continue; 52 | } 53 | 54 | const source = getTranfserIdFromHeader(header); 55 | if (source) { 56 | info.source = source; 57 | continue; 58 | } 59 | 60 | } 61 | 62 | return info; 63 | } -------------------------------------------------------------------------------- /src/js/utils/getFilenameFromURL.js: -------------------------------------------------------------------------------- 1 | export const getFilenameFromURL = url => 2 | `${url}` 3 | .split('/') 4 | .pop() 5 | .split('?') 6 | .shift(); 7 | -------------------------------------------------------------------------------- /src/js/utils/getFilenameWithoutExtension.js: -------------------------------------------------------------------------------- 1 | export const getFilenameWithoutExtension = name => 2 | name.substring(0, name.lastIndexOf('.')) || name; 3 | -------------------------------------------------------------------------------- /src/js/utils/getMimeTypeFromBase64DataURI.js: -------------------------------------------------------------------------------- 1 | export const getMimeTypeFromBase64DataURI = dataURI => { 2 | return (/^data:(.+);/.exec(dataURI) || [])[1] || null; 3 | }; 4 | -------------------------------------------------------------------------------- /src/js/utils/getNonNumeric.js: -------------------------------------------------------------------------------- 1 | export const getNonNumeric = str => /[^0-9]+/.exec(str); 2 | -------------------------------------------------------------------------------- /src/js/utils/getNumericAspectRatioFromString.js: -------------------------------------------------------------------------------- 1 | import { isEmpty } from './isEmpty'; 2 | 3 | export const getNumericAspectRatioFromString = aspectRatio => { 4 | if (isEmpty(aspectRatio)) { 5 | return aspectRatio; 6 | } 7 | if(/:/.test(aspectRatio)) { 8 | const parts = aspectRatio.split(':'); 9 | return parts[1] / parts[0]; 10 | } 11 | return parseFloat(aspectRatio); 12 | }; -------------------------------------------------------------------------------- /src/js/utils/getParameters.js: -------------------------------------------------------------------------------- 1 | export const getParameters = (args, filters) => { 2 | return Object.keys(filters).reduce((acc, name) => { 3 | acc[name] = args.find(arg => typeof arg === filters[name]); 4 | return acc; 5 | }, {}); 6 | }; 7 | -------------------------------------------------------------------------------- /src/js/utils/getRandomNumber.js: -------------------------------------------------------------------------------- 1 | export const getRandomNumber = (min = 0, max = 1) => 2 | min + Math.random() * (max - min); 3 | -------------------------------------------------------------------------------- /src/js/utils/getRootNode.js: -------------------------------------------------------------------------------- 1 | export const getRootNode = element => 2 | 'getRootNode' in element ? element.getRootNode() : document; 3 | -------------------------------------------------------------------------------- /src/js/utils/getThousandsSeparator.js: -------------------------------------------------------------------------------- 1 | import { getNonNumeric } from './getNonNumeric'; 2 | import { getDecimalSeparator } from './getDecimalSeparator'; 3 | 4 | export const getThousandsSeparator = () => { 5 | // Added for browsers that do not return the thousands separator (happend on native browser Android 4.4.4) 6 | // We check against the normal toString output and if they're the same return a comma when decimal separator is a dot 7 | const decimalSeparator = getDecimalSeparator(); 8 | const thousandsStringWithSeparator = (1000.0).toLocaleString(); 9 | const thousandsStringWithoutSeparator = (1000.0).toString(); 10 | if (thousandsStringWithSeparator !== thousandsStringWithoutSeparator) { 11 | return getNonNumeric(thousandsStringWithSeparator)[0]; 12 | } 13 | return decimalSeparator === '.' ? ',' : '.'; 14 | }; 15 | -------------------------------------------------------------------------------- /src/js/utils/getUniqueId.js: -------------------------------------------------------------------------------- 1 | export const getUniqueId = () => 2 | Math.random() 3 | .toString(36) 4 | .substring(2, 11); 5 | -------------------------------------------------------------------------------- /src/js/utils/guesstimateExtension.js: -------------------------------------------------------------------------------- 1 | export const guesstimateExtension = type => { 2 | // if no extension supplied, exit here 3 | if (typeof type !== 'string') { 4 | return ''; 5 | } 6 | 7 | // get subtype 8 | const subtype = type.split('/').pop(); 9 | 10 | // is svg subtype 11 | if (/svg/.test(subtype)) { 12 | return 'svg'; 13 | } 14 | 15 | if (/zip|compressed/.test(subtype)) { 16 | return 'zip'; 17 | } 18 | 19 | if (/plain/.test(subtype)) { 20 | return 'txt'; 21 | } 22 | 23 | if (/msword/.test(subtype)) { 24 | return 'doc'; 25 | } 26 | 27 | // if is valid subtype 28 | if (/[a-z]+/.test(subtype)) { 29 | // always use jpg extension 30 | if (subtype === 'jpeg') { 31 | return 'jpg'; 32 | } 33 | 34 | // return subtype 35 | return subtype; 36 | } 37 | 38 | return ''; 39 | }; 40 | -------------------------------------------------------------------------------- /src/js/utils/guesstimateMimeType.js: -------------------------------------------------------------------------------- 1 | const images = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'tiff']; 2 | const text = ['css', 'csv', 'html', 'txt']; 3 | const map = { 4 | zip: 'zip|compressed', 5 | epub: 'application/epub+zip' 6 | }; 7 | 8 | export const guesstimateMimeType = (extension = '') => { 9 | extension = extension.toLowerCase(); 10 | if (images.includes(extension)) { 11 | return ( 12 | 'image/' + 13 | (extension === 'jpg' 14 | ? 'jpeg' 15 | : extension === 'svg' ? 'svg+xml' : extension) 16 | ); 17 | } 18 | if (text.includes(extension)) { 19 | return 'text/' + extension; 20 | } 21 | 22 | return map[extension] || ''; 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/utils/hasQueryString.js: -------------------------------------------------------------------------------- 1 | export const hasQueryString = url => /[?&]/.test(url); 2 | -------------------------------------------------------------------------------- /src/js/utils/insertAfter.js: -------------------------------------------------------------------------------- 1 | export const insertAfter = (newNode, referenceNode) => { 2 | return referenceNode.parentNode.insertBefore( 3 | newNode, 4 | referenceNode.nextSibling 5 | ); 6 | }; 7 | -------------------------------------------------------------------------------- /src/js/utils/insertBefore.js: -------------------------------------------------------------------------------- 1 | export const insertBefore = (newNode, referenceNode) => referenceNode.parentNode.insertBefore(newNode, referenceNode); 2 | -------------------------------------------------------------------------------- /src/js/utils/isArray.js: -------------------------------------------------------------------------------- 1 | export const isArray = value => Array.isArray(value); 2 | -------------------------------------------------------------------------------- /src/js/utils/isBase64DataURI.js: -------------------------------------------------------------------------------- 1 | export const isBase64DataURI = str => 2 | /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*)\s*$/i.test( 3 | str 4 | ); 5 | -------------------------------------------------------------------------------- /src/js/utils/isBoolean.js: -------------------------------------------------------------------------------- 1 | export const isBoolean = value => typeof value === 'boolean'; 2 | -------------------------------------------------------------------------------- /src/js/utils/isBrowser.js: -------------------------------------------------------------------------------- 1 | const IS_BROWSER = (() => typeof window !== 'undefined' && typeof window.document !== 'undefined')(); 2 | export const isBrowser = () => IS_BROWSER; -------------------------------------------------------------------------------- /src/js/utils/isDefined.js: -------------------------------------------------------------------------------- 1 | export const isDefined = value => value != null; 2 | -------------------------------------------------------------------------------- /src/js/utils/isEmpty.js: -------------------------------------------------------------------------------- 1 | export const isEmpty = value => value == null; 2 | -------------------------------------------------------------------------------- /src/js/utils/isExternalURL.js: -------------------------------------------------------------------------------- 1 | import { getDomainFromURL } from './getDomainFromURL'; 2 | export const isExternalURL = url => 3 | (url.indexOf(':') > -1 || url.indexOf('//') > -1) && 4 | getDomainFromURL(location.href) !== getDomainFromURL(url); 5 | -------------------------------------------------------------------------------- /src/js/utils/isFile.js: -------------------------------------------------------------------------------- 1 | export const isFile = value => !!(value instanceof File || (value instanceof Blob && value.name)); 2 | -------------------------------------------------------------------------------- /src/js/utils/isFunction.js: -------------------------------------------------------------------------------- 1 | export const isFunction = value => typeof value === 'function'; 2 | -------------------------------------------------------------------------------- /src/js/utils/isIOS.js: -------------------------------------------------------------------------------- 1 | let testResult = null; 2 | export const isIOS = () => { 3 | if (testResult === null) { 4 | testResult = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 5 | } 6 | return testResult; 7 | } -------------------------------------------------------------------------------- /src/js/utils/isInt.js: -------------------------------------------------------------------------------- 1 | import { isNumber } from './isNumber'; 2 | export const isInt = value => 3 | isNumber(value) && isFinite(value) && Math.floor(value) === value; 4 | -------------------------------------------------------------------------------- /src/js/utils/isNode.js: -------------------------------------------------------------------------------- 1 | export const isNode = value => value instanceof HTMLElement; 2 | -------------------------------------------------------------------------------- /src/js/utils/isNull.js: -------------------------------------------------------------------------------- 1 | export const isNull = value => value === null; 2 | -------------------------------------------------------------------------------- /src/js/utils/isNumber.js: -------------------------------------------------------------------------------- 1 | export const isNumber = value => typeof value === 'number'; 2 | -------------------------------------------------------------------------------- /src/js/utils/isObject.js: -------------------------------------------------------------------------------- 1 | export const isObject = value => typeof value === 'object' && value !== null; -------------------------------------------------------------------------------- /src/js/utils/isString.js: -------------------------------------------------------------------------------- 1 | export const isString = value => typeof value === 'string'; 2 | -------------------------------------------------------------------------------- /src/js/utils/leftPad.js: -------------------------------------------------------------------------------- 1 | export const leftPad = (value, padding = '') => 2 | (padding + value).slice(-padding.length); 3 | -------------------------------------------------------------------------------- /src/js/utils/limit.js: -------------------------------------------------------------------------------- 1 | export const limit = (value, min, max) => Math.max(Math.min(max, value), min); 2 | -------------------------------------------------------------------------------- /src/js/utils/loadImage.js: -------------------------------------------------------------------------------- 1 | export const loadImage = (url) => 2 | new Promise((resolve, reject) => { 3 | const img = new Image(); 4 | img.onload = () => { 5 | resolve(img); 6 | }; 7 | img.onerror = e => { 8 | reject(e); 9 | }; 10 | img.src = url; 11 | }); 12 | -------------------------------------------------------------------------------- /src/js/utils/lowerCaseFirstLetter.js: -------------------------------------------------------------------------------- 1 | export const lowerCaseFirstLetter = string => 2 | string.charAt(0).toLowerCase() + string.slice(1); 3 | -------------------------------------------------------------------------------- /src/js/utils/percentageArc.js: -------------------------------------------------------------------------------- 1 | import { describeArc } from './describeArc'; 2 | 3 | export const percentageArc = (x, y, radius, from, to) => { 4 | let arcSweep = 1; 5 | if (to > from && to - from <= 0.5) { 6 | arcSweep = 0; 7 | } 8 | if (from > to && from - to >= 0.5) { 9 | arcSweep = 0; 10 | } 11 | return describeArc( 12 | x, 13 | y, 14 | radius, 15 | Math.min(0.9999, from) * 360, 16 | Math.min(0.9999, to) * 360, 17 | arcSweep 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/js/utils/polarToCartesian.js: -------------------------------------------------------------------------------- 1 | export const polarToCartesian = (centerX, centerY, radius, angleInDegrees) => { 2 | const angleInRadians = (angleInDegrees % 360 - 90) * Math.PI / 180.0; 3 | return { 4 | x: centerX + radius * Math.cos(angleInRadians), 5 | y: centerY + radius * Math.sin(angleInRadians) 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /src/js/utils/renameFile.js: -------------------------------------------------------------------------------- 1 | export const renameFile = (file, name) => { 2 | const renamedFile = file.slice(0, file.size, file.type); 3 | renamedFile.lastModifiedDate = file.lastModifiedDate; 4 | renamedFile.name = name; 5 | return renamedFile; 6 | }; 7 | -------------------------------------------------------------------------------- /src/js/utils/replaceInString.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Replaces placeholders in given string with replacements 3 | * @param string - "Foo {bar}"" 4 | * @param replacements - { "bar": 10 } 5 | */ 6 | export const replaceInString = (string, replacements) => 7 | string.replace(/(?:{([a-zA-Z]+)})/g, (match, group) => replacements[group]); 8 | -------------------------------------------------------------------------------- /src/js/utils/resetFileInput.js: -------------------------------------------------------------------------------- 1 | import { createElement } from './createElement'; 2 | 3 | export const resetFileInput = input => { 4 | // no value, no need to reset 5 | if (!input || input.value === '') { 6 | return; 7 | } 8 | 9 | try { 10 | // for modern browsers 11 | input.value = ''; 12 | } catch (err) {} 13 | 14 | // for IE10 15 | if (input.value) { 16 | // quickly append input to temp form and reset form 17 | const form = createElement('form'); 18 | const parentNode = input.parentNode; 19 | const ref = input.nextSibling; 20 | form.appendChild(input); 21 | form.reset(); 22 | 23 | // re-inject input where it originally was 24 | if (ref) { 25 | parentNode.insertBefore(input, ref); 26 | } else { 27 | parentNode.appendChild(input); 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/js/utils/setInputFiles.js: -------------------------------------------------------------------------------- 1 | export const setInputFiles = (element, files) => { 2 | try { 3 | // Create a DataTransfer instance and add a newly created file 4 | const dataTransfer = new DataTransfer(); 5 | files.forEach(file => { 6 | if (file instanceof File) { 7 | dataTransfer.items.add(file); 8 | } else { 9 | dataTransfer.items.add( 10 | new File([file], file.name, { 11 | type: file.type, 12 | }) 13 | ); 14 | } 15 | }); 16 | 17 | // Assign the DataTransfer files list to the file input 18 | element.files = dataTransfer.files; 19 | } catch (err) { 20 | return false; 21 | } 22 | return true; 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/utils/text.js: -------------------------------------------------------------------------------- 1 | export const text = (node, value) => { 2 | let textNode = node.childNodes[0]; 3 | if (!textNode) { 4 | textNode = document.createTextNode(value); 5 | node.appendChild(textNode); 6 | } else if (value !== textNode.nodeValue) { 7 | textNode.nodeValue = value; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/js/utils/toArray.js: -------------------------------------------------------------------------------- 1 | import { isArray } from './isArray'; 2 | import { isEmpty } from './isEmpty'; 3 | import { trim } from './trim'; 4 | import { toString } from './toString'; 5 | 6 | export const toArray = (value, splitter = ',') => { 7 | if (isEmpty(value)) { 8 | return []; 9 | } 10 | if (isArray(value)) { 11 | return value; 12 | } 13 | return toString(value) 14 | .split(splitter) 15 | .map(trim) 16 | .filter(str => str.length); 17 | }; 18 | -------------------------------------------------------------------------------- /src/js/utils/toBoolean.js: -------------------------------------------------------------------------------- 1 | import { isBoolean } from './isBoolean'; 2 | export const toBoolean = value => (isBoolean(value) ? value : value === 'true'); 3 | -------------------------------------------------------------------------------- /src/js/utils/toBytes.js: -------------------------------------------------------------------------------- 1 | import { toString } from './toString'; 2 | import { isInt } from './isInt'; 3 | import { toInt } from './toInt'; 4 | 5 | export const toBytes = (value, base = 1000) => { 6 | // is in bytes 7 | if (isInt(value)) { 8 | return value; 9 | } 10 | 11 | // is natural file size 12 | let naturalFileSize = toString(value).trim(); 13 | 14 | // if is value in megabytes 15 | if (/MB$/i.test(naturalFileSize)) { 16 | naturalFileSize = naturalFileSize.replace(/MB$i/, '').trim(); 17 | return toInt(naturalFileSize) * base * base; 18 | } 19 | 20 | // if is value in kilobytes 21 | if (/KB/i.test(naturalFileSize)) { 22 | naturalFileSize = naturalFileSize.replace(/KB$i/, '').trim(); 23 | return toInt(naturalFileSize) * base; 24 | } 25 | 26 | return toInt(naturalFileSize); 27 | }; 28 | -------------------------------------------------------------------------------- /src/js/utils/toCamels.js: -------------------------------------------------------------------------------- 1 | export const toCamels = (string, separator = '-') => 2 | string.replace(new RegExp(`${separator}.`, 'g'), sub => 3 | sub.charAt(1).toUpperCase() 4 | ); 5 | -------------------------------------------------------------------------------- /src/js/utils/toFloat.js: -------------------------------------------------------------------------------- 1 | import { toNumber } from './toNumber'; 2 | export const toFloat = value => parseFloat(toNumber(value)); 3 | -------------------------------------------------------------------------------- /src/js/utils/toFunctionReference.js: -------------------------------------------------------------------------------- 1 | export const toFunctionReference = string => { 2 | let ref = self; 3 | let levels = string.split('.'); 4 | let level = null; 5 | while ((level = levels.shift())) { 6 | ref = ref[level]; 7 | if (!ref) { 8 | return null; 9 | } 10 | } 11 | return ref; 12 | }; 13 | -------------------------------------------------------------------------------- /src/js/utils/toInt.js: -------------------------------------------------------------------------------- 1 | import { toNumber } from './toNumber'; 2 | export const toInt = value => parseInt(toNumber(value), 10); 3 | -------------------------------------------------------------------------------- /src/js/utils/toNaturalFileSize.js: -------------------------------------------------------------------------------- 1 | export const toNaturalFileSize = (bytes, decimalSeparator = '.', base = 1000, options = {}) => { 2 | const { 3 | labelBytes = 'bytes', 4 | labelKilobytes = 'KB', 5 | labelMegabytes = 'MB', 6 | labelGigabytes = 'GB', 7 | } = options; 8 | 9 | // no negative byte sizes 10 | bytes = Math.round(Math.abs(bytes)); 11 | 12 | const KB = base; 13 | const MB = base * base; 14 | const GB = base * base * base; 15 | 16 | // just bytes 17 | if (bytes < KB) { 18 | return `${bytes} ${labelBytes}`; 19 | } 20 | 21 | // kilobytes 22 | if (bytes < MB) { 23 | return `${Math.floor(bytes / KB)} ${labelKilobytes}`; 24 | } 25 | 26 | // megabytes 27 | if (bytes < GB) { 28 | return `${removeDecimalsWhenZero(bytes / MB, 1, decimalSeparator)} ${labelMegabytes}`; 29 | } 30 | 31 | // gigabytes 32 | return `${removeDecimalsWhenZero(bytes / GB, 2, decimalSeparator)} ${labelGigabytes}`; 33 | }; 34 | 35 | const removeDecimalsWhenZero = (value, decimalCount, separator) => { 36 | return value 37 | .toFixed(decimalCount) 38 | .split('.') 39 | .filter(part => part !== '0') 40 | .join(separator); 41 | }; 42 | -------------------------------------------------------------------------------- /src/js/utils/toNumber.js: -------------------------------------------------------------------------------- 1 | import { isNumber } from './isNumber'; 2 | import { isString } from './isString'; 3 | import { toString } from './toString'; 4 | export const toNumber = value => 5 | isNumber(value) 6 | ? value 7 | : isString(value) ? toString(value).replace(/[a-z]+/gi, '') : 0; 8 | -------------------------------------------------------------------------------- /src/js/utils/toPercentage.js: -------------------------------------------------------------------------------- 1 | export const toPercentage = value => Math.round(value * 100); 2 | -------------------------------------------------------------------------------- /src/js/utils/toString.js: -------------------------------------------------------------------------------- 1 | export const toString = value => '' + value; 2 | -------------------------------------------------------------------------------- /src/js/utils/trim.js: -------------------------------------------------------------------------------- 1 | export const trim = str => str.trim(); 2 | -------------------------------------------------------------------------------- /types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "lib": ["es6", "dom"], 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "strictNullChecks": true, 8 | "strictFunctionTypes": true, 9 | "noEmit": true, 10 | 11 | // If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index". 12 | // If the library is global (cannot be imported via `import` or `require`), leave this out. 13 | "baseUrl": ".", 14 | "paths": { "filepond": ["."] } 15 | } 16 | } --------------------------------------------------------------------------------