├── .babelrc
├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── dist
├── fileup.bootstrap.min.css
├── fileup.bootstrap.min.css.map
├── fileup.css
├── fileup.js
├── fileup.min.css
├── fileup.min.css.map
├── fileup.min.js
└── fileup.min.js.map
├── gulpfile.js
├── package.json
└── src
├── css
├── _varaible.scss
├── fileup.bootstrap.scss
├── fileup.scss
└── main.scss
├── html
└── file.html
└── js
├── fileup.events.js
├── fileup.file.js
├── fileup.instance.js
├── fileup.js
├── fileup.private.js
├── fileup.templates.js
├── fileup.utils.js
├── lang
├── en.js
├── es.js
├── pt.js
└── ru.js
└── main.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env"
4 | ]
5 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 6,
4 | "sourceType": "module",
5 | "ecmaFeatures": {}
6 | },
7 | "rules": {
8 | "constructor-super": 2,
9 | "for-direction": 2,
10 | "getter-return": 2,
11 | "no-async-promise-executor": 2,
12 | "no-case-declarations": 2,
13 | "no-class-assign": 2,
14 | "no-compare-neg-zero": 2,
15 | "no-const-assign": 2,
16 | "no-debugger": 2,
17 | "no-dupe-args": 2,
18 | "no-dupe-class-members": 2,
19 | "no-dupe-else-if": 2,
20 | "no-dupe-keys": 2,
21 | "no-duplicate-case": 2,
22 | "no-empty-character-class": 2,
23 | "no-empty-pattern": 2,
24 | "no-ex-assign": 2,
25 | "no-import-assign": 2,
26 | "no-invalid-regexp": 2,
27 | "no-irregular-whitespace": 2,
28 | "no-misleading-character-class": 2,
29 | "no-new-symbol": 2,
30 | "no-obj-calls": 2,
31 | "no-octal": 2,
32 | "no-regex-spaces": 2,
33 | "no-self-assign": 2,
34 | "no-setter-return": 2,
35 | "no-sparse-arrays": 2,
36 | "no-this-before-super": 2,
37 | "no-unexpected-multiline": 2,
38 | "no-unreachable": 2,
39 | "no-unsafe-finally": 2,
40 | "no-unsafe-negation": 2,
41 | "no-unused-labels": 2,
42 | "no-useless-catch": 2,
43 | "require-yield": 2,
44 | "use-isnan": 2,
45 | "valid-typeof": 2
46 | },
47 | "env": {
48 | "browser": true,
49 | "jquery": true
50 | }
51 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FileUp
2 | Библиотека для загрузки файлов на сервер.
3 | Поддерживает выбор нескольких файлов, перетаскивание и индикатор выполнения.
4 |
5 | [[DEMO]](https://n2ref.github.io/fileup/)
6 |
7 | 
8 |
9 | ## Documentation
10 |
11 | ### Install with npm
12 | ```shell
13 | $ npm install fileup-js
14 | ```
15 |
16 | ### 1. Events
17 |
18 | - onSelect (file)
19 | - onRemove (file)
20 | - onBeforeStart (file, xhr)
21 | - onStart (file)
22 | - onProgress (file, ProgressEvent)
23 | - onSuccess (file, response)
24 | - onError (errorType, options)
25 | - onAbort (file)
26 | - onFinish (file)
27 | - onDragEnter (event)
28 | - onDragOver (event)
29 | - onDragLeave (event)
30 | - onDragEnd (event)
31 |
32 | ### 2. Options
33 |
34 | - id: '',
35 | - url: '',
36 | - input: '',
37 | - queue: '',
38 | - dropzone: '',
39 | - files: [],
40 | - fieldName: 'file',
41 | - extraFields: {},
42 | - lang: 'en',
43 | - sizeLimit: 0,
44 | - filesLimit: 0,
45 | - httpMethod: 'post',
46 | - timeout: null,
47 | - autostart: false,
48 | - templateFile:
49 |
50 | ```html
51 |
52 |
53 |
![[NAME]]([PREVIEW_SRC])
54 |
55 |
56 |
57 |
58 | [NAME]
59 | ([SIZE])
60 |
61 |
62 |
63 | ✕
64 | [UPLOAD]
65 | [ABORT]
66 |
67 |
68 |
69 |
70 |
73 |
74 |
75 | ```
76 |
--------------------------------------------------------------------------------
/dist/fileup.css:
--------------------------------------------------------------------------------
1 | .fileup-file {
2 | font-size: 12px;
3 | width: 350px;
4 | position: relative;
5 | overflow: hidden;
6 | }
7 | .fileup-file.fileup-image .fileup-preview.no-preview {
8 | width: 80px;
9 | height: 56px;
10 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA4CAAAAABP3SBGAAACW0lEQVRYw+3Y3U8aQRAAcP7/98bb3YFDxSvUBCKlxigllVrFILFEmmJrxdYrB7e7Q+JfUD4Ocgcs7OX2oQ/OAwmZ8Mt+zO7NkcraZiOVSRuNTMp+BU2BzCIJAyIgK19eJIv6PoRB0njBRDHiBRYG6Rf0EwXvv/3fQM6Ngsjd5/GHKZCLdvkgV2wOhSmwRglj1Kp43AgoG9a05mCnKk2AvO+w4HjZj8IAKLsAwcmlLdQEl4oiCt6x+VVAGpogf3KFEhQPmWCEwNpSAZKLKHh0NNwwxhIJZuy4XAvEO2adqGctuzad7gm9RV8H5H6RpklVqMWOM74Arb2m9LVAbFFIA6lJteg2q6dXT9LXArlXmMwIyLla5CglCl8PxMZszWGlOKX+9RUC+XMuqDOg1xGx31Ev6wYQz6153QK0wkt7Qz4rRTUoe7uLg5Bm6a+jxU9ch9LToYwL4pkVesyyTAdDIwer/FfGA+XP+bmaXyjfZxn5y54krMMexgJFhURbAbp7P02JD7MEyXUxBojfAJaaC7r/gNPTGCSo3cYYIyzRlXaFOj3JB4eLBIPGasUrQLylsNoAkfzvl6vQVjH6iQstkA/e0XUtFSneH7DQdyDHntQB8Zqsb9JYdmngVukPbge5GxlHOGB1GR5wKyjrRL+zpHsd3AJyL09j9KoscxPqRdaDBRan+2WsLrhJcLzZZ0NhEpzcFa7cBDo7NGa8cX5w9S57teOTuFH5OHs0ry9sIeOHP9TpHJL32MlBLx8FL0c8UYhB9D0FCpX3yaKchei7Hk0a8PoCbgw0/a/IP7jBCOMW5IDRAAAAAElFTkSuQmCC);
11 | background-repeat: no-repeat;
12 | background-size: contain;
13 | }
14 | .fileup-file.fileup-image .fileup-preview.no-preview img {
15 | display: none;
16 | }
17 | .fileup-file.fileup-image .fileup-preview .fileup-icon {
18 | display: none;
19 | }
20 | .fileup-file.fileup-doc .fileup-preview img {
21 | display: none;
22 | }
23 | .fileup-file .fileup-preview img {
24 | max-height: 80px;
25 | max-width: 80px;
26 | }
27 | .fileup-file .fileup-description {
28 | padding-right: 20px;
29 | word-break: break-all;
30 | }
31 | .fileup-file .fileup-controls .fileup-remove {
32 | cursor: pointer;
33 | position: absolute;
34 | top: 0;
35 | right: 2px;
36 | width: 16px;
37 | height: 16px;
38 | font-size: 16px;
39 | color: #9e9e9e;
40 | }
41 | .fileup-file .fileup-controls .fileup-remove:hover {
42 | color: #616161;
43 | }
44 | .fileup-file .fileup-controls .fileup-upload,
45 | .fileup-file .fileup-controls .fileup-abort {
46 | cursor: pointer;
47 | }
48 | .fileup-file .fileup-result.fileup-success {
49 | color: #4CAE4C;
50 | }
51 | .fileup-file .fileup-result.fileup-error {
52 | color: #CE0000;
53 | }
54 | .fileup-file .fileup-progress {
55 | height: 3px;
56 | }
57 | .fileup-file .fileup-progress-bar {
58 | width: 1px;
59 | -webkit-transition: width 0.1s ease-out 0.1s;
60 | -moz-transition: width 0.1s ease-out 0.1s;
61 | -o-transition: width 0.1s ease-out 0.1s;
62 | transition: width 0.1s ease-out 0.1s;
63 | }
64 |
65 | .fileup-btn {
66 | position: relative;
67 | overflow: hidden;
68 | display: inline-block;
69 | }
70 | .fileup-btn input {
71 | position: absolute;
72 | top: 0;
73 | right: 0;
74 | margin: 0;
75 | opacity: 0;
76 | -ms-filter: "alpha(opacity=0)";
77 | font-size: 200px;
78 | direction: ltr;
79 | cursor: pointer;
80 | }
81 |
82 | .fileup-dropzone {
83 | background-color: #f6f6ff;
84 | border-width: 1px;
85 | border-style: dashed;
86 | border-color: #0018ff;
87 | cursor: pointer;
88 | }
89 | .fileup-dropzone.over {
90 | opacity: 0.7;
91 | border-style: solid;
92 | }
--------------------------------------------------------------------------------
/dist/fileup.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.fileUp = factory());
5 | })(this, (function () { 'use strict';
6 |
7 | function _typeof(o) {
8 | "@babel/helpers - typeof";
9 |
10 | return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
11 | return typeof o;
12 | } : function (o) {
13 | return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
14 | }, _typeof(o);
15 | }
16 |
17 | var fileUpUtils = {
18 | /**
19 | * Проверка на объект
20 | * @param value
21 | */
22 | isObject: function isObject(value) {
23 | return _typeof(value) === 'object' && !Array.isArray(value) && value !== null;
24 | },
25 | /**
26 | * Проверка на число
27 | * @param num
28 | * @returns {boolean}
29 | * @private
30 | */
31 | isNumeric: function isNumeric(num) {
32 | return (typeof num === 'number' || typeof num === "string" && num.trim() !== '') && !isNaN(num);
33 | },
34 | /**
35 | * Получение размера файла в байтах
36 | * @param {File} file
37 | * @return {int|null}
38 | */
39 | getFileSize: function getFileSize(file) {
40 | if (!(file instanceof File)) {
41 | return null;
42 | }
43 | return file.size || file.fileSize;
44 | },
45 | /**
46 | * Получение названия файла
47 | * @param {File} file
48 | * @return {string|null}
49 | */
50 | getFileName: function getFileName(file) {
51 | if (!(file instanceof File)) {
52 | return null;
53 | }
54 | return file.name || file.fileName;
55 | },
56 | /**
57 | * Formatting size
58 | * @param {int} size
59 | * @returns {string}
60 | */
61 | getSizeHuman: function getSizeHuman(size) {
62 | if (!fileUpUtils.isNumeric(size)) {
63 | return '';
64 | }
65 | size = Number(size);
66 | var result = '';
67 | if (size >= 1073741824) {
68 | result = (size / 1073741824).toFixed(2) + ' Gb';
69 | } else if (size >= 1048576) {
70 | result = (size / 1048576).toFixed(2) + ' Mb';
71 | } else if (size >= 1024) {
72 | result = (size / 1024).toFixed(2) + ' Kb';
73 | } else if (size >= 0) {
74 | result = size + ' bytes';
75 | }
76 | return result;
77 | },
78 | /**
79 | * Создание уникальной строки хэша
80 | * @returns {string}
81 | * @private
82 | */
83 | hashCode: function hashCode() {
84 | return this.crc32((new Date().getTime() + Math.random()).toString()).toString(16);
85 | },
86 | /**
87 | * Hash crc32
88 | * @param str
89 | * @returns {number}
90 | * @private
91 | */
92 | crc32: function crc32(str) {
93 | for (var a, o = [], c = 0; c < 256; c++) {
94 | a = c;
95 | for (var f = 0; f < 8; f++) {
96 | a = 1 & a ? 3988292384 ^ a >>> 1 : a >>> 1;
97 | }
98 | o[c] = a;
99 | }
100 | for (var n = -1, t = 0; t < str.length; t++) {
101 | n = n >>> 8 ^ o[255 & (n ^ str.charCodeAt(t))];
102 | }
103 | return (-1 ^ n) >>> 0;
104 | }
105 | };
106 |
107 | var fileUpEvents = {
108 | /**
109 | * Событие начала загрузки
110 | * @param {object} file
111 | */
112 | onLoadStart: function onLoadStart(file) {
113 | var $file = file.getElement();
114 | if ($file) {
115 | $file.find('.fileup-upload').hide();
116 | $file.find('.fileup-abort').show();
117 | $file.find('.fileup-result').removeClass('fileup-error').removeClass('fileup-success').text('');
118 | }
119 | },
120 | /**
121 | * Событие начала изменения прогресса загрузки
122 | * @param {object} file
123 | * @param {ProgressEvent} ProgressEvent
124 | */
125 | onLoadProgress: function onLoadProgress(file, ProgressEvent) {
126 | if (ProgressEvent.lengthComputable) {
127 | var percent = Math.ceil(ProgressEvent.loaded / ProgressEvent.total * 100);
128 | var $file = file.getElement();
129 | if ($file) {
130 | $file.find('.fileup-progress-bar').css('width', percent + "%");
131 | }
132 | }
133 | },
134 | /**
135 | * Событие начала загрузки
136 | * @param {object} file
137 | */
138 | onLoadAbort: function onLoadAbort(file) {
139 | var $file = file.getElement();
140 | if ($file) {
141 | $file.find('.fileup-abort').hide();
142 | $file.find('.fileup-upload').show();
143 | $file.find('.fileup-result').removeClass('fileup-error').removeClass('fileup-success').text('');
144 | }
145 | },
146 | /**
147 | * Событие успешной загрузки файла
148 | * @param {object} file
149 | */
150 | onSuccess: function onSuccess(file) {
151 | var $file = file.getElement();
152 | if ($file) {
153 | var lang = this.getLang();
154 | $file.find('.fileup-abort').hide();
155 | $file.find('.fileup-upload').hide();
156 | $file.find('.fileup-result').removeClass('fileup-error').addClass('fileup-success').text(lang.complete);
157 | }
158 | },
159 | /**
160 | * Событие ошибки
161 | * @param {string} eventName
162 | * @param {object} options
163 | */
164 | onError: function onError(eventName, options) {
165 | var lang = this.getLang();
166 | switch (eventName) {
167 | case 'files_limit':
168 | alert(lang.errorFilesLimit.replace(/%filesLimit%/g, options.filesLimit));
169 | break;
170 | case 'size_limit':
171 | var size = fileUpUtils.getSizeHuman(options.sizeLimit);
172 | var message = lang.errorSizeLimit;
173 | message = message.replace(/%sizeLimit%/g, size);
174 | message = message.replace(/%fileName%/g, fileUpUtils.getFileName(options.fileData));
175 | alert(message);
176 | break;
177 | case 'file_type':
178 | alert(lang.errorFileType.replace(/%fileName%/g, fileUpUtils.getFileName(options.fileData)));
179 | break;
180 | case 'load_bad_status':
181 | case 'load_error':
182 | case 'load_timeout':
183 | var $file = options.file.getElement();
184 | if ($file) {
185 | var _message = eventName === 'load_bad_status' ? lang.errorBadStatus : lang.errorLoad;
186 | $file.find('.fileup-abort').hide();
187 | $file.find('.fileup-upload').show();
188 | $file.find('.fileup-result').addClass('fileup-error').text(_message);
189 | }
190 | break;
191 | case 'old_browser':
192 | alert(lang.errorOldBrowser);
193 | break;
194 | }
195 | },
196 | /**
197 | * Событие переноса файла через dropzone
198 | * @param {Event} event
199 | */
200 | onDragOver: function onDragOver(event) {
201 | event.stopPropagation();
202 | event.preventDefault();
203 | event.dataTransfer.dropEffect = 'copy';
204 | var dropzone = this.getDropzone();
205 | if (dropzone) {
206 | dropzone.addClass('over');
207 | }
208 | },
209 | /**
210 | * Событие завершения перетаскивания с отпускаем кнопки мыши
211 | * @param {Event} event
212 | */
213 | onDragLeave: function onDragLeave(event) {
214 | var dropzone = this.getDropzone();
215 | if (dropzone) {
216 | dropzone.removeClass('over');
217 | }
218 | },
219 | /**
220 | * Событие когда перетаскиваемый элемент или выделенный текст покидают допустимую цель перетаскивания
221 | * @param {Event} event
222 | */
223 | onDragEnd: function onDragEnd(event) {
224 | var dropzone = this.getDropzone();
225 | if (dropzone) {
226 | dropzone.removeClass('over');
227 | }
228 | },
229 | /**
230 | * Событие переноса файла в dropzone
231 | * @param {Event} event
232 | */
233 | onDragEnter: function onDragEnter(event) {
234 | event.stopPropagation();
235 | event.preventDefault();
236 | event.dataTransfer.dropEffect = 'copy';
237 | }
238 | };
239 |
240 | var fileUpPrivate = {
241 | /**
242 | *
243 | * @param {object} fileUp
244 | */
245 | initInput: function initInput(fileUp) {
246 | var input = null;
247 | if (fileUp._options.input instanceof HTMLElement || fileUp._options.input instanceof jQuery) {
248 | input = $(fileUp._options.input);
249 | } else if (typeof fileUp._options.input === 'string' && fileUp._options.input) {
250 | input = $('#' + fileUp._options.input);
251 | }
252 | if (!input || !$(input)[0] || $(input)[0].type !== 'file') {
253 | throw new Error('Not found input element');
254 | }
255 | fileUp._input = input;
256 | },
257 | /**
258 | *
259 | * @param {object} fileUp
260 | */
261 | initQueue: function initQueue(fileUp) {
262 | var queue = null;
263 | if (fileUp._options.queue instanceof HTMLElement || fileUp._options.queue instanceof jQuery) {
264 | queue = $(fileUp._options.queue);
265 | } else if (typeof fileUp._options.queue === 'string' && fileUp._options.queue) {
266 | queue = $('#' + fileUp._options.queue);
267 | }
268 | if (!queue || !$(queue)[0]) {
269 | throw new Error('Not found queue element');
270 | }
271 | fileUp._queue = queue;
272 | },
273 | /**
274 | *
275 | * @param {object} fileUp
276 | */
277 | initDropzone: function initDropzone(fileUp) {
278 | var dropzone = null;
279 | if (fileUp._options.dropzone instanceof HTMLElement || fileUp._options.dropzone instanceof jQuery) {
280 | dropzone = $(fileUp._options.dropzone);
281 | } else if (typeof fileUp._options.dropzone === 'string' && fileUp._options.dropzone) {
282 | dropzone = $('#' + fileUp._options.dropzone);
283 | }
284 | if (dropzone) {
285 | fileUp._dropzone = dropzone;
286 | var that = this;
287 | dropzone.on('click', function () {
288 | fileUp.getInput().click();
289 | });
290 | dropzone[0].addEventListener('dragover', function (event) {
291 | that.trigger(fileUp, 'drag_over', [event]);
292 | });
293 | dropzone[0].addEventListener('dragleave', function (event) {
294 | that.trigger(fileUp, 'drag_leave', [event]);
295 | });
296 | dropzone[0].addEventListener('dragenter', function (event) {
297 | that.trigger(fileUp, 'drag_enter', [event]);
298 | });
299 | dropzone[0].addEventListener('dragend', function (event) {
300 | that.trigger(fileUp, 'drag_end', [event]);
301 | });
302 | dropzone[0].addEventListener('drop', function (event) {
303 | fileUp.getInput()[0].files = event.target.files || event.dataTransfer.files;
304 | that.appendFiles(fileUp, event);
305 | });
306 | }
307 | },
308 | /**
309 | * Инициализация событий
310 | * @param {object} fileUp
311 | */
312 | initEvents: function initEvents(fileUp) {
313 | /**
314 | * @param {string} name
315 | * @param {function|string} func
316 | */
317 | function setEvent(name, func) {
318 | var event = null;
319 | if (typeof func === 'function') {
320 | event = func;
321 | } else if (typeof func === 'string') {
322 | event = new Function(func);
323 | }
324 | if (event) {
325 | fileUp.on(name, event);
326 | }
327 | }
328 | var options = fileUp.getOptions();
329 | var that = this;
330 | setEvent('load_start', fileUpEvents.onLoadStart);
331 | setEvent('load_progress', fileUpEvents.onLoadProgress);
332 | setEvent('load_abort', fileUpEvents.onLoadAbort);
333 | setEvent('load_success', fileUpEvents.onSuccess);
334 | setEvent('error', fileUpEvents.onError);
335 | setEvent('drag_over', fileUpEvents.onDragOver);
336 | setEvent('drag_leave', fileUpEvents.onDragEnter);
337 | setEvent('drag_end', fileUpEvents.onDragLeave);
338 | setEvent('drag_enter', fileUpEvents.onDragEnd);
339 | if (options.onSelect) {
340 | setEvent('select', options.onSelect);
341 | }
342 | if (options.onRemove) {
343 | setEvent('remove', options.onRemove);
344 | }
345 | if (options.onBeforeStart) {
346 | setEvent('load_before_start', options.onBeforeStart);
347 | }
348 | if (options.onStart) {
349 | setEvent('load_start', options.onStart);
350 | }
351 | if (options.onProgress) {
352 | setEvent('load_progress', options.onProgress);
353 | }
354 | if (options.onAbort) {
355 | setEvent('load_abort', options.onAbort);
356 | }
357 | if (options.onSuccess) {
358 | setEvent('load_success', options.onSuccess);
359 | }
360 | if (options.onFinish) {
361 | setEvent('load_finish', options.onFinish);
362 | }
363 | if (options.onError) {
364 | setEvent('error', options.onError);
365 | }
366 | if (options.onDragOver) {
367 | setEvent('drag_over', options.onDragOver);
368 | }
369 | if (options.onDragLeave) {
370 | setEvent('drag_leave', options.onDragLeave);
371 | }
372 | if (options.onDragEnd) {
373 | setEvent('drag_end', options.onDragEnd);
374 | }
375 | if (options.onDragEnter) {
376 | setEvent('drag_enter', options.onDragEnter);
377 | }
378 | fileUp.getInput().on('change', function (event) {
379 | that.appendFiles(fileUp, event);
380 | });
381 | },
382 | /**
383 | * Формирование списка ранее загруженных файлов
384 | * @param {object} fileUp
385 | */
386 | renderFiles: function renderFiles(fileUp) {
387 | var options = fileUp.getOptions();
388 | if (Array.isArray(options.files) && options.files.length > 0) {
389 | for (var i = 0; i < options.files.length; i++) {
390 | if (!fileUpUtils.isObject(options.files[i])) {
391 | continue;
392 | }
393 | fileUp.appendFileByData(options.files[i]);
394 | }
395 | }
396 | },
397 | /**
398 | * @param fileUp
399 | * @param name
400 | * @param params
401 | * @return {object}
402 | * @private
403 | */
404 | trigger: function trigger(fileUp, name, params) {
405 | params = params || [];
406 | var results = [];
407 | if (fileUp._events[name] instanceof Object && fileUp._events[name].length > 0) {
408 | for (var i = 0; i < fileUp._events[name].length; i++) {
409 | var callback = fileUp._events[name][i].callback;
410 | results.push(callback.apply(fileUp._events[name][i].context || fileUp, params));
411 | if (fileUp._events[name][i].singleExec) {
412 | fileUp._events[name].splice(i, 1);
413 | i--;
414 | }
415 | }
416 | }
417 | return results;
418 | },
419 | /**
420 | * Append files in queue
421 | * @param {object} fileUp
422 | * @param {Event} event
423 | */
424 | appendFiles: function appendFiles(fileUp, event) {
425 | var _this = this;
426 | event.preventDefault();
427 | event.stopPropagation();
428 | var options = fileUp.getOptions();
429 | var input = fileUp.getInput();
430 | var files = input[0].files;
431 | var multiple = input.is("[multiple]");
432 | if (files.length > 0) {
433 | var _loop = function _loop() {
434 | var file = files[i];
435 | if (options.sizeLimit > 0 && fileUpUtils.getFileSize(file) > options.sizeLimit) {
436 | _this.trigger(fileUp, 'error', ['size_limit', {
437 | fileData: file,
438 | sizeLimit: options.sizeLimit
439 | }]);
440 | return 0; // continue
441 | }
442 | if (options.filesLimit > 0 && Object.keys(fileUp._files).length >= options.filesLimit) {
443 | _this.trigger(fileUp, 'error', ['files_limit', {
444 | fileData: file,
445 | filesLimit: options.filesLimit
446 | }]);
447 | return 1; // break
448 | }
449 | if (typeof input[0].accept === 'string') {
450 | var accept = input[0].accept;
451 | if (accept && /[^\w]+/.test(accept)) {
452 | var isAccept = false;
453 | var types = accept.split(',');
454 | if (types.length > 0) {
455 | for (t = 0; t < types.length; t++) {
456 | types[t] = types[t].replace(/\s/g, '');
457 | if (new RegExp(types[t].replace('*', '.*')).test(file.type) || new RegExp(types[t].replace('.', '.*/')).test(file.type)) {
458 | isAccept = true;
459 | break;
460 | }
461 | }
462 | }
463 | if (!isAccept) {
464 | _this.trigger(fileUp, 'error', ['file_type', {
465 | fileData: file
466 | }]);
467 | return 0; // continue
468 | }
469 | }
470 | }
471 | var results = _this.trigger(fileUp, 'select', [file]);
472 | if (results) {
473 | var isContinue = false;
474 | $.each(results, function (key, result) {
475 | if (result === false) {
476 | isContinue = true;
477 | return false;
478 | }
479 | });
480 | if (isContinue) {
481 | return 0; // continue
482 | }
483 | }
484 | if (!multiple) {
485 | fileUp.removeAll();
486 | }
487 | fileUp.appendFile(file);
488 | if (!multiple) {
489 | return 1; // break
490 | }
491 | },
492 | t,
493 | _ret;
494 | for (var i = 0; i < files.length; i++) {
495 | _ret = _loop();
496 | if (_ret === 0) continue;
497 | if (_ret === 1) break;
498 | }
499 | input.val('');
500 | }
501 | this.trigger(fileUp, 'dragEnd', [event]);
502 | }
503 | };
504 |
505 | var fileUpFile = {
506 | _options: {
507 | name: null,
508 | size: null,
509 | urlPreview: null,
510 | urlDownload: null
511 | },
512 | _id: '',
513 | _status: 'stand_by',
514 | _fileElement: null,
515 | _file: null,
516 | _fileUp: null,
517 | _xhr: null,
518 | /**
519 | * Инициализация
520 | * @param {object} fileUp
521 | * @param {int} id
522 | * @param {object} options
523 | * @param {File} file
524 | * @private
525 | */
526 | _init: function _init(fileUp, id, options, file) {
527 | if (!fileUpUtils.isObject(options)) {
528 | throw new Error('File incorrect options param');
529 | }
530 | if (typeof id !== 'number' || id < 0) {
531 | throw new Error('File dont set or incorrect id param');
532 | }
533 | if (typeof options.name !== 'string' || !options.name) {
534 | throw new Error('File dont set name param');
535 | }
536 | this._fileUp = fileUp;
537 | this._options = $.extend(true, {}, this._options, options);
538 | this._id = id;
539 | if (file instanceof File) {
540 | var xhr = null;
541 | if (window.XMLHttpRequest) {
542 | xhr = "onload" in new XMLHttpRequest() ? new XMLHttpRequest() : new XDomainRequest();
543 | } else if (window.ActiveXObject) {
544 | try {
545 | xhr = new ActiveXObject("Msxml2.XMLHTTP");
546 | } catch (e) {
547 | try {
548 | xhr = new ActiveXObject("Microsoft.XMLHTTP");
549 | } catch (e) {
550 | fileUpPrivate.trigger(fileUp, 'error', ['old_browser', {
551 | file: this
552 | }]);
553 | }
554 | }
555 | } else {
556 | fileUpPrivate.trigger(fileUp, 'error', ['old_browser', {
557 | file: this
558 | }]);
559 | }
560 | if (!xhr) {
561 | throw new Error('xhr dont created. Check your browser');
562 | }
563 | this._xhr = xhr;
564 | this._file = file;
565 | } else {
566 | this._status = 'finish';
567 | }
568 | },
569 | /**
570 | * Получение id файла
571 | * @return {null}
572 | */
573 | getId: function getId() {
574 | return this._id;
575 | },
576 | /**
577 | * Получение name
578 | * @return {string|null}
579 | */
580 | getName: function getName() {
581 | return this._file ? fileUpUtils.getFileName(this._file) : this._options.name;
582 | },
583 | /**
584 | * Получение элемента файла
585 | * @return {jQuery|null}
586 | */
587 | getElement: function getElement() {
588 | return this._fileElement;
589 | },
590 | /**
591 | * Получение urlPreview
592 | * @return {string|null}
593 | */
594 | getUrlPreview: function getUrlPreview() {
595 | return this._options.urlPreview;
596 | },
597 | /**
598 | * Получение urlDownload
599 | * @return {string|null}
600 | */
601 | getUrlDownload: function getUrlDownload() {
602 | return this._options.urlDownload;
603 | },
604 | /**
605 | * Получение size
606 | * @return {int|null}
607 | */
608 | getSize: function getSize() {
609 | return this._file ? fileUpUtils.getFileSize(this._file) : this._options.size;
610 | },
611 | /**
612 | * Formatting size
613 | * @returns {string}
614 | */
615 | getSizeHuman: function getSizeHuman() {
616 | var size = this.getSize();
617 | return fileUpUtils.getSizeHuman(size);
618 | },
619 | /**
620 | * Получение xhr
621 | * @return {XMLHttpRequest|null}
622 | */
623 | getXhr: function getXhr() {
624 | return this._xhr;
625 | },
626 | /**
627 | * Получение файла
628 | * @return {File|null}
629 | */
630 | getFile: function getFile() {
631 | if (!(this._file instanceof File)) {
632 | return null;
633 | }
634 | return this._file;
635 | },
636 | /**
637 | * Получение статуса
638 | * @return {string}
639 | */
640 | getStatus: function getStatus() {
641 | return this._status;
642 | },
643 | /**
644 | * Установка статуса
645 | * @param {string} status
646 | */
647 | setStatus: function setStatus(status) {
648 | if (typeof status !== 'string') {
649 | return;
650 | }
651 | this._status = status;
652 | },
653 | /**
654 | * Получение параметров
655 | *
656 | * @returns {object}
657 | */
658 | getOptions: function getOptions() {
659 | return this._options;
660 | },
661 | /**
662 | * Получение параметра
663 | * @param {string} name
664 | * @returns {*}
665 | */
666 | getOption: function getOption(name) {
667 | if (typeof name !== 'string' || !this._options.hasOwnProperty(name)) {
668 | return null;
669 | }
670 | return this._options[name];
671 | },
672 | /**
673 | * Установка параметра
674 | * @param {string} name
675 | * @param {*} value
676 | */
677 | setOption: function setOption(name, value) {
678 | if (typeof name !== 'string') {
679 | return;
680 | }
681 | this._options[name] = value;
682 | },
683 | /**
684 | * Показ сообщения об ошибке
685 | * @param {string} message
686 | */
687 | showError: function showError(message) {
688 | if (typeof message !== 'string') {
689 | return;
690 | }
691 | var element = this.getElement();
692 | if (element) {
693 | element.find('.fileup-result').removeClass('fileup-success').addClass('fileup-error').text(message);
694 | }
695 | },
696 | /**
697 | * Показ сообщения об успехе
698 | * @param {string} message
699 | */
700 | showSuccess: function showSuccess(message) {
701 | if (typeof message !== 'string') {
702 | return;
703 | }
704 | var element = this.getElement();
705 | if (element) {
706 | element.find('.fileup-result').removeClass('fileup-error').addClass('fileup-success').text(message);
707 | }
708 | },
709 | /**
710 | * Удаление файла на странице и из памяти
711 | */
712 | remove: function remove() {
713 | this.abort();
714 | if (this._fileElement) {
715 | this._fileElement.fadeOut('fast', function () {
716 | this.remove();
717 | });
718 | }
719 | var fileId = this.getId();
720 | if (this._fileUp._files.hasOwnProperty(fileId)) {
721 | delete this._fileUp._files[fileId];
722 | }
723 | fileUpPrivate.trigger(this._fileUp, 'remove', [this]);
724 | },
725 | /**
726 | * Загрузка файла
727 | * @return {boolean}
728 | */
729 | upload: function upload() {
730 | var file = this.getFile();
731 | var xhr = this.getXhr();
732 | if (!file || !xhr) {
733 | return false;
734 | }
735 | var options = this._fileUp.getOptions();
736 | var that = this;
737 | if (typeof options.timeout === 'number') {
738 | xhr.timeout = options.timeout;
739 | }
740 |
741 | // запрос начат
742 | xhr.onloadstart = function () {
743 | that.setStatus('load_start');
744 | fileUpPrivate.trigger(that._fileUp, 'load_start', [that]);
745 | };
746 |
747 | // браузер получил очередной пакет данных
748 | xhr.upload.onprogress = function (ProgressEvent) {
749 | fileUpPrivate.trigger(that._fileUp, 'load_progress', [that, ProgressEvent]);
750 | };
751 |
752 | // запрос был успешно (без ошибок) завершён
753 | xhr.onload = function () {
754 | that.setStatus('loaded');
755 | if (xhr.status === 200) {
756 | fileUpPrivate.trigger(that._fileUp, 'load_success', [that, xhr.responseText]);
757 | } else {
758 | fileUpPrivate.trigger(that._fileUp, 'error', ['load_bad_status', {
759 | file: that,
760 | fileData: file,
761 | response: xhr.responseText,
762 | xhr: xhr
763 | }]);
764 | }
765 | };
766 |
767 | // запрос был завершён (успешно или неуспешно)
768 | xhr.onloadend = function () {
769 | that.setStatus('finish');
770 | fileUpPrivate.trigger(that._fileUp, 'load_finish', [that]);
771 | };
772 |
773 | // запрос был отменён вызовом xhr.abort()
774 | xhr.onabort = function () {
775 | that.setStatus('stand_by');
776 | fileUpPrivate.trigger(that._fileUp, 'load_abort', [that]);
777 | };
778 |
779 | // запрос был прекращён по таймауту
780 | xhr.ontimeout = function () {
781 | that.setStatus('stand_by');
782 | fileUpPrivate.trigger(that._fileUp, 'error', ['load_timeout', {
783 | file: that,
784 | fileData: file
785 | }]);
786 | };
787 |
788 | // произошла ошибка
789 | xhr.onerror = function (event) {
790 | that.setStatus('stand_by');
791 | fileUpPrivate.trigger(that._fileUp, 'error', ['load_error', {
792 | file: that,
793 | fileData: file,
794 | event: event
795 | }]);
796 | };
797 | xhr.open(options.httpMethod || 'post', options.url, true);
798 | xhr.setRequestHeader('Cache-Control', 'no-cache');
799 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
800 | fileUpPrivate.trigger(that._fileUp, 'load_before_start', [that, xhr]);
801 | if (window.FormData !== undefined) {
802 | var formData = new FormData();
803 | formData.append(options.fieldName, file);
804 | if (Object.keys(options.extraFields).length) {
805 | $.each(options.extraFields, function (name, value) {
806 | formData.append(name, value);
807 | });
808 | }
809 | return xhr.send(formData);
810 | } else {
811 | // IE 8,9
812 | return xhr.send(file);
813 | }
814 | },
815 | /**
816 | * Отмена загрузки
817 | */
818 | abort: function abort() {
819 | if (this._xhr) {
820 | this._xhr.abort();
821 | }
822 | },
823 | /**
824 | * Рендер элемента
825 | * @param {string} tpl
826 | * @return {string|null}
827 | */
828 | render: function render(tpl) {
829 | if (!tpl || typeof tpl !== 'string') {
830 | return null;
831 | }
832 | var lang = this._fileUp.getLang();
833 | var options = this._fileUp.getOptions();
834 | var that = this;
835 | var isNoPreview = false;
836 | var mimeTypes = fileUpUtils.isObject(options.mimeTypes) ? options.mimeTypes : {};
837 | var iconDefault = typeof options.iconDefault === 'string' ? options.iconDefault : '';
838 | var showRemove = typeof options.showRemove === 'boolean' ? options.showRemove : true;
839 | var size = this.getSizeHuman();
840 | var icon = null;
841 | var fileType = null;
842 | var fileExt = null;
843 | tpl = tpl.replace(/\[NAME\]/g, this.getName());
844 | tpl = tpl.replace(/\[SIZE\]/g, size);
845 | tpl = tpl.replace(/\[UPLOAD\]/g, lang.upload);
846 | tpl = tpl.replace(/\[REMOVE\]/g, lang.remove);
847 | tpl = tpl.replace(/\[ABORT\]/g, lang.abort);
848 | if (this._file && this._file instanceof File) {
849 | if (this._file.type && typeof this._file.type === 'string' && this._file.type.match(/^image\/.*/)) {
850 | if (typeof FileReader !== 'undefined') {
851 | var reader = new FileReader();
852 | reader.onload = function (ProgressEvent) {
853 | if (that._fileElement) {
854 | var preview = that._fileElement.find('.fileup-preview');
855 | preview.removeClass('no-preview').find('img').attr('src', ProgressEvent.target.result);
856 | }
857 | };
858 | reader.readAsDataURL(this._file);
859 | }
860 | isNoPreview = true;
861 | tpl = tpl.replace(/\[PREVIEW_SRC\]/g, '');
862 | tpl = tpl.replace(/\[TYPE\]/g, 'fileup-image fileup-no-preview');
863 | } else {
864 | tpl = tpl.replace(/\[PREVIEW_SRC\]/g, '');
865 | tpl = tpl.replace(/\[TYPE\]/g, 'fileup-doc');
866 | fileType = this._file.type;
867 | fileExt = this.getName().split('.').pop();
868 | }
869 | } else {
870 | var urlPreview = this.getUrlPreview();
871 | tpl = tpl.replace(/\[PREVIEW_SRC\]/g, urlPreview ? urlPreview : '');
872 | tpl = tpl.replace(/\[TYPE\]/g, urlPreview ? 'fileup-image' : 'fileup-doc');
873 | fileExt = this.getName() ? this.getName().split('.').pop().toLowerCase() : '';
874 | }
875 | this._fileElement = $(tpl);
876 | if (isNoPreview) {
877 | this._fileElement.find('.fileup-preview').addClass('no-preview');
878 | }
879 | if (!size) {
880 | this._fileElement.find('.fileup-size').hide();
881 | }
882 | if (fileType || fileExt) {
883 | $.each(mimeTypes, function (name, type) {
884 | if (!fileUpUtils.isObject(type) || !type.hasOwnProperty('icon') || typeof type.icon !== 'string' || type.icon === '') {
885 | return;
886 | }
887 | if (fileType && type.hasOwnProperty('mime')) {
888 | if (typeof type.mime === 'string') {
889 | if (type.mime === fileType) {
890 | icon = type.icon;
891 | return false;
892 | }
893 | } else if (Array.isArray(type.mime)) {
894 | $.each(type.mime, function (key, mime) {
895 | if (typeof mime === 'string' && mime === fileType) {
896 | icon = type.icon;
897 | return false;
898 | }
899 | });
900 | if (icon) {
901 | return false;
902 | }
903 | } else if (type.mime instanceof RegExp) {
904 | if (type.mime.test(fileType)) {
905 | icon = type.icon;
906 | return false;
907 | }
908 | }
909 | }
910 | if (fileExt && type.hasOwnProperty('ext') && Array.isArray(type.ext)) {
911 | $.each(type.ext, function (key, ext) {
912 | if (typeof ext === 'string' && ext === fileExt) {
913 | icon = type.icon;
914 | return false;
915 | }
916 | });
917 | if (icon) {
918 | return false;
919 | }
920 | }
921 | });
922 | }
923 | if (!icon) {
924 | icon = iconDefault;
925 | }
926 | this._fileElement.find('.fileup-icon').addClass(icon);
927 | if (!showRemove) {
928 | this._fileElement.find('.fileup-remove').hide();
929 | }
930 | if (this.getUrlDownload()) {
931 | var $name = this._fileElement.find('.fileup-name');
932 | if ($name[0]) {
933 | $name.replaceWith('' + this.getName() + '');
934 | }
935 | }
936 | if (this._status === 'finish') {
937 | this._fileElement.find('.fileup-upload').hide();
938 | this._fileElement.find('.fileup-abort').hide();
939 | this._fileElement.find('.fileup-progress').hide();
940 | } else {
941 | this._fileElement.find('.fileup-upload').click(function () {
942 | that.upload();
943 | });
944 | this._fileElement.find('.fileup-abort').click(function () {
945 | that.abort();
946 | });
947 | }
948 | this._fileElement.find('.fileup-remove').click(function () {
949 | that.remove();
950 | });
951 | return this._fileElement;
952 | }
953 | };
954 |
955 | var tpl = Object.create(null);
956 | tpl['file.html'] = ' [NAME] ([SIZE])
✕ [UPLOAD] [ABORT]
';
957 |
958 | var fileUpInstance = {
959 | _options: {
960 | id: null,
961 | url: null,
962 | input: null,
963 | queue: null,
964 | dropzone: null,
965 | files: [],
966 | fieldName: 'file',
967 | extraFields: {},
968 | lang: 'en',
969 | langItems: null,
970 | sizeLimit: 0,
971 | filesLimit: 0,
972 | httpMethod: 'post',
973 | timeout: null,
974 | autostart: false,
975 | showRemove: true,
976 | templateFile: null,
977 | onSelect: null,
978 | onRemove: null,
979 | onBeforeStart: null,
980 | onStart: null,
981 | onProgress: null,
982 | onAbort: null,
983 | onSuccess: null,
984 | onFinish: null,
985 | onError: null,
986 | onDragOver: null,
987 | onDragLeave: null,
988 | onDragEnd: null,
989 | onDragEnter: null,
990 | iconDefault: 'bi bi-file-earmark-text',
991 | mimeTypes: {
992 | archive: {
993 | mime: ['application/zip', 'application/gzip', 'application/x-bzip', 'application/x-bzip2', 'application/x-7z-compressed'],
994 | ext: ['zip', '7z', 'bz', 'bz2', 'gz', 'jar', 'rar', 'tar'],
995 | icon: 'bi bi-file-earmark-zip'
996 | },
997 | word: {
998 | mime: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
999 | ext: ['doc', 'docx'],
1000 | icon: 'bi bi-file-earmark-word'
1001 | },
1002 | excel: {
1003 | mime: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
1004 | ext: ['xls', 'xlsx'],
1005 | icon: 'bi bi-file-earmark-excel'
1006 | },
1007 | image: {
1008 | mime: /image\/.*/,
1009 | ext: ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'raw', 'webp', 'heic', 'ico'],
1010 | icon: 'bi bi-file-earmark-image'
1011 | },
1012 | video: {
1013 | mime: /video\/.*/,
1014 | ext: ['avi', 'mp4', 'mpeg', 'ogv', 'ts', 'webm', '3gp', '3g2', 'mkv'],
1015 | icon: 'bi bi-file-earmark-play'
1016 | },
1017 | audio: {
1018 | mime: /audio\/.*/,
1019 | ext: ['avi', 'mp4', 'mpeg', 'ogv', 'ts', 'webm', '3gp', '3g2', 'mkv'],
1020 | icon: 'bi bi-file-earmark-music'
1021 | },
1022 | pdf: {
1023 | mime: ['application/pdf'],
1024 | ext: ['pdf'],
1025 | icon: 'bi bi-file-earmark-pdf'
1026 | },
1027 | binary: {
1028 | mime: ['application\/octet-stream'],
1029 | ext: ['bin', 'exe', 'dat', 'dll'],
1030 | icon: 'bi bi-file-earmark-binary'
1031 | }
1032 | }
1033 | },
1034 | _id: null,
1035 | _fileUp: null,
1036 | _fileIndex: 0,
1037 | _input: null,
1038 | _queue: null,
1039 | _dropzone: null,
1040 | _files: {},
1041 | _events: {},
1042 | /**
1043 | * Инициализация
1044 | * @param {object} fileUp
1045 | * @param {object} options
1046 | * @private
1047 | */
1048 | _init: function _init(fileUp, options) {
1049 | if (typeof options.url !== 'string' || !options.url) {
1050 | throw new Error('Dont set url param');
1051 | }
1052 | this._fileUp = fileUp;
1053 | this._options = $.extend(true, {}, this._options, options);
1054 | this._id = typeof this._options.id === 'string' && this._options.id ? this._options.id : fileUpUtils.hashCode();
1055 | if (!this._options.templateFile || typeof this._options.templateFile !== 'string') {
1056 | this._options.templateFile = tpl['file.html'];
1057 | }
1058 | fileUpPrivate.initInput(this);
1059 | fileUpPrivate.initQueue(this);
1060 | fileUpPrivate.initDropzone(this);
1061 | fileUpPrivate.initEvents(this);
1062 | fileUpPrivate.renderFiles(this);
1063 | },
1064 | /**
1065 | * Разрушение экземпляра
1066 | */
1067 | destruct: function destruct() {
1068 | var id = this.getId();
1069 | if (!this._fileUp._instances.hasOwnProperty(id)) {
1070 | return;
1071 | }
1072 | delete this._fileUp._instances[id];
1073 | },
1074 | /**
1075 | * Получение параметров
1076 | * @returns {object}
1077 | */
1078 | getOptions: function getOptions() {
1079 | return this._options;
1080 | },
1081 | /**
1082 | * Получение id
1083 | * @return {string|null}
1084 | */
1085 | getId: function getId() {
1086 | return this._id;
1087 | },
1088 | /**
1089 | * Получение input
1090 | * @return {jQuery|null}
1091 | */
1092 | getInput: function getInput() {
1093 | return this._input;
1094 | },
1095 | /**
1096 | * Получение queue
1097 | * @return {jQuery|null}
1098 | */
1099 | getQueue: function getQueue() {
1100 | return this._queue;
1101 | },
1102 | /**
1103 | * Получение dropzone
1104 | * @return {jQuery|null}
1105 | */
1106 | getDropzone: function getDropzone() {
1107 | return this._dropzone;
1108 | },
1109 | /**
1110 | * Подписка на событие
1111 | * @param {string} eventName
1112 | * @param {function|string} callback
1113 | * @param {object|undefined} context
1114 | */
1115 | on: function on(eventName, callback, context) {
1116 | if (_typeof(this._events[eventName]) !== 'object') {
1117 | this._events[eventName] = [];
1118 | }
1119 | this._events[eventName].push({
1120 | context: context || this,
1121 | callback: callback,
1122 | singleExec: false
1123 | });
1124 | },
1125 | /**
1126 | * Подписка на событие таким образом, что выполнение произойдет лишь один раз
1127 | * @param {string} eventName
1128 | * @param {function|string} callback
1129 | * @param {object|undefined} context
1130 | */
1131 | one: function one(eventName, callback, context) {
1132 | if (_typeof(this._events[eventName]) !== 'object') {
1133 | this._events[eventName] = [];
1134 | }
1135 | this._events[eventName].push({
1136 | context: context || this,
1137 | callback: callback,
1138 | singleExec: true
1139 | });
1140 | },
1141 | /**
1142 | * Получение настроек языка
1143 | */
1144 | getLang: function getLang() {
1145 | return $.extend(true, {}, this._options.langItems);
1146 | },
1147 | /**
1148 | * Получение всех файлов
1149 | * @return {object}
1150 | */
1151 | getFiles: function getFiles() {
1152 | return this._files;
1153 | },
1154 | /**
1155 | * Получение файла по его id
1156 | * @param {int} fileId
1157 | * @return {object|null}
1158 | */
1159 | getFileById: function getFileById(fileId) {
1160 | var result = null;
1161 | $.each(this._files, function (key, file) {
1162 | if (fileId === file.getId()) {
1163 | result = file;
1164 | }
1165 | });
1166 | return result;
1167 | },
1168 | /**
1169 | * Удаление всех файлов
1170 | */
1171 | removeAll: function removeAll() {
1172 | $.each(this._files, function (key, file) {
1173 | file.remove();
1174 | });
1175 | },
1176 | /**
1177 | * Загрузка всех файлов
1178 | */
1179 | uploadAll: function uploadAll() {
1180 | $.each(this._files, function (key, file) {
1181 | file.upload();
1182 | });
1183 | },
1184 | /**
1185 | * Отмена загрузки всех файлов
1186 | */
1187 | abortAll: function abortAll() {
1188 | $.each(this._files, function (key, file) {
1189 | file.abort();
1190 | });
1191 | },
1192 | /**
1193 | * Добавление файла в список из объекта File
1194 | * @param {object} file
1195 | * @result {boolean}
1196 | */
1197 | appendFile: function appendFile(file) {
1198 | if (!(file instanceof File)) {
1199 | return false;
1200 | }
1201 | var fileInstance = $.extend(true, {}, fileUpFile);
1202 | var data = {
1203 | name: fileUpUtils.getFileName(file),
1204 | size: fileUpUtils.getFileSize(file),
1205 | type: file.type
1206 | };
1207 | fileInstance._init(this, this._fileIndex, data, file);
1208 | this._files[this._fileIndex] = fileInstance;
1209 | var queue = this.getQueue();
1210 | if (queue) {
1211 | queue.append(fileInstance.render(this._options.templateFile));
1212 | }
1213 | this._fileIndex++;
1214 | if (typeof this._options.autostart === 'boolean' && this._options.autostart) {
1215 | fileInstance.upload();
1216 | }
1217 | return true;
1218 | },
1219 | /**
1220 | * Добавление файла в список из данных
1221 | * @param {object} data
1222 | * @result {boolean}
1223 | */
1224 | appendFileByData: function appendFileByData(data) {
1225 | if (!fileUpUtils.isObject(data)) {
1226 | return false;
1227 | }
1228 | var fileInstance = $.extend(true, {}, fileUpFile);
1229 | fileInstance._init(this, this._fileIndex, data);
1230 | fileInstance.setStatus('finish');
1231 | this._files[this._fileIndex] = fileInstance;
1232 | var queue = this.getQueue();
1233 | if (queue) {
1234 | queue.append(fileInstance.render(this._options.templateFile));
1235 | }
1236 | this._fileIndex++;
1237 | return true;
1238 | }
1239 | };
1240 |
1241 | var fileUp = {
1242 | lang: {},
1243 | _instances: {},
1244 | /**
1245 | * Создание экземпляра
1246 | * @param {object} options
1247 | * @returns {object}
1248 | */
1249 | create: function create(options) {
1250 | options = fileUpUtils.isObject(options) ? options : {};
1251 | if (!options.hasOwnProperty('lang')) {
1252 | options.lang = 'en';
1253 | }
1254 | var langList = this.lang.hasOwnProperty(options.lang) ? this.lang[options.lang] : {};
1255 | options.langItems = options.hasOwnProperty('langItems') && fileUpUtils.isObject(options.langItems) ? $.extend(true, {}, langList, options.langItems) : langList;
1256 | var instance = $.extend(true, {}, fileUpInstance);
1257 | instance._init(this, options);
1258 | var id = instance.getId();
1259 | this._instances[id] = instance;
1260 | return instance;
1261 | },
1262 | /**
1263 | * Получение экземпляра по id
1264 | * @param {string} id
1265 | * @returns {object|null}
1266 | */
1267 | get: function get(id) {
1268 | if (!this._instances.hasOwnProperty(id)) {
1269 | return null;
1270 | }
1271 | if (!$.contains(document, this._instances[id]._input[0])) {
1272 | delete this._instances[id];
1273 | return null;
1274 | }
1275 | return this._instances[id];
1276 | }
1277 | };
1278 |
1279 | fileUp.lang.en = {
1280 | upload: 'Upload',
1281 | abort: 'Abort',
1282 | remove: 'Remove',
1283 | complete: 'Complete',
1284 | error: 'Error',
1285 | errorLoad: 'Error uploading file',
1286 | errorBadStatus: 'Error uploading file. Bad request.',
1287 | errorFilesLimit: 'The number of selected files exceeds the limit (%filesLimit%)',
1288 | errorSizeLimit: 'File "%fileName%" exceeds the size limit (%sizeLimit%)',
1289 | errorFileType: 'File "%fileName%" is incorrect',
1290 | errorOldBrowser: 'Your browser can not upload files. Update to the latest version'
1291 | };
1292 |
1293 | fileUp.lang.ru = {
1294 | upload: 'Загрузить',
1295 | abort: 'Остановить',
1296 | remove: 'Удалить',
1297 | complete: 'Готово',
1298 | error: 'Ошибка',
1299 | errorLoad: 'Ошибка при загрузке файла',
1300 | errorBadStatus: 'Ошибка при загрузке файла. Некорректный запрос.',
1301 | errorFilesLimit: 'Количество выбранных файлов превышает лимит (%filesLimit%)',
1302 | errorSizeLimit: 'Файл "%fileName%" превышает предельный размер (%sizeLimit%)',
1303 | errorFileType: 'Файл "%fileName%" является некорректным',
1304 | errorOldBrowser: 'Обновите ваш браузер до последней версии'
1305 | };
1306 |
1307 | fileUp.lang.es = {
1308 | upload: 'Subir',
1309 | abort: 'Cancelar',
1310 | remove: 'Eliminar',
1311 | complete: 'Cargado',
1312 | error: 'Error',
1313 | errorLoad: 'Error al cargar el archivo',
1314 | errorBadStatus: 'Error al cargar el archivo. Solicitud no válida.',
1315 | errorFilesLimit: 'El número de archivo selecccionados excede el límite (%filesLimit%)',
1316 | errorSizeLimit: 'El archivo "%fileName%" excede el limite de tamaño (%sizeLimit%)',
1317 | errorFileType: 'El archivo "%fileName%" es inválido',
1318 | errorOldBrowser: 'Tu navegador no puede subir archivos. Actualiza a la última versión'
1319 | };
1320 |
1321 | fileUp.lang.pt = {
1322 | upload: 'Enviar',
1323 | abort: 'Cancelar',
1324 | remove: 'Remover',
1325 | complete: 'Enviado',
1326 | error: 'Erro',
1327 | errorLoad: 'Erro ao carregar o arquivo',
1328 | errorBadStatus: 'Erro ao carregar o arquivo. Pedido inválido.',
1329 | errorFilesLimit: 'O número de arquivos selecionados excede o limite (%filesLimit%)',
1330 | errorSizeLimit: 'Arquivo "%fileName%" excede o limite (%sizeLimit%)',
1331 | errorFileType: 'Arquivo "%fileName%" inválido',
1332 | errorOldBrowser: 'Seu navegador não pode enviar os arquivos. Atualize para a versão mais recente'
1333 | };
1334 |
1335 | return fileUp;
1336 |
1337 | }));
1338 |
--------------------------------------------------------------------------------
/dist/fileup.min.css:
--------------------------------------------------------------------------------
1 | .fileup-file{font-size:12px;width:350px;position:relative;overflow:hidden}.fileup-file.fileup-image .fileup-preview.no-preview{width:80px;height:56px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA4CAAAAABP3SBGAAACW0lEQVRYw+3Y3U8aQRAAcP7/98bb3YFDxSvUBCKlxigllVrFILFEmmJrxdYrB7e7Q+JfUD4Ocgcs7OX2oQ/OAwmZ8Mt+zO7NkcraZiOVSRuNTMp+BU2BzCIJAyIgK19eJIv6PoRB0njBRDHiBRYG6Rf0EwXvv/3fQM6Ngsjd5/GHKZCLdvkgV2wOhSmwRglj1Kp43AgoG9a05mCnKk2AvO+w4HjZj8IAKLsAwcmlLdQEl4oiCt6x+VVAGpogf3KFEhQPmWCEwNpSAZKLKHh0NNwwxhIJZuy4XAvEO2adqGctuzad7gm9RV8H5H6RpklVqMWOM74Arb2m9LVAbFFIA6lJteg2q6dXT9LXArlXmMwIyLla5CglCl8PxMZszWGlOKX+9RUC+XMuqDOg1xGx31Ev6wYQz6153QK0wkt7Qz4rRTUoe7uLg5Bm6a+jxU9ch9LToYwL4pkVesyyTAdDIwer/FfGA+XP+bmaXyjfZxn5y54krMMexgJFhURbAbp7P02JD7MEyXUxBojfAJaaC7r/gNPTGCSo3cYYIyzRlXaFOj3JB4eLBIPGasUrQLylsNoAkfzvl6vQVjH6iQstkA/e0XUtFSneH7DQdyDHntQB8Zqsb9JYdmngVukPbge5GxlHOGB1GR5wKyjrRL+zpHsd3AJyL09j9KoscxPqRdaDBRan+2WsLrhJcLzZZ0NhEpzcFa7cBDo7NGa8cX5w9S57teOTuFH5OHs0ry9sIeOHP9TpHJL32MlBLx8FL0c8UYhB9D0FCpX3yaKchei7Hk0a8PoCbgw0/a/IP7jBCOMW5IDRAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.fileup-file.fileup-image .fileup-preview.no-preview img{display:none}.fileup-file.fileup-image .fileup-preview .fileup-icon{display:none}.fileup-file.fileup-doc .fileup-preview img{display:none}.fileup-file .fileup-preview img{max-height:80px;max-width:80px}.fileup-file .fileup-description{padding-right:20px;word-break:break-all}.fileup-file .fileup-controls .fileup-remove{cursor:pointer;position:absolute;top:0;right:2px;width:16px;height:16px;font-size:16px;color:#9e9e9e}.fileup-file .fileup-controls .fileup-remove:hover{color:#616161}.fileup-file .fileup-controls .fileup-upload,.fileup-file .fileup-controls .fileup-abort{cursor:pointer}.fileup-file .fileup-result.fileup-success{color:#4cae4c}.fileup-file .fileup-result.fileup-error{color:#ce0000}.fileup-file .fileup-progress{height:3px}.fileup-file .fileup-progress-bar{width:1px;-webkit-transition:width .1s ease-out .1s;-moz-transition:width .1s ease-out .1s;-o-transition:width .1s ease-out .1s;transition:width .1s ease-out .1s}.fileup-btn{position:relative;overflow:hidden;display:inline-block}.fileup-btn input{position:absolute;top:0;right:0;margin:0;opacity:0;-ms-filter:"alpha(opacity=0)";font-size:200px;direction:ltr;cursor:pointer}.fileup-dropzone{background-color:#f6f6ff;border-width:1px;border-style:dashed;border-color:#0018ff;cursor:pointer}.fileup-dropzone.over{opacity:.7;border-style:solid}
2 | /*# sourceMappingURL=fileup.min.css.map */
3 |
--------------------------------------------------------------------------------
/dist/fileup.min.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["fileup.scss","_varaible.scss"],"names":[],"mappings":"AAAA,aACI,eACA,MCCmB,wBDCnB,gBAII,qDACI,WACA,YACA,65BACA,4BACA,wBAEA,yDACI,aAIR,uDACI,aAKJ,4CACI,aAIR,iCACI,gBACA,eAGJ,iCACI,mBACA,qBAIA,6CACI,eACA,kBACA,MACA,UACA,WACA,YACA,eACA,cAEJ,mDACI,cAGJ,yFAEI,eAMJ,2CACI,MChEW,QDkEf,yCACI,MClEW,QDsEnB,8BACI,WAEJ,kCACI,UACA,0CACA,uCACA,qCACA,kCAIR,YACI,kBACA,gBACA,qBAEA,kBACI,kBACA,MACA,QACA,SACA,UACA,8BACA,gBACA,cACA,eAIR,iBACI,iBClG2B,QDmG3B,aChG2B,IDiG3B,aClG2B,ODmG3B,aCpG2B,QDqG3B,eAEA,sBACI,WACA","file":"fileup.min.css","sourcesContent":[".fileup-file {\r\n font-size: 12px;\r\n width: $fileup-file-width;\r\n position: relative;\r\n overflow: hidden;\r\n\r\n &.fileup-image .fileup-preview {\r\n\r\n &.no-preview {\r\n width: 80px;\r\n height: 56px;\r\n background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA4CAAAAABP3SBGAAACW0lEQVRYw+3Y3U8aQRAAcP7/98bb3YFDxSvUBCKlxigllVrFILFEmmJrxdYrB7e7Q+JfUD4Ocgcs7OX2oQ/OAwmZ8Mt+zO7NkcraZiOVSRuNTMp+BU2BzCIJAyIgK19eJIv6PoRB0njBRDHiBRYG6Rf0EwXvv/3fQM6Ngsjd5/GHKZCLdvkgV2wOhSmwRglj1Kp43AgoG9a05mCnKk2AvO+w4HjZj8IAKLsAwcmlLdQEl4oiCt6x+VVAGpogf3KFEhQPmWCEwNpSAZKLKHh0NNwwxhIJZuy4XAvEO2adqGctuzad7gm9RV8H5H6RpklVqMWOM74Arb2m9LVAbFFIA6lJteg2q6dXT9LXArlXmMwIyLla5CglCl8PxMZszWGlOKX+9RUC+XMuqDOg1xGx31Ev6wYQz6153QK0wkt7Qz4rRTUoe7uLg5Bm6a+jxU9ch9LToYwL4pkVesyyTAdDIwer/FfGA+XP+bmaXyjfZxn5y54krMMexgJFhURbAbp7P02JD7MEyXUxBojfAJaaC7r/gNPTGCSo3cYYIyzRlXaFOj3JB4eLBIPGasUrQLylsNoAkfzvl6vQVjH6iQstkA/e0XUtFSneH7DQdyDHntQB8Zqsb9JYdmngVukPbge5GxlHOGB1GR5wKyjrRL+zpHsd3AJyL09j9KoscxPqRdaDBRan+2WsLrhJcLzZZ0NhEpzcFa7cBDo7NGa8cX5w9S57teOTuFH5OHs0ry9sIeOHP9TpHJL32MlBLx8FL0c8UYhB9D0FCpX3yaKchei7Hk0a8PoCbgw0/a/IP7jBCOMW5IDRAAAAAElFTkSuQmCC);\r\n background-repeat: no-repeat;\r\n background-size: contain;\r\n\r\n img {\r\n display: none;\r\n }\r\n }\r\n\r\n .fileup-icon {\r\n display: none;\r\n }\r\n }\r\n\r\n &.fileup-doc .fileup-preview {\r\n img {\r\n display: none;\r\n }\r\n }\r\n\r\n .fileup-preview img {\r\n max-height: 80px;\r\n max-width: 80px;\r\n }\r\n\r\n .fileup-description {\r\n padding-right: 20px;\r\n word-break: break-all;\r\n }\r\n\r\n .fileup-controls {\r\n .fileup-remove {\r\n cursor: pointer;\r\n position: absolute;\r\n top: 0;\r\n right: 2px;\r\n width: 16px;\r\n height: 16px;\r\n font-size: 16px;\r\n color: #9e9e9e;\r\n }\r\n .fileup-remove:hover {\r\n color: #616161;\r\n }\r\n\r\n .fileup-upload,\r\n .fileup-abort {\r\n cursor: pointer;\r\n }\r\n }\r\n\r\n\r\n .fileup-result {\r\n &.fileup-success {\r\n color: $fileup-color-success;\r\n }\r\n &.fileup-error {\r\n color: $fileup-color-error;\r\n }\r\n }\r\n\r\n .fileup-progress {\r\n height: 3px;\r\n }\r\n .fileup-progress-bar {\r\n width: 1px;\r\n -webkit-transition: width .1s ease-out 0.1s;\r\n -moz-transition: width .1s ease-out 0.1s;\r\n -o-transition: width .1s ease-out 0.1s;\r\n transition: width .1s ease-out 0.1s\r\n }\r\n}\r\n\r\n.fileup-btn {\r\n position: relative;\r\n overflow: hidden;\r\n display: inline-block;\r\n\r\n input {\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n margin: 0;\r\n opacity: 0;\r\n -ms-filter: 'alpha(opacity=0)';\r\n font-size: 200px;\r\n direction: ltr;\r\n cursor: pointer;\r\n }\r\n}\r\n\r\n.fileup-dropzone {\r\n background-color: $fileup-dropzone-bg-color;\r\n border-width: $fileup-dropzone-border-width;\r\n border-style:$fileup-dropzone-border-style;\r\n border-color: $fileup-dropzone-border-color;\r\n cursor: pointer;\r\n\r\n &.over {\r\n opacity: .7;\r\n border-style: solid;\r\n }\r\n}","\r\n$fileup-color-success: #4CAE4C !default;\r\n$fileup-color-error: #CE0000 !default;\r\n$fileup-file-width: 350px !default;\r\n\r\n$fileup-dropzone-bg-color: #f6f6ff !default;\r\n$fileup-dropzone-border-color: #0018ff !default;\r\n$fileup-dropzone-border-style: dashed !default;\r\n$fileup-dropzone-border-width: 1px !default;"]}
--------------------------------------------------------------------------------
/dist/fileup.min.js:
--------------------------------------------------------------------------------
1 | !function(e,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(e="undefined"!=typeof globalThis?globalThis:e||self).fileUp=i()}(this,function(){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var d={isObject:function(e){return"object"===r(e)&&!Array.isArray(e)&&null!==e},isNumeric:function(e){return("number"==typeof e||"string"==typeof e&&""!==e.trim())&&!isNaN(e)},getFileSize:function(e){return e instanceof File?e.size||e.fileSize:null},getFileName:function(e){return e instanceof File?e.name||e.fileName:null},getSizeHuman:function(e){var i;return d.isNumeric(e)?(i="",1073741824<=(e=Number(e))?i=(e/1073741824).toFixed(2)+" Gb":1048576<=e?i=(e/1048576).toFixed(2)+" Mb":1024<=e?i=(e/1024).toFixed(2)+" Kb":0<=e&&(i=e+" bytes"),i):""},hashCode:function(){return this.crc32(((new Date).getTime()+Math.random()).toString()).toString(16)},crc32:function(e){for(var i=[],t=0;t<256;t++){for(var r=t,n=0;n<8;n++)r=1&r?3988292384^r>>>1:r>>>1;i[t]=r}for(var o=-1,s=0;s>>8^i[255&(o^e.charCodeAt(s))];return(-1^o)>>>0}},n=function(e){e=e.getElement();e&&(e.find(".fileup-upload").hide(),e.find(".fileup-abort").show(),e.find(".fileup-result").removeClass("fileup-error").removeClass("fileup-success").text(""))},o=function(e,i){i.lengthComputable&&(i=Math.ceil(i.loaded/i.total*100),e=e.getElement())&&e.find(".fileup-progress-bar").css("width",i+"%")},s=function(e){e=e.getElement();e&&(e.find(".fileup-abort").hide(),e.find(".fileup-upload").show(),e.find(".fileup-result").removeClass("fileup-error").removeClass("fileup-success").text(""))},l=function(e){var i,e=e.getElement();e&&(i=this.getLang(),e.find(".fileup-abort").hide(),e.find(".fileup-upload").hide(),e.find(".fileup-result").removeClass("fileup-error").addClass("fileup-success").text(i.complete))},a=function(e,i){var t=this.getLang();switch(e){case"files_limit":alert(t.errorFilesLimit.replace(/%filesLimit%/g,i.filesLimit));break;case"size_limit":var r=d.getSizeHuman(i.sizeLimit),n=t.errorSizeLimit;n=(n=n.replace(/%sizeLimit%/g,r)).replace(/%fileName%/g,d.getFileName(i.fileData)),alert(n);break;case"file_type":alert(t.errorFileType.replace(/%fileName%/g,d.getFileName(i.fileData)));break;case"load_bad_status":case"load_error":case"load_timeout":r=i.file.getElement();r&&(n="load_bad_status"===e?t.errorBadStatus:t.errorLoad,r.find(".fileup-abort").hide(),r.find(".fileup-upload").show(),r.find(".fileup-result").addClass("fileup-error").text(n));break;case"old_browser":alert(t.errorOldBrowser)}},f=function(e){e.stopPropagation(),e.preventDefault(),e.dataTransfer.dropEffect="copy";e=this.getDropzone();e&&e.addClass("over")},u=function(e){var i=this.getDropzone();i&&i.removeClass("over")},p=function(e){var i=this.getDropzone();i&&i.removeClass("over")},c=function(e){e.stopPropagation(),e.preventDefault(),e.dataTransfer.dropEffect="copy"},m={initInput:function(e){var i=null;if(e._options.input instanceof HTMLElement||e._options.input instanceof jQuery?i=$(e._options.input):"string"==typeof e._options.input&&e._options.input&&(i=$("#"+e._options.input)),!i||!$(i)[0]||"file"!==$(i)[0].type)throw new Error("Not found input element");e._input=i},initQueue:function(e){var i=null;if(e._options.queue instanceof HTMLElement||e._options.queue instanceof jQuery?i=$(e._options.queue):"string"==typeof e._options.queue&&e._options.queue&&(i=$("#"+e._options.queue)),!i||!$(i)[0])throw new Error("Not found queue element");e._queue=i},initDropzone:function(i){var t,e=null;i._options.dropzone instanceof HTMLElement||i._options.dropzone instanceof jQuery?e=$(i._options.dropzone):"string"==typeof i._options.dropzone&&i._options.dropzone&&(e=$("#"+i._options.dropzone)),e&&(i._dropzone=e,t=this,e.on("click",function(){i.getInput().click()}),e[0].addEventListener("dragover",function(e){t.trigger(i,"drag_over",[e])}),e[0].addEventListener("dragleave",function(e){t.trigger(i,"drag_leave",[e])}),e[0].addEventListener("dragenter",function(e){t.trigger(i,"drag_enter",[e])}),e[0].addEventListener("dragend",function(e){t.trigger(i,"drag_end",[e])}),e[0].addEventListener("drop",function(e){i.getInput()[0].files=e.target.files||e.dataTransfer.files,t.appendFiles(i,e)}))},initEvents:function(r){function e(e,i){var t=null;"function"==typeof i?t=i:"string"==typeof i&&(t=new Function(i)),t&&r.on(e,t)}var i=r.getOptions(),t=this;e("load_start",n),e("load_progress",o),e("load_abort",s),e("load_success",l),e("error",a),e("drag_over",f),e("drag_leave",c),e("drag_end",u),e("drag_enter",p),i.onSelect&&e("select",i.onSelect),i.onRemove&&e("remove",i.onRemove),i.onBeforeStart&&e("load_before_start",i.onBeforeStart),i.onStart&&e("load_start",i.onStart),i.onProgress&&e("load_progress",i.onProgress),i.onAbort&&e("load_abort",i.onAbort),i.onSuccess&&e("load_success",i.onSuccess),i.onFinish&&e("load_finish",i.onFinish),i.onError&&e("error",i.onError),i.onDragOver&&e("drag_over",i.onDragOver),i.onDragLeave&&e("drag_leave",i.onDragLeave),i.onDragEnd&&e("drag_end",i.onDragEnd),i.onDragEnter&&e("drag_enter",i.onDragEnter),r.getInput().on("change",function(e){t.appendFiles(r,e)})},renderFiles:function(e){var i=e.getOptions();if(Array.isArray(i.files)&&0l.sizeLimit)return s.trigger(o,"error",["size_limit",{fileData:e,sizeLimit:l.sizeLimit}]),0;if(0=l.filesLimit)return s.trigger(o,"error",["files_limit",{fileData:e,filesLimit:l.filesLimit}]),1;if("string"==typeof a[0].accept){var i=a[0].accept;if(i&&/[^\w]+/.test(i)){var t=!1,r=i.split(",");if(0'+this.getName()+""),"finish"===this._status?(this._fileElement.find(".fileup-upload").hide(),this._fileElement.find(".fileup-abort").hide(),this._fileElement.find(".fileup-progress").hide()):(this._fileElement.find(".fileup-upload").click(function(){i.upload()}),this._fileElement.find(".fileup-abort").click(function(){i.abort()})),this._fileElement.find(".fileup-remove").click(function(){i.remove()}),this._fileElement):null}},t=Object.create(null),h={_options:{id:null,url:null,input:null,queue:null,dropzone:null,files:[],fieldName:"file",extraFields:{},lang:"en",langItems:null,sizeLimit:0,filesLimit:0,httpMethod:"post",timeout:null,autostart:!(t["file.html"]=' [NAME] ([SIZE])
✕ [UPLOAD] [ABORT]
'),showRemove:!0,templateFile:null,onSelect:null,onRemove:null,onBeforeStart:null,onStart:null,onProgress:null,onAbort:null,onSuccess:null,onFinish:null,onError:null,onDragOver:null,onDragLeave:null,onDragEnd:null,onDragEnter:null,iconDefault:"bi bi-file-earmark-text",mimeTypes:{archive:{mime:["application/zip","application/gzip","application/x-bzip","application/x-bzip2","application/x-7z-compressed"],ext:["zip","7z","bz","bz2","gz","jar","rar","tar"],icon:"bi bi-file-earmark-zip"},word:{mime:["application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document"],ext:["doc","docx"],icon:"bi bi-file-earmark-word"},excel:{mime:["application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],ext:["xls","xlsx"],icon:"bi bi-file-earmark-excel"},image:{mime:/image\/.*/,ext:["jpg","jpeg","png","bmp","gif","raw","webp","heic","ico"],icon:"bi bi-file-earmark-image"},video:{mime:/video\/.*/,ext:["avi","mp4","mpeg","ogv","ts","webm","3gp","3g2","mkv"],icon:"bi bi-file-earmark-play"},audio:{mime:/audio\/.*/,ext:["avi","mp4","mpeg","ogv","ts","webm","3gp","3g2","mkv"],icon:"bi bi-file-earmark-music"},pdf:{mime:["application/pdf"],ext:["pdf"],icon:"bi bi-file-earmark-pdf"},binary:{mime:["application/octet-stream"],ext:["bin","exe","dat","dll"],icon:"bi bi-file-earmark-binary"}}},_id:null,_fileUp:null,_fileIndex:0,_input:null,_queue:null,_dropzone:null,_files:{},_events:{},_init:function(e,i){if("string"!=typeof i.url||!i.url)throw new Error("Dont set url param");this._fileUp=e,this._options=$.extend(!0,{},this._options,i),this._id="string"==typeof this._options.id&&this._options.id?this._options.id:d.hashCode(),this._options.templateFile&&"string"==typeof this._options.templateFile||(this._options.templateFile=t["file.html"]),m.initInput(this),m.initQueue(this),m.initDropzone(this),m.initEvents(this),m.renderFiles(this)},destruct:function(){var e=this.getId();this._fileUp._instances.hasOwnProperty(e)&&delete this._fileUp._instances[e]},getOptions:function(){return this._options},getId:function(){return this._id},getInput:function(){return this._input},getQueue:function(){return this._queue},getDropzone:function(){return this._dropzone},on:function(e,i,t){"object"!==r(this._events[e])&&(this._events[e]=[]),this._events[e].push({context:t||this,callback:i,singleExec:!1})},one:function(e,i,t){"object"!==r(this._events[e])&&(this._events[e]=[]),this._events[e].push({context:t||this,callback:i,singleExec:!0})},getLang:function(){return $.extend(!0,{},this._options.langItems)},getFiles:function(){return this._files},getFileById:function(t){var r=null;return $.each(this._files,function(e,i){t===i.getId()&&(r=i)}),r},removeAll:function(){$.each(this._files,function(e,i){i.remove()})},uploadAll:function(){$.each(this._files,function(e,i){i.upload()})},abortAll:function(){$.each(this._files,function(e,i){i.abort()})},appendFile:function(e){var i,t;return e instanceof File&&(i=$.extend(!0,{},g),t={name:d.getFileName(e),size:d.getFileSize(e),type:e.type},i._init(this,this._fileIndex,t,e),this._files[this._fileIndex]=i,(t=this.getQueue())&&t.append(i.render(this._options.templateFile)),this._fileIndex++,"boolean"==typeof this._options.autostart&&this._options.autostart&&i.upload(),!0)},appendFileByData:function(e){var i;return!!d.isObject(e)&&((i=$.extend(!0,{},g))._init(this,this._fileIndex,e),i.setStatus("finish"),this._files[this._fileIndex]=i,(e=this.getQueue())&&e.append(i.render(this._options.templateFile)),this._fileIndex++,!0)}},e={lang:{},_instances:{},create:function(e){(e=d.isObject(e)?e:{}).hasOwnProperty("lang")||(e.lang="en");var i=this.lang.hasOwnProperty(e.lang)?this.lang[e.lang]:{},i=(e.langItems=e.hasOwnProperty("langItems")&&d.isObject(e.langItems)?$.extend(!0,{},i,e.langItems):i,$.extend(!0,{},h)),e=(i._init(this,e),i.getId());return this._instances[e]=i},get:function(e){return this._instances.hasOwnProperty(e)?$.contains(document,this._instances[e]._input[0])?this._instances[e]:(delete this._instances[e],null):null}};return e.lang.en={upload:"Upload",abort:"Abort",remove:"Remove",complete:"Complete",error:"Error",errorLoad:"Error uploading file",errorBadStatus:"Error uploading file. Bad request.",errorFilesLimit:"The number of selected files exceeds the limit (%filesLimit%)",errorSizeLimit:'File "%fileName%" exceeds the size limit (%sizeLimit%)',errorFileType:'File "%fileName%" is incorrect',errorOldBrowser:"Your browser can not upload files. Update to the latest version"},e.lang.ru={upload:"Загрузить",abort:"Остановить",remove:"Удалить",complete:"Готово",error:"Ошибка",errorLoad:"Ошибка при загрузке файла",errorBadStatus:"Ошибка при загрузке файла. Некорректный запрос.",errorFilesLimit:"Количество выбранных файлов превышает лимит (%filesLimit%)",errorSizeLimit:'Файл "%fileName%" превышает предельный размер (%sizeLimit%)',errorFileType:'Файл "%fileName%" является некорректным',errorOldBrowser:"Обновите ваш браузер до последней версии"},e.lang.es={upload:"Subir",abort:"Cancelar",remove:"Eliminar",complete:"Cargado",error:"Error",errorLoad:"Error al cargar el archivo",errorBadStatus:"Error al cargar el archivo. Solicitud no válida.",errorFilesLimit:"El número de archivo selecccionados excede el límite (%filesLimit%)",errorSizeLimit:'El archivo "%fileName%" excede el limite de tamaño (%sizeLimit%)',errorFileType:'El archivo "%fileName%" es inválido',errorOldBrowser:"Tu navegador no puede subir archivos. Actualiza a la última versión"},e.lang.pt={upload:"Enviar",abort:"Cancelar",remove:"Remover",complete:"Enviado",error:"Erro",errorLoad:"Erro ao carregar o arquivo",errorBadStatus:"Erro ao carregar o arquivo. Pedido inválido.",errorFilesLimit:"O número de arquivos selecionados excede o limite (%filesLimit%)",errorSizeLimit:'Arquivo "%fileName%" excede o limite (%sizeLimit%)',errorFileType:'Arquivo "%fileName%" inválido',errorOldBrowser:"Seu navegador não pode enviar os arquivos. Atualize para a versão mais recente"},e});
2 | //# sourceMappingURL=fileup.min.js.map
3 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp');
2 | const concat = require('gulp-concat');
3 | const sourcemaps = require('gulp-sourcemaps');
4 | const uglify = require('gulp-uglify');
5 | const htmlToJs = require('gulp-html-to-js');
6 | const wrapFile = require('gulp-wrap-file');
7 | const sass = require('gulp-sass')(require('sass'));
8 | const rollup = require('@rollup/stream');
9 | const rollupSourcemaps = require('rollup-plugin-sourcemaps');
10 | const rollupBabel = require('@rollup/plugin-babel');
11 | const nodeResolve = require('@rollup/plugin-node-resolve');
12 | const source = require('vinyl-source-stream');
13 | const buffer = require("vinyl-buffer");
14 |
15 |
16 | var conf = {
17 | dist: "./dist",
18 | js: {
19 | file: 'fileup.js',
20 | fileMin: 'fileup.min.js',
21 | main: 'src/js/main.js',
22 | src: 'src/js/**/*.js'
23 | },
24 | css: {
25 | fileMin: 'fileup.min.css',
26 | file: 'fileup.css',
27 | main: 'src/css/main.scss',
28 | src: [
29 | 'src/css/**/*.scss',
30 | ]
31 | },
32 | css_bootstrap: {
33 | fileMin: 'fileup.bootstrap.min.css',
34 | main: 'src/css/fileup.bootstrap.scss',
35 | },
36 | tpl: {
37 | file: 'fileup.templates.js',
38 | dist: './src/js',
39 | src: [
40 | 'src/html/**/*.html',
41 | 'src/html/*.html'
42 | ]
43 | }
44 | };
45 |
46 |
47 |
48 | gulp.task('build_css_min', function(){
49 | return gulp.src(conf.css.main)
50 | .pipe(sourcemaps.init())
51 | .pipe(sass({includePaths: ['node_modules'], outputStyle: 'compressed'}).on('error', sass.logError))
52 | .pipe(concat(conf.css.fileMin))
53 | .pipe(sourcemaps.write('.'))
54 | .pipe(gulp.dest(conf.dist));
55 | });
56 |
57 | gulp.task('build_css_min_fast', function(){
58 | return gulp.src(conf.css.main)
59 | .pipe(sass({includePaths: ['node_modules']}).on('error', sass.logError))
60 | .pipe(concat(conf.css.fileMin))
61 | .pipe(gulp.dest(conf.dist));
62 | });
63 |
64 | gulp.task('build_css', function(){
65 | return gulp.src(conf.css.main)
66 | .pipe(sass({includePaths: ['node_modules']}).on('error', sass.logError))
67 | .pipe(concat(conf.css.file))
68 | .pipe(gulp.dest(conf.dist));
69 | });
70 |
71 |
72 |
73 | gulp.task('build_js', function() {
74 | return rollup({
75 | input: conf.js.main,
76 | output: {
77 | sourcemap: false,
78 | format: 'umd',
79 | name: "fileUp"
80 | },
81 | onwarn: function (log, handler) {
82 | if (log.code === 'CIRCULAR_DEPENDENCY') {
83 | return; // Ignore circular dependency warnings
84 | }
85 | handler(log.message);
86 | },
87 | context: "window",
88 | plugins: [
89 | nodeResolve(),
90 | rollupBabel({babelHelpers: 'bundled'}),
91 | ]
92 | })
93 | .pipe(source(conf.js.file))
94 | .pipe(buffer())
95 | .pipe(gulp.dest(conf.dist));
96 | });
97 |
98 | gulp.task('build_js_min_fast', function() {
99 | return rollup({
100 | input: conf.js.main,
101 | output: {
102 | sourcemap: false,
103 | format: 'umd',
104 | name: "fileUp"
105 | },
106 | onwarn: function (log, handler) {
107 | if (log.code === 'CIRCULAR_DEPENDENCY') {
108 | return; // Ignore circular dependency warnings
109 | }
110 | handler(log.message);
111 | },
112 | context: "window",
113 | plugins: [
114 | nodeResolve(),
115 | rollupSourcemaps(),
116 | rollupBabel({babelHelpers: 'bundled'}),
117 | ]
118 | })
119 | .pipe(source(conf.js.fileMin))
120 | .pipe(buffer())
121 | .pipe(gulp.dest(conf.dist));
122 | });
123 |
124 |
125 | gulp.task('build_js_min', function() {
126 | return rollup({
127 | input: conf.js.main,
128 | output: {
129 | sourcemap: false,
130 | format: 'umd',
131 | name: "fileUp"
132 | },
133 | onwarn: function (log, handler) {
134 | if (log.code === 'CIRCULAR_DEPENDENCY') {
135 | return; // Ignore circular dependency warnings
136 | }
137 | handler(log.message);
138 | },
139 | context: "window",
140 | plugins: [
141 | nodeResolve(),
142 | rollupSourcemaps(),
143 | rollupBabel({babelHelpers: 'bundled'}),
144 | ]
145 | })
146 | .pipe(source(conf.js.fileMin))
147 | .pipe(buffer())
148 | .pipe(sourcemaps.init())
149 | .pipe(uglify())
150 | .pipe(sourcemaps.write('.'))
151 | .pipe(gulp.dest(conf.dist));
152 | });
153 |
154 |
155 | gulp.task('build_tpl', function() {
156 | return gulp.src(conf.tpl.src)
157 | .pipe(htmlToJs({global: 'tpl', concat: conf.tpl.file}))
158 | .pipe(wrapFile({
159 | wrapper: function(content, file) {
160 | content = content.replace(/\\n/g, ' ');
161 | content = content.replace(/[ ]{2,}/g, ' ');
162 | return 'let ' + content + ";\nexport default tpl;"
163 | }
164 | }))
165 | .pipe(gulp.dest(conf.tpl.dist));
166 | });
167 |
168 |
169 | gulp.task('build_bootstrap', function() {
170 | return gulp.src(conf.css_bootstrap.main)
171 | .pipe(sourcemaps.init())
172 | .pipe(sass({includePaths: ['node_modules'], outputStyle: 'compressed'}).on('error', sass.logError))
173 | .pipe(concat(conf.css_bootstrap.fileMin))
174 | .pipe(sourcemaps.write('.'))
175 | .pipe(gulp.dest(conf.dist));
176 | });
177 |
178 |
179 |
180 | gulp.task('build_watch', function() {
181 | gulp.watch(conf.tpl.src, gulp.series(['build_tpl', 'build_js_min_fast']));
182 | gulp.watch(conf.js.src, gulp.parallel(['build_js_min_fast']));
183 | gulp.watch(conf.css.src, gulp.parallel(['build_css_min_fast']));
184 | });
185 |
186 | gulp.task("default", gulp.series([ 'build_tpl', 'build_js_min', 'build_js']));
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fileup-js",
3 | "version": "1.0.3",
4 | "description": "Fileup - file upload lib",
5 | "scripts": {
6 | "build_all": "gulp build_tpl && gulp build_js_min && gulp build_js && gulp build_css_min && gulp build_css && npm run test_js",
7 |
8 | "build_tpl": "gulp build_tpl",
9 | "build_js": "gulp build_tpl && gulp build_js",
10 | "build_js_min": "gulp build_tpl && gulp build_js_min",
11 |
12 | "build_css": "gulp build_css",
13 | "build_css_min": "gulp build_css_min",
14 |
15 | "build_watch": "gulp build_watch",
16 | "build_bootstrap": "gulp build_bootstrap",
17 | "test_js": "eslint -c .eslintrc.json --max-warnings 100 --ext .js ./dist"
18 | },
19 | "devDependencies": {
20 | "gulp": "5.0.0",
21 | "gulp-concat": "2.6.1",
22 | "gulp-sourcemaps": "3.0.0",
23 | "gulp-sass": "5.1.0",
24 | "gulp-uglify": "3.0.2",
25 | "gulp-wrap-file": "0.1.2",
26 | "gulp-html-to-js": "0.0.7",
27 | "@rollup/stream": "3.0.1",
28 | "rollup-plugin-sourcemaps": "0.6.3",
29 | "@rollup/plugin-babel": "6.0.4",
30 | "@rollup/plugin-node-resolve": "15.2.3",
31 | "vinyl-source-stream": "2.0.0",
32 | "vinyl-buffer": "1.0.1",
33 | "sass": "1.76.0",
34 | "eslint": "8.57.0",
35 | "@babel/plugin-transform-template-literals": "7.24.1",
36 | "@babel/preset-env": "7.24.5",
37 | "bootstrap": "5.3.3"
38 | },
39 | "repository": {
40 | "type": "git",
41 | "url": "git+https://github.com/n2ref/fileup.git"
42 | },
43 | "keywords": [
44 | "fileup",
45 | "js",
46 | "javascript",
47 | "frontend",
48 | "libriary",
49 | "lib",
50 | "form",
51 | "file",
52 | "upload",
53 | "bootstrap"
54 | ],
55 | "author": "n2ref",
56 | "license": "ISC",
57 | "bugs": {
58 | "url": "https://github.com/n2ref/fileup/issues"
59 | },
60 | "homepage": "https://github.com/n2ref/fileup"
61 | }
62 |
--------------------------------------------------------------------------------
/src/css/_varaible.scss:
--------------------------------------------------------------------------------
1 |
2 | $fileup-color-success: #4CAE4C !default;
3 | $fileup-color-error: #CE0000 !default;
4 | $fileup-file-width: 350px !default;
5 |
6 | $fileup-dropzone-bg-color: #f6f6ff !default;
7 | $fileup-dropzone-border-color: #0018ff !default;
8 | $fileup-dropzone-border-style: dashed !default;
9 | $fileup-dropzone-border-width: 1px !default;
--------------------------------------------------------------------------------
/src/css/fileup.bootstrap.scss:
--------------------------------------------------------------------------------
1 |
2 | .fileup-file {
3 |
4 | @import "bootstrap/scss/functions";
5 | @import "bootstrap/scss/variables";
6 | @import "bootstrap/scss/mixins";
7 | @import "bootstrap/scss/maps";
8 | @import "bootstrap/scss/progress";
9 | @import "bootstrap/scss/helpers/colored-links";
10 | @import "bootstrap/scss/utilities";
11 | @import "bootstrap/scss/utilities/api";
12 | }
--------------------------------------------------------------------------------
/src/css/fileup.scss:
--------------------------------------------------------------------------------
1 | .fileup-file {
2 | font-size: 12px;
3 | width: $fileup-file-width;
4 | position: relative;
5 | overflow: hidden;
6 |
7 | &.fileup-image .fileup-preview {
8 |
9 | &.no-preview {
10 | width: 80px;
11 | height: 56px;
12 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA4CAAAAABP3SBGAAACW0lEQVRYw+3Y3U8aQRAAcP7/98bb3YFDxSvUBCKlxigllVrFILFEmmJrxdYrB7e7Q+JfUD4Ocgcs7OX2oQ/OAwmZ8Mt+zO7NkcraZiOVSRuNTMp+BU2BzCIJAyIgK19eJIv6PoRB0njBRDHiBRYG6Rf0EwXvv/3fQM6Ngsjd5/GHKZCLdvkgV2wOhSmwRglj1Kp43AgoG9a05mCnKk2AvO+w4HjZj8IAKLsAwcmlLdQEl4oiCt6x+VVAGpogf3KFEhQPmWCEwNpSAZKLKHh0NNwwxhIJZuy4XAvEO2adqGctuzad7gm9RV8H5H6RpklVqMWOM74Arb2m9LVAbFFIA6lJteg2q6dXT9LXArlXmMwIyLla5CglCl8PxMZszWGlOKX+9RUC+XMuqDOg1xGx31Ev6wYQz6153QK0wkt7Qz4rRTUoe7uLg5Bm6a+jxU9ch9LToYwL4pkVesyyTAdDIwer/FfGA+XP+bmaXyjfZxn5y54krMMexgJFhURbAbp7P02JD7MEyXUxBojfAJaaC7r/gNPTGCSo3cYYIyzRlXaFOj3JB4eLBIPGasUrQLylsNoAkfzvl6vQVjH6iQstkA/e0XUtFSneH7DQdyDHntQB8Zqsb9JYdmngVukPbge5GxlHOGB1GR5wKyjrRL+zpHsd3AJyL09j9KoscxPqRdaDBRan+2WsLrhJcLzZZ0NhEpzcFa7cBDo7NGa8cX5w9S57teOTuFH5OHs0ry9sIeOHP9TpHJL32MlBLx8FL0c8UYhB9D0FCpX3yaKchei7Hk0a8PoCbgw0/a/IP7jBCOMW5IDRAAAAAElFTkSuQmCC);
13 | background-repeat: no-repeat;
14 | background-size: contain;
15 |
16 | img {
17 | display: none;
18 | }
19 | }
20 |
21 | .fileup-icon {
22 | display: none;
23 | }
24 | }
25 |
26 | &.fileup-doc .fileup-preview {
27 | img {
28 | display: none;
29 | }
30 | }
31 |
32 | .fileup-preview img {
33 | max-height: 80px;
34 | max-width: 80px;
35 | }
36 |
37 | .fileup-description {
38 | padding-right: 20px;
39 | word-break: break-all;
40 | }
41 |
42 | .fileup-controls {
43 | .fileup-remove {
44 | cursor: pointer;
45 | position: absolute;
46 | top: 0;
47 | right: 2px;
48 | width: 16px;
49 | height: 16px;
50 | font-size: 16px;
51 | color: #9e9e9e;
52 | }
53 | .fileup-remove:hover {
54 | color: #616161;
55 | }
56 |
57 | .fileup-upload,
58 | .fileup-abort {
59 | cursor: pointer;
60 | }
61 | }
62 |
63 |
64 | .fileup-result {
65 | &.fileup-success {
66 | color: $fileup-color-success;
67 | }
68 | &.fileup-error {
69 | color: $fileup-color-error;
70 | }
71 | }
72 |
73 | .fileup-progress {
74 | height: 3px;
75 | }
76 | .fileup-progress-bar {
77 | width: 1px;
78 | -webkit-transition: width .1s ease-out 0.1s;
79 | -moz-transition: width .1s ease-out 0.1s;
80 | -o-transition: width .1s ease-out 0.1s;
81 | transition: width .1s ease-out 0.1s
82 | }
83 | }
84 |
85 | .fileup-btn {
86 | position: relative;
87 | overflow: hidden;
88 | display: inline-block;
89 |
90 | input {
91 | position: absolute;
92 | top: 0;
93 | right: 0;
94 | margin: 0;
95 | opacity: 0;
96 | -ms-filter: 'alpha(opacity=0)';
97 | font-size: 200px;
98 | direction: ltr;
99 | cursor: pointer;
100 | }
101 | }
102 |
103 | .fileup-dropzone {
104 | background-color: $fileup-dropzone-bg-color;
105 | border-width: $fileup-dropzone-border-width;
106 | border-style:$fileup-dropzone-border-style;
107 | border-color: $fileup-dropzone-border-color;
108 | cursor: pointer;
109 |
110 | &.over {
111 | opacity: .7;
112 | border-style: solid;
113 | }
114 | }
--------------------------------------------------------------------------------
/src/css/main.scss:
--------------------------------------------------------------------------------
1 |
2 | @import "_varaible";
3 | @import "fileup";
--------------------------------------------------------------------------------
/src/html/file.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![[NAME]]([PREVIEW_SRC])
4 |
5 |
6 |
7 |
8 | [NAME]
9 | ([SIZE])
10 |
11 |
12 |
13 | ✕
14 | [UPLOAD]
15 | [ABORT]
16 |
17 |
18 |
19 |
20 |
23 |
24 |
--------------------------------------------------------------------------------
/src/js/fileup.events.js:
--------------------------------------------------------------------------------
1 | import fileUpUtils from "./fileup.utils";
2 |
3 | let fileUpEvents = {
4 |
5 | /**
6 | * Событие начала загрузки
7 | * @param {object} file
8 | */
9 | onLoadStart: function(file) {
10 |
11 | let $file = file.getElement();
12 |
13 | if ($file) {
14 | $file.find('.fileup-upload').hide();
15 | $file.find('.fileup-abort').show();
16 |
17 | $file.find('.fileup-result')
18 | .removeClass('fileup-error')
19 | .removeClass('fileup-success')
20 | .text('');
21 | }
22 | },
23 |
24 |
25 | /**
26 | * Событие начала изменения прогресса загрузки
27 | * @param {object} file
28 | * @param {ProgressEvent} ProgressEvent
29 | */
30 | onLoadProgress: function(file, ProgressEvent) {
31 |
32 | if (ProgressEvent.lengthComputable) {
33 | let percent = Math.ceil(ProgressEvent.loaded / ProgressEvent.total * 100);
34 | let $file = file.getElement();
35 |
36 | if ($file) {
37 | $file.find('.fileup-progress-bar').css('width', percent + "%");
38 | }
39 | }
40 | },
41 |
42 |
43 | /**
44 | * Событие начала загрузки
45 | * @param {object} file
46 | */
47 | onLoadAbort: function(file) {
48 |
49 | let $file = file.getElement();
50 |
51 | if ($file) {
52 | $file.find('.fileup-abort').hide();
53 | $file.find('.fileup-upload').show();
54 | $file.find('.fileup-result')
55 | .removeClass('fileup-error')
56 | .removeClass('fileup-success')
57 | .text('');
58 | }
59 | },
60 |
61 |
62 | /**
63 | * Событие успешной загрузки файла
64 | * @param {object} file
65 | */
66 | onSuccess: function(file) {
67 |
68 | let $file = file.getElement();
69 |
70 | if ($file) {
71 | let lang = this.getLang();
72 |
73 | $file.find('.fileup-abort').hide();
74 | $file.find('.fileup-upload').hide();
75 | $file.find('.fileup-result')
76 | .removeClass('fileup-error')
77 | .addClass('fileup-success')
78 | .text(lang.complete);
79 | }
80 | },
81 |
82 |
83 | /**
84 | * Событие ошибки
85 | * @param {string} eventName
86 | * @param {object} options
87 | */
88 | onError: function(eventName, options) {
89 |
90 | let lang = this.getLang();
91 |
92 | switch(eventName) {
93 | case 'files_limit':
94 | alert(lang.errorFilesLimit.replace(/%filesLimit%/g, options.filesLimit));
95 | break;
96 |
97 | case 'size_limit':
98 | let size = fileUpUtils.getSizeHuman(options.sizeLimit);
99 | let message = lang.errorSizeLimit;
100 |
101 | message = message.replace(/%sizeLimit%/g, size);
102 | message = message.replace(/%fileName%/g, fileUpUtils.getFileName(options.fileData));
103 |
104 | alert(message);
105 | break;
106 |
107 | case 'file_type':
108 | alert(lang.errorFileType.replace(/%fileName%/g, fileUpUtils.getFileName(options.fileData)));
109 | break;
110 |
111 | case 'load_bad_status':
112 | case 'load_error':
113 | case 'load_timeout':
114 | let $file = options.file.getElement();
115 |
116 | if ($file) {
117 | let message = eventName === 'load_bad_status'
118 | ? lang.errorBadStatus
119 | : lang.errorLoad;
120 |
121 | $file.find('.fileup-abort').hide();
122 | $file.find('.fileup-upload').show();
123 | $file.find('.fileup-result')
124 | .addClass('fileup-error')
125 | .text(message);
126 | }
127 | break;
128 |
129 | case 'old_browser':
130 | alert(lang.errorOldBrowser);
131 | break;
132 | }
133 | },
134 |
135 |
136 | /**
137 | * Событие переноса файла через dropzone
138 | * @param {Event} event
139 | */
140 | onDragOver: function(event) {
141 |
142 | event.stopPropagation();
143 | event.preventDefault();
144 | event.dataTransfer.dropEffect = 'copy';
145 |
146 | let dropzone = this.getDropzone();
147 |
148 | if (dropzone) {
149 | dropzone.addClass('over');
150 | }
151 | },
152 |
153 |
154 | /**
155 | * Событие завершения перетаскивания с отпускаем кнопки мыши
156 | * @param {Event} event
157 | */
158 | onDragLeave: function(event) {
159 |
160 | let dropzone = this.getDropzone();
161 | if (dropzone) {
162 | dropzone.removeClass('over');
163 | }
164 | },
165 |
166 |
167 | /**
168 | * Событие когда перетаскиваемый элемент или выделенный текст покидают допустимую цель перетаскивания
169 | * @param {Event} event
170 | */
171 | onDragEnd: function(event) {
172 |
173 | let dropzone = this.getDropzone();
174 | if (dropzone) {
175 | dropzone.removeClass('over');
176 | }
177 | },
178 |
179 |
180 | /**
181 | * Событие переноса файла в dropzone
182 | * @param {Event} event
183 | */
184 | onDragEnter: function(event) {
185 |
186 | event.stopPropagation();
187 | event.preventDefault();
188 | event.dataTransfer.dropEffect = 'copy';
189 | }
190 | }
191 |
192 | export default fileUpEvents;
--------------------------------------------------------------------------------
/src/js/fileup.file.js:
--------------------------------------------------------------------------------
1 | import fileUpPrivate from "./fileup.private";
2 | import fileUpUtils from "./fileup.utils";
3 |
4 | let fileUpFile = {
5 |
6 | _options: {
7 | name: null,
8 | size: null,
9 | urlPreview: null,
10 | urlDownload: null
11 | },
12 |
13 | _id: '',
14 | _status: 'stand_by',
15 | _fileElement: null,
16 | _file: null,
17 | _fileUp: null,
18 | _xhr: null,
19 |
20 |
21 | /**
22 | * Инициализация
23 | * @param {object} fileUp
24 | * @param {int} id
25 | * @param {object} options
26 | * @param {File} file
27 | * @private
28 | */
29 | _init: function (fileUp, id, options, file) {
30 |
31 | if ( ! fileUpUtils.isObject(options)) {
32 | throw new Error('File incorrect options param');
33 | }
34 |
35 | if (typeof id !== 'number' || id < 0) {
36 | throw new Error('File dont set or incorrect id param');
37 | }
38 | if (typeof options.name !== 'string' || ! options.name) {
39 | throw new Error('File dont set name param');
40 | }
41 |
42 | this._fileUp = fileUp;
43 | this._options = $.extend(true, {}, this._options, options);
44 | this._id = id;
45 |
46 |
47 | if (file instanceof File) {
48 | let xhr = null;
49 |
50 | if (window.XMLHttpRequest) {
51 | xhr = ("onload" in new XMLHttpRequest()) ? new XMLHttpRequest : new XDomainRequest;
52 |
53 | } else if (window.ActiveXObject) {
54 | try {
55 | xhr = new ActiveXObject("Msxml2.XMLHTTP");
56 | } catch (e) {
57 | try {
58 | xhr = new ActiveXObject("Microsoft.XMLHTTP");
59 | } catch (e) {
60 | fileUpPrivate.trigger(fileUp, 'error', ['old_browser', { file: this }]);
61 | }
62 | }
63 | } else {
64 | fileUpPrivate.trigger(fileUp, 'error', ['old_browser', { file: this }]);
65 | }
66 |
67 | if ( ! xhr) {
68 | throw new Error('xhr dont created. Check your browser');
69 | }
70 |
71 | this._xhr = xhr;
72 | this._file = file;
73 |
74 | } else {
75 | this._status = 'finish';
76 | }
77 | },
78 |
79 |
80 | /**
81 | * Получение id файла
82 | * @return {null}
83 | */
84 | getId: function () {
85 | return this._id;
86 | },
87 |
88 |
89 | /**
90 | * Получение name
91 | * @return {string|null}
92 | */
93 | getName: function () {
94 |
95 | return this._file
96 | ? fileUpUtils.getFileName(this._file)
97 | : this._options.name;
98 | },
99 |
100 |
101 | /**
102 | * Получение элемента файла
103 | * @return {jQuery|null}
104 | */
105 | getElement: function () {
106 | return this._fileElement;
107 | },
108 |
109 |
110 | /**
111 | * Получение urlPreview
112 | * @return {string|null}
113 | */
114 | getUrlPreview: function () {
115 | return this._options.urlPreview;
116 | },
117 |
118 |
119 | /**
120 | * Получение urlDownload
121 | * @return {string|null}
122 | */
123 | getUrlDownload: function () {
124 | return this._options.urlDownload;
125 | },
126 |
127 |
128 | /**
129 | * Получение size
130 | * @return {int|null}
131 | */
132 | getSize: function () {
133 |
134 | return this._file
135 | ? fileUpUtils.getFileSize(this._file)
136 | : this._options.size;
137 | },
138 |
139 |
140 | /**
141 | * Formatting size
142 | * @returns {string}
143 | */
144 | getSizeHuman: function() {
145 |
146 | let size = this.getSize();
147 |
148 | return fileUpUtils.getSizeHuman(size);
149 | },
150 |
151 |
152 | /**
153 | * Получение xhr
154 | * @return {XMLHttpRequest|null}
155 | */
156 | getXhr: function () {
157 | return this._xhr;
158 | },
159 |
160 |
161 | /**
162 | * Получение файла
163 | * @return {File|null}
164 | */
165 | getFile: function () {
166 |
167 | if ( ! (this._file instanceof File)) {
168 | return null;
169 | }
170 |
171 | return this._file;
172 | },
173 |
174 |
175 | /**
176 | * Получение статуса
177 | * @return {string}
178 | */
179 | getStatus: function () {
180 | return this._status;
181 | },
182 |
183 |
184 |
185 | /**
186 | * Установка статуса
187 | * @param {string} status
188 | */
189 | setStatus: function (status) {
190 |
191 | if (typeof status !== 'string') {
192 | return;
193 | }
194 |
195 | this._status = status;
196 | },
197 |
198 |
199 | /**
200 | * Получение параметров
201 | *
202 | * @returns {object}
203 | */
204 | getOptions: function () {
205 | return this._options;
206 | },
207 |
208 |
209 | /**
210 | * Получение параметра
211 | * @param {string} name
212 | * @returns {*}
213 | */
214 | getOption: function (name) {
215 |
216 | if (typeof name !== 'string' || ! this._options.hasOwnProperty(name)) {
217 | return null;
218 | }
219 |
220 | return this._options[name];
221 | },
222 |
223 |
224 | /**
225 | * Установка параметра
226 | * @param {string} name
227 | * @param {*} value
228 | */
229 | setOption: function (name, value) {
230 |
231 | if (typeof name !== 'string') {
232 | return;
233 | }
234 |
235 | this._options[name] = value;
236 | },
237 |
238 |
239 | /**
240 | * Показ сообщения об ошибке
241 | * @param {string} message
242 | */
243 | showError: function (message) {
244 |
245 | if (typeof message !== 'string') {
246 | return;
247 | }
248 |
249 | let element = this.getElement();
250 |
251 | if (element) {
252 | element.find('.fileup-result')
253 | .removeClass('fileup-success')
254 | .addClass('fileup-error')
255 | .text(message);
256 | }
257 | },
258 |
259 |
260 | /**
261 | * Показ сообщения об успехе
262 | * @param {string} message
263 | */
264 | showSuccess: function (message) {
265 |
266 | if (typeof message !== 'string') {
267 | return;
268 | }
269 |
270 | let element = this.getElement();
271 |
272 | if (element) {
273 | element.find('.fileup-result')
274 | .removeClass('fileup-error')
275 | .addClass('fileup-success')
276 | .text(message);
277 | }
278 | },
279 |
280 |
281 | /**
282 | * Удаление файла на странице и из памяти
283 | */
284 | remove: function () {
285 |
286 | this.abort();
287 |
288 | if (this._fileElement) {
289 | this._fileElement.fadeOut('fast', function () {
290 | this.remove();
291 | });
292 | }
293 |
294 | let fileId = this.getId();
295 |
296 | if (this._fileUp._files.hasOwnProperty(fileId)) {
297 | delete this._fileUp._files[fileId];
298 | }
299 |
300 | fileUpPrivate.trigger(this._fileUp, 'remove', [this]);
301 | },
302 |
303 |
304 | /**
305 | * Загрузка файла
306 | * @return {boolean}
307 | */
308 | upload: function() {
309 |
310 | let file = this.getFile();
311 | let xhr = this.getXhr();
312 |
313 | if ( ! file || ! xhr) {
314 | return false;
315 | }
316 |
317 |
318 | let options = this._fileUp.getOptions();
319 | let that = this;
320 |
321 | if (typeof options.timeout === 'number') {
322 | xhr.timeout = options.timeout;
323 | }
324 |
325 | // запрос начат
326 | xhr.onloadstart = function() {
327 | that.setStatus('load_start');
328 | fileUpPrivate.trigger(that._fileUp, 'load_start', [that]);
329 | };
330 |
331 | // браузер получил очередной пакет данных
332 | xhr.upload.onprogress = function(ProgressEvent) {
333 | fileUpPrivate.trigger(that._fileUp, 'load_progress', [that, ProgressEvent]);
334 | };
335 |
336 | // запрос был успешно (без ошибок) завершён
337 | xhr.onload = function() {
338 | that.setStatus('loaded');
339 |
340 | if (xhr.status === 200) {
341 | fileUpPrivate.trigger(that._fileUp, 'load_success', [that, xhr.responseText]);
342 | } else {
343 | fileUpPrivate.trigger(that._fileUp, 'error', [
344 | 'load_bad_status',
345 | {
346 | file: that,
347 | fileData: file,
348 | response: xhr.responseText,
349 | xhr: xhr,
350 | }
351 | ]);
352 | }
353 | };
354 |
355 | // запрос был завершён (успешно или неуспешно)
356 | xhr.onloadend = function() {
357 | that.setStatus('finish');
358 | fileUpPrivate.trigger(that._fileUp, 'load_finish', [that]);
359 | };
360 |
361 | // запрос был отменён вызовом xhr.abort()
362 | xhr.onabort = function() {
363 | that.setStatus('stand_by');
364 | fileUpPrivate.trigger(that._fileUp, 'load_abort', [that]);
365 | };
366 |
367 | // запрос был прекращён по таймауту
368 | xhr.ontimeout = function() {
369 | that.setStatus('stand_by');
370 | fileUpPrivate.trigger(that._fileUp, 'error', [
371 | 'load_timeout',
372 | {
373 | file: that,
374 | fileData: file
375 | }
376 | ]);
377 | };
378 |
379 | // произошла ошибка
380 | xhr.onerror = function(event) {
381 | that.setStatus('stand_by');
382 | fileUpPrivate.trigger(that._fileUp, 'error', [
383 | 'load_error',
384 | {
385 | file: that,
386 | fileData: file,
387 | event: event
388 | }
389 | ]);
390 | };
391 |
392 | xhr.open(options.httpMethod || 'post', options.url, true);
393 | xhr.setRequestHeader('Cache-Control', 'no-cache');
394 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
395 |
396 |
397 | fileUpPrivate.trigger(that._fileUp, 'load_before_start', [that, xhr]);
398 |
399 | if (window.FormData !== undefined) {
400 | let formData = new FormData();
401 | formData.append(options.fieldName, file);
402 |
403 | if (Object.keys(options.extraFields).length) {
404 | $.each(options.extraFields, function(name, value){
405 | formData.append(name, value);
406 | });
407 | }
408 |
409 | return xhr.send(formData);
410 |
411 | } else {
412 | // IE 8,9
413 | return xhr.send(file);
414 | }
415 | },
416 |
417 |
418 | /**
419 | * Отмена загрузки
420 | */
421 | abort: function() {
422 |
423 | if (this._xhr) {
424 | this._xhr.abort();
425 | }
426 | },
427 |
428 |
429 | /**
430 | * Рендер элемента
431 | * @param {string} tpl
432 | * @return {string|null}
433 | */
434 | render: function (tpl) {
435 |
436 | if ( ! tpl || typeof tpl !== 'string') {
437 | return null;
438 | }
439 |
440 | let lang = this._fileUp.getLang();
441 | let options = this._fileUp.getOptions();
442 | let that = this;
443 | let isNoPreview = false;
444 | let mimeTypes = fileUpUtils.isObject(options.mimeTypes) ? options.mimeTypes : {};
445 | let iconDefault = typeof options.iconDefault === 'string' ? options.iconDefault : '';
446 | let showRemove = typeof options.showRemove === 'boolean' ? options.showRemove : true;
447 | let size = this.getSizeHuman();
448 | let icon = null;
449 |
450 | let fileType = null;
451 | let fileExt = null;
452 |
453 | tpl = tpl.replace(/\[NAME\]/g, this.getName());
454 | tpl = tpl.replace(/\[SIZE\]/g, size);
455 | tpl = tpl.replace(/\[UPLOAD\]/g, lang.upload);
456 | tpl = tpl.replace(/\[REMOVE\]/g, lang.remove);
457 | tpl = tpl.replace(/\[ABORT\]/g, lang.abort);
458 |
459 | if (this._file &&
460 | this._file instanceof File
461 | ) {
462 | if (this._file.type &&
463 | typeof this._file.type === 'string' &&
464 | this._file.type.match(/^image\/.*/)
465 | ) {
466 | if (typeof FileReader !== 'undefined') {
467 | let reader = new FileReader();
468 | reader.onload = function (ProgressEvent) {
469 | if (that._fileElement) {
470 | let preview = that._fileElement.find('.fileup-preview');
471 |
472 | preview.removeClass('no-preview')
473 | .find('img').attr('src', ProgressEvent.target.result)
474 | }
475 | };
476 | reader.readAsDataURL(this._file);
477 | }
478 |
479 | isNoPreview = true;
480 |
481 | tpl = tpl.replace(/\[PREVIEW_SRC\]/g, '');
482 | tpl = tpl.replace(/\[TYPE\]/g, 'fileup-image fileup-no-preview');
483 |
484 | } else {
485 | tpl = tpl.replace(/\[PREVIEW_SRC\]/g, '');
486 | tpl = tpl.replace(/\[TYPE\]/g, 'fileup-doc');
487 |
488 | fileType = this._file.type;
489 | fileExt = this.getName().split('.').pop();
490 | }
491 |
492 | } else {
493 | let urlPreview = this.getUrlPreview();
494 |
495 | tpl = tpl.replace(/\[PREVIEW_SRC\]/g, urlPreview ? urlPreview : '');
496 | tpl = tpl.replace(/\[TYPE\]/g, urlPreview ? 'fileup-image' : 'fileup-doc');
497 |
498 | fileExt = this.getName() ? this.getName().split('.').pop().toLowerCase() : '';
499 | }
500 |
501 |
502 | this._fileElement = $(tpl);
503 |
504 | if (isNoPreview) {
505 | this._fileElement.find('.fileup-preview').addClass('no-preview');
506 | }
507 | if ( ! size) {
508 | this._fileElement.find('.fileup-size').hide();
509 | }
510 |
511 | if (fileType || fileExt) {
512 | $.each(mimeTypes, function (name, type) {
513 | if ( ! fileUpUtils.isObject(type) ||
514 | ! type.hasOwnProperty('icon') ||
515 | typeof type.icon !== 'string' ||
516 | type.icon === ''
517 | ) {
518 | return;
519 | }
520 |
521 | if (fileType && type.hasOwnProperty('mime')) {
522 | if (typeof type.mime === 'string') {
523 | if (type.mime === fileType) {
524 | icon = type.icon;
525 | return false;
526 | }
527 |
528 | } else if (Array.isArray(type.mime)) {
529 | $.each(type.mime, function (key, mime) {
530 | if (typeof mime === 'string' && mime === fileType) {
531 | icon = type.icon;
532 | return false;
533 | }
534 | });
535 |
536 | if (icon) {
537 | return false;
538 | }
539 |
540 | } else if (type.mime instanceof RegExp) {
541 | if (type.mime.test(fileType)) {
542 | icon = type.icon;
543 | return false;
544 | }
545 | }
546 | }
547 |
548 | if (fileExt && type.hasOwnProperty('ext') && Array.isArray(type.ext)) {
549 | $.each(type.ext, function (key, ext) {
550 | if (typeof ext === 'string' && ext === fileExt) {
551 | icon = type.icon;
552 | return false;
553 | }
554 | });
555 |
556 | if (icon) {
557 | return false;
558 | }
559 | }
560 | });
561 | }
562 |
563 | if ( ! icon) {
564 | icon = iconDefault;
565 | }
566 |
567 | this._fileElement.find('.fileup-icon').addClass(icon);
568 |
569 |
570 | if ( ! showRemove) {
571 | this._fileElement.find('.fileup-remove').hide();
572 | }
573 |
574 | if (this.getUrlDownload()) {
575 | let $name = this._fileElement.find('.fileup-name');
576 | if ($name[0]) {
577 | $name.replaceWith(
578 | '' +
579 | this.getName() +
580 | ''
581 | );
582 | }
583 | }
584 |
585 | if (this._status === 'finish') {
586 | this._fileElement.find('.fileup-upload').hide();
587 | this._fileElement.find('.fileup-abort').hide();
588 | this._fileElement.find('.fileup-progress').hide();
589 |
590 | } else {
591 | this._fileElement.find('.fileup-upload').click(function () {
592 | that.upload();
593 | });
594 |
595 | this._fileElement.find('.fileup-abort').click(function () {
596 | that.abort();
597 | });
598 | }
599 |
600 | this._fileElement.find('.fileup-remove').click(function () {
601 | that.remove();
602 | });
603 |
604 |
605 | return this._fileElement;
606 | }
607 | }
608 |
609 | export default fileUpFile;
--------------------------------------------------------------------------------
/src/js/fileup.instance.js:
--------------------------------------------------------------------------------
1 | import fileUpUtils from './fileup.utils';
2 | import fileUpPrivate from './fileup.private';
3 | import fileUpFile from "./fileup.file";
4 | import tpl from './fileup.templates';
5 |
6 | let fileUpInstance = {
7 |
8 | _options: {
9 | id: null,
10 | url: null,
11 | input: null,
12 | queue: null,
13 | dropzone: null,
14 | files: [],
15 | fieldName: 'file',
16 | extraFields: {},
17 | lang: 'en',
18 | langItems: null,
19 | sizeLimit: 0,
20 | filesLimit: 0,
21 | httpMethod: 'post',
22 | timeout: null,
23 | autostart: false,
24 | showRemove: true,
25 | templateFile: null,
26 |
27 | onSelect: null,
28 | onRemove: null,
29 | onBeforeStart: null,
30 | onStart: null,
31 | onProgress: null,
32 | onAbort: null,
33 | onSuccess: null,
34 | onFinish: null,
35 | onError: null,
36 | onDragOver: null,
37 | onDragLeave: null,
38 | onDragEnd: null,
39 | onDragEnter: null,
40 |
41 | iconDefault: 'bi bi-file-earmark-text',
42 | mimeTypes: {
43 | archive: {
44 | mime: ['application/zip', 'application/gzip', 'application/x-bzip', 'application/x-bzip2', 'application/x-7z-compressed'],
45 | ext: ['zip', '7z', 'bz', 'bz2', 'gz', 'jar', 'rar', 'tar'],
46 | icon: 'bi bi-file-earmark-zip'
47 | },
48 | word: {
49 | mime: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
50 | ext: ['doc', 'docx'],
51 | icon: 'bi bi-file-earmark-word'
52 | },
53 | excel: {
54 | mime: ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
55 | ext: ['xls', 'xlsx'],
56 | icon: 'bi bi-file-earmark-excel'
57 | },
58 | image: {
59 | mime: /image\/.*/,
60 | ext: ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'raw', 'webp', 'heic', 'ico'],
61 | icon: 'bi bi-file-earmark-image'
62 | },
63 | video: {
64 | mime: /video\/.*/,
65 | ext: ['avi', 'mp4', 'mpeg', 'ogv', 'ts', 'webm', '3gp', '3g2', 'mkv'],
66 | icon: 'bi bi-file-earmark-play'
67 | },
68 | audio: {
69 | mime: /audio\/.*/,
70 | ext: ['avi', 'mp4', 'mpeg', 'ogv', 'ts', 'webm', '3gp', '3g2', 'mkv'],
71 | icon: 'bi bi-file-earmark-music'
72 | },
73 | pdf: {
74 | mime: ['application/pdf'],
75 | ext: ['pdf'],
76 | icon: 'bi bi-file-earmark-pdf'
77 | },
78 | binary: {
79 | mime: ['application\/octet-stream'],
80 | ext: ['bin', 'exe', 'dat', 'dll'],
81 | icon: 'bi bi-file-earmark-binary'
82 | }
83 | }
84 | },
85 |
86 | _id: null,
87 | _fileUp: null,
88 | _fileIndex: 0,
89 | _input: null,
90 | _queue: null,
91 | _dropzone: null,
92 | _files: {},
93 | _events: {},
94 |
95 |
96 | /**
97 | * Инициализация
98 | * @param {object} fileUp
99 | * @param {object} options
100 | * @private
101 | */
102 | _init: function (fileUp, options) {
103 |
104 | if (typeof options.url !== 'string' || ! options.url) {
105 | throw new Error('Dont set url param');
106 | }
107 |
108 | this._fileUp = fileUp;
109 | this._options = $.extend(true, {}, this._options, options);
110 | this._id = typeof this._options.id === 'string' && this._options.id
111 | ? this._options.id
112 | : fileUpUtils.hashCode();
113 |
114 | if ( ! this._options.templateFile || typeof this._options.templateFile !== 'string') {
115 | this._options.templateFile = tpl['file.html'];
116 | }
117 |
118 |
119 | fileUpPrivate.initInput(this);
120 | fileUpPrivate.initQueue(this);
121 | fileUpPrivate.initDropzone(this);
122 | fileUpPrivate.initEvents(this);
123 |
124 | fileUpPrivate.renderFiles(this);
125 | },
126 |
127 |
128 | /**
129 | * Разрушение экземпляра
130 | */
131 | destruct: function () {
132 |
133 | let id = this.getId();
134 |
135 | if ( ! this._fileUp._instances.hasOwnProperty(id)) {
136 | return;
137 | }
138 |
139 | delete this._fileUp._instances[id];
140 | },
141 |
142 |
143 | /**
144 | * Получение параметров
145 | * @returns {object}
146 | */
147 | getOptions: function () {
148 | return this._options;
149 | },
150 |
151 |
152 | /**
153 | * Получение id
154 | * @return {string|null}
155 | */
156 | getId: function () {
157 | return this._id;
158 | },
159 |
160 |
161 | /**
162 | * Получение input
163 | * @return {jQuery|null}
164 | */
165 | getInput: function () {
166 | return this._input;
167 | },
168 |
169 |
170 | /**
171 | * Получение queue
172 | * @return {jQuery|null}
173 | */
174 | getQueue: function () {
175 | return this._queue;
176 | },
177 |
178 |
179 | /**
180 | * Получение dropzone
181 | * @return {jQuery|null}
182 | */
183 | getDropzone: function () {
184 | return this._dropzone;
185 | },
186 |
187 |
188 | /**
189 | * Подписка на событие
190 | * @param {string} eventName
191 | * @param {function|string} callback
192 | * @param {object|undefined} context
193 | */
194 | on: function(eventName, callback, context) {
195 | if (typeof this._events[eventName] !== 'object') {
196 | this._events[eventName] = [];
197 | }
198 | this._events[eventName].push({
199 | context : context || this,
200 | callback: callback,
201 | singleExec: false
202 | });
203 | },
204 |
205 |
206 | /**
207 | * Подписка на событие таким образом, что выполнение произойдет лишь один раз
208 | * @param {string} eventName
209 | * @param {function|string} callback
210 | * @param {object|undefined} context
211 | */
212 | one: function(eventName, callback, context) {
213 | if (typeof this._events[eventName] !== 'object') {
214 | this._events[eventName] = [];
215 | }
216 | this._events[eventName].push({
217 | context : context || this,
218 | callback: callback,
219 | singleExec: true,
220 | });
221 | },
222 |
223 |
224 | /**
225 | * Получение настроек языка
226 | */
227 | getLang: function () {
228 | return $.extend(true, {}, this._options.langItems);
229 | },
230 |
231 |
232 | /**
233 | * Получение всех файлов
234 | * @return {object}
235 | */
236 | getFiles: function () {
237 |
238 | return this._files;
239 | },
240 |
241 |
242 | /**
243 | * Получение файла по его id
244 | * @param {int} fileId
245 | * @return {object|null}
246 | */
247 | getFileById: function (fileId) {
248 |
249 | let result = null;
250 |
251 | $.each(this._files, function (key, file) {
252 | if (fileId === file.getId()) {
253 | result = file;
254 | }
255 | });
256 |
257 | return result;
258 | },
259 |
260 |
261 | /**
262 | * Удаление всех файлов
263 | */
264 | removeAll: function() {
265 |
266 | $.each(this._files, function (key, file) {
267 | file.remove();
268 | });
269 | },
270 |
271 |
272 | /**
273 | * Загрузка всех файлов
274 | */
275 | uploadAll: function() {
276 |
277 | $.each(this._files, function (key, file) {
278 | file.upload();
279 | });
280 | },
281 |
282 |
283 | /**
284 | * Отмена загрузки всех файлов
285 | */
286 | abortAll: function() {
287 |
288 | $.each(this._files, function (key, file) {
289 | file.abort();
290 | });
291 | },
292 |
293 |
294 | /**
295 | * Добавление файла в список из объекта File
296 | * @param {object} file
297 | * @result {boolean}
298 | */
299 | appendFile: function (file) {
300 |
301 | if ( ! (file instanceof File)) {
302 | return false;
303 | }
304 |
305 | let fileInstance = $.extend(true, {}, fileUpFile);
306 | let data = {
307 | name: fileUpUtils.getFileName(file),
308 | size: fileUpUtils.getFileSize(file),
309 | type: file.type
310 | };
311 |
312 |
313 | fileInstance._init(this, this._fileIndex, data, file);
314 |
315 | this._files[this._fileIndex] = fileInstance;
316 |
317 | let queue = this.getQueue();
318 | if (queue) {
319 | queue.append(
320 | fileInstance.render(this._options.templateFile)
321 | );
322 | }
323 |
324 | this._fileIndex++;
325 |
326 |
327 | if (typeof this._options.autostart === 'boolean' &&
328 | this._options.autostart
329 | ) {
330 | fileInstance.upload();
331 | }
332 |
333 | return true;
334 | },
335 |
336 |
337 | /**
338 | * Добавление файла в список из данных
339 | * @param {object} data
340 | * @result {boolean}
341 | */
342 | appendFileByData: function (data) {
343 |
344 | if ( ! fileUpUtils.isObject(data)) {
345 | return false;
346 | }
347 |
348 | let fileInstance = $.extend(true, {}, fileUpFile);
349 |
350 | fileInstance._init(this, this._fileIndex, data);
351 | fileInstance.setStatus('finish');
352 |
353 | this._files[this._fileIndex] = fileInstance;
354 |
355 | let queue = this.getQueue();
356 | if (queue) {
357 | queue.append(
358 | fileInstance.render(this._options.templateFile)
359 | );
360 | }
361 |
362 | this._fileIndex++;
363 |
364 | return true;
365 | }
366 | }
367 |
368 | export default fileUpInstance;
--------------------------------------------------------------------------------
/src/js/fileup.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUpInstance from './fileup.instance';
3 | import fileUpUtils from './fileup.utils';
4 |
5 | let fileUp = {
6 |
7 | lang: {},
8 |
9 | _instances: {},
10 |
11 | /**
12 | * Создание экземпляра
13 | * @param {object} options
14 | * @returns {object}
15 | */
16 | create: function (options) {
17 |
18 | options = fileUpUtils.isObject(options) ? options : {};
19 |
20 | if ( ! options.hasOwnProperty('lang')) {
21 | options.lang = 'en';
22 | }
23 |
24 | let langList = this.lang.hasOwnProperty(options.lang) ? this.lang[options.lang] : {};
25 | options.langItems = options.hasOwnProperty('langItems') && fileUpUtils.isObject(options.langItems)
26 | ? $.extend(true, {}, langList, options.langItems)
27 | : langList;
28 |
29 | let instance = $.extend(true, {}, fileUpInstance);
30 | instance._init(this, options);
31 |
32 | let id = instance.getId();
33 | this._instances[id] = instance;
34 |
35 | return instance;
36 | },
37 |
38 |
39 | /**
40 | * Получение экземпляра по id
41 | * @param {string} id
42 | * @returns {object|null}
43 | */
44 | get: function (id) {
45 |
46 | if ( ! this._instances.hasOwnProperty(id)) {
47 | return null;
48 | }
49 |
50 | if ( ! $.contains(document, this._instances[id]._input[0])) {
51 | delete this._instances[id];
52 | return null;
53 | }
54 |
55 | return this._instances[id];
56 | }
57 | }
58 |
59 | export default fileUp;
--------------------------------------------------------------------------------
/src/js/fileup.private.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUpUtils from "./fileup.utils";
3 | import fileUpEvents from "./fileup.events";
4 |
5 |
6 | let fileUpPrivate = {
7 |
8 | /**
9 | *
10 | * @param {object} fileUp
11 | */
12 | initInput: function (fileUp) {
13 |
14 | let input = null;
15 |
16 | if (fileUp._options.input instanceof HTMLElement ||
17 | fileUp._options.input instanceof jQuery
18 | ) {
19 | input = $(fileUp._options.input);
20 |
21 | } else if (typeof fileUp._options.input === 'string' &&
22 | fileUp._options.input
23 | ) {
24 | input = $('#' + fileUp._options.input);
25 | }
26 |
27 | if ( ! input || ! $(input)[0] || $(input)[0].type !== 'file') {
28 | throw new Error('Not found input element');
29 | }
30 |
31 | fileUp._input = input;
32 | },
33 |
34 |
35 | /**
36 | *
37 | * @param {object} fileUp
38 | */
39 | initQueue: function (fileUp) {
40 |
41 | let queue = null;
42 |
43 | if (fileUp._options.queue instanceof HTMLElement ||
44 | fileUp._options.queue instanceof jQuery
45 | ) {
46 | queue = $(fileUp._options.queue);
47 |
48 | } else if (typeof fileUp._options.queue === 'string' &&
49 | fileUp._options.queue
50 | ) {
51 | queue = $('#' + fileUp._options.queue);
52 | }
53 |
54 | if ( ! queue || ! $(queue)[0]) {
55 | throw new Error('Not found queue element');
56 | }
57 |
58 | fileUp._queue = queue;
59 | },
60 |
61 |
62 | /**
63 | *
64 | * @param {object} fileUp
65 | */
66 | initDropzone: function (fileUp) {
67 |
68 | let dropzone = null;
69 |
70 | if (fileUp._options.dropzone instanceof HTMLElement ||
71 | fileUp._options.dropzone instanceof jQuery
72 | ) {
73 | dropzone = $(fileUp._options.dropzone);
74 |
75 | } else if (typeof fileUp._options.dropzone === 'string' &&
76 | fileUp._options.dropzone
77 | ) {
78 | dropzone = $('#' + fileUp._options.dropzone);
79 | }
80 |
81 |
82 | if (dropzone) {
83 | fileUp._dropzone = dropzone;
84 |
85 | let that = this;
86 |
87 | dropzone.on('click', function () {
88 | fileUp.getInput().click();
89 | });
90 |
91 | dropzone[0].addEventListener('dragover', function (event) {
92 | that.trigger(fileUp, 'drag_over', [event]);
93 | });
94 |
95 | dropzone[0].addEventListener('dragleave', function (event) {
96 | that.trigger(fileUp, 'drag_leave', [event]);
97 | });
98 |
99 | dropzone[0].addEventListener('dragenter', function (event) {
100 | that.trigger(fileUp, 'drag_enter', [event]);
101 | });
102 |
103 | dropzone[0].addEventListener('dragend', function (event) {
104 | that.trigger(fileUp, 'drag_end', [event]);
105 | });
106 |
107 | dropzone[0].addEventListener('drop', function (event) {
108 | fileUp.getInput()[0].files = event.target.files || event.dataTransfer.files
109 | that.appendFiles(fileUp, event)
110 | });
111 | }
112 | },
113 |
114 |
115 | /**
116 | * Инициализация событий
117 | * @param {object} fileUp
118 | */
119 | initEvents: function (fileUp) {
120 |
121 | /**
122 | * @param {string} name
123 | * @param {function|string} func
124 | */
125 | function setEvent(name, func) {
126 |
127 | let event = null;
128 |
129 | if (typeof func === 'function') {
130 | event = func;
131 | } else if (typeof func === 'string') {
132 | event = new Function(func);
133 | }
134 |
135 | if (event) {
136 | fileUp.on(name, event);
137 | }
138 | }
139 |
140 |
141 | let options = fileUp.getOptions();
142 | let that = this;
143 |
144 | setEvent('load_start', fileUpEvents.onLoadStart);
145 | setEvent('load_progress', fileUpEvents.onLoadProgress);
146 | setEvent('load_abort', fileUpEvents.onLoadAbort);
147 | setEvent('load_success', fileUpEvents.onSuccess);
148 | setEvent('error', fileUpEvents.onError);
149 | setEvent('drag_over', fileUpEvents.onDragOver);
150 | setEvent('drag_leave', fileUpEvents.onDragEnter);
151 | setEvent('drag_end', fileUpEvents.onDragLeave);
152 | setEvent('drag_enter', fileUpEvents.onDragEnd);
153 |
154 | if (options.onSelect) { setEvent('select', options.onSelect) }
155 | if (options.onRemove) { setEvent('remove', options.onRemove) }
156 | if (options.onBeforeStart) { setEvent('load_before_start', options.onBeforeStart) }
157 | if (options.onStart) { setEvent('load_start', options.onStart) }
158 | if (options.onProgress) { setEvent('load_progress', options.onProgress) }
159 | if (options.onAbort) { setEvent('load_abort', options.onAbort) }
160 | if (options.onSuccess) { setEvent('load_success', options.onSuccess) }
161 | if (options.onFinish) { setEvent('load_finish', options.onFinish) }
162 | if (options.onError) { setEvent('error', options.onError) }
163 | if (options.onDragOver) { setEvent('drag_over', options.onDragOver) }
164 | if (options.onDragLeave) { setEvent('drag_leave', options.onDragLeave) }
165 | if (options.onDragEnd) { setEvent('drag_end', options.onDragEnd) }
166 | if (options.onDragEnter) { setEvent('drag_enter', options.onDragEnter) }
167 |
168 |
169 | fileUp.getInput().on('change', function (event) {
170 | that.appendFiles(fileUp, event);
171 | });
172 | },
173 |
174 |
175 | /**
176 | * Формирование списка ранее загруженных файлов
177 | * @param {object} fileUp
178 | */
179 | renderFiles: function (fileUp) {
180 |
181 | let options = fileUp.getOptions();
182 |
183 | if (Array.isArray(options.files) && options.files.length > 0) {
184 | for (var i = 0; i < options.files.length; i++) {
185 | if ( ! fileUpUtils.isObject(options.files[i])) {
186 | continue;
187 | }
188 |
189 | fileUp.appendFileByData(options.files[i]);
190 | }
191 | }
192 | },
193 |
194 |
195 | /**
196 | * @param fileUp
197 | * @param name
198 | * @param params
199 | * @return {object}
200 | * @private
201 | */
202 | trigger: function(fileUp, name, params) {
203 |
204 | params = params || [];
205 | let results = [];
206 |
207 | if (fileUp._events[name] instanceof Object && fileUp._events[name].length > 0) {
208 | for (var i = 0; i < fileUp._events[name].length; i++) {
209 | let callback = fileUp._events[name][i].callback;
210 |
211 | results.push(
212 | callback.apply(fileUp._events[name][i].context || fileUp, params)
213 | );
214 |
215 | if (fileUp._events[name][i].singleExec) {
216 | fileUp._events[name].splice(i, 1);
217 | i--;
218 | }
219 | }
220 | }
221 |
222 | return results;
223 | },
224 |
225 |
226 | /**
227 | * Append files in queue
228 | * @param {object} fileUp
229 | * @param {Event} event
230 | */
231 | appendFiles: function(fileUp, event) {
232 |
233 | event.preventDefault();
234 | event.stopPropagation();
235 |
236 | let options = fileUp.getOptions();
237 | let input = fileUp.getInput();
238 | let files = input[0].files;
239 | let multiple = input.is("[multiple]");
240 |
241 | if (files.length > 0) {
242 | for (var i = 0; i < files.length; i++) {
243 | let file = files[i];
244 |
245 | if (options.sizeLimit > 0 && fileUpUtils.getFileSize(file) > options.sizeLimit) {
246 | this.trigger(fileUp, 'error', ['size_limit', { fileData: file, sizeLimit: options.sizeLimit }]);
247 | continue;
248 | }
249 |
250 | if (options.filesLimit > 0 && Object.keys(fileUp._files).length >= options.filesLimit) {
251 | this.trigger(fileUp, 'error', ['files_limit', { fileData: file, filesLimit: options.filesLimit }]);
252 | break;
253 | }
254 |
255 | if (typeof input[0].accept === 'string') {
256 | let accept = input[0].accept;
257 | if (accept && /[^\w]+/.test(accept)) {
258 | let isAccept = false;
259 | let types = accept.split(',');
260 |
261 | if (types.length > 0) {
262 | for (var t = 0; t < types.length; t++) {
263 | types[t] = types[t].replace(/\s/g, '');
264 | if (new RegExp(types[t].replace('*', '.*')).test(file.type) ||
265 | new RegExp(types[t].replace('.', '.*/')).test(file.type)
266 | ) {
267 | isAccept = true;
268 | break;
269 | }
270 | }
271 | }
272 | if ( ! isAccept) {
273 | this.trigger(fileUp, 'error', ['file_type', { fileData: file }]);
274 | continue;
275 | }
276 | }
277 | }
278 |
279 | let results = this.trigger(fileUp, 'select', [file]);
280 |
281 | if (results) {
282 | let isContinue = false;
283 |
284 | $.each(results, function (key, result) {
285 | if (result === false) {
286 | isContinue = true;
287 | return false;
288 | }
289 | })
290 |
291 | if (isContinue) {
292 | continue;
293 | }
294 | }
295 |
296 | if ( ! multiple) {
297 | fileUp.removeAll();
298 | }
299 |
300 | fileUp.appendFile(file);
301 |
302 | if ( ! multiple) {
303 | break;
304 | }
305 | }
306 |
307 | input.val('');
308 | }
309 |
310 | this.trigger(fileUp, 'dragEnd', [event]);
311 | }
312 | }
313 |
314 | export default fileUpPrivate;
--------------------------------------------------------------------------------
/src/js/fileup.templates.js:
--------------------------------------------------------------------------------
1 | let tpl = Object.create(null)
2 | tpl['file.html'] = ' [NAME] ([SIZE])
✕ [UPLOAD] [ABORT]
';
3 | export default tpl;
--------------------------------------------------------------------------------
/src/js/fileup.utils.js:
--------------------------------------------------------------------------------
1 |
2 | let fileUpUtils = {
3 |
4 |
5 | /**
6 | * Проверка на объект
7 | * @param value
8 | */
9 | isObject: function (value) {
10 |
11 | return typeof value === 'object' &&
12 | ! Array.isArray(value) &&
13 | value !== null;
14 | },
15 |
16 |
17 | /**
18 | * Проверка на число
19 | * @param num
20 | * @returns {boolean}
21 | * @private
22 | */
23 | isNumeric: function(num) {
24 | return (typeof(num) === 'number' || typeof(num) === "string" && num.trim() !== '') && ! isNaN(num);
25 | },
26 |
27 |
28 | /**
29 | * Получение размера файла в байтах
30 | * @param {File} file
31 | * @return {int|null}
32 | */
33 | getFileSize: function (file) {
34 |
35 | if ( ! (file instanceof File)) {
36 | return null;
37 | }
38 |
39 | return file.size || file.fileSize;
40 | },
41 |
42 |
43 | /**
44 | * Получение названия файла
45 | * @param {File} file
46 | * @return {string|null}
47 | */
48 | getFileName: function (file) {
49 |
50 | if ( ! (file instanceof File)) {
51 | return null;
52 | }
53 |
54 | return file.name || file.fileName;
55 | },
56 |
57 |
58 | /**
59 | * Formatting size
60 | * @param {int} size
61 | * @returns {string}
62 | */
63 | getSizeHuman: function(size) {
64 |
65 | if ( ! fileUpUtils.isNumeric(size)) {
66 | return '';
67 | }
68 |
69 | size = Number(size);
70 |
71 | let result = '';
72 |
73 | if (size >= 1073741824) {
74 | result = (size / 1073741824).toFixed(2) + ' Gb';
75 | } else if (size >= 1048576) {
76 | result = (size / 1048576).toFixed(2) + ' Mb';
77 | } else if (size >= 1024) {
78 | result = (size / 1024).toFixed(2) + ' Kb';
79 | } else if (size >= 0) {
80 | result = size + ' bytes';
81 | }
82 |
83 | return result;
84 | },
85 |
86 |
87 | /**
88 | * Создание уникальной строки хэша
89 | * @returns {string}
90 | * @private
91 | */
92 | hashCode: function() {
93 | return this.crc32((new Date().getTime() + Math.random()).toString()).toString(16);
94 | },
95 |
96 |
97 | /**
98 | * Hash crc32
99 | * @param str
100 | * @returns {number}
101 | * @private
102 | */
103 | crc32: function (str) {
104 |
105 | for (var a, o = [], c = 0; c < 256; c++) {
106 | a = c;
107 | for (var f = 0; f < 8; f++) {
108 | a = 1 & a ? 3988292384 ^ a >>> 1 : a >>> 1
109 | }
110 | o[c] = a
111 | }
112 |
113 | for (var n = -1, t = 0; t < str.length; t++) {
114 | n = n >>> 8 ^ o[255 & (n ^ str.charCodeAt(t))]
115 | }
116 |
117 | return (-1 ^ n) >>> 0;
118 | }
119 | }
120 |
121 | export default fileUpUtils;
--------------------------------------------------------------------------------
/src/js/lang/en.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUp from "../fileup";
3 |
4 | fileUp.lang.en = {
5 | upload: 'Upload',
6 | abort: 'Abort',
7 | remove: 'Remove',
8 | complete: 'Complete',
9 | error: 'Error',
10 | errorLoad: 'Error uploading file',
11 | errorBadStatus: 'Error uploading file. Bad request.',
12 | errorFilesLimit: 'The number of selected files exceeds the limit (%filesLimit%)',
13 | errorSizeLimit: 'File "%fileName%" exceeds the size limit (%sizeLimit%)',
14 | errorFileType: 'File "%fileName%" is incorrect',
15 | errorOldBrowser: 'Your browser can not upload files. Update to the latest version'
16 | }
--------------------------------------------------------------------------------
/src/js/lang/es.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUp from "../fileup";
3 |
4 | fileUp.lang.es = {
5 | upload: 'Subir',
6 | abort: 'Cancelar',
7 | remove: 'Eliminar',
8 | complete: 'Cargado',
9 | error: 'Error',
10 | errorLoad: 'Error al cargar el archivo',
11 | errorBadStatus: 'Error al cargar el archivo. Solicitud no válida.',
12 | errorFilesLimit: 'El número de archivo selecccionados excede el límite (%filesLimit%)',
13 | errorSizeLimit: 'El archivo "%fileName%" excede el limite de tamaño (%sizeLimit%)',
14 | errorFileType: 'El archivo "%fileName%" es inválido',
15 | errorOldBrowser: 'Tu navegador no puede subir archivos. Actualiza a la última versión'
16 | }
--------------------------------------------------------------------------------
/src/js/lang/pt.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUp from "../fileup";
3 |
4 | fileUp.lang.pt = {
5 | upload: 'Enviar',
6 | abort: 'Cancelar',
7 | remove: 'Remover',
8 | complete: 'Enviado',
9 | error: 'Erro',
10 | errorLoad: 'Erro ao carregar o arquivo',
11 | errorBadStatus: 'Erro ao carregar o arquivo. Pedido inválido.',
12 | errorFilesLimit: 'O número de arquivos selecionados excede o limite (%filesLimit%)',
13 | errorSizeLimit: 'Arquivo "%fileName%" excede o limite (%sizeLimit%)',
14 | errorFileType: 'Arquivo "%fileName%" inválido',
15 | errorOldBrowser: 'Seu navegador não pode enviar os arquivos. Atualize para a versão mais recente'
16 | }
--------------------------------------------------------------------------------
/src/js/lang/ru.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUp from "../fileup";
3 |
4 | fileUp.lang.ru = {
5 | upload: 'Загрузить',
6 | abort: 'Остановить',
7 | remove: 'Удалить',
8 | complete: 'Готово',
9 | error: 'Ошибка',
10 | errorLoad: 'Ошибка при загрузке файла',
11 | errorBadStatus: 'Ошибка при загрузке файла. Некорректный запрос.',
12 | errorFilesLimit: 'Количество выбранных файлов превышает лимит (%filesLimit%)',
13 | errorSizeLimit: 'Файл "%fileName%" превышает предельный размер (%sizeLimit%)',
14 | errorFileType: 'Файл "%fileName%" является некорректным',
15 | errorOldBrowser: 'Обновите ваш браузер до последней версии'
16 | }
--------------------------------------------------------------------------------
/src/js/main.js:
--------------------------------------------------------------------------------
1 |
2 | import fileUp from "./fileup";
3 |
4 | import "./lang/en";
5 | import "./lang/ru";
6 | import "./lang/es";
7 | import "./lang/pt";
8 |
9 | export default fileUp;
--------------------------------------------------------------------------------