Ticket #48277: 48277.diff
File 48277.diff, 372.0 KB (added by , 6 years ago) |
---|
-
src/js/_enqueues/vendor/plupload/license.txt
1 GNUGENERAL PUBLIC LICENSE2 Version 2, June 1991 1 GNU AFFERO GENERAL PUBLIC LICENSE 2 Version 3, 19 November 2007 3 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. 4 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> 5 Everyone is permitted to copy and distribute verbatim copies 6 of this license document, but changing it is not allowed. 8 7 9 8 Preamble 10 9 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. 10 The GNU Affero General Public License is a free, copyleft license for 11 software and other kinds of works, specifically designed to ensure 12 cooperation with the community in the case of network server software. 20 13 21 When we speak of free software, we are referring to freedom, not 14 The licenses for most software and other practical works are designed 15 to take away your freedom to share and change the works. By contrast, 16 our General Public Licenses are intended to guarantee your freedom to 17 share and change all versions of a program--to make sure it remains free 18 software for all its users. 19 20 When we speak of free software, we are referring to freedom, not 22 21 price. Our General Public Licenses are designed to make sure that you 23 22 have the freedom to distribute copies of free software (and charge for 24 th is service if you wish), that you receive source code or can get it25 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.23 them if you wish), that you receive source code or can get it if you 24 want it, that you can change the software or use pieces of it in new 25 free programs, and that you know you can do these things. 27 26 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.27 Developers that use our General Public Licenses protect your rights 28 with two steps: (1) assert copyright on the software, and (2) offer 29 you this License which gives you legal permission to copy, distribute 30 and/or modify the software. 32 31 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. 32 A secondary benefit of defending all users' freedom is that 33 improvements made in alternate versions of the program, if they 34 receive widespread use, become available for other developers to 35 incorporate. Many developers of free software are heartened and 36 encouraged by the resulting cooperation. However, in the case of 37 software used on network servers, this result may fail to come about. 38 The GNU General Public License permits making a modified version and 39 letting the public access it on a server without ever releasing its 40 source code to the public. 38 41 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 The GNU Affero General Public License is designed specifically to 43 ensure that, in such cases, the modified source code becomes available 44 to the community. It requires the operator of a network server to 45 provide the source code of the modified version running there to the 46 users of that server. Therefore, public use of a modified version, on 47 a publicly accessible server, gives the public access to the source 48 code of the modified version. 42 49 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. 50 An older license, called the Affero General Public License and 51 published by Affero, was designed to accomplish similar goals. This is 52 a different license, not a version of the Affero GPL, but Affero has 53 released a new version of the Affero GPL which permits relicensing under 54 this license. 49 55 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 56 The precise terms and conditions for copying, distribution and 57 57 modification follow. 58 58 59 GNU GENERAL PUBLIC LICENSE 60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 59 TERMS AND CONDITIONS 61 60 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". 61 0. Definitions. 71 62 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. 63 "This License" refers to version 3 of the GNU Affero General Public License. 78 64 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. 65 "Copyright" also means copyright-like laws that apply to other kinds of 66 works, such as semiconductor masks. 86 67 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. 68 "The Program" refers to any copyrightable work licensed under this 69 License. Each licensee is addressed as "you". "Licensees" and 70 "recipients" may be individuals or organizations. 89 71 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: 72 To "modify" a work means to copy from or adapt all or part of the work 73 in a fashion requiring copyright permission, other than the making of an 74 exact copy. The resulting work is called a "modified version" of the 75 earlier work or a work "based on" the earlier work. 94 76 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.77 A "covered work" means either the unmodified Program or a work based 78 on the Program. 97 79 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. 80 To "propagate" a work means to do anything with it that, without 81 permission, would make you directly or secondarily liable for 82 infringement under applicable copyright law, except executing it on a 83 computer or modifying a private copy. Propagation includes copying, 84 distribution (with or without modification), making available to the 85 public, and in some countries other activities as well. 102 86 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.) 87 To "convey" a work means any kind of propagation that enables other 88 parties to make or receive copies. Mere interaction with a user through 89 a computer network, with no transfer of a copy, is not conveying. 113 90 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. 91 An interactive user interface displays "Appropriate Legal Notices" 92 to the extent that it includes a convenient and prominently visible 93 feature that (1) displays an appropriate copyright notice, and (2) 94 tells the user that there is no warranty for the work (except to the 95 extent that warranties are provided), that licensees may convey the 96 work under this License, and how to view a copy of this License. If 97 the interface presents a list of user commands or options, such as a 98 menu, a prominent item in the list meets this criterion. 123 99 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. 100 1. Source Code. 128 101 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. 102 The "source code" for a work means the preferred form of the work 103 for making modifications to it. "Object code" means any non-source 104 form of a work. 133 105 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: 106 A "Standard Interface" means an interface that either is an official 107 standard defined by a recognized standards body, or, in the case of 108 interfaces specified for a particular programming language, one that 109 is widely used among developers working in that language. 137 110 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, 111 The "System Libraries" of an executable work include anything, other 112 than the work as a whole, that (a) is included in the normal form of 113 packaging a Major Component, but which is not part of that Major 114 Component, and (b) serves only to enable use of the work with that 115 Major Component, or to implement a Standard Interface for which an 116 implementation is available to the public in source code form. A 117 "Major Component", in this context, means a major essential component 118 (kernel, window system, and so on) of the specific operating system 119 (if any) on which the executable work runs, or a compiler used to 120 produce the work, or an object code interpreter used to run it. 141 121 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, 122 The "Corresponding Source" for a work in object code form means all 123 the source code needed to generate, install, and (for an executable 124 work) run the object code and to modify the work, including scripts to 125 control those activities. However, it does not include the work's 126 System Libraries, or general-purpose tools or generally available free 127 programs which are used unmodified in performing those activities but 128 which are not part of the work. For example, Corresponding Source 129 includes interface definition files associated with source files for 130 the work, and the source code for shared libraries and dynamically 131 linked subprograms that the work is specifically designed to require, 132 such as by intimate data communication or control flow between those 133 subprograms and other parts of the work. 148 134 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.) 135 The Corresponding Source need not include anything that users 136 can regenerate automatically from other parts of the Corresponding 137 Source. 154 138 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. 139 The Corresponding Source for a work in source code form is that 140 same work. 165 141 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. 142 2. Basic Permissions. 171 143 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.144 All rights granted under this License are granted for the term of 145 copyright on the Program, and are irrevocable provided the stated 146 conditions are met. This License explicitly affirms your unlimited 147 permission to run the unmodified Program. The output from running a 148 covered work is covered by this License only if the output, given its 149 content, constitutes a covered work. This License acknowledges your 150 rights of fair use or other equivalent, as provided by copyright law. 179 151 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. 152 You may make, run and propagate covered works that you do not 153 convey, without conditions so long as your license otherwise remains 154 in force. You may convey covered works to others for the sole purpose 155 of having them make modifications exclusively for you, or provide you 156 with facilities for running those works, provided that you comply with 157 the terms of this License in conveying all material for which you do 158 not control copyright. Those thus making or running the covered works 159 for you must do so exclusively on your behalf, under your direction 160 and control, on terms that prohibit them from making any copies of 161 your copyrighted material outside their relationship with you. 188 162 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 163 Conveying under any other circumstances is permitted solely under 164 the conditions stated below. Sublicensing is not allowed; section 10 165 makes it unnecessary. 166 167 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 169 No covered work shall be deemed part of an effective technological 170 measure under any applicable law fulfilling obligations under article 171 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 similar laws prohibiting or restricting circumvention of such 173 measures. 174 175 When you convey a covered work, you waive any legal power to forbid 176 circumvention of technological measures to the extent such circumvention 177 is effected by exercising rights under this License with respect to 178 the covered work, and you disclaim any intention to limit operation or 179 modification of the work as a means of enforcing, against the work's 180 users, your or third parties' legal rights to forbid circumvention of 181 technological measures. 182 183 4. Conveying Verbatim Copies. 184 185 You may convey verbatim copies of the Program's source code as you 186 receive it, in any medium, provided that you conspicuously and 187 appropriately publish on each copy an appropriate copyright notice; 188 keep intact all notices stating that this License and any 189 non-permissive terms added in accord with section 7 apply to the code; 190 keep intact all notices of the absence of any warranty; and give all 191 recipients a copy of this License along with the Program. 192 193 You may charge any price or no price for each copy that you convey, 194 and you may offer support or warranty protection for a fee. 195 196 5. Conveying Modified Source Versions. 197 198 You may convey a work based on the Program, or the modifications to 199 produce it from the Program, in the form of source code under the 200 terms of section 4, provided that you also meet all of these conditions: 201 202 a) The work must carry prominent notices stating that you modified 203 it, and giving a relevant date. 204 205 b) The work must carry prominent notices stating that it is 206 released under this License and any conditions added under section 207 7. This requirement modifies the requirement in section 4 to 208 "keep intact all notices". 209 210 c) You must license the entire work, as a whole, under this 211 License to anyone who comes into possession of a copy. This 212 License will therefore apply, along with any applicable section 7 213 additional terms, to the whole of the work, and all its parts, 214 regardless of how they are packaged. This License gives no 215 permission to license the work in any other way, but it does not 216 invalidate such permission if you have separately received it. 217 218 d) If the work has interactive user interfaces, each must display 219 Appropriate Legal Notices; however, if the Program has interactive 220 interfaces that do not display Appropriate Legal Notices, your 221 work need not make them do so. 222 223 A compilation of a covered work with other separate and independent 224 works, which are not by their nature extensions of the covered work, 225 and which are not combined with it such as to form a larger program, 226 in or on a volume of a storage or distribution medium, is called an 227 "aggregate" if the compilation and its resulting copyright are not 228 used to limit the access or legal rights of the compilation's users 229 beyond what the individual works permit. Inclusion of a covered work 230 in an aggregate does not cause this License to apply to the other 231 parts of the aggregate. 232 233 6. Conveying Non-Source Forms. 234 235 You may convey a covered work in object code form under the terms 236 of sections 4 and 5, provided that you also convey the 237 machine-readable Corresponding Source under the terms of this License, 238 in one of these ways: 239 240 a) Convey the object code in, or embodied in, a physical product 241 (including a physical distribution medium), accompanied by the 242 Corresponding Source fixed on a durable physical medium 243 customarily used for software interchange. 244 245 b) Convey the object code in, or embodied in, a physical product 246 (including a physical distribution medium), accompanied by a 247 written offer, valid for at least three years and valid for as 248 long as you offer spare parts or customer support for that product 249 model, to give anyone who possesses the object code either (1) a 250 copy of the Corresponding Source for all the software in the 251 product that is covered by this License, on a durable physical 252 medium customarily used for software interchange, for a price no 253 more than your reasonable cost of physically performing this 254 conveying of source, or (2) access to copy the 255 Corresponding Source from a network server at no charge. 256 257 c) Convey individual copies of the object code with a copy of the 258 written offer to provide the Corresponding Source. This 259 alternative is allowed only occasionally and noncommercially, and 260 only if you received the object code with such an offer, in accord 261 with subsection 6b. 262 263 d) Convey the object code by offering access from a designated 264 place (gratis or for a charge), and offer equivalent access to the 265 Corresponding Source in the same way through the same place at no 266 further charge. You need not require recipients to copy the 267 Corresponding Source along with the object code. If the place to 268 copy the object code is a network server, the Corresponding Source 269 may be on a different server (operated by you or a third party) 270 that supports equivalent copying facilities, provided you maintain 271 clear directions next to the object code saying where to find the 272 Corresponding Source. Regardless of what server hosts the 273 Corresponding Source, you remain obligated to ensure that it is 274 available for as long as needed to satisfy these requirements. 275 276 e) Convey the object code using peer-to-peer transmission, provided 277 you inform other peers where the object code and Corresponding 278 Source of the work are being offered to the general public at no 279 charge under subsection 6d. 280 281 A separable portion of the object code, whose source code is excluded 282 from the Corresponding Source as a System Library, need not be 283 included in conveying the object code work. 284 285 A "User Product" is either (1) a "consumer product", which means any 286 tangible personal property which is normally used for personal, family, 287 or household purposes, or (2) anything designed or sold for incorporation 288 into a dwelling. In determining whether a product is a consumer product, 289 doubtful cases shall be resolved in favor of coverage. For a particular 290 product received by a particular user, "normally used" refers to a 291 typical or common use of that class of product, regardless of the status 292 of the particular user or of the way in which the particular user 293 actually uses, or expects or is expected to use, the product. A product 294 is a consumer product regardless of whether the product has substantial 295 commercial, industrial or non-consumer uses, unless such uses represent 296 the only significant mode of use of the product. 297 298 "Installation Information" for a User Product means any methods, 299 procedures, authorization keys, or other information required to install 300 and execute modified versions of a covered work in that User Product from 301 a modified version of its Corresponding Source. The information must 302 suffice to ensure that the continued functioning of the modified object 303 code is in no case prevented or interfered with solely because 304 modification has been made. 305 306 If you convey an object code work under this section in, or with, or 307 specifically for use in, a User Product, and the conveying occurs as 308 part of a transaction in which the right of possession and use of the 309 User Product is transferred to the recipient in perpetuity or for a 310 fixed term (regardless of how the transaction is characterized), the 311 Corresponding Source conveyed under this section must be accompanied 312 by the Installation Information. But this requirement does not apply 313 if neither you nor any third party retains the ability to install 314 modified object code on the User Product (for example, the work has 315 been installed in ROM). 316 317 The requirement to provide Installation Information does not include a 318 requirement to continue to provide support service, warranty, or updates 319 for a work that has been modified or installed by the recipient, or for 320 the User Product in which it has been modified or installed. Access to a 321 network may be denied when the modification itself materially and 322 adversely affects the operation of the network or violates the rules and 323 protocols for communication across the network. 324 325 Corresponding Source conveyed, and Installation Information provided, 326 in accord with this section must be in a format that is publicly 327 documented (and with an implementation available to the public in 328 source code form), and must require no special password or key for 329 unpacking, reading or copying. 330 331 7. Additional Terms. 332 333 "Additional permissions" are terms that supplement the terms of this 334 License by making exceptions from one or more of its conditions. 335 Additional permissions that are applicable to the entire Program shall 336 be treated as though they were included in this License, to the extent 337 that they are valid under applicable law. If additional permissions 338 apply only to part of the Program, that part may be used separately 339 under those permissions, but the entire Program remains governed by 340 this License without regard to the additional permissions. 341 342 When you convey a copy of a covered work, you may at your option 343 remove any additional permissions from that copy, or from any part of 344 it. (Additional permissions may be written to require their own 345 removal in certain cases when you modify the work.) You may place 346 additional permissions on material, added by you to a covered work, 347 for which you have or can give appropriate copyright permission. 348 349 Notwithstanding any other provision of this License, for material you 350 add to a covered work, you may (if authorized by the copyright holders of 351 that material) supplement the terms of this License with terms: 352 353 a) Disclaiming warranty or limiting liability differently from the 354 terms of sections 15 and 16 of this License; or 355 356 b) Requiring preservation of specified reasonable legal notices or 357 author attributions in that material or in the Appropriate Legal 358 Notices displayed by works containing it; or 359 360 c) Prohibiting misrepresentation of the origin of that material, or 361 requiring that modified versions of such material be marked in 362 reasonable ways as different from the original version; or 363 364 d) Limiting the use for publicity purposes of names of licensors or 365 authors of the material; or 366 367 e) Declining to grant rights under trademark law for use of some 368 trade names, trademarks, or service marks; or 369 370 f) Requiring indemnification of licensors and authors of that 371 material by anyone who conveys the material (or modified versions of 372 it) with contractual assumptions of liability to the recipient, for 373 any liability that these contractual assumptions directly impose on 374 those licensors and authors. 375 376 All other non-permissive additional terms are considered "further 377 restrictions" within the meaning of section 10. If the Program as you 378 received it, or any part of it, contains a notice stating that it is 379 governed by this License along with a term that is a further 380 restriction, you may remove that term. If a license document contains 381 a further restriction but permits relicensing or conveying under this 382 License, you may add to a covered work material governed by the terms 383 of that license document, provided that the further restriction does 384 not survive such relicensing or conveying. 385 386 If you add terms to a covered work in accord with this section, you 387 must place, in the relevant source files, a statement of the 388 additional terms that apply to those files, or a notice indicating 389 where to find the applicable terms. 390 391 Additional terms, permissive or non-permissive, may be stated in the 392 form of a separately written license, or stated as exceptions; 393 the above requirements apply either way. 394 395 8. Termination. 396 397 You may not propagate or modify a covered work except as expressly 398 provided under this License. Any attempt otherwise to propagate or 399 modify it is void, and will automatically terminate your rights under 400 this License (including any patent licenses granted under the third 401 paragraph of section 11). 402 403 However, if you cease all violation of this License, then your 404 license from a particular copyright holder is reinstated (a) 405 provisionally, unless and until the copyright holder explicitly and 406 finally terminates your license, and (b) permanently, if the copyright 407 holder fails to notify you of the violation by some reasonable means 408 prior to 60 days after the cessation. 409 410 Moreover, your license from a particular copyright holder is 411 reinstated permanently if the copyright holder notifies you of the 412 violation by some reasonable means, this is the first time you have 413 received notice of violation of this License (for any work) from that 414 copyright holder, and you cure the violation prior to 30 days after 415 your receipt of the notice. 416 417 Termination of your rights under this section does not terminate the 418 licenses of parties who have received copies or rights from you under 419 this License. If your rights have been terminated and not permanently 420 reinstated, you do not qualify to receive new licenses for the same 421 material under section 10. 422 423 9. Acceptance Not Required for Having Copies. 424 425 You are not required to accept this License in order to receive or 426 run a copy of the Program. Ancillary propagation of a covered work 427 occurring solely as a consequence of using peer-to-peer transmission 428 to receive a copy likewise does not require acceptance. However, 429 nothing other than this License grants you permission to propagate or 430 modify any covered work. These actions infringe copyright if you do 431 not accept this License. Therefore, by modifying or propagating a 432 covered work, you indicate your acceptance of this License to do so. 433 434 10. Automatic Licensing of Downstream Recipients. 435 436 Each time you convey a covered work, the recipient automatically 437 receives a license from the original licensors, to run, modify and 438 propagate that work, subject to this License. You are not responsible 439 for enforcing compliance by third parties with this License. 440 441 An "entity transaction" is a transaction transferring control of an 442 organization, or substantially all assets of one, or subdividing an 443 organization, or merging organizations. If propagation of a covered 444 work results from an entity transaction, each party to that 445 transaction who receives a copy of the work also receives whatever 446 licenses to the work the party's predecessor in interest had or could 447 give under the previous paragraph, plus a right to possession of the 448 Corresponding Source of the work from the predecessor in interest, if 449 the predecessor has it or can get it with reasonable efforts. 450 451 You may not impose any further restrictions on the exercise of the 452 rights granted or affirmed under this License. For example, you may 453 not impose a license fee, royalty, or other charge for exercise of 454 rights granted under this License, and you may not initiate litigation 455 (including a cross-claim or counterclaim in a lawsuit) alleging that 456 any patent claim is infringed by making, using, selling, offering for 457 sale, or importing the Program or any portion of it. 458 459 11. Patents. 460 461 A "contributor" is a copyright holder who authorizes use under this 462 License of the Program or a work on which the Program is based. The 463 work thus licensed is called the contributor's "contributor version". 464 465 A contributor's "essential patent claims" are all patent claims 466 owned or controlled by the contributor, whether already acquired or 467 hereafter acquired, that would be infringed by some manner, permitted 468 by this License, of making, using, or selling its contributor version, 469 but do not include claims that would be infringed only as a 470 consequence of further modification of the contributor version. For 471 purposes of this definition, "control" includes the right to grant 472 patent sublicenses in a manner consistent with the requirements of 195 473 this License. 196 474 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 475 Each contributor grants you a non-exclusive, worldwide, royalty-free 476 patent license under the contributor's essential patent claims, to 477 make, use, sell, offer for sale, import and otherwise run, modify and 478 propagate the contents of its contributor version. 479 480 In the following three paragraphs, a "patent license" is any express 481 agreement or commitment, however denominated, not to enforce a patent 482 (such as an express permission to practice a patent or covenant not to 483 sue for patent infringement). To "grant" such a patent license to a 484 party means to make such an agreement or commitment not to enforce a 485 patent against the party. 486 487 If you convey a covered work, knowingly relying on a patent license, 488 and the Corresponding Source of the work is not available for anyone 489 to copy, free of charge and under the terms of this License, through a 490 publicly available network server or other readily accessible means, 491 then you must either (1) cause the Corresponding Source to be so 492 available, or (2) arrange to deprive yourself of the benefit of the 493 patent license for this particular work, or (3) arrange, in a manner 494 consistent with the requirements of this License, to extend the patent 495 license to downstream recipients. "Knowingly relying" means you have 496 actual knowledge that, but for the patent license, your conveying the 497 covered work in a country, or your recipient's use of the covered work 498 in a country, would infringe one or more identifiable patents in that 499 country that you have reason to believe are valid. 500 501 If, pursuant to or in connection with a single transaction or 502 arrangement, you convey, or propagate by procuring conveyance of, a 503 covered work, and grant a patent license to some of the parties 504 receiving the covered work authorizing them to use, propagate, modify 505 or convey a specific copy of the covered work, then the patent license 506 you grant is automatically extended to all recipients of the covered 507 work and works based on it. 508 509 A patent license is "discriminatory" if it does not include within 510 the scope of its coverage, prohibits the exercise of, or is 511 conditioned on the non-exercise of one or more of the rights that are 512 specifically granted under this License. You may not convey a covered 513 work if you are a party to an arrangement with a third party that is 514 in the business of distributing software, under which you make payment 515 to the third party based on the extent of your activity of conveying 516 the work, and under which the third party grants, to any of the 517 parties who would receive the covered work from you, a discriminatory 518 patent license (a) in connection with copies of the covered work 519 conveyed by you (or copies made from those copies), or (b) primarily 520 for and in connection with specific products or compilations that 521 contain the covered work, unless you entered into that arrangement, 522 or that patent license was granted, prior to 28 March 2007. 523 524 Nothing in this License shall be construed as excluding or limiting 525 any implied license or other defenses to infringement that may 526 otherwise be available to you under applicable patent law. 527 528 12. No Surrender of Others' Freedom. 529 530 If conditions are imposed on you (whether by court order, agreement or 200 531 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. 532 excuse you from the conditions of this License. If you cannot convey a 533 covered work so as to satisfy simultaneously your obligations under this 534 License and any other pertinent obligations, then as a consequence you may 535 not convey it at all. For example, if you agree to terms that obligate you 536 to collect a royalty for further conveying from those to whom you convey 537 the Program, the only way you could satisfy both those terms and this 538 License would be to refrain entirely from conveying the Program. 209 539 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. 540 13. Remote Network Interaction; Use with the GNU General Public License. 214 541 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 made220 generous contributions to the wide range of software distributed 221 through that system in reliance on consistent application of that 222 s ystem; it is up to the author/donor to decide if he or she is willing223 to distribute software through any other system and a licensee cannot 224 impose that choice.542 Notwithstanding any other provision of this License, if you modify the 543 Program, your modified version must prominently offer all users 544 interacting with it remotely through a computer network (if your version 545 supports such interaction) an opportunity to receive the Corresponding 546 Source of your version by providing access to the Corresponding Source 547 from a network server at no charge, through some standard or customary 548 means of facilitating copying of software. This Corresponding Source 549 shall include the Corresponding Source for any work covered by version 3 550 of the GNU General Public License that is incorporated pursuant to the 551 following paragraph. 225 552 226 This section is intended to make thoroughly clear what is believed to 227 be a consequence of the rest of this License. 553 Notwithstanding any other provision of this License, you have 554 permission to link or combine any covered work with a work licensed 555 under version 3 of the GNU General Public License into a single 556 combined work, and to convey the resulting work. The terms of this 557 License will continue to apply to the part which is the covered work, 558 but the work with which it is combined will remain governed by version 559 3 of the GNU General Public License. 228 560 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. 561 14. Revised Versions of this License. 236 562 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 to563 The Free Software Foundation may publish revised and/or new versions of 564 the GNU Affero General Public License from time to time. Such new versions 565 will be similar in spirit to the present version, but may differ in detail to 240 566 address new problems or concerns. 241 567 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. 568 Each version is given a distinguishing version number. If the 569 Program specifies that a certain numbered version of the GNU Affero General 570 Public License "or any later version" applies to it, you have the 571 option of following the terms and conditions either of that numbered 572 version or of any later version published by the Free Software 573 Foundation. If the Program does not specify a version number of the 574 GNU Affero General Public License, you may choose any version ever published 575 by the Free Software Foundation. 249 576 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. 577 If the Program specifies that a proxy can decide which future 578 versions of the GNU Affero General Public License can be used, that proxy's 579 public statement of acceptance of a version permanently authorizes you 580 to choose that version for the Program. 257 581 258 NO WARRANTY 582 Later license versions may give you additional or different 583 permissions. However, no additional obligations are imposed on any 584 author or copyright holder as a result of your choosing to follow a 585 later version. 259 586 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. 587 15. Disclaimer of Warranty. 269 588 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. 589 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 279 597 280 END OF TERMS AND CONDITIONS 598 16. Limitation of Liability. 281 599 282 How to Apply These Terms to Your New Programs 600 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 SUCH DAMAGES. 283 609 284 If you develop a new program, and you want it to be of the greatest 610 17. Interpretation of Sections 15 and 16. 611 612 If the disclaimer of warranty and limitation of liability provided 613 above cannot be given local legal effect according to their terms, 614 reviewing courts shall apply local law that most closely approximates 615 an absolute waiver of all civil liability in connection with the 616 Program, unless a warranty or assumption of liability accompanies a 617 copy of the Program in return for a fee. 618 619 END OF TERMS AND CONDITIONS 620 621 How to Apply These Terms to Your New Programs 622 623 If you develop a new program, and you want it to be of the greatest 285 624 possible use to the public, the best way to achieve this is to make it 286 625 free software which everyone can redistribute and change under these terms. 287 626 288 627 To do so, attach the following notices to the program. It is safest 289 628 to attach them to the start of each source file to most effectively 290 conveythe exclusion of warranty; and each file should have at least629 state the exclusion of warranty; and each file should have at least 291 630 the "copyright" line and a pointer to where the full notice is found. 292 631 293 294 632 <one line to give the program's name and a brief idea of what it does.> 633 Copyright (C) <year> <name of author> 295 634 296 This program is free software;you can redistribute it and/or modify297 it under the terms of the GNUGeneral Public License as published by298 the Free Software Foundation; either version 2of the License, or299 635 This program is free software: you can redistribute it and/or modify 636 it under the terms of the GNU Affero General Public License as published by 637 the Free Software Foundation, either version 3 of the License, or 638 (at your option) any later version. 300 639 301 302 303 304 GNUGeneral Public License for more details.640 This program is distributed in the hope that it will be useful, 641 but WITHOUT ANY WARRANTY; without even the implied warranty of 642 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 GNU Affero General Public License for more details. 305 644 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. 645 You should have received a copy of the GNU Affero General Public License 646 along with this program. If not, see <http://www.gnu.org/licenses/>. 309 647 310 648 Also add information on how to contact you by electronic and paper mail. 311 649 312 If the program is interactive, make it output a short notice like this 313 when it starts in an interactive mode: 650 If your software can interact with users remotely through a computer 651 network, you should also make sure that it provides a way for users to 652 get its source. For example, if your program is a web application, its 653 interface could display a "Source" link that leads users to an archive 654 of the code. There are many ways you could offer source, and different 655 solutions will be better for different programs; see section 13 for the 656 specific requirements. 314 657 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. 658 You should also get your employer (if you work as a programmer) or school, 659 if any, to sign a "copyright disclaimer" for the program, if necessary. 660 For more information on this, and how to apply and follow the GNU AGPL, see 661 <http://www.gnu.org/licenses/>. -
src/js/_enqueues/vendor/plupload/moxie.js
1 1 ;var MXI_DEBUG = false; 2 2 /** 3 3 * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill 4 * v1. 3.54 * v1.5.7 5 5 * 6 6 * Copyright 2013, Moxiecode Systems AB 7 7 * Released under GPL License. … … 9 9 * License: http://www.plupload.com/license 10 10 * Contributing: http://www.plupload.com/contributing 11 11 * 12 * Date: 201 6-05-1512 * Date: 2017-11-03 13 13 */ 14 ;(function (global, factory) { 15 var extract = function() { 16 var ctx = {}; 17 factory.apply(ctx, arguments); 18 return ctx.moxie; 19 }; 20 21 if (typeof define === "function" && define.amd) { 22 define("moxie", [], extract); 23 } else if (typeof module === "object" && module.exports) { 24 module.exports = extract(); 25 } else { 26 global.moxie = extract(); 27 } 28 }(this || window, function() { 14 29 /** 15 30 * Compiled inline version. (Library mode) 16 31 */ 17 32 18 /**19 * Modified for WordPress, Silverlight and Flash runtimes support was removed.20 * See https://core.trac.wordpress.org/ticket/41755.21 */22 23 33 /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ 24 34 /*globals $code */ 25 35 … … 110 120 * Contributing: http://www.plupload.com/contributing 111 121 */ 112 122 123 /** 124 @class moxie/core/utils/Basic 125 @public 126 @static 127 */ 128 113 129 define('moxie/core/utils/Basic', [], function() { 114 130 /** 115 131 Gets the true type of the built-in object (better version of typeof). … … 116 132 @author Angus Croll (http://javascriptweblog.wordpress.com/) 117 133 118 134 @method typeOf 119 @for Utils120 135 @static 121 136 @param {Object} o Object to check. 122 137 @return {String} Object [[Class]] 123 138 */ 124 var typeOf = function(o) {139 function typeOf(o) { 125 140 var undef; 126 141 127 142 if (o === undef) { … … 134 149 135 150 // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8 136 151 return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); 137 } ;138 152 } 153 139 154 /** 140 Extends the specified object with another object .155 Extends the specified object with another object(s). 141 156 142 157 @method extend 143 158 @static … … 145 160 @param {Object} [obj]* Multiple objects to extend with. 146 161 @return {Object} Same as target, the extended object. 147 162 */ 148 var extend = function(target) { 163 function extend() { 164 return merge(false, false, arguments); 165 } 166 167 168 /** 169 Extends the specified object with another object(s), but only if the property exists in the target. 170 171 @method extendIf 172 @static 173 @param {Object} target Object to extend. 174 @param {Object} [obj]* Multiple objects to extend with. 175 @return {Object} Same as target, the extended object. 176 */ 177 function extendIf() { 178 return merge(true, false, arguments); 179 } 180 181 182 function extendImmutable() { 183 return merge(false, true, arguments); 184 } 185 186 187 function extendImmutableIf() { 188 return merge(true, true, arguments); 189 } 190 191 192 function clone(value) { 193 switch (typeOf(value)) { 194 case 'array': 195 return merge(false, true, [[], value]); 196 197 case 'object': 198 return merge(false, true, [{}, value]); 199 200 default: 201 return value; 202 } 203 } 204 205 206 function shallowCopy(obj) { 207 switch (typeOf(obj)) { 208 case 'array': 209 return Array.prototype.slice.call(obj); 210 211 case 'object': 212 return extend({}, obj); 213 } 214 return obj; 215 } 216 217 218 function merge(strict, immutable, args) { 149 219 var undef; 220 var target = args[0]; 150 221 151 each(arg uments, function(arg, i) {222 each(args, function(arg, i) { 152 223 if (i > 0) { 153 224 each(arg, function(value, key) { 154 if (value !== undef) { 155 if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) { 156 extend(target[key], value); 157 } else { 158 target[key] = value; 159 } 225 var isComplex = inArray(typeOf(value), ['array', 'object']) !== -1; 226 227 if (value === undef || strict && target[key] === undef) { 228 return true; 160 229 } 230 231 if (isComplex && immutable) { 232 value = shallowCopy(value); 233 } 234 235 if (typeOf(target[key]) === typeOf(value) && isComplex) { 236 merge(strict, immutable, [target[key], value]); 237 } else { 238 target[key] = value; 239 } 161 240 }); 162 241 } 163 242 }); 243 164 244 return target; 165 }; 166 245 } 246 247 167 248 /** 249 A way to inherit one `class` from another in a consisstent way (more or less) 250 251 @method inherit 252 @static 253 @since >1.4.1 254 @param {Function} child 255 @param {Function} parent 256 @return {Function} Prepared constructor 257 */ 258 function inherit(child, parent) { 259 // copy over all parent properties 260 for (var key in parent) { 261 if ({}.hasOwnProperty.call(parent, key)) { 262 child[key] = parent[key]; 263 } 264 } 265 266 // give child `class` a place to define its own methods 267 function ctor() { 268 this.constructor = child; 269 270 if (MXI_DEBUG) { 271 var getCtorName = function(fn) { 272 var m = fn.toString().match(/^function\s([^\(\s]+)/); 273 return m ? m[1] : false; 274 }; 275 276 this.ctorName = getCtorName(child); 277 } 278 } 279 ctor.prototype = parent.prototype; 280 child.prototype = new ctor(); 281 282 // keep a way to reference parent methods 283 child.parent = parent.prototype; 284 return child; 285 } 286 287 288 /** 168 289 Executes the callback function for each item in array/object. If you return false in the 169 290 callback it will break the loop. 170 291 … … 173 294 @param {Object} obj Object to iterate. 174 295 @param {function} callback Callback function to execute for each item. 175 296 */ 176 var each = function(obj, callback) {297 function each(obj, callback) { 177 298 var length, key, i, undef; 178 299 179 300 if (obj) { 180 if (typeOf(obj.length) === 'number') { // it might be Array, FileList or even arguments object 181 // Loop array items 182 for (i = 0, length = obj.length; i < length; i++) { 183 if (callback(obj[i], i) === false) { 184 return; 185 } 186 } 187 } else if (typeOf(obj) === 'object') { 301 try { 302 length = obj.length; 303 } catch(ex) { 304 length = undef; 305 } 306 307 if (length === undef || typeof(length) !== 'number') { 188 308 // Loop object items 189 309 for (key in obj) { 190 310 if (obj.hasOwnProperty(key)) { … … 193 313 } 194 314 } 195 315 } 316 } else { 317 // Loop array items 318 for (i = 0; i < length; i++) { 319 if (callback(obj[i], i) === false) { 320 return; 321 } 322 } 196 323 } 197 324 } 198 } ;325 } 199 326 200 327 /** 201 328 Checks if object is empty. 202 329 203 330 @method isEmptyObj 204 331 @static 205 332 @param {Object} o Object to check. 206 333 @return {Boolean} 207 334 */ 208 var isEmptyObj = function(obj) {335 function isEmptyObj(obj) { 209 336 var prop; 210 337 211 338 if (!obj || typeOf(obj) !== 'object') { … … 217 344 } 218 345 219 346 return true; 220 } ;347 } 221 348 222 349 /** 223 350 Recieve an array of functions (usually async) to call in sequence, each function … … 231 358 @param {Array} queue Array of functions to call in sequence 232 359 @param {Function} cb Main callback that is called in the end, or in case of error 233 360 */ 234 var inSeries = function(queue, cb) {361 function inSeries(queue, cb) { 235 362 var i = 0, length = queue.length; 236 363 237 364 if (typeOf(cb) !== 'function') { … … 251 378 } 252 379 } 253 380 callNext(i); 254 } ;381 } 255 382 256 383 257 384 /** 258 385 Recieve an array of functions (usually async) to call in parallel, each function 259 receives a callback as first argument that it should call, when it completes. After 386 receives a callback as first argument that it should call, when it completes. After 260 387 everything is complete, main callback is called. Passing truthy value to the 261 388 callback as a first argument will interrupt the process and invoke main callback 262 389 immediately. … … 264 391 @method inParallel 265 392 @static 266 393 @param {Array} queue Array of functions to call in sequence 267 @param {Function} cb Main callback that is called in the end, or in case of erro r394 @param {Function} cb Main callback that is called in the end, or in case of erro 268 395 */ 269 var inParallel = function(queue, cb) {396 function inParallel(queue, cb) { 270 397 var count = 0, num = queue.length, cbArgs = new Array(num); 271 398 272 399 each(queue, function(fn, i) { … … 274 401 if (error) { 275 402 return cb(error); 276 403 } 277 404 278 405 var args = [].slice.call(arguments); 279 406 args.shift(); // strip error - undefined or not 280 407 … … 284 411 if (count === num) { 285 412 cbArgs.unshift(null); 286 413 cb.apply(this, cbArgs); 287 } 414 } 288 415 }); 289 416 }); 290 } ;291 292 417 } 418 419 293 420 /** 294 421 Find an element in array and return it's index if present, otherwise return -1. 295 422 296 423 @method inArray 297 424 @static 298 425 @param {Mixed} needle Element to find … … 299 426 @param {Array} array 300 427 @return {Int} Index of the element, or -1 if not found 301 428 */ 302 var inArray = function(needle, array) {429 function inArray(needle, array) { 303 430 if (array) { 304 431 if (Array.prototype.indexOf) { 305 432 return Array.prototype.indexOf.call(array, needle); 306 433 } 307 434 308 435 for (var i = 0, length = array.length; i < length; i++) { 309 436 if (array[i] === needle) { 310 437 return i; … … 312 439 } 313 440 } 314 441 return -1; 315 } ;442 } 316 443 317 444 318 445 /** … … 324 451 @param {Array} array 325 452 @return {Array|Boolean} 326 453 */ 327 var arrayDiff = function(needles, array) {454 function arrayDiff(needles, array) { 328 455 var diff = []; 329 456 330 457 if (typeOf(needles) !== 'array') { … … 338 465 for (var i in needles) { 339 466 if (inArray(needles[i], array) === -1) { 340 467 diff.push(needles[i]); 341 } 468 } 342 469 } 343 470 return diff.length ? diff : false; 344 } ;471 } 345 472 346 473 347 474 /** … … 353 480 @param {Array} array2 354 481 @return {Array} Intersection of two arrays or null if there is none 355 482 */ 356 var arrayIntersect = function(array1, array2) {483 function arrayIntersect(array1, array2) { 357 484 var result = []; 358 485 each(array1, function(item) { 359 486 if (inArray(item, array2) !== -1) { … … 361 488 } 362 489 }); 363 490 return result.length ? result : null; 364 } ;365 366 491 } 492 493 367 494 /** 368 495 Forces anything into an array. 369 496 370 497 @method toArray 371 498 @static 372 499 @param {Object} obj Object with length field. 373 500 @return {Array} Array object containing all items. 374 501 */ 375 var toArray = function(obj) {502 function toArray(obj) { 376 503 var i, arr = []; 377 504 378 505 for (i = 0; i < obj.length; i++) { … … 380 507 } 381 508 382 509 return arr; 383 } ;384 385 510 } 511 512 386 513 /** 387 514 Generates an unique ID. The only way a user would be able to get the same ID is if the two persons 388 at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses 389 a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth 515 at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses 516 a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth 390 517 to be hit with an asteroid. 391 518 392 519 @method guid 393 520 @static 394 521 @param {String} prefix to prepend (by default 'o' will be prepended). … … 397 524 */ 398 525 var guid = (function() { 399 526 var counter = 0; 400 527 401 528 return function(prefix) { 402 529 var guid = new Date().getTime().toString(32), i; 403 530 … … 404 531 for (i = 0; i < 5; i++) { 405 532 guid += Math.floor(Math.random() * 65535).toString(32); 406 533 } 407 534 408 535 return (prefix || 'o_') + guid + (counter++).toString(32); 409 536 }; 410 537 }()); 411 412 538 539 413 540 /** 414 541 Trims white spaces around the string 415 542 416 543 @method trim 417 544 @static 418 545 @param {String} str 419 546 @return {String} 420 547 */ 421 var trim = function(str) {548 function trim(str) { 422 549 if (!str) { 423 550 return str; 424 551 } 425 552 return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, ''); 426 } ;553 } 427 554 428 555 429 556 /** 430 557 Parses the specified size string into a byte value. For example 10kb becomes 10240. 431 558 432 559 @method parseSizeStr 433 560 @static 434 561 @param {String/Number} size String to parse or number to just pass through. 435 562 @return {Number} Size in bytes. 436 563 */ 437 var parseSizeStr = function(size) {564 function parseSizeStr(size) { 438 565 if (typeof(size) !== 'string') { 439 566 return size; 440 567 } 441 568 442 569 var muls = { 443 570 t: 1099511627776, 444 571 g: 1073741824, … … 447 574 }, 448 575 mul; 449 576 450 451 577 size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, '')); 452 578 mul = size[2]; 453 579 size = +size[1]; 454 580 455 581 if (muls.hasOwnProperty(mul)) { 456 582 size *= muls[mul]; 457 583 } 458 584 return Math.floor(size); 459 } ;585 } 460 586 461 587 462 588 /** … … 465 591 * @param {String} str String with tokens 466 592 * @return {String} String with replaced tokens 467 593 */ 468 var sprintf = function(str) {594 function sprintf(str) { 469 595 var args = [].slice.call(arguments, 1); 470 596 471 return str.replace(/% [a-z]/g, function() {597 return str.replace(/%([a-z])/g, function($0, $1) { 472 598 var value = args.shift(); 473 return typeOf(value) !== 'undefined' ? value : ''; 599 600 switch ($1) { 601 case 's': 602 return value + ''; 603 604 case 'd': 605 return parseInt(value, 10); 606 607 case 'f': 608 return parseFloat(value); 609 610 case 'c': 611 return ''; 612 613 default: 614 return value; 615 } 474 616 }); 475 }; 476 617 } 477 618 619 620 621 function delay(cb, timeout) { 622 var self = this; 623 setTimeout(function() { 624 cb.call(self); 625 }, timeout || 1); 626 } 627 628 478 629 return { 479 630 guid: guid, 480 631 typeOf: typeOf, 481 632 extend: extend, 633 extendIf: extendIf, 634 extendImmutable: extendImmutable, 635 extendImmutableIf: extendImmutableIf, 636 clone: clone, 637 inherit: inherit, 482 638 each: each, 483 639 isEmptyObj: isEmptyObj, 484 640 inSeries: inSeries, … … 489 645 toArray: toArray, 490 646 trim: trim, 491 647 sprintf: sprintf, 492 parseSizeStr: parseSizeStr 648 parseSizeStr: parseSizeStr, 649 delay: delay 493 650 }; 494 651 }); 495 652 653 // Included from: src/javascript/core/utils/Encode.js 654 655 /** 656 * Encode.js 657 * 658 * Copyright 2013, Moxiecode Systems AB 659 * Released under GPL License. 660 * 661 * License: http://www.plupload.com/license 662 * Contributing: http://www.plupload.com/contributing 663 */ 664 665 /** 666 @class moxie/core/utils/Encode 667 @public 668 @static 669 */ 670 671 define('moxie/core/utils/Encode', [], function() { 672 673 /** 674 Encode string with UTF-8 675 676 @method utf8_encode 677 @static 678 @param {String} str String to encode 679 @return {String} UTF-8 encoded string 680 */ 681 var utf8_encode = function(str) { 682 return unescape(encodeURIComponent(str)); 683 }; 684 685 /** 686 Decode UTF-8 encoded string 687 688 @method utf8_decode 689 @static 690 @param {String} str String to decode 691 @return {String} Decoded string 692 */ 693 var utf8_decode = function(str_data) { 694 return decodeURIComponent(escape(str_data)); 695 }; 696 697 /** 698 Decode Base64 encoded string (uses browser's default method if available), 699 from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js 700 701 @method atob 702 @static 703 @param {String} data String to decode 704 @return {String} Decoded string 705 */ 706 var atob = function(data, utf8) { 707 if (typeof(window.atob) === 'function') { 708 return utf8 ? utf8_decode(window.atob(data)) : window.atob(data); 709 } 710 711 // http://kevin.vanzonneveld.net 712 // + original by: Tyler Akins (http://rumkin.com) 713 // + improved by: Thunder.m 714 // + input by: Aman Gupta 715 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 716 // + bugfixed by: Onno Marsman 717 // + bugfixed by: Pellentesque Malesuada 718 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 719 // + input by: Brett Zamir (http://brett-zamir.me) 720 // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 721 // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); 722 // * returns 1: 'Kevin van Zonneveld' 723 // mozilla has this native 724 // - but breaks in 2.0.0.12! 725 //if (typeof this.window.atob == 'function') { 726 // return atob(data); 727 //} 728 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 729 var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, 730 ac = 0, 731 dec = "", 732 tmp_arr = []; 733 734 if (!data) { 735 return data; 736 } 737 738 data += ''; 739 740 do { // unpack four hexets into three octets using index points in b64 741 h1 = b64.indexOf(data.charAt(i++)); 742 h2 = b64.indexOf(data.charAt(i++)); 743 h3 = b64.indexOf(data.charAt(i++)); 744 h4 = b64.indexOf(data.charAt(i++)); 745 746 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; 747 748 o1 = bits >> 16 & 0xff; 749 o2 = bits >> 8 & 0xff; 750 o3 = bits & 0xff; 751 752 if (h3 == 64) { 753 tmp_arr[ac++] = String.fromCharCode(o1); 754 } else if (h4 == 64) { 755 tmp_arr[ac++] = String.fromCharCode(o1, o2); 756 } else { 757 tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); 758 } 759 } while (i < data.length); 760 761 dec = tmp_arr.join(''); 762 763 return utf8 ? utf8_decode(dec) : dec; 764 }; 765 766 /** 767 Base64 encode string (uses browser's default method if available), 768 from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js 769 770 @method btoa 771 @static 772 @param {String} data String to encode 773 @return {String} Base64 encoded string 774 */ 775 var btoa = function(data, utf8) { 776 if (utf8) { 777 data = utf8_encode(data); 778 } 779 780 if (typeof(window.btoa) === 'function') { 781 return window.btoa(data); 782 } 783 784 // http://kevin.vanzonneveld.net 785 // + original by: Tyler Akins (http://rumkin.com) 786 // + improved by: Bayron Guevara 787 // + improved by: Thunder.m 788 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 789 // + bugfixed by: Pellentesque Malesuada 790 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 791 // + improved by: Rafał Kukawski (http://kukawski.pl) 792 // * example 1: base64_encode('Kevin van Zonneveld'); 793 // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' 794 // mozilla has this native 795 // - but breaks in 2.0.0.12! 796 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 797 var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, 798 ac = 0, 799 enc = "", 800 tmp_arr = []; 801 802 if (!data) { 803 return data; 804 } 805 806 do { // pack three octets into four hexets 807 o1 = data.charCodeAt(i++); 808 o2 = data.charCodeAt(i++); 809 o3 = data.charCodeAt(i++); 810 811 bits = o1 << 16 | o2 << 8 | o3; 812 813 h1 = bits >> 18 & 0x3f; 814 h2 = bits >> 12 & 0x3f; 815 h3 = bits >> 6 & 0x3f; 816 h4 = bits & 0x3f; 817 818 // use hexets to index into b64, and append result to encoded string 819 tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); 820 } while (i < data.length); 821 822 enc = tmp_arr.join(''); 823 824 var r = data.length % 3; 825 826 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); 827 }; 828 829 830 return { 831 utf8_encode: utf8_encode, 832 utf8_decode: utf8_decode, 833 atob: atob, 834 btoa: btoa 835 }; 836 }); 837 496 838 // Included from: src/javascript/core/utils/Env.js 497 839 498 840 /** … … 505 847 * Contributing: http://www.plupload.com/contributing 506 848 */ 507 849 850 /** 851 @class moxie/core/utils/Env 852 @public 853 @static 854 */ 855 508 856 define("moxie/core/utils/Env", [ 509 857 "moxie/core/utils/Basic" 510 858 ], function(Basic) { 511 859 512 860 /** 513 861 * UAParser.js v0.7.7 514 862 * Lightweight JavaScript-based User-Agent string parser … … 711 1059 var regexes = { 712 1060 713 1061 browser : [[ 714 1062 715 1063 // Presto based 716 1064 /(opera\smini)\/([\w\.-]+)/i, // Opera Mini 717 1065 /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet … … 1046 1394 1047 1395 var can = (function() { 1048 1396 var caps = { 1049 define_property: (function() { 1050 /* // currently too much extra code required, not exactly worth it 1051 try { // as of IE8, getters/setters are supported only on DOM elements 1052 var obj = {}; 1053 if (Object.defineProperty) { 1054 Object.defineProperty(obj, 'prop', { 1055 enumerable: true, 1056 configurable: true 1057 }); 1058 return true; 1059 } 1060 } catch(ex) {} 1397 access_global_ns: function () { 1398 return !!window.moxie; 1399 }, 1061 1400 1062 if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { 1401 define_property: (function() { 1402 /* // currently too much extra code required, not exactly worth it 1403 try { // as of IE8, getters/setters are supported only on DOM elements 1404 var obj = {}; 1405 if (Object.defineProperty) { 1406 Object.defineProperty(obj, 'prop', { 1407 enumerable: true, 1408 configurable: true 1409 }); 1063 1410 return true; 1064 }*/ 1065 return false; 1066 }()), 1411 } 1412 } catch(ex) {} 1067 1413 1068 create_canvas: (function() { 1069 // On the S60 and BB Storm, getContext exists, but always returns undefined 1070 // so we actually have to call getContext() to verify 1071 // github.com/Modernizr/Modernizr/issues/issue/97/ 1072 var el = document.createElement('canvas'); 1073 return !!(el.getContext && el.getContext('2d')); 1074 }()), 1414 if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { 1415 return true; 1416 }*/ 1417 return false; 1418 }()), 1075 1419 1076 return_response_type: function(responseType) { 1077 try { 1078 if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) { 1420 create_canvas: function() { 1421 // On the S60 and BB Storm, getContext exists, but always returns undefined 1422 // so we actually have to call getContext() to verify 1423 // github.com/Modernizr/Modernizr/issues/issue/97/ 1424 var el = document.createElement('canvas'); 1425 var isSupported = !!(el.getContext && el.getContext('2d')); 1426 caps.create_canvas = isSupported; 1427 return isSupported; 1428 }, 1429 1430 return_response_type: function(responseType) { 1431 try { 1432 if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) { 1433 return true; 1434 } else if (window.XMLHttpRequest) { 1435 var xhr = new XMLHttpRequest(); 1436 xhr.open('get', '/'); // otherwise Gecko throws an exception 1437 if ('responseType' in xhr) { 1438 xhr.responseType = responseType; 1439 // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?) 1440 if (xhr.responseType !== responseType) { 1441 return false; 1442 } 1079 1443 return true; 1080 } else if (window.XMLHttpRequest) {1081 var xhr = new XMLHttpRequest();1082 xhr.open('get', '/'); // otherwise Gecko throws an exception1083 if ('responseType' in xhr) {1084 xhr.responseType = responseType;1085 // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)1086 if (xhr.responseType !== responseType) {1087 return false;1088 }1089 return true;1090 }1091 1444 } 1092 } catch (ex) {} 1093 return false; 1094 }, 1445 } 1446 } catch (ex) {} 1447 return false; 1448 }, 1095 1449 1096 // ideas for this heavily come from Modernizr (http://modernizr.com/) 1097 use_data_uri: (function() { 1098 var du = new Image(); 1450 use_blob_uri: function() { 1451 var URL = window.URL; 1452 caps.use_blob_uri = (URL && 1453 'createObjectURL' in URL && 1454 'revokeObjectURL' in URL && 1455 (Env.browser !== 'IE' || Env.verComp(Env.version, '11.0.46', '>=')) // IE supports createObjectURL, but not fully, for example it fails to use it as a src for the image 1456 ); 1457 return caps.use_blob_uri; 1458 }, 1099 1459 1100 du.onload = function() { 1101 caps.use_data_uri = (du.width === 1 && du.height === 1); 1102 }; 1103 1104 setTimeout(function() { 1105 du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; 1106 }, 1); 1107 return false; 1108 }()), 1460 // ideas for this heavily come from Modernizr (http://modernizr.com/) 1461 use_data_uri: (function() { 1462 var du = new Image(); 1109 1463 1110 use_data_uri_over32kb: function() { // IE81111 return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);1112 } ,1464 du.onload = function() { 1465 caps.use_data_uri = (du.width === 1 && du.height === 1); 1466 }; 1113 1467 1114 use_data_uri_of: function(bytes) { 1115 return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); 1116 }, 1468 setTimeout(function() { 1469 du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; 1470 }, 1); 1471 return false; 1472 }()), 1117 1473 1118 use_fileinput: function() { 1119 if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) { 1120 return false; 1121 } 1474 use_data_uri_over32kb: function() { // IE8 1475 return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9); 1476 }, 1122 1477 1123 var el = document.createElement('input'); 1124 el.setAttribute('type', 'file'); 1125 return !el.disabled; 1478 use_data_uri_of: function(bytes) { 1479 return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); 1480 }, 1481 1482 use_fileinput: function() { 1483 if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) { 1484 return false; 1126 1485 } 1127 };1128 1486 1487 var el = document.createElement('input'); 1488 el.setAttribute('type', 'file'); 1489 return caps.use_fileinput = !el.disabled; 1490 }, 1491 1492 use_webgl: function() { 1493 var canvas = document.createElement('canvas'); 1494 var gl = null, isSupported; 1495 try { 1496 gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); 1497 } 1498 catch(e) {} 1499 1500 if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context 1501 gl = null; 1502 } 1503 1504 isSupported = !!gl; 1505 caps.use_webgl = isSupported; // save result of our check 1506 canvas = undefined; 1507 return isSupported; 1508 } 1509 }; 1510 1129 1511 return function(cap) { 1130 1512 var args = [].slice.call(arguments); 1131 1513 args.shift(); // shift of cap … … 1141 1523 can: can, 1142 1524 1143 1525 uaParser: UAParser, 1144 1526 1145 1527 browser: uaResult.browser.name, 1146 1528 version: uaResult.browser.version, 1147 1529 os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason … … 1149 1531 1150 1532 verComp: version_compare, 1151 1533 1534 swf_url: "../flash/Moxie.swf", 1535 xap_url: "../silverlight/Moxie.xap", 1152 1536 global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent" 1153 1537 }; 1154 1538 … … 1163 1547 }; 1164 1548 1165 1549 Env.log = function() { 1166 1550 1167 1551 function logObj(data) { 1168 1552 // TODO: this should recursively print out the object in a pretty way 1169 1553 console.appendChild(document.createTextNode(data + "\n")); 1170 1554 } 1171 1555 1172 var data = arguments[0]; 1173 1174 if (Basic.typeOf(data) === 'string') { 1175 data = Basic.sprintf.apply(this, arguments); 1176 } 1177 1178 if (window && window.console && window.console.log) { 1179 window.console.log(data); 1556 // if debugger present, IE8 might have window.console.log method, but not be able to apply on it (why...) 1557 if (window && window.console && window.console.log && window.console.log.apply) { 1558 window.console.log.apply(window.console, arguments); 1180 1559 } else if (document) { 1181 1560 var console = document.getElementById('moxie-console'); 1182 1561 if (!console) { … … 1186 1565 document.body.appendChild(console); 1187 1566 } 1188 1567 1189 if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) { 1568 var data = arguments[0]; 1569 if (Basic.typeOf(data) === 'string') { 1570 data = Basic.sprintf.apply(this, arguments); 1571 } else if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) { 1190 1572 logObj(data); 1191 } else { 1192 console.appendChild(document.createTextNode(data + "\n")); 1573 return; 1193 1574 } 1575 1576 console.appendChild(document.createTextNode(data + "\n")); 1194 1577 } 1195 1578 }; 1196 1579 } … … 1198 1581 return Env; 1199 1582 }); 1200 1583 1201 // Included from: src/javascript/core/ I18n.js1584 // Included from: src/javascript/core/Exceptions.js 1202 1585 1203 1586 /** 1204 * I18n.js1587 * Exceptions.js 1205 1588 * 1206 1589 * Copyright 2013, Moxiecode Systems AB 1207 1590 * Released under GPL License. … … 1210 1593 * Contributing: http://www.plupload.com/contributing 1211 1594 */ 1212 1595 1213 define( "moxie/core/I18n", [1214 "moxie/core/utils/Basic"1596 define('moxie/core/Exceptions', [ 1597 'moxie/core/utils/Basic' 1215 1598 ], function(Basic) { 1216 var i18n = {}; 1599 1600 function _findKey(obj, value) { 1601 var key; 1602 for (key in obj) { 1603 if (obj[key] === value) { 1604 return key; 1605 } 1606 } 1607 return null; 1608 } 1217 1609 1610 /** 1611 @class moxie/core/Exception 1612 */ 1218 1613 return { 1219 /** 1220 * Extends the language pack object with new items. 1221 * 1222 * @param {Object} pack Language pack items to add. 1223 * @return {Object} Extended language pack object. 1224 */ 1225 addI18n: function(pack) { 1226 return Basic.extend(i18n, pack); 1227 }, 1614 RuntimeError: (function() { 1615 var namecodes = { 1616 NOT_INIT_ERR: 1, 1617 EXCEPTION_ERR: 3, 1618 NOT_SUPPORTED_ERR: 9, 1619 JS_ERR: 4 1620 }; 1228 1621 1229 /** 1230 * Translates the specified string by checking for the english string in the language pack lookup. 1231 * 1232 * @param {String} str String to look for. 1233 * @return {String} Translated string or the input string if it wasn't found. 1234 */ 1235 translate: function(str) { 1236 return i18n[str] || str; 1237 }, 1238 1239 /** 1240 * Shortcut for translate function 1241 * 1242 * @param {String} str String to look for. 1243 * @return {String} Translated string or the input string if it wasn't found. 1244 */ 1245 _: function(str) { 1246 return this.translate(str); 1247 }, 1248 1249 /** 1250 * Pseudo sprintf implementation - simple way to replace tokens with specified values. 1251 * 1252 * @param {String} str String with tokens 1253 * @return {String} String with replaced tokens 1254 */ 1255 sprintf: function(str) { 1256 var args = [].slice.call(arguments, 1); 1257 1258 return str.replace(/%[a-z]/g, function() { 1259 var value = args.shift(); 1260 return Basic.typeOf(value) !== 'undefined' ? value : ''; 1622 function RuntimeError(code, message) { 1623 this.code = code; 1624 this.name = _findKey(namecodes, code); 1625 this.message = this.name + (message || ": RuntimeError " + this.code); 1626 } 1627 1628 Basic.extend(RuntimeError, namecodes); 1629 RuntimeError.prototype = Error.prototype; 1630 return RuntimeError; 1631 }()), 1632 1633 OperationNotAllowedException: (function() { 1634 1635 function OperationNotAllowedException(code) { 1636 this.code = code; 1637 this.name = 'OperationNotAllowedException'; 1638 } 1639 1640 Basic.extend(OperationNotAllowedException, { 1641 NOT_ALLOWED_ERR: 1 1261 1642 }); 1262 } 1263 }; 1264 }); 1643 1644 OperationNotAllowedException.prototype = Error.prototype; 1645 1646 return OperationNotAllowedException; 1647 }()), 1265 1648 1266 // Included from: src/javascript/core/utils/Mime.js 1649 ImageError: (function() { 1650 var namecodes = { 1651 WRONG_FORMAT: 1, 1652 MAX_RESOLUTION_ERR: 2, 1653 INVALID_META_ERR: 3 1654 }; 1267 1655 1268 /** 1269 * Mime.js 1270 * 1271 * Copyright 2013, Moxiecode Systems AB 1272 * Released under GPL License. 1273 * 1274 * License: http://www.plupload.com/license 1275 * Contributing: http://www.plupload.com/contributing 1276 */ 1277 1278 define("moxie/core/utils/Mime", [ 1279 "moxie/core/utils/Basic", 1280 "moxie/core/I18n" 1281 ], function(Basic, I18n) { 1282 1283 var mimeData = "" + 1284 "application/msword,doc dot," + 1285 "application/pdf,pdf," + 1286 "application/pgp-signature,pgp," + 1287 "application/postscript,ps ai eps," + 1288 "application/rtf,rtf," + 1289 "application/vnd.ms-excel,xls xlb," + 1290 "application/vnd.ms-powerpoint,ppt pps pot," + 1291 "application/zip,zip," + 1292 "application/x-shockwave-flash,swf swfl," + 1293 "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," + 1294 "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," + 1295 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," + 1296 "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," + 1297 "application/vnd.openxmlformats-officedocument.presentationml.template,potx," + 1298 "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," + 1299 "application/x-javascript,js," + 1300 "application/json,json," + 1301 "audio/mpeg,mp3 mpga mpega mp2," + 1302 "audio/x-wav,wav," + 1303 "audio/x-m4a,m4a," + 1304 "audio/ogg,oga ogg," + 1305 "audio/aiff,aiff aif," + 1306 "audio/flac,flac," + 1307 "audio/aac,aac," + 1308 "audio/ac3,ac3," + 1309 "audio/x-ms-wma,wma," + 1310 "image/bmp,bmp," + 1311 "image/gif,gif," + 1312 "image/jpeg,jpg jpeg jpe," + 1313 "image/photoshop,psd," + 1314 "image/png,png," + 1315 "image/svg+xml,svg svgz," + 1316 "image/tiff,tiff tif," + 1317 "text/plain,asc txt text diff log," + 1318 "text/html,htm html xhtml," + 1319 "text/css,css," + 1320 "text/csv,csv," + 1321 "text/rtf,rtf," + 1322 "video/mpeg,mpeg mpg mpe m2v," + 1323 "video/quicktime,qt mov," + 1324 "video/mp4,mp4," + 1325 "video/x-m4v,m4v," + 1326 "video/x-flv,flv," + 1327 "video/x-ms-wmv,wmv," + 1328 "video/avi,avi," + 1329 "video/webm,webm," + 1330 "video/3gpp,3gpp 3gp," + 1331 "video/3gpp2,3g2," + 1332 "video/vnd.rn-realvideo,rv," + 1333 "video/ogg,ogv," + 1334 "video/x-matroska,mkv," + 1335 "application/vnd.oasis.opendocument.formula-template,otf," + 1336 "application/octet-stream,exe"; 1337 1338 1339 var Mime = { 1340 1341 mimes: {}, 1342 1343 extensions: {}, 1344 1345 // Parses the default mime types string into a mimes and extensions lookup maps 1346 addMimeType: function (mimeData) { 1347 var items = mimeData.split(/,/), i, ii, ext; 1348 1349 for (i = 0; i < items.length; i += 2) { 1350 ext = items[i + 1].split(/ /); 1351 1352 // extension to mime lookup 1353 for (ii = 0; ii < ext.length; ii++) { 1354 this.mimes[ext[ii]] = items[i]; 1355 } 1356 // mime to extension lookup 1357 this.extensions[items[i]] = ext; 1656 function ImageError(code) { 1657 this.code = code; 1658 this.name = _findKey(namecodes, code); 1659 this.message = this.name + ": ImageError " + this.code; 1358 1660 } 1359 },1360 1361 1362 extList2mimes: function (filters, addMissingExtensions) {1363 var self = this, ext, i, ii, type, mimes = [];1364 1661 1365 // convert extensions to mime types list 1366 for (i = 0; i < filters.length; i++) { 1367 ext = filters[i].extensions.split(/\s*,\s*/); 1662 Basic.extend(ImageError, namecodes); 1663 ImageError.prototype = Error.prototype; 1368 1664 1369 for (ii = 0; ii < ext.length; ii++) { 1370 1371 // if there's an asterisk in the list, then accept attribute is not required 1372 if (ext[ii] === '*') { 1373 return []; 1374 } 1665 return ImageError; 1666 }()), 1375 1667 1376 type = self.mimes[ext[ii]]; 1377 if (type && Basic.inArray(type, mimes) === -1) { 1378 mimes.push(type); 1379 } 1668 FileException: (function() { 1669 var namecodes = { 1670 NOT_FOUND_ERR: 1, 1671 SECURITY_ERR: 2, 1672 ABORT_ERR: 3, 1673 NOT_READABLE_ERR: 4, 1674 ENCODING_ERR: 5, 1675 NO_MODIFICATION_ALLOWED_ERR: 6, 1676 INVALID_STATE_ERR: 7, 1677 SYNTAX_ERR: 8 1678 }; 1380 1679 1381 // future browsers should filter by extension, finally 1382 if (addMissingExtensions && /^\w+$/.test(ext[ii])) { 1383 mimes.push('.' + ext[ii]); 1384 } else if (!type) { 1385 // if we have no type in our map, then accept all 1386 return []; 1387 } 1388 } 1680 function FileException(code) { 1681 this.code = code; 1682 this.name = _findKey(namecodes, code); 1683 this.message = this.name + ": FileException " + this.code; 1389 1684 } 1390 return mimes;1391 },1392 1393 1394 mimes2exts: function(mimes) {1395 var self = this, exts = [];1396 1685 1397 Basic.each(mimes, function(mime) { 1398 if (mime === '*') { 1399 exts = []; 1400 return false; 1401 } 1686 Basic.extend(FileException, namecodes); 1687 FileException.prototype = Error.prototype; 1688 return FileException; 1689 }()), 1690 1691 DOMException: (function() { 1692 var namecodes = { 1693 INDEX_SIZE_ERR: 1, 1694 DOMSTRING_SIZE_ERR: 2, 1695 HIERARCHY_REQUEST_ERR: 3, 1696 WRONG_DOCUMENT_ERR: 4, 1697 INVALID_CHARACTER_ERR: 5, 1698 NO_DATA_ALLOWED_ERR: 6, 1699 NO_MODIFICATION_ALLOWED_ERR: 7, 1700 NOT_FOUND_ERR: 8, 1701 NOT_SUPPORTED_ERR: 9, 1702 INUSE_ATTRIBUTE_ERR: 10, 1703 INVALID_STATE_ERR: 11, 1704 SYNTAX_ERR: 12, 1705 INVALID_MODIFICATION_ERR: 13, 1706 NAMESPACE_ERR: 14, 1707 INVALID_ACCESS_ERR: 15, 1708 VALIDATION_ERR: 16, 1709 TYPE_MISMATCH_ERR: 17, 1710 SECURITY_ERR: 18, 1711 NETWORK_ERR: 19, 1712 ABORT_ERR: 20, 1713 URL_MISMATCH_ERR: 21, 1714 QUOTA_EXCEEDED_ERR: 22, 1715 TIMEOUT_ERR: 23, 1716 INVALID_NODE_TYPE_ERR: 24, 1717 DATA_CLONE_ERR: 25 1718 }; 1402 1719 1403 // check if this thing looks like mime type 1404 var m = mime.match(/^(\w+)\/(\*|\w+)$/); 1405 if (m) { 1406 if (m[2] === '*') { 1407 // wildcard mime type detected 1408 Basic.each(self.extensions, function(arr, mime) { 1409 if ((new RegExp('^' + m[1] + '/')).test(mime)) { 1410 [].push.apply(exts, self.extensions[mime]); 1411 } 1412 }); 1413 } else if (self.extensions[mime]) { 1414 [].push.apply(exts, self.extensions[mime]); 1415 } 1416 } 1417 }); 1418 return exts; 1419 }, 1420 1421 1422 mimes2extList: function(mimes) { 1423 var accept = [], exts = []; 1424 1425 if (Basic.typeOf(mimes) === 'string') { 1426 mimes = Basic.trim(mimes).split(/\s*,\s*/); 1720 function DOMException(code) { 1721 this.code = code; 1722 this.name = _findKey(namecodes, code); 1723 this.message = this.name + ": DOMException " + this.code; 1427 1724 } 1428 1429 exts = this.mimes2exts(mimes);1430 1725 1431 accept.push({ 1432 title: I18n.translate('Files'), 1433 extensions: exts.length ? exts.join(',') : '*' 1726 Basic.extend(DOMException, namecodes); 1727 DOMException.prototype = Error.prototype; 1728 return DOMException; 1729 }()), 1730 1731 EventException: (function() { 1732 function EventException(code) { 1733 this.code = code; 1734 this.name = 'EventException'; 1735 } 1736 1737 Basic.extend(EventException, { 1738 UNSPECIFIED_EVENT_TYPE_ERR: 0 1434 1739 }); 1435 1740 1436 // save original mimes string 1437 accept.mimes = mimes; 1438 1439 return accept; 1440 }, 1441 1442 1443 getFileExtension: function(fileName) { 1444 var matches = fileName && fileName.match(/\.([^.]+)$/); 1445 if (matches) { 1446 return matches[1].toLowerCase(); 1447 } 1448 return ''; 1449 }, 1450 1451 getFileMime: function(fileName) { 1452 return this.mimes[this.getFileExtension(fileName)] || ''; 1453 } 1741 EventException.prototype = Error.prototype; 1742 1743 return EventException; 1744 }()) 1454 1745 }; 1455 1456 Mime.addMimeType(mimeData);1457 1458 return Mime;1459 1746 }); 1460 1747 1461 1748 // Included from: src/javascript/core/utils/Dom.js … … 1470 1757 * Contributing: http://www.plupload.com/contributing 1471 1758 */ 1472 1759 1760 /** 1761 @class moxie/core/utils/Dom 1762 @public 1763 @static 1764 */ 1765 1473 1766 define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) { 1474 1767 1475 1768 /** … … 1476 1769 Get DOM Element by it's id. 1477 1770 1478 1771 @method get 1479 @for Utils1480 1772 @param {String} id Identifier of the DOM Element 1481 1773 @return {DOMElement} 1482 1774 */ … … 1641 1933 }; 1642 1934 }); 1643 1935 1644 // Included from: src/javascript/core/E xceptions.js1936 // Included from: src/javascript/core/EventTarget.js 1645 1937 1646 1938 /** 1647 * E xceptions.js1939 * EventTarget.js 1648 1940 * 1649 1941 * Copyright 2013, Moxiecode Systems AB 1650 1942 * Released under GPL License. … … 1653 1945 * Contributing: http://www.plupload.com/contributing 1654 1946 */ 1655 1947 1656 define('moxie/core/Exceptions', [ 1948 define('moxie/core/EventTarget', [ 1949 'moxie/core/utils/Env', 1950 'moxie/core/Exceptions', 1657 1951 'moxie/core/utils/Basic' 1658 ], function(Basic) { 1659 function _findKey(obj, value) { 1660 var key; 1661 for (key in obj) { 1662 if (obj[key] === value) { 1663 return key; 1664 } 1665 } 1666 return null; 1952 ], function(Env, x, Basic) { 1953 1954 // hash of event listeners by object uid 1955 var eventpool = {}; 1956 1957 /** 1958 Parent object for all event dispatching components and objects 1959 1960 @class moxie/core/EventTarget 1961 @constructor EventTarget 1962 */ 1963 function EventTarget() { 1964 /** 1965 Unique id of the event dispatcher, usually overriden by children 1966 1967 @property uid 1968 @type String 1969 */ 1970 this.uid = Basic.guid(); 1667 1971 } 1668 1972 1669 return {1670 RuntimeError: (function() {1671 var namecodes = {1672 NOT_INIT_ERR: 1,1673 NOT_SUPPORTED_ERR: 9,1674 JS_ERR: 41675 };1676 1973 1677 function RuntimeError(code) { 1678 this.code = code; 1679 this.name = _findKey(namecodes, code); 1680 this.message = this.name + ": RuntimeError " + this.code; 1681 } 1682 1683 Basic.extend(RuntimeError, namecodes); 1684 RuntimeError.prototype = Error.prototype; 1685 return RuntimeError; 1686 }()), 1687 1688 OperationNotAllowedException: (function() { 1689 1690 function OperationNotAllowedException(code) { 1691 this.code = code; 1692 this.name = 'OperationNotAllowedException'; 1693 } 1694 1695 Basic.extend(OperationNotAllowedException, { 1696 NOT_ALLOWED_ERR: 1 1697 }); 1698 1699 OperationNotAllowedException.prototype = Error.prototype; 1700 1701 return OperationNotAllowedException; 1702 }()), 1974 Basic.extend(EventTarget.prototype, { 1703 1975 1704 ImageError: (function() { 1705 var namecodes = { 1706 WRONG_FORMAT: 1, 1707 MAX_RESOLUTION_ERR: 2, 1708 INVALID_META_ERR: 3 1709 }; 1976 /** 1977 Can be called from within a child in order to acquire uniqie id in automated manner 1710 1978 1711 function ImageError(code) { 1712 this.code = code; 1713 this.name = _findKey(namecodes, code); 1714 this.message = this.name + ": ImageError " + this.code; 1979 @method init 1980 */ 1981 init: function() { 1982 if (!this.uid) { 1983 this.uid = Basic.guid('uid_'); 1715 1984 } 1716 1717 Basic.extend(ImageError, namecodes); 1718 ImageError.prototype = Error.prototype; 1985 }, 1719 1986 1720 return ImageError;1721 }()),1987 /** 1988 Register a handler to a specific event dispatched by the object 1722 1989 1723 FileException: (function() { 1724 var namecodes = { 1725 NOT_FOUND_ERR: 1, 1726 SECURITY_ERR: 2, 1727 ABORT_ERR: 3, 1728 NOT_READABLE_ERR: 4, 1729 ENCODING_ERR: 5, 1730 NO_MODIFICATION_ALLOWED_ERR: 6, 1731 INVALID_STATE_ERR: 7, 1732 SYNTAX_ERR: 8 1733 }; 1990 @method addEventListener 1991 @param {String} type Type or basically a name of the event to subscribe to 1992 @param {Function} fn Callback function that will be called when event happens 1993 @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first 1994 @param {Object} [scope=this] A scope to invoke event handler in 1995 */ 1996 addEventListener: function(type, fn, priority, scope) { 1997 var self = this, list; 1734 1998 1735 function FileException(code) { 1736 this.code = code; 1737 this.name = _findKey(namecodes, code); 1738 this.message = this.name + ": FileException " + this.code; 1999 // without uid no event handlers can be added, so make sure we got one 2000 if (!this.hasOwnProperty('uid')) { 2001 this.uid = Basic.guid('uid_'); 1739 2002 } 1740 1741 Basic.extend(FileException, namecodes);1742 FileException.prototype = Error.prototype;1743 return FileException;1744 }()),1745 1746 DOMException: (function() {1747 var namecodes = {1748 INDEX_SIZE_ERR: 1,1749 DOMSTRING_SIZE_ERR: 2,1750 HIERARCHY_REQUEST_ERR: 3,1751 WRONG_DOCUMENT_ERR: 4,1752 INVALID_CHARACTER_ERR: 5,1753 NO_DATA_ALLOWED_ERR: 6,1754 NO_MODIFICATION_ALLOWED_ERR: 7,1755 NOT_FOUND_ERR: 8,1756 NOT_SUPPORTED_ERR: 9,1757 INUSE_ATTRIBUTE_ERR: 10,1758 INVALID_STATE_ERR: 11,1759 SYNTAX_ERR: 12,1760 INVALID_MODIFICATION_ERR: 13,1761 NAMESPACE_ERR: 14,1762 INVALID_ACCESS_ERR: 15,1763 VALIDATION_ERR: 16,1764 TYPE_MISMATCH_ERR: 17,1765 SECURITY_ERR: 18,1766 NETWORK_ERR: 19,1767 ABORT_ERR: 20,1768 URL_MISMATCH_ERR: 21,1769 QUOTA_EXCEEDED_ERR: 22,1770 TIMEOUT_ERR: 23,1771 INVALID_NODE_TYPE_ERR: 24,1772 DATA_CLONE_ERR: 251773 };1774 2003 1775 function DOMException(code) { 1776 this.code = code; 1777 this.name = _findKey(namecodes, code); 1778 this.message = this.name + ": DOMException " + this.code; 2004 type = Basic.trim(type); 2005 2006 if (/\s/.test(type)) { 2007 // multiple event types were passed for one handler 2008 Basic.each(type.split(/\s+/), function(type) { 2009 self.addEventListener(type, fn, priority, scope); 2010 }); 2011 return; 1779 2012 } 1780 1781 Basic.extend(DOMException, namecodes);1782 DOMException.prototype = Error.prototype;1783 return DOMException;1784 }()),1785 1786 EventException: (function() {1787 function EventException(code) {1788 this.code = code;1789 this.name = 'EventException';1790 }1791 1792 Basic.extend(EventException, {1793 UNSPECIFIED_EVENT_TYPE_ERR: 01794 });1795 1796 EventException.prototype = Error.prototype;1797 1798 return EventException;1799 }())1800 };1801 });1802 2013 1803 // Included from: src/javascript/core/EventTarget.js 2014 type = type.toLowerCase(); 2015 priority = parseInt(priority, 10) || 0; 1804 2016 1805 /** 1806 * EventTarget.js 1807 * 1808 * Copyright 2013, Moxiecode Systems AB 1809 * Released under GPL License. 1810 * 1811 * License: http://www.plupload.com/license 1812 * Contributing: http://www.plupload.com/contributing 1813 */ 2017 list = eventpool[this.uid] && eventpool[this.uid][type] || []; 2018 list.push({fn : fn, priority : priority, scope : scope || this}); 1814 2019 1815 define('moxie/core/EventTarget', [ 1816 'moxie/core/utils/Env', 1817 'moxie/core/Exceptions', 1818 'moxie/core/utils/Basic' 1819 ], function(Env, x, Basic) { 1820 /** 1821 Parent object for all event dispatching components and objects 2020 if (!eventpool[this.uid]) { 2021 eventpool[this.uid] = {}; 2022 } 2023 eventpool[this.uid][type] = list; 2024 }, 1822 2025 1823 @class EventTarget 1824 @constructor EventTarget 1825 */ 1826 function EventTarget() { 1827 // hash of event listeners by object uid 1828 var eventpool = {}; 1829 1830 Basic.extend(this, { 1831 1832 /** 1833 Unique id of the event dispatcher, usually overriden by children 2026 /** 2027 Check if any handlers were registered to the specified event 1834 2028 1835 @property uid 1836 @type String 1837 */ 1838 uid: null, 1839 1840 /** 1841 Can be called from within a child in order to acquire uniqie id in automated manner 2029 @method hasEventListener 2030 @param {String} [type] Type or basically a name of the event to check 2031 @return {Mixed} Returns a handler if it was found and false, if - not 2032 */ 2033 hasEventListener: function(type) { 2034 var list; 2035 if (type) { 2036 type = type.toLowerCase(); 2037 list = eventpool[this.uid] && eventpool[this.uid][type]; 2038 } else { 2039 list = eventpool[this.uid]; 2040 } 2041 return list ? list : false; 2042 }, 1842 2043 1843 @method init 1844 */ 1845 init: function() { 1846 if (!this.uid) { 1847 this.uid = Basic.guid('uid_'); 1848 } 1849 }, 2044 /** 2045 Unregister the handler from the event, or if former was not specified - unregister all handlers 1850 2046 1851 /** 1852 Register a handler to a specific event dispatched by the object 2047 @method removeEventListener 2048 @param {String} type Type or basically a name of the event 2049 @param {Function} [fn] Handler to unregister 2050 */ 2051 removeEventListener: function(type, fn) { 2052 var self = this, list, i; 1853 2053 1854 @method addEventListener 1855 @param {String} type Type or basically a name of the event to subscribe to 1856 @param {Function} fn Callback function that will be called when event happens 1857 @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first 1858 @param {Object} [scope=this] A scope to invoke event handler in 1859 */ 1860 addEventListener: function(type, fn, priority, scope) { 1861 var self = this, list; 2054 type = type.toLowerCase(); 1862 2055 1863 // without uid no event handlers can be added, so make sure we got one 1864 if (!this.hasOwnProperty('uid')) { 1865 this.uid = Basic.guid('uid_'); 1866 } 1867 1868 type = Basic.trim(type); 1869 1870 if (/\s/.test(type)) { 1871 // multiple event types were passed for one handler 1872 Basic.each(type.split(/\s+/), function(type) { 1873 self.addEventListener(type, fn, priority, scope); 1874 }); 1875 return; 1876 } 1877 1878 type = type.toLowerCase(); 1879 priority = parseInt(priority, 10) || 0; 1880 1881 list = eventpool[this.uid] && eventpool[this.uid][type] || []; 1882 list.push({fn : fn, priority : priority, scope : scope || this}); 1883 1884 if (!eventpool[this.uid]) { 1885 eventpool[this.uid] = {}; 1886 } 1887 eventpool[this.uid][type] = list; 1888 }, 1889 1890 /** 1891 Check if any handlers were registered to the specified event 2056 if (/\s/.test(type)) { 2057 // multiple event types were passed for one handler 2058 Basic.each(type.split(/\s+/), function(type) { 2059 self.removeEventListener(type, fn); 2060 }); 2061 return; 2062 } 1892 2063 1893 @method hasEventListener 1894 @param {String} type Type or basically a name of the event to check 1895 @return {Mixed} Returns a handler if it was found and false, if - not 1896 */ 1897 hasEventListener: function(type) { 1898 var list = type ? eventpool[this.uid] && eventpool[this.uid][type] : eventpool[this.uid]; 1899 return list ? list : false; 1900 }, 1901 1902 /** 1903 Unregister the handler from the event, or if former was not specified - unregister all handlers 2064 list = eventpool[this.uid] && eventpool[this.uid][type]; 1904 2065 1905 @method removeEventListener 1906 @param {String} type Type or basically a name of the event 1907 @param {Function} [fn] Handler to unregister 1908 */ 1909 removeEventListener: function(type, fn) { 1910 type = type.toLowerCase(); 1911 1912 var list = eventpool[this.uid] && eventpool[this.uid][type], i; 1913 1914 if (list) { 1915 if (fn) { 1916 for (i = list.length - 1; i >= 0; i--) { 1917 if (list[i].fn === fn) { 1918 list.splice(i, 1); 1919 break; 1920 } 2066 if (list) { 2067 if (fn) { 2068 for (i = list.length - 1; i >= 0; i--) { 2069 if (list[i].fn === fn) { 2070 list.splice(i, 1); 2071 break; 1921 2072 } 1922 } else {1923 list = [];1924 2073 } 1925 1926 // delete event list if it has become empty 1927 if (!list.length) { 1928 delete eventpool[this.uid][type]; 1929 1930 // and object specific entry in a hash if it has no more listeners attached 1931 if (Basic.isEmptyObj(eventpool[this.uid])) { 1932 delete eventpool[this.uid]; 1933 } 1934 } 2074 } else { 2075 list = []; 1935 2076 } 1936 },1937 1938 /**1939 Remove all event handlers from the object1940 2077 1941 @method removeAllEventListeners 1942 */ 1943 removeAllEventListeners: function() { 1944 if (eventpool[this.uid]) { 1945 delete eventpool[this.uid]; 2078 // delete event list if it has become empty 2079 if (!list.length) { 2080 delete eventpool[this.uid][type]; 2081 2082 // and object specific entry in a hash if it has no more listeners attached 2083 if (Basic.isEmptyObj(eventpool[this.uid])) { 2084 delete eventpool[this.uid]; 2085 } 1946 2086 } 1947 }, 1948 1949 /** 1950 Dispatch the event 2087 } 2088 }, 1951 2089 1952 @method dispatchEvent 1953 @param {String/Object} Type of event or event object to dispatch 1954 @param {Mixed} [...] Variable number of arguments to be passed to a handlers 1955 @return {Boolean} true by default and false if any handler returned false 1956 */ 1957 dispatchEvent: function(type) { 1958 var uid, list, args, tmpEvt, evt = {}, result = true, undef; 1959 1960 if (Basic.typeOf(type) !== 'string') { 1961 // we can't use original object directly (because of Silverlight) 1962 tmpEvt = type; 2090 /** 2091 Remove all event handlers from the object 1963 2092 1964 if (Basic.typeOf(tmpEvt.type) === 'string') { 1965 type = tmpEvt.type; 2093 @method removeAllEventListeners 2094 */ 2095 removeAllEventListeners: function() { 2096 if (eventpool[this.uid]) { 2097 delete eventpool[this.uid]; 2098 } 2099 }, 1966 2100 1967 if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event 1968 evt.total = tmpEvt.total; 1969 evt.loaded = tmpEvt.loaded; 1970 } 1971 evt.async = tmpEvt.async || false; 1972 } else { 1973 throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR); 2101 /** 2102 Dispatch the event 2103 2104 @method dispatchEvent 2105 @param {String/Object} Type of event or event object to dispatch 2106 @param {Mixed} [...] Variable number of arguments to be passed to a handlers 2107 @return {Boolean} true by default and false if any handler returned false 2108 */ 2109 dispatchEvent: function(type) { 2110 var uid, list, args, tmpEvt, evt = {}, result = true, undef; 2111 2112 if (Basic.typeOf(type) !== 'string') { 2113 // we can't use original object directly (because of Silverlight) 2114 tmpEvt = type; 2115 2116 if (Basic.typeOf(tmpEvt.type) === 'string') { 2117 type = tmpEvt.type; 2118 2119 if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event 2120 evt.total = tmpEvt.total; 2121 evt.loaded = tmpEvt.loaded; 1974 2122 } 1975 } 1976 1977 // check if event is meant to be dispatched on an object having specific uid 1978 if (type.indexOf('::') !== -1) { 1979 (function(arr) { 1980 uid = arr[0]; 1981 type = arr[1]; 1982 }(type.split('::'))); 2123 evt.async = tmpEvt.async || false; 1983 2124 } else { 1984 uid = this.uid;2125 throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR); 1985 2126 } 1986 1987 type = type.toLowerCase(); 1988 1989 list = eventpool[uid] && eventpool[uid][type]; 2127 } 1990 2128 1991 if (list) { 1992 // sort event list by prority 1993 list.sort(function(a, b) { return b.priority - a.priority; }); 1994 1995 args = [].slice.call(arguments); 1996 1997 // first argument will be pseudo-event object 1998 args.shift(); 1999 evt.type = type; 2000 args.unshift(evt); 2129 // check if event is meant to be dispatched on an object having specific uid 2130 if (type.indexOf('::') !== -1) { 2131 (function(arr) { 2132 uid = arr[0]; 2133 type = arr[1]; 2134 }(type.split('::'))); 2135 } else { 2136 uid = this.uid; 2137 } 2001 2138 2002 if (MXI_DEBUG && Env.debug.events) { 2003 Env.log("Event '%s' fired on %u", evt.type, uid); 2004 } 2139 type = type.toLowerCase(); 2005 2140 2006 // Dispatch event to all listeners 2007 var queue = []; 2008 Basic.each(list, function(handler) { 2009 // explicitly set the target, otherwise events fired from shims do not get it 2010 args[0].target = handler.scope; 2011 // if event is marked as async, detach the handler 2012 if (evt.async) { 2013 queue.push(function(cb) { 2014 setTimeout(function() { 2015 cb(handler.fn.apply(handler.scope, args) === false); 2016 }, 1); 2017 }); 2018 } else { 2019 queue.push(function(cb) { 2020 cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation 2021 }); 2022 } 2023 }); 2024 if (queue.length) { 2025 Basic.inSeries(queue, function(err) { 2026 result = !err; 2141 list = eventpool[uid] && eventpool[uid][type]; 2142 2143 if (list) { 2144 // sort event list by prority 2145 list.sort(function(a, b) { return b.priority - a.priority; }); 2146 2147 args = [].slice.call(arguments); 2148 2149 // first argument will be pseudo-event object 2150 args.shift(); 2151 evt.type = type; 2152 args.unshift(evt); 2153 2154 if (MXI_DEBUG && Env.debug.events) { 2155 Env.log("%cEvent '%s' fired on %s", 'color: #999;', evt.type, (this.ctorName ? this.ctorName + '::' : '') + uid); 2156 } 2157 2158 // Dispatch event to all listeners 2159 var queue = []; 2160 Basic.each(list, function(handler) { 2161 // explicitly set the target, otherwise events fired from shims do not get it 2162 args[0].target = handler.scope; 2163 // if event is marked as async, detach the handler 2164 if (evt.async) { 2165 queue.push(function(cb) { 2166 setTimeout(function() { 2167 cb(handler.fn.apply(handler.scope, args) === false); 2168 }, 1); 2027 2169 }); 2170 } else { 2171 queue.push(function(cb) { 2172 cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation 2173 }); 2028 2174 } 2175 }); 2176 if (queue.length) { 2177 Basic.inSeries(queue, function(err) { 2178 result = !err; 2179 }); 2029 2180 } 2030 return result; 2031 }, 2032 2033 /** 2034 Alias for addEventListener 2181 } 2182 return result; 2183 }, 2035 2184 2036 @method bind 2037 @protected 2038 */ 2039 bind: function() { 2040 this.addEventListener.apply(this, arguments); 2041 }, 2042 2043 /** 2044 Alias for removeEventListener 2185 /** 2186 Register a handler to the event type that will run only once 2045 2187 2046 @method unbind 2047 @protected 2048 */ 2049 unbind: function() { 2050 this.removeEventListener.apply(this, arguments); 2051 }, 2052 2053 /** 2054 Alias for removeAllEventListeners 2188 @method bindOnce 2189 @since >1.4.1 2190 @param {String} type Type or basically a name of the event to subscribe to 2191 @param {Function} fn Callback function that will be called when event happens 2192 @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first 2193 @param {Object} [scope=this] A scope to invoke event handler in 2194 */ 2195 bindOnce: function(type, fn, priority, scope) { 2196 var self = this; 2197 self.bind.call(this, type, function cb() { 2198 self.unbind(type, cb); 2199 return fn.apply(this, arguments); 2200 }, priority, scope); 2201 }, 2055 2202 2056 @method unbindAll 2057 @protected 2058 */ 2059 unbindAll: function() { 2060 this.removeAllEventListeners.apply(this, arguments); 2061 }, 2062 2063 /** 2064 Alias for dispatchEvent 2203 /** 2204 Alias for addEventListener 2065 2205 2066 @method trigger 2067 @protected 2068 */ 2069 trigger: function() { 2070 return this.dispatchEvent.apply(this, arguments); 2071 }, 2072 2206 @method bind 2207 @protected 2208 */ 2209 bind: function() { 2210 this.addEventListener.apply(this, arguments); 2211 }, 2073 2212 2074 2075 Handle properties of on[event] type.2213 /** 2214 Alias for removeEventListener 2076 2215 2077 @method handleEventProps 2078 @private 2079 */ 2080 handleEventProps: function(dispatches) { 2081 var self = this; 2216 @method unbind 2217 @protected 2218 */ 2219 unbind: function() { 2220 this.removeEventListener.apply(this, arguments); 2221 }, 2082 2222 2083 this.bind(dispatches.join(' '), function(e) { 2084 var prop = 'on' + e.type.toLowerCase(); 2085 if (Basic.typeOf(this[prop]) === 'function') { 2086 this[prop].apply(this, arguments); 2087 } 2088 }); 2223 /** 2224 Alias for removeAllEventListeners 2089 2225 2090 // object must have defined event properties, even if it doesn't make use of them 2091 Basic.each(dispatches, function(prop) { 2092 prop = 'on' + prop.toLowerCase(prop); 2093 if (Basic.typeOf(self[prop]) === 'undefined') { 2094 self[prop] = null; 2095 } 2096 }); 2097 } 2098 2099 }); 2100 } 2226 @method unbindAll 2227 @protected 2228 */ 2229 unbindAll: function() { 2230 this.removeAllEventListeners.apply(this, arguments); 2231 }, 2101 2232 2102 EventTarget.instance = new EventTarget(); 2233 /** 2234 Alias for dispatchEvent 2103 2235 2236 @method trigger 2237 @protected 2238 */ 2239 trigger: function() { 2240 return this.dispatchEvent.apply(this, arguments); 2241 }, 2242 2243 2244 /** 2245 Handle properties of on[event] type. 2246 2247 @method handleEventProps 2248 @private 2249 */ 2250 handleEventProps: function(dispatches) { 2251 var self = this; 2252 2253 this.bind(dispatches.join(' '), function(e) { 2254 var prop = 'on' + e.type.toLowerCase(); 2255 if (Basic.typeOf(this[prop]) === 'function') { 2256 this[prop].apply(this, arguments); 2257 } 2258 }); 2259 2260 // object must have defined event properties, even if it doesn't make use of them 2261 Basic.each(dispatches, function(prop) { 2262 prop = 'on' + prop.toLowerCase(prop); 2263 if (Basic.typeOf(self[prop]) === 'undefined') { 2264 self[prop] = null; 2265 } 2266 }); 2267 } 2268 2269 }); 2270 2271 2272 EventTarget.instance = new EventTarget(); 2273 2104 2274 return EventTarget; 2105 2275 }); 2106 2276 … … 2127 2297 /** 2128 2298 Common set of methods and properties for every runtime instance 2129 2299 2130 @class Runtime2300 @class moxie/runtime/Runtime 2131 2301 2132 2302 @param {Object} options 2133 2303 @param {String} type Sanitized name of the runtime … … 2371 2541 2372 2542 // if no container for shim, create one 2373 2543 if (!shimContainer) { 2374 container = this.options.container ? Dom.get(this.options.container) :document.body;2544 container = Dom.get(this.options.container) || document.body; 2375 2545 2376 2546 // create shim container and insert it at an absolute position into the outer container 2377 2547 shimContainer = document.createElement('div'); … … 2475 2645 @type String 2476 2646 @static 2477 2647 */ 2478 Runtime.order = 'html5, html4';2648 Runtime.order = 'html5,flash,silverlight,html4'; 2479 2649 2480 2650 2481 2651 /** … … 2646 2816 // if cap requires conflicting mode - runtime cannot fulfill required caps 2647 2817 2648 2818 if (MXI_DEBUG && Env.debug.runtime) { 2649 Env.log("\t\t% c: %v (conflicting mode requested: %s)", cap, value, capMode);2819 Env.log("\t\t%s: %s (conflicting mode requested: %s)", cap, value, capMode); 2650 2820 } 2651 2821 2652 2822 return (mode = false); … … 2654 2824 } 2655 2825 2656 2826 if (MXI_DEBUG && Env.debug.runtime) { 2657 Env.log("\t\t% c: %v (compatible modes: %s)", cap, value, mode);2827 Env.log("\t\t%s: %s (compatible modes: %s)", cap, value, mode); 2658 2828 } 2659 2829 }); 2660 2830 … … 2669 2839 2670 2840 2671 2841 /** 2842 * Third party shims (Flash and Silverlight) require global event target against which they 2843 * will fire their events. However when moxie is not loaded to global namespace, default 2844 * event target is not accessible and we have to create artificial ones. 2845 * 2846 * @method getGlobalEventTarget 2847 * @static 2848 * @return {String} Name of the global event target 2849 */ 2850 Runtime.getGlobalEventTarget = function() { 2851 if (/^moxie\./.test(Env.global_event_dispatcher) && !Env.can('access_global_ns')) { 2852 var uniqueCallbackName = Basic.guid('moxie_event_target_'); 2853 2854 window[uniqueCallbackName] = function(e, data) { 2855 EventTarget.instance.dispatchEvent(e, data); 2856 }; 2857 2858 Env.global_event_dispatcher = uniqueCallbackName; 2859 } 2860 2861 return Env.global_event_dispatcher; 2862 }; 2863 2864 2865 /** 2672 2866 Capability check that always returns true 2673 2867 2674 2868 @private … … 2728 2922 /** 2729 2923 Set of methods and properties, required by a component to acquire ability to connect to a runtime 2730 2924 2731 @class RuntimeClient2925 @class moxie/runtime/RuntimeClient 2732 2926 */ 2733 2927 return function RuntimeClient() { 2734 2928 var runtime; … … 2758 2952 type = items.shift().toLowerCase(); 2759 2953 constructor = Runtime.getConstructor(type); 2760 2954 if (!constructor) { 2955 if (MXI_DEBUG && Env.debug.runtime) { 2956 Env.log("Constructor for '%s' runtime is not available.", type); 2957 } 2761 2958 initialize(items); 2762 2959 return; 2763 2960 } … … 2781 2978 // jailbreak ... 2782 2979 setTimeout(function() { 2783 2980 runtime.clients++; 2981 comp.ruid = runtime.uid; 2784 2982 // this will be triggered on component 2785 2983 comp.trigger('RuntimeInit', runtime); 2786 2984 }, 1); … … 2795 2993 initialize(items); 2796 2994 }); 2797 2995 2798 /*runtime.bind('Exception', function() { });*/ 2996 runtime.bind('Exception', function(e, err) { 2997 var message = err.name + "(#" + err.code + ")" + (err.message ? ", from: " + err.message : ''); 2998 2999 if (MXI_DEBUG && Env.debug.runtime) { 3000 Env.log("Runtime '%s' has thrown an exception: %s", this.type, message); 3001 } 3002 comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.EXCEPTION_ERR, message)); 3003 }); 2799 3004 2800 3005 if (MXI_DEBUG && Env.debug.runtime) { 2801 3006 Env.log("\tselected mode: %s", runtime.mode); … … 2820 3025 if (ruid) { 2821 3026 runtime = Runtime.getRuntime(ruid); 2822 3027 if (runtime) { 3028 comp.ruid = ruid; 2823 3029 runtime.clients++; 2824 3030 return runtime; 2825 3031 } else { … … 2871 3077 @return {Mixed} Whatever runtime extension method returns 2872 3078 */ 2873 3079 exec: function() { 2874 if (runtime) { 2875 return runtime.exec.apply(this, arguments); 3080 return runtime ? runtime.exec.apply(this, arguments) : null; 3081 }, 3082 3083 3084 /** 3085 Test runtime client for specific capability 3086 3087 @method can 3088 @param {String} cap 3089 @return {Bool} 3090 */ 3091 can: function(cap) { 3092 return runtime ? runtime.can(cap) : false; 3093 } 3094 3095 }); 3096 }; 3097 3098 3099 }); 3100 3101 // Included from: src/javascript/file/Blob.js 3102 3103 /** 3104 * Blob.js 3105 * 3106 * Copyright 2013, Moxiecode Systems AB 3107 * Released under GPL License. 3108 * 3109 * License: http://www.plupload.com/license 3110 * Contributing: http://www.plupload.com/contributing 3111 */ 3112 3113 define('moxie/file/Blob', [ 3114 'moxie/core/utils/Basic', 3115 'moxie/core/utils/Encode', 3116 'moxie/runtime/RuntimeClient' 3117 ], function(Basic, Encode, RuntimeClient) { 3118 3119 var blobpool = {}; 3120 3121 /** 3122 @class moxie/file/Blob 3123 @constructor 3124 @param {String} ruid Unique id of the runtime, to which this blob belongs to 3125 @param {Object} blob Object "Native" blob object, as it is represented in the runtime 3126 */ 3127 function Blob(ruid, blob) { 3128 3129 function _sliceDetached(start, end, type) { 3130 var blob, data = blobpool[this.uid]; 3131 3132 if (Basic.typeOf(data) !== 'string' || !data.length) { 3133 return null; // or throw exception 3134 } 3135 3136 blob = new Blob(null, { 3137 type: type, 3138 size: end - start 3139 }); 3140 blob.detach(data.substr(start, blob.size)); 3141 3142 return blob; 3143 } 3144 3145 RuntimeClient.call(this); 3146 3147 if (ruid) { 3148 this.connectRuntime(ruid); 3149 } 3150 3151 if (!blob) { 3152 blob = {}; 3153 } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string 3154 blob = { data: blob }; 3155 } 3156 3157 Basic.extend(this, { 3158 3159 /** 3160 Unique id of the component 3161 3162 @property uid 3163 @type {String} 3164 */ 3165 uid: blob.uid || Basic.guid('uid_'), 3166 3167 /** 3168 Unique id of the connected runtime, if falsy, then runtime will have to be initialized 3169 before this Blob can be used, modified or sent 3170 3171 @property ruid 3172 @type {String} 3173 */ 3174 ruid: ruid, 3175 3176 /** 3177 Size of blob 3178 3179 @property size 3180 @type {Number} 3181 @default 0 3182 */ 3183 size: blob.size || 0, 3184 3185 /** 3186 Mime type of blob 3187 3188 @property type 3189 @type {String} 3190 @default '' 3191 */ 3192 type: blob.type || '', 3193 3194 /** 3195 @method slice 3196 @param {Number} [start=0] 3197 */ 3198 slice: function(start, end, type) { 3199 if (this.isDetached()) { 3200 return _sliceDetached.apply(this, arguments); 2876 3201 } 2877 return null; 3202 return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type); 3203 }, 3204 3205 /** 3206 Returns "native" blob object (as it is represented in connected runtime) or null if not found 3207 3208 @method getSource 3209 @return {Blob} Returns "native" blob object or null if not found 3210 */ 3211 getSource: function() { 3212 if (!blobpool[this.uid]) { 3213 return null; 3214 } 3215 return blobpool[this.uid]; 3216 }, 3217 3218 /** 3219 Detaches blob from any runtime that it depends on and initialize with standalone value 3220 3221 @method detach 3222 @protected 3223 @param {DOMString} [data=''] Standalone value 3224 */ 3225 detach: function(data) { 3226 if (this.ruid) { 3227 this.getRuntime().exec.call(this, 'Blob', 'destroy'); 3228 this.disconnectRuntime(); 3229 this.ruid = null; 3230 } 3231 3232 data = data || ''; 3233 3234 // if dataUrl, convert to binary string 3235 if (data.substr(0, 5) == 'data:') { 3236 var base64Offset = data.indexOf(';base64,'); 3237 this.type = data.substring(5, base64Offset); 3238 data = Encode.atob(data.substring(base64Offset + 8)); 3239 } 3240 3241 this.size = data.length; 3242 3243 blobpool[this.uid] = data; 3244 }, 3245 3246 /** 3247 Checks if blob is standalone (detached of any runtime) 3248 3249 @method isDetached 3250 @protected 3251 @return {Boolean} 3252 */ 3253 isDetached: function() { 3254 return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string'; 3255 }, 3256 3257 /** 3258 Destroy Blob and free any resources it was using 3259 3260 @method destroy 3261 */ 3262 destroy: function() { 3263 this.detach(); 3264 delete blobpool[this.uid]; 2878 3265 } 3266 }); 2879 3267 3268 3269 if (blob.data) { 3270 this.detach(blob.data); // auto-detach if payload has been passed 3271 } else { 3272 blobpool[this.uid] = blob; 3273 } 3274 } 3275 3276 return Blob; 3277 }); 3278 3279 // Included from: src/javascript/core/I18n.js 3280 3281 /** 3282 * I18n.js 3283 * 3284 * Copyright 2013, Moxiecode Systems AB 3285 * Released under GPL License. 3286 * 3287 * License: http://www.plupload.com/license 3288 * Contributing: http://www.plupload.com/contributing 3289 */ 3290 3291 define("moxie/core/I18n", [ 3292 "moxie/core/utils/Basic" 3293 ], function(Basic) { 3294 var i18n = {}; 3295 3296 /** 3297 @class moxie/core/I18n 3298 */ 3299 return { 3300 /** 3301 * Extends the language pack object with new items. 3302 * 3303 * @param {Object} pack Language pack items to add. 3304 * @return {Object} Extended language pack object. 3305 */ 3306 addI18n: function(pack) { 3307 return Basic.extend(i18n, pack); 3308 }, 3309 3310 /** 3311 * Translates the specified string by checking for the english string in the language pack lookup. 3312 * 3313 * @param {String} str String to look for. 3314 * @return {String} Translated string or the input string if it wasn't found. 3315 */ 3316 translate: function(str) { 3317 return i18n[str] || str; 3318 }, 3319 3320 /** 3321 * Shortcut for translate function 3322 * 3323 * @param {String} str String to look for. 3324 * @return {String} Translated string or the input string if it wasn't found. 3325 */ 3326 _: function(str) { 3327 return this.translate(str); 3328 }, 3329 3330 /** 3331 * Pseudo sprintf implementation - simple way to replace tokens with specified values. 3332 * 3333 * @param {String} str String with tokens 3334 * @return {String} String with replaced tokens 3335 */ 3336 sprintf: function(str) { 3337 var args = [].slice.call(arguments, 1); 3338 3339 return str.replace(/%[a-z]/g, function() { 3340 var value = args.shift(); 3341 return Basic.typeOf(value) !== 'undefined' ? value : ''; 3342 }); 3343 } 3344 }; 3345 }); 3346 3347 // Included from: src/javascript/core/utils/Mime.js 3348 3349 /** 3350 * Mime.js 3351 * 3352 * Copyright 2013, Moxiecode Systems AB 3353 * Released under GPL License. 3354 * 3355 * License: http://www.plupload.com/license 3356 * Contributing: http://www.plupload.com/contributing 3357 */ 3358 3359 /** 3360 @class moxie/core/utils/Mime 3361 @public 3362 @static 3363 */ 3364 3365 define("moxie/core/utils/Mime", [ 3366 "moxie/core/utils/Basic", 3367 "moxie/core/I18n" 3368 ], function(Basic, I18n) { 3369 3370 var mimeData = "" + 3371 "application/msword,doc dot," + 3372 "application/pdf,pdf," + 3373 "application/pgp-signature,pgp," + 3374 "application/postscript,ps ai eps," + 3375 "application/rtf,rtf," + 3376 "application/vnd.ms-excel,xls xlb xlt xla," + 3377 "application/vnd.ms-powerpoint,ppt pps pot ppa," + 3378 "application/zip,zip," + 3379 "application/x-shockwave-flash,swf swfl," + 3380 "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," + 3381 "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," + 3382 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," + 3383 "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," + 3384 "application/vnd.openxmlformats-officedocument.presentationml.template,potx," + 3385 "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," + 3386 "application/x-javascript,js," + 3387 "application/json,json," + 3388 "audio/mpeg,mp3 mpga mpega mp2," + 3389 "audio/x-wav,wav," + 3390 "audio/x-m4a,m4a," + 3391 "audio/ogg,oga ogg," + 3392 "audio/aiff,aiff aif," + 3393 "audio/flac,flac," + 3394 "audio/aac,aac," + 3395 "audio/ac3,ac3," + 3396 "audio/x-ms-wma,wma," + 3397 "image/bmp,bmp," + 3398 "image/gif,gif," + 3399 "image/jpeg,jpg jpeg jpe," + 3400 "image/photoshop,psd," + 3401 "image/png,png," + 3402 "image/svg+xml,svg svgz," + 3403 "image/tiff,tiff tif," + 3404 "text/plain,asc txt text diff log," + 3405 "text/html,htm html xhtml," + 3406 "text/css,css," + 3407 "text/csv,csv," + 3408 "text/rtf,rtf," + 3409 "video/mpeg,mpeg mpg mpe m2v," + 3410 "video/quicktime,qt mov," + 3411 "video/mp4,mp4," + 3412 "video/x-m4v,m4v," + 3413 "video/x-flv,flv," + 3414 "video/x-ms-wmv,wmv," + 3415 "video/avi,avi," + 3416 "video/webm,webm," + 3417 "video/3gpp,3gpp 3gp," + 3418 "video/3gpp2,3g2," + 3419 "video/vnd.rn-realvideo,rv," + 3420 "video/ogg,ogv," + 3421 "video/x-matroska,mkv," + 3422 "application/vnd.oasis.opendocument.formula-template,otf," + 3423 "application/octet-stream,exe"; 3424 3425 3426 /** 3427 * Map of mimes to extensions 3428 * 3429 * @property mimes 3430 * @type {Object} 3431 */ 3432 var mimes = {}; 3433 3434 /** 3435 * Map of extensions to mimes 3436 * 3437 * @property extensions 3438 * @type {Object} 3439 */ 3440 var extensions = {}; 3441 3442 3443 /** 3444 * Parses mimeData string into a mimes and extensions lookup maps. String should have the 3445 * following format: 3446 * 3447 * application/msword,doc dot,application/pdf,pdf, ... 3448 * 3449 * so mime-type followed by comma and followed by space-separated list of associated extensions, 3450 * then comma again and then another mime-type, etc. 3451 * 3452 * If invoked externally will replace override internal lookup maps with user-provided data. 3453 * 3454 * @method addMimeType 3455 * @param {String} mimeData 3456 */ 3457 var addMimeType = function (mimeData) { 3458 var items = mimeData.split(/,/), i, ii, ext; 3459 3460 for (i = 0; i < items.length; i += 2) { 3461 ext = items[i + 1].split(/ /); 3462 3463 // extension to mime lookup 3464 for (ii = 0; ii < ext.length; ii++) { 3465 mimes[ext[ii]] = items[i]; 3466 } 3467 // mime to extension lookup 3468 extensions[items[i]] = ext; 3469 } 3470 }; 3471 3472 3473 var extList2mimes = function (filters, addMissingExtensions) { 3474 var ext, i, ii, type, mimes = []; 3475 3476 // convert extensions to mime types list 3477 for (i = 0; i < filters.length; i++) { 3478 ext = filters[i].extensions.toLowerCase().split(/\s*,\s*/); 3479 3480 for (ii = 0; ii < ext.length; ii++) { 3481 3482 // if there's an asterisk in the list, then accept attribute is not required 3483 if (ext[ii] === '*') { 3484 return []; 3485 } 3486 3487 type = mimes[ext[ii]]; 3488 3489 // future browsers should filter by extension, finally 3490 if (addMissingExtensions && /^\w+$/.test(ext[ii])) { 3491 mimes.push('.' + ext[ii]); 3492 } else if (type && Basic.inArray(type, mimes) === -1) { 3493 mimes.push(type); 3494 } else if (!type) { 3495 // if we have no type in our map, then accept all 3496 return []; 3497 } 3498 } 3499 } 3500 return mimes; 3501 }; 3502 3503 3504 var mimes2exts = function(mimes) { 3505 var exts = []; 3506 3507 Basic.each(mimes, function(mime) { 3508 mime = mime.toLowerCase(); 3509 3510 if (mime === '*') { 3511 exts = []; 3512 return false; 3513 } 3514 3515 // check if this thing looks like mime type 3516 var m = mime.match(/^(\w+)\/(\*|\w+)$/); 3517 if (m) { 3518 if (m[2] === '*') { 3519 // wildcard mime type detected 3520 Basic.each(extensions, function(arr, mime) { 3521 if ((new RegExp('^' + m[1] + '/')).test(mime)) { 3522 [].push.apply(exts, extensions[mime]); 3523 } 3524 }); 3525 } else if (extensions[mime]) { 3526 [].push.apply(exts, extensions[mime]); 3527 } 3528 } 2880 3529 }); 3530 return exts; 2881 3531 }; 2882 3532 2883 3533 3534 var mimes2extList = function(mimes) { 3535 var accept = [], exts = []; 3536 3537 if (Basic.typeOf(mimes) === 'string') { 3538 mimes = Basic.trim(mimes).split(/\s*,\s*/); 3539 } 3540 3541 exts = mimes2exts(mimes); 3542 3543 accept.push({ 3544 title: I18n.translate('Files'), 3545 extensions: exts.length ? exts.join(',') : '*' 3546 }); 3547 3548 return accept; 3549 }; 3550 3551 /** 3552 * Extract extension from the given filename 3553 * 3554 * @method getFileExtension 3555 * @param {String} fileName 3556 * @return {String} File extension 3557 */ 3558 var getFileExtension = function(fileName) { 3559 var matches = fileName && fileName.match(/\.([^.]+)$/); 3560 if (matches) { 3561 return matches[1].toLowerCase(); 3562 } 3563 return ''; 3564 }; 3565 3566 3567 /** 3568 * Get file mime-type from it's filename - will try to match the extension 3569 * against internal mime-type lookup map 3570 * 3571 * @method getFileMime 3572 * @param {String} fileName 3573 * @return File mime-type if found or an empty string if not 3574 */ 3575 var getFileMime = function(fileName) { 3576 return mimes[getFileExtension(fileName)] || ''; 3577 }; 3578 3579 3580 addMimeType(mimeData); 3581 3582 return { 3583 mimes: mimes, 3584 extensions: extensions, 3585 addMimeType: addMimeType, 3586 extList2mimes: extList2mimes, 3587 mimes2exts: mimes2exts, 3588 mimes2extList: mimes2extList, 3589 getFileExtension: getFileExtension, 3590 getFileMime: getFileMime 3591 } 2884 3592 }); 2885 3593 2886 3594 // Included from: src/javascript/file/FileInput.js … … 2911 3619 converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory 2912 3620 with _FileReader_ or uploaded to a server through _XMLHttpRequest_. 2913 3621 2914 @class FileInput3622 @class moxie/file/FileInput 2915 3623 @constructor 2916 3624 @extends EventTarget 2917 3625 @uses RuntimeClient … … 2918 3626 @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_. 2919 3627 @param {String|DOMElement} options.browse_button DOM Element to turn into file picker. 2920 3628 @param {Array} [options.accept] Array of mime types to accept. By default accepts all. 2921 @param {String} [options.file='file'] Name of the file field (not the filename).2922 3629 @param {Boolean} [options.multiple=false] Enable selection of multiple files. 2923 3630 @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time). 2924 @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode 3631 @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode 2925 3632 for _browse\_button_. 2926 3633 @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support. 2927 3634 … … 2931 3638 </div> 2932 3639 2933 3640 <script> 2934 var fileInput = new m Oxie.FileInput({3641 var fileInput = new moxie.file.FileInput({ 2935 3642 browse_button: 'file-picker', // or document.getElementById('file-picker') 2936 3643 container: 'container', 2937 3644 accept: [ … … 2958 3665 'ready', 2959 3666 2960 3667 /** 2961 Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. 3668 Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. 2962 3669 Check [corresponding documentation entry](#method_refresh) for more info. 2963 3670 2964 3671 @event refresh … … 3012 3719 3013 3720 function FileInput(options) { 3014 3721 if (MXI_DEBUG) { 3015 Env.log("Instantiating FileInput..."); 3722 Env.log("Instantiating FileInput..."); 3016 3723 } 3017 3724 3018 var self = this, 3019 container, browseButton, defaults; 3725 var container, browseButton, defaults; 3020 3726 3021 3727 // if flat argument passed it should be browse_button id 3022 3728 if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) { … … 3036 3742 title: I18n.translate('All Files'), 3037 3743 extensions: '*' 3038 3744 }], 3039 name: 'file',3040 3745 multiple: false, 3041 3746 required_caps: false, 3042 3747 container: browseButton.parentNode || document.body 3043 3748 }; 3044 3749 3045 3750 options = Basic.extend({}, defaults, options); 3046 3751 3047 3752 // convert to object representation … … 3048 3753 if (typeof(options.required_caps) === 'string') { 3049 3754 options.required_caps = Runtime.parseCaps(options.required_caps); 3050 3755 } 3051 3756 3052 3757 // normalize accept option (could be list of mime types or array of title/extensions pairs) 3053 3758 if (typeof(options.accept) === 'string') { 3054 3759 options.accept = Mime.mimes2extList(options.accept); … … 3066 3771 } 3067 3772 3068 3773 container = browseButton = null; // IE 3069 3070 RuntimeClient.call( self);3071 3072 Basic.extend( self, {3774 3775 RuntimeClient.call(this); 3776 3777 Basic.extend(this, { 3073 3778 /** 3074 3779 Unique id of the component 3075 3780 … … 3080 3785 @default UID 3081 3786 */ 3082 3787 uid: Basic.guid('uid_'), 3083 3788 3084 3789 /** 3085 3790 Unique id of the connected runtime, if any. 3086 3791 … … 3098 3803 @type {String} 3099 3804 */ 3100 3805 shimid: null, 3101 3806 3102 3807 /** 3103 Array of selected m Oxie.File objects3808 Array of selected moxie.file.File objects 3104 3809 3105 3810 @property files 3106 3811 @type {Array} … … 3114 3819 @method init 3115 3820 */ 3116 3821 init: function() { 3822 var self = this; 3823 3117 3824 self.bind('RuntimeInit', function(e, runtime) { 3118 3825 self.ruid = runtime.uid; 3119 3826 self.shimid = runtime.shimid; … … 3124 3831 3125 3832 // re-position and resize shim container 3126 3833 self.bind('Refresh', function() { 3127 var pos, size, browseButton, shimContainer ;3128 3834 var pos, size, browseButton, shimContainer, zIndex; 3835 3129 3836 browseButton = Dom.get(options.browse_button); 3130 3837 shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist 3131 3838 … … 3132 3839 if (browseButton) { 3133 3840 pos = Dom.getPos(browseButton, Dom.get(options.container)); 3134 3841 size = Dom.getSize(browseButton); 3842 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 0; 3135 3843 3136 3844 if (shimContainer) { 3137 3845 Basic.extend(shimContainer.style, { 3138 top : pos.y + 'px', 3139 left : pos.x + 'px', 3140 width : size.w + 'px', 3141 height : size.h + 'px' 3846 top: pos.y + 'px', 3847 left: pos.x + 'px', 3848 width: size.w + 'px', 3849 height: size.h + 'px', 3850 zIndex: zIndex + 1 3142 3851 }); 3143 3852 } 3144 3853 } 3145 3854 shimContainer = browseButton = null; 3146 3855 }); 3147 3856 3148 3857 runtime.exec.call(self, 'FileInput', 'init', options); 3149 3858 }); 3150 3859 … … 3156 3865 })); 3157 3866 }, 3158 3867 3868 3159 3869 /** 3870 * Get current option value by its name 3871 * 3872 * @method getOption 3873 * @param name 3874 * @return {Mixed} 3875 */ 3876 getOption: function(name) { 3877 return options[name]; 3878 }, 3879 3880 3881 /** 3882 * Sets a new value for the option specified by name 3883 * 3884 * @method setOption 3885 * @param name 3886 * @param value 3887 */ 3888 setOption: function(name, value) { 3889 if (!options.hasOwnProperty(name)) { 3890 return; 3891 } 3892 3893 var oldValue = options[name]; 3894 3895 switch (name) { 3896 case 'accept': 3897 if (typeof(value) === 'string') { 3898 value = Mime.mimes2extList(value); 3899 } 3900 break; 3901 3902 case 'container': 3903 case 'required_caps': 3904 throw new x.FileException(x.FileException.NO_MODIFICATION_ALLOWED_ERR); 3905 } 3906 3907 options[name] = value; 3908 this.exec('FileInput', 'setOption', name, value); 3909 3910 this.trigger('OptionChanged', name, value, oldValue); 3911 }, 3912 3913 /** 3160 3914 Disables file-picker element, so that it doesn't react to mouse clicks. 3161 3915 3162 3916 @method disable … … 3165 3919 disable: function(state) { 3166 3920 var runtime = this.getRuntime(); 3167 3921 if (runtime) { 3168 runtime.exec.call(this,'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);3922 this.exec('FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state); 3169 3923 } 3170 3924 }, 3171 3925 … … 3176 3930 @method refresh 3177 3931 */ 3178 3932 refresh: function() { 3179 self.trigger("Refresh");3933 this.trigger("Refresh"); 3180 3934 }, 3181 3935 3182 3936 … … 3197 3951 Basic.each(this.files, function(file) { 3198 3952 file.destroy(); 3199 3953 }); 3200 } 3954 } 3201 3955 this.files = null; 3202 3956 3203 3957 this.unbindAll(); … … 3212 3966 return FileInput; 3213 3967 }); 3214 3968 3215 // Included from: src/javascript/core/utils/Encode.js3216 3217 /**3218 * Encode.js3219 *3220 * Copyright 2013, Moxiecode Systems AB3221 * Released under GPL License.3222 *3223 * License: http://www.plupload.com/license3224 * Contributing: http://www.plupload.com/contributing3225 */3226 3227 define('moxie/core/utils/Encode', [], function() {3228 3229 /**3230 Encode string with UTF-83231 3232 @method utf8_encode3233 @for Utils3234 @static3235 @param {String} str String to encode3236 @return {String} UTF-8 encoded string3237 */3238 var utf8_encode = function(str) {3239 return unescape(encodeURIComponent(str));3240 };3241 3242 /**3243 Decode UTF-8 encoded string3244 3245 @method utf8_decode3246 @static3247 @param {String} str String to decode3248 @return {String} Decoded string3249 */3250 var utf8_decode = function(str_data) {3251 return decodeURIComponent(escape(str_data));3252 };3253 3254 /**3255 Decode Base64 encoded string (uses browser's default method if available),3256 from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js3257 3258 @method atob3259 @static3260 @param {String} data String to decode3261 @return {String} Decoded string3262 */3263 var atob = function(data, utf8) {3264 if (typeof(window.atob) === 'function') {3265 return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);3266 }3267 3268 // http://kevin.vanzonneveld.net3269 // + original by: Tyler Akins (http://rumkin.com)3270 // + improved by: Thunder.m3271 // + input by: Aman Gupta3272 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)3273 // + bugfixed by: Onno Marsman3274 // + bugfixed by: Pellentesque Malesuada3275 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)3276 // + input by: Brett Zamir (http://brett-zamir.me)3277 // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)3278 // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');3279 // * returns 1: 'Kevin van Zonneveld'3280 // mozilla has this native3281 // - but breaks in 2.0.0.12!3282 //if (typeof this.window.atob == 'function') {3283 // return atob(data);3284 //}3285 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";3286 var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,3287 ac = 0,3288 dec = "",3289 tmp_arr = [];3290 3291 if (!data) {3292 return data;3293 }3294 3295 data += '';3296 3297 do { // unpack four hexets into three octets using index points in b643298 h1 = b64.indexOf(data.charAt(i++));3299 h2 = b64.indexOf(data.charAt(i++));3300 h3 = b64.indexOf(data.charAt(i++));3301 h4 = b64.indexOf(data.charAt(i++));3302 3303 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;3304 3305 o1 = bits >> 16 & 0xff;3306 o2 = bits >> 8 & 0xff;3307 o3 = bits & 0xff;3308 3309 if (h3 == 64) {3310 tmp_arr[ac++] = String.fromCharCode(o1);3311 } else if (h4 == 64) {3312 tmp_arr[ac++] = String.fromCharCode(o1, o2);3313 } else {3314 tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);3315 }3316 } while (i < data.length);3317 3318 dec = tmp_arr.join('');3319 3320 return utf8 ? utf8_decode(dec) : dec;3321 };3322 3323 /**3324 Base64 encode string (uses browser's default method if available),3325 from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js3326 3327 @method btoa3328 @static3329 @param {String} data String to encode3330 @return {String} Base64 encoded string3331 */3332 var btoa = function(data, utf8) {3333 if (utf8) {3334 data = utf8_encode(data);3335 }3336 3337 if (typeof(window.btoa) === 'function') {3338 return window.btoa(data);3339 }3340 3341 // http://kevin.vanzonneveld.net3342 // + original by: Tyler Akins (http://rumkin.com)3343 // + improved by: Bayron Guevara3344 // + improved by: Thunder.m3345 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)3346 // + bugfixed by: Pellentesque Malesuada3347 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)3348 // + improved by: Rafał Kukawski (http://kukawski.pl)3349 // * example 1: base64_encode('Kevin van Zonneveld');3350 // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='3351 // mozilla has this native3352 // - but breaks in 2.0.0.12!3353 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";3354 var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,3355 ac = 0,3356 enc = "",3357 tmp_arr = [];3358 3359 if (!data) {3360 return data;3361 }3362 3363 do { // pack three octets into four hexets3364 o1 = data.charCodeAt(i++);3365 o2 = data.charCodeAt(i++);3366 o3 = data.charCodeAt(i++);3367 3368 bits = o1 << 16 | o2 << 8 | o3;3369 3370 h1 = bits >> 18 & 0x3f;3371 h2 = bits >> 12 & 0x3f;3372 h3 = bits >> 6 & 0x3f;3373 h4 = bits & 0x3f;3374 3375 // use hexets to index into b64, and append result to encoded string3376 tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);3377 } while (i < data.length);3378 3379 enc = tmp_arr.join('');3380 3381 var r = data.length % 3;3382 3383 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);3384 };3385 3386 3387 return {3388 utf8_encode: utf8_encode,3389 utf8_decode: utf8_decode,3390 atob: atob,3391 btoa: btoa3392 };3393 });3394 3395 // Included from: src/javascript/file/Blob.js3396 3397 /**3398 * Blob.js3399 *3400 * Copyright 2013, Moxiecode Systems AB3401 * Released under GPL License.3402 *3403 * License: http://www.plupload.com/license3404 * Contributing: http://www.plupload.com/contributing3405 */3406 3407 define('moxie/file/Blob', [3408 'moxie/core/utils/Basic',3409 'moxie/core/utils/Encode',3410 'moxie/runtime/RuntimeClient'3411 ], function(Basic, Encode, RuntimeClient) {3412 3413 var blobpool = {};3414 3415 /**3416 @class Blob3417 @constructor3418 @param {String} ruid Unique id of the runtime, to which this blob belongs to3419 @param {Object} blob Object "Native" blob object, as it is represented in the runtime3420 */3421 function Blob(ruid, blob) {3422 3423 function _sliceDetached(start, end, type) {3424 var blob, data = blobpool[this.uid];3425 3426 if (Basic.typeOf(data) !== 'string' || !data.length) {3427 return null; // or throw exception3428 }3429 3430 blob = new Blob(null, {3431 type: type,3432 size: end - start3433 });3434 blob.detach(data.substr(start, blob.size));3435 3436 return blob;3437 }3438 3439 RuntimeClient.call(this);3440 3441 if (ruid) {3442 this.connectRuntime(ruid);3443 }3444 3445 if (!blob) {3446 blob = {};3447 } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string3448 blob = { data: blob };3449 }3450 3451 Basic.extend(this, {3452 3453 /**3454 Unique id of the component3455 3456 @property uid3457 @type {String}3458 */3459 uid: blob.uid || Basic.guid('uid_'),3460 3461 /**3462 Unique id of the connected runtime, if falsy, then runtime will have to be initialized3463 before this Blob can be used, modified or sent3464 3465 @property ruid3466 @type {String}3467 */3468 ruid: ruid,3469 3470 /**3471 Size of blob3472 3473 @property size3474 @type {Number}3475 @default 03476 */3477 size: blob.size || 0,3478 3479 /**3480 Mime type of blob3481 3482 @property type3483 @type {String}3484 @default ''3485 */3486 type: blob.type || '',3487 3488 /**3489 @method slice3490 @param {Number} [start=0]3491 */3492 slice: function(start, end, type) {3493 if (this.isDetached()) {3494 return _sliceDetached.apply(this, arguments);3495 }3496 return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type);3497 },3498 3499 /**3500 Returns "native" blob object (as it is represented in connected runtime) or null if not found3501 3502 @method getSource3503 @return {Blob} Returns "native" blob object or null if not found3504 */3505 getSource: function() {3506 if (!blobpool[this.uid]) {3507 return null;3508 }3509 return blobpool[this.uid];3510 },3511 3512 /**3513 Detaches blob from any runtime that it depends on and initialize with standalone value3514 3515 @method detach3516 @protected3517 @param {DOMString} [data=''] Standalone value3518 */3519 detach: function(data) {3520 if (this.ruid) {3521 this.getRuntime().exec.call(this, 'Blob', 'destroy');3522 this.disconnectRuntime();3523 this.ruid = null;3524 }3525 3526 data = data || '';3527 3528 // if dataUrl, convert to binary string3529 if (data.substr(0, 5) == 'data:') {3530 var base64Offset = data.indexOf(';base64,');3531 this.type = data.substring(5, base64Offset);3532 data = Encode.atob(data.substring(base64Offset + 8));3533 }3534 3535 this.size = data.length;3536 3537 blobpool[this.uid] = data;3538 },3539 3540 /**3541 Checks if blob is standalone (detached of any runtime)3542 3543 @method isDetached3544 @protected3545 @return {Boolean}3546 */3547 isDetached: function() {3548 return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string';3549 },3550 3551 /**3552 Destroy Blob and free any resources it was using3553 3554 @method destroy3555 */3556 destroy: function() {3557 this.detach();3558 delete blobpool[this.uid];3559 }3560 });3561 3562 3563 if (blob.data) {3564 this.detach(blob.data); // auto-detach if payload has been passed3565 } else {3566 blobpool[this.uid] = blob;3567 }3568 }3569 3570 return Blob;3571 });3572 3573 3969 // Included from: src/javascript/file/File.js 3574 3970 3575 3971 /** … … 3588 3984 'moxie/file/Blob' 3589 3985 ], function(Basic, Mime, Blob) { 3590 3986 /** 3591 @class File3987 @class moxie/file/File 3592 3988 @extends Blob 3593 3989 @constructor 3594 3990 @param {String} ruid Unique id of the runtime, to which this blob belongs to … … 3691 4087 <div id="filelist"></div> 3692 4088 3693 4089 <script type="text/javascript"> 3694 var fileDrop = new m Oxie.FileDrop('drop_zone'), fileList = mOxie.get('filelist');4090 var fileDrop = new moxie.file.FileDrop('drop_zone'), fileList = moxie.utils.Dom.get('filelist'); 3695 4091 3696 4092 fileDrop.ondrop = function() { 3697 m Oxie.each(this.files, function(file) {4093 moxie.utils.Basic.each(this.files, function(file) { 3698 4094 fileList.innerHTML += '<div>' + file.name + '</div>'; 3699 4095 }); 3700 4096 }; … … 3702 4098 fileDrop.init(); 3703 4099 </script> 3704 4100 3705 @class FileDrop4101 @class moxie/file/FileDrop 3706 4102 @constructor 3707 4103 @extends EventTarget 3708 4104 @uses RuntimeClient … … 3855 4251 Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader) 3856 4252 interface. Where possible uses native FileReader, where - not falls back to shims. 3857 4253 3858 @class FileReader4254 @class moxie/file/FileReader 3859 4255 @constructor FileReader 3860 4256 @extends EventTarget 3861 4257 @uses RuntimeClient … … 4118 4514 * Contributing: http://www.plupload.com/contributing 4119 4515 */ 4120 4516 4121 define('moxie/core/utils/Url', [], function() { 4517 /** 4518 @class moxie/core/utils/Url 4519 @public 4520 @static 4521 */ 4522 4523 define('moxie/core/utils/Url', [ 4524 'moxie/core/utils/Basic' 4525 ], function(Basic) { 4122 4526 /** 4123 4527 Parse url into separate components and fill in absent parts with parts from current url, 4124 4528 based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js 4125 4529 4126 4530 @method parseUrl 4127 @for Utils4128 4531 @static 4129 4532 @param {String} url Url to parse (defaults to empty string if undefined) 4130 4533 @return {Object} Hash containing extracted uri components … … 4137 4540 https: 443 4138 4541 } 4139 4542 , uri = {} 4140 , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?( [^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/4543 , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/ 4141 4544 , m = regex.exec(url || '') 4545 , isRelative 4546 , isSchemeLess = /^\/\/\w/.test(url) 4142 4547 ; 4143 4548 4549 switch (Basic.typeOf(currentUrl)) { 4550 case 'undefined': 4551 currentUrl = parseUrl(document.location.href, false); 4552 break; 4553 4554 case 'string': 4555 currentUrl = parseUrl(currentUrl, false); 4556 break; 4557 } 4558 4144 4559 while (i--) { 4145 4560 if (m[i]) { 4146 4561 uri[key[i]] = m[i]; … … 4147 4562 } 4148 4563 } 4149 4564 4150 // when url is relative, we set the origin and the path ourselves 4151 if (!uri.scheme) { 4152 // come up with defaults 4153 if (!currentUrl || typeof(currentUrl) === 'string') { 4154 currentUrl = parseUrl(currentUrl || document.location.href); 4155 } 4565 isRelative = !isSchemeLess && !uri.scheme; 4156 4566 4567 if (isSchemeLess || isRelative) { 4157 4568 uri.scheme = currentUrl.scheme; 4569 } 4570 4571 // when url is relative, we set the origin and the path ourselves 4572 if (isRelative) { 4158 4573 uri.host = currentUrl.host; 4159 4574 uri.port = currentUrl.port; 4160 4575 … … 4175 4590 4176 4591 if (!uri.port) { 4177 4592 uri.port = ports[uri.scheme] || 80; 4178 } 4179 4593 } 4594 4180 4595 uri.port = parseInt(uri.port, 10); 4181 4596 4182 4597 if (!uri.path) { … … 4211 4626 Check if specified url has the same origin as the current document 4212 4627 4213 4628 @method hasSameOrigin 4629 @static 4214 4630 @param {String|Object} url 4215 4631 @return {Boolean} 4216 4632 */ … … 4218 4634 function origin(url) { 4219 4635 return [url.scheme, url.host, url.port].join('/'); 4220 4636 } 4221 4637 4222 4638 if (typeof url === 'string') { 4223 4639 url = parseUrl(url); 4224 } 4225 4640 } 4641 4226 4642 return origin(parseUrl()) === origin(url); 4227 4643 }; 4228 4644 … … 4254 4670 Instance of this class can be used as a target for the events dispatched by shims, 4255 4671 when allowing them onto components is for either reason inappropriate 4256 4672 4257 @class RuntimeTarget4673 @class moxie/runtime/RuntimeTarget 4258 4674 @constructor 4259 4675 @protected 4260 4676 @extends EventTarget … … 4297 4713 it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be, 4298 4714 but probably < 1mb). Not meant to be used directly by user. 4299 4715 4300 @class FileReaderSync4716 @class moxie/file/FileReaderSync 4301 4717 @private 4302 4718 @constructor 4303 4719 */ … … 4368 4784 /** 4369 4785 FormData 4370 4786 4371 @class FormData4787 @class moxie/xhr/FormData 4372 4788 @constructor 4373 4789 */ 4374 4790 function FormData() { … … 4555 4971 function XMLHttpRequestUpload() { 4556 4972 this.uid = Basic.guid('uid_'); 4557 4973 } 4558 4974 4559 4975 XMLHttpRequestUpload.prototype = EventTarget.instance; 4560 4976 4561 4977 /** 4562 4978 Implementation of XMLHttpRequest 4563 4979 4564 @class XMLHttpRequest4980 @class moxie/xhr/XMLHttpRequest 4565 4981 @constructor 4566 4982 @uses RuntimeClient 4567 4983 @extends EventTarget … … 4582 4998 'loadend' 4583 4999 4584 5000 // readystatechange (for historical reasons) 4585 ]; 4586 5001 ]; 5002 4587 5003 var NATIVE = 1, RUNTIME = 2; 4588 5004 4589 5005 function XMLHttpRequest() { 4590 5006 var self = this, 4591 5007 // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible … … 4651 5067 /** 4652 5068 Returns the response type. Can be set to change the response type. Values are: 4653 5069 the empty string (default), "arraybuffer", "blob", "document", "json", and "text". 4654 5070 4655 5071 @property responseType 4656 5072 @type String 4657 5073 */ … … 4659 5075 4660 5076 /** 4661 5077 Returns the document response entity body. 4662 5078 4663 5079 Throws an "InvalidStateError" exception if responseType is not the empty string or "document". 4664 5080 4665 5081 @property responseXML … … 4669 5085 4670 5086 /** 4671 5087 Returns the text response entity body. 4672 5088 4673 5089 Throws an "InvalidStateError" exception if responseType is not the empty string or "text". 4674 5090 4675 5091 @property responseText … … 4680 5096 /** 4681 5097 Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body). 4682 5098 Can become: ArrayBuffer, Blob, Document, JSON, Text 4683 5099 4684 5100 @property response 4685 5101 @type Mixed 4686 5102 */ … … 4717 5133 _responseHeadersBag 4718 5134 ; 4719 5135 4720 5136 4721 5137 Basic.extend(this, props, { 4722 5138 /** 4723 5139 Unique id of the component … … 4726 5142 @type String 4727 5143 */ 4728 5144 uid: Basic.guid('uid_'), 4729 5145 4730 5146 /** 4731 5147 Target for Upload events 4732 5148 … … 4734 5150 @type XMLHttpRequestUpload 4735 5151 */ 4736 5152 upload: new XMLHttpRequestUpload(), 4737 4738 5153 5154 4739 5155 /** 4740 5156 Sets the request method, request URL, synchronous flag, request username, and request password. 4741 5157 … … 4762 5178 */ 4763 5179 open: function(method, url, async, user, password) { 4764 5180 var urlp; 4765 5181 4766 5182 // first two arguments are required 4767 5183 if (!method || !url) { 4768 5184 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 4769 5185 } 4770 5186 4771 5187 // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method 4772 5188 if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) { 4773 5189 throw new x.DOMException(x.DOMException.SYNTAX_ERR); … … 4777 5193 if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) { 4778 5194 _method = method.toUpperCase(); 4779 5195 } 4780 4781 5196 5197 4782 5198 // 4 - allowing these methods poses a security risk 4783 5199 if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) { 4784 5200 throw new x.DOMException(x.DOMException.SECURITY_ERR); … … 4786 5202 4787 5203 // 5 4788 5204 url = Encode.utf8_encode(url); 4789 5205 4790 5206 // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError". 4791 5207 urlp = Url.parseUrl(url); 4792 5208 4793 5209 _same_origin_flag = Url.hasSameOrigin(urlp); 4794 5210 4795 5211 // 7 - manually build up absolute url 4796 5212 _url = Url.resolveUrl(url); 4797 5213 4798 5214 // 9-10, 12-13 4799 5215 if ((user || password) && !_same_origin_flag) { 4800 5216 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); … … 4802 5218 4803 5219 _user = user || urlp.user; 4804 5220 _password = password || urlp.pass; 4805 5221 4806 5222 // 11 4807 5223 _async = async || true; 4808 5224 4809 5225 if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) { 4810 5226 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 4811 5227 } 4812 5228 4813 5229 // 14 - terminate abort() 4814 5230 4815 5231 // 15 - terminate send() 4816 5232 4817 5233 // 18 … … 4822 5238 4823 5239 // 19 4824 5240 _p('readyState', XMLHttpRequest.OPENED); 4825 5241 4826 5242 // 20 4827 5243 this.dispatchEvent('readystatechange'); 4828 5244 }, 4829 5245 4830 5246 /** 4831 5247 Appends an header to the list of author request headers, or if header is already 4832 5248 in the list of author request headers, combines its value with value. … … 4834 5250 Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. 4835 5251 Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value 4836 5252 is not a valid HTTP header field value. 4837 5253 4838 5254 @method setRequestHeader 4839 5255 @param {String} header 4840 5256 @param {String|Number} value … … 4863 5279 "user-agent", 4864 5280 "via" 4865 5281 ]; 4866 5282 4867 5283 // 1-2 4868 5284 if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) { 4869 5285 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); … … 4881 5297 }*/ 4882 5298 4883 5299 header = Basic.trim(header).toLowerCase(); 4884 5300 4885 5301 // setting of proxy-* and sec-* headers is prohibited by spec 4886 5302 if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) { 4887 5303 return false; … … 4890 5306 // camelize 4891 5307 // browsers lowercase header names (at least for custom ones) 4892 5308 // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); }); 4893 5309 4894 5310 if (!_headers[header]) { 4895 5311 _headers[header] = value; 4896 5312 } else { … … 4901 5317 }, 4902 5318 4903 5319 /** 5320 * Test if the specified header is already set on this request. 5321 * Returns a header value or boolean false if it's not yet set. 5322 * 5323 * @method hasRequestHeader 5324 * @param {String} header Name of the header to test 5325 * @return {Boolean|String} 5326 */ 5327 hasRequestHeader: function(header) { 5328 return header && _headers[header.toLowerCase()] || false; 5329 }, 5330 5331 /** 4904 5332 Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2. 4905 5333 4906 5334 @method getAllResponseHeaders … … 4911 5339 }, 4912 5340 4913 5341 /** 4914 Returns the header field value from the response of which the field name matches header, 5342 Returns the header field value from the response of which the field name matches header, 4915 5343 unless the field name is Set-Cookie or Set-Cookie2. 4916 5344 4917 5345 @method getResponseHeader … … 4946 5374 } 4947 5375 return null; 4948 5376 }, 4949 5377 4950 5378 /** 4951 5379 Sets the Content-Type header for the response to mime. 4952 5380 Throws an "InvalidStateError" exception if the state is LOADING or DONE. … … 4957 5385 */ 4958 5386 overrideMimeType: function(mime) { 4959 5387 var matches, charset; 4960 5388 4961 5389 // 1 4962 5390 if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { 4963 5391 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); … … 4981 5409 _finalMime = mime; 4982 5410 _finalCharset = charset; 4983 5411 }, 4984 5412 4985 5413 /** 4986 5414 Initiates the request. The optional argument provides the request entity body. 4987 5415 The argument is ignored if request method is GET or HEAD. … … 4992 5420 @param {Blob|Document|String|FormData} [data] Request entity body 4993 5421 @param {Object} [options] Set of requirements and pre-requisities for runtime initialization 4994 5422 */ 4995 send: function(data, options) { 5423 send: function(data, options) { 4996 5424 if (Basic.typeOf(options) === 'string') { 4997 5425 _options = { ruid: options }; 4998 5426 } else if (!options) { … … 5000 5428 } else { 5001 5429 _options = options; 5002 5430 } 5003 5431 5004 5432 // 1-2 5005 5433 if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) { 5006 5434 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5007 5435 } 5008 5009 // 3 5436 5437 // 3 5010 5438 // sending Blob 5011 5439 if (data instanceof Blob) { 5012 5440 _options.ruid = data.ruid; 5013 5441 _mimeType = data.type || 'application/octet-stream'; 5014 5442 } 5015 5443 5016 5444 // FormData 5017 5445 else if (data instanceof FormData) { 5018 5446 if (data.hasBlob()) { … … 5021 5449 _mimeType = blob.type || 'application/octet-stream'; 5022 5450 } 5023 5451 } 5024 5452 5025 5453 // DOMString 5026 5454 else if (typeof data === 'string') { 5027 5455 _encoding = 'UTF-8'; 5028 5456 _mimeType = 'text/plain;charset=UTF-8'; 5029 5457 5030 5458 // data should be converted to Unicode and encoded as UTF-8 5031 5459 data = Encode.utf8_encode(data); 5032 5460 } … … 5057 5485 // 8.5 - Return the send() method call, but continue running the steps in this algorithm. 5058 5486 _doXHR.call(this, data); 5059 5487 }, 5060 5488 5061 5489 /** 5062 5490 Cancels any network activity. 5063 5491 5064 5492 @method abort 5065 5493 */ 5066 5494 abort: function() { … … 5267 5695 } 5268 5696 } 5269 5697 } 5270 5698 5271 5699 /* 5272 5700 function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) { 5273 5701 // TODO: http://tools.ietf.org/html/rfc3490#section-4.1 … … 5274 5702 return str.toLowerCase(); 5275 5703 } 5276 5704 */ 5277 5278 5705 5706 5279 5707 function _doXHR(data) { 5280 5708 var self = this; 5281 5709 5282 5710 _start_time = new Date().getTime(); 5283 5711 5284 5712 _xhr = new RuntimeTarget(); … … 5298 5726 self.dispatchEvent('readystatechange'); 5299 5727 5300 5728 self.dispatchEvent(e); 5301 5729 5302 5730 if (_upload_events_flag) { 5303 5731 self.upload.dispatchEvent(e); 5304 5732 } 5305 5733 }); 5306 5734 5307 5735 _xhr.bind('Progress', function(e) { 5308 5736 if (_p('readyState') !== XMLHttpRequest.LOADING) { 5309 5737 _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example) … … 5311 5739 } 5312 5740 self.dispatchEvent(e); 5313 5741 }); 5314 5742 5315 5743 _xhr.bind('UploadProgress', function(e) { 5316 5744 if (_upload_events_flag) { 5317 5745 self.upload.dispatchEvent({ … … 5322 5750 }); 5323 5751 } 5324 5752 }); 5325 5753 5326 5754 _xhr.bind('Load', function(e) { 5327 5755 _p('readyState', XMLHttpRequest.DONE); 5328 5756 _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0)); 5329 5757 _p('statusText', httpCode[_p('status')] || ""); 5330 5758 5331 5759 _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType'))); 5332 5760 5333 5761 if (!!~Basic.inArray(_p('responseType'), ['text', ''])) { … … 5339 5767 _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders'); 5340 5768 5341 5769 self.dispatchEvent('readystatechange'); 5342 5770 5343 5771 if (_p('status') > 0) { // status 0 usually means that server is unreachable 5344 5772 if (_upload_events_flag) { 5345 5773 self.upload.dispatchEvent(e); … … 5356 5784 self.dispatchEvent(e); 5357 5785 loadEnd(); 5358 5786 }); 5359 5787 5360 5788 _xhr.bind('Error', function(e) { 5361 5789 _error_flag = true; 5362 5790 _p('readyState', XMLHttpRequest.DONE); … … 5401 5829 if (!_same_origin_flag) { 5402 5830 _options.required_caps.do_cors = true; 5403 5831 } 5404 5405 5832 5833 5406 5834 if (_options.ruid) { // we do not need to wait if we can connect directly 5407 5835 exec(_xhr.connectRuntime(_options)); 5408 5836 } else { … … 5415 5843 _xhr.connectRuntime(_options); 5416 5844 } 5417 5845 } 5418 5419 5846 5847 5420 5848 function _reset() { 5421 5849 _p('responseText', ""); 5422 5850 _p('responseXML', null); … … 5432 5860 XMLHttpRequest.HEADERS_RECEIVED = 2; 5433 5861 XMLHttpRequest.LOADING = 3; 5434 5862 XMLHttpRequest.DONE = 4; 5435 5863 5436 5864 XMLHttpRequest.prototype = EventTarget.instance; 5437 5865 5438 5866 return XMLHttpRequest; … … 5456 5884 "moxie/runtime/RuntimeClient", 5457 5885 "moxie/core/EventTarget" 5458 5886 ], function(Basic, Encode, RuntimeClient, EventTarget) { 5887 5888 /** 5889 @class moxie/runtime/Transporter 5890 @private 5891 @constructor 5892 */ 5459 5893 function Transporter() { 5460 5894 var mod, _runtime, _data, _size, _pos, _chunk_size; 5461 5895 … … 5605 6039 /** 5606 6040 Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data. 5607 6041 5608 @class Image6042 @class moxie/image/Image 5609 6043 @constructor 5610 6044 @extends EventTarget 5611 6045 */ … … 5624 6058 5625 6059 /** 5626 6060 Dispatched when resize operation is complete. 5627 6061 5628 6062 @event resize 5629 6063 @param {Object} event 5630 6064 */ … … 5716 6150 meta: {}, 5717 6151 5718 6152 /** 5719 Alias for load method, that takes another m Oxie.Image object as a source (see load).6153 Alias for load method, that takes another moxie.image.Image object as a source (see load). 5720 6154 5721 6155 @method clone 5722 6156 @param {Image} src Source for the image … … 5727 6161 }, 5728 6162 5729 6163 /** 5730 Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File, 5731 native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL, 5732 Image will be downloaded from remote destination and loaded in memory. 6164 Loads image from various sources. Currently the source for new image can be: moxie.image.Image, 6165 moxie.file.Blob/moxie.file.File, native Blob/File, dataUrl or URL. Depending on the type of the 6166 source, arguments - differ. When source is URL, Image will be downloaded from remote destination 6167 and loaded in memory. 5733 6168 5734 6169 @example 5735 var img = new m Oxie.Image();6170 var img = new moxie.image.Image(); 5736 6171 img.onload = function() { 5737 6172 var blob = img.getAsBlob(); 5738 5739 var formData = new m Oxie.FormData();6173 6174 var formData = new moxie.xhr.FormData(); 5740 6175 formData.append('file', blob); 5741 6176 5742 var xhr = new m Oxie.XMLHttpRequest();6177 var xhr = new moxie.xhr.XMLHttpRequest(); 5743 6178 xhr.onload = function() { 5744 6179 // upload complete 5745 6180 }; … … 5747 6182 xhr.send(formData); 5748 6183 }; 5749 6184 img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg) 5750 5751 6185 6186 5752 6187 @method load 5753 6188 @param {Image|Blob|File|String} src Source for the image 5754 6189 @param {Boolean|Object} [mixed] … … 5757 6192 _load.apply(this, arguments); 5758 6193 }, 5759 6194 6195 5760 6196 /** 6197 Resizes the image to fit the specified width/height. If crop is specified, image will also be 6198 cropped to the exact dimensions. 6199 6200 @method resize 6201 @since 3.0 6202 @param {Object} options 6203 @param {Number} options.width Resulting width 6204 @param {Number} [options.height=width] Resulting height (optional, if not supplied will default to width) 6205 @param {String} [options.type='image/jpeg'] MIME type of the resulting image 6206 @param {Number} [options.quality=90] In the case of JPEG, controls the quality of resulting image 6207 @param {Boolean} [options.crop='cc'] If not falsy, image will be cropped, by default from center 6208 @param {Boolean} [options.fit=true] Whether to upscale the image to fit the exact dimensions 6209 @param {Boolean} [options.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) 6210 @param {String} [options.resample='default'] Resampling algorithm to use during resize 6211 @param {Boolean} [options.multipass=true] Whether to scale the image in steps (results in better quality) 6212 */ 6213 resize: function(options) { 6214 var self = this; 6215 var orientation; 6216 var scale; 6217 6218 var srcRect = { 6219 x: 0, 6220 y: 0, 6221 width: self.width, 6222 height: self.height 6223 }; 6224 6225 var opts = Basic.extendIf({ 6226 width: self.width, 6227 height: self.height, 6228 type: self.type || 'image/jpeg', 6229 quality: 90, 6230 crop: false, 6231 fit: true, 6232 preserveHeaders: true, 6233 resample: 'default', 6234 multipass: true 6235 }, options); 6236 6237 try { 6238 if (!self.size) { // only preloaded image objects can be used as source 6239 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 6240 } 6241 6242 // no way to reliably intercept the crash due to high resolution, so we simply avoid it 6243 if (self.width > Image.MAX_RESIZE_WIDTH || self.height > Image.MAX_RESIZE_HEIGHT) { 6244 throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); 6245 } 6246 6247 // take into account orientation tag 6248 orientation = (self.meta && self.meta.tiff && self.meta.tiff.Orientation) || 1; 6249 6250 if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation 6251 var tmp = opts.width; 6252 opts.width = opts.height; 6253 opts.height = tmp; 6254 } 6255 6256 if (opts.crop) { 6257 scale = Math.max(opts.width/self.width, opts.height/self.height); 6258 6259 if (options.fit) { 6260 // first scale it up or down to fit the original image 6261 srcRect.width = Math.min(Math.ceil(opts.width/scale), self.width); 6262 srcRect.height = Math.min(Math.ceil(opts.height/scale), self.height); 6263 6264 // recalculate the scale for adapted dimensions 6265 scale = opts.width/srcRect.width; 6266 } else { 6267 srcRect.width = Math.min(opts.width, self.width); 6268 srcRect.height = Math.min(opts.height, self.height); 6269 6270 // now we do not need to scale it any further 6271 scale = 1; 6272 } 6273 6274 if (typeof(opts.crop) === 'boolean') { 6275 opts.crop = 'cc'; 6276 } 6277 6278 switch (opts.crop.toLowerCase().replace(/_/, '-')) { 6279 case 'rb': 6280 case 'right-bottom': 6281 srcRect.x = self.width - srcRect.width; 6282 srcRect.y = self.height - srcRect.height; 6283 break; 6284 6285 case 'cb': 6286 case 'center-bottom': 6287 srcRect.x = Math.floor((self.width - srcRect.width) / 2); 6288 srcRect.y = self.height - srcRect.height; 6289 break; 6290 6291 case 'lb': 6292 case 'left-bottom': 6293 srcRect.x = 0; 6294 srcRect.y = self.height - srcRect.height; 6295 break; 6296 6297 case 'lt': 6298 case 'left-top': 6299 srcRect.x = 0; 6300 srcRect.y = 0; 6301 break; 6302 6303 case 'ct': 6304 case 'center-top': 6305 srcRect.x = Math.floor((self.width - srcRect.width) / 2); 6306 srcRect.y = 0; 6307 break; 6308 6309 case 'rt': 6310 case 'right-top': 6311 srcRect.x = self.width - srcRect.width; 6312 srcRect.y = 0; 6313 break; 6314 6315 case 'rc': 6316 case 'right-center': 6317 case 'right-middle': 6318 srcRect.x = self.width - srcRect.width; 6319 srcRect.y = Math.floor((self.height - srcRect.height) / 2); 6320 break; 6321 6322 6323 case 'lc': 6324 case 'left-center': 6325 case 'left-middle': 6326 srcRect.x = 0; 6327 srcRect.y = Math.floor((self.height - srcRect.height) / 2); 6328 break; 6329 6330 case 'cc': 6331 case 'center-center': 6332 case 'center-middle': 6333 default: 6334 srcRect.x = Math.floor((self.width - srcRect.width) / 2); 6335 srcRect.y = Math.floor((self.height - srcRect.height) / 2); 6336 } 6337 6338 // original image might be smaller than requested crop, so - avoid negative values 6339 srcRect.x = Math.max(srcRect.x, 0); 6340 srcRect.y = Math.max(srcRect.y, 0); 6341 } else { 6342 scale = Math.min(opts.width/self.width, opts.height/self.height); 6343 6344 // do not upscale if we were asked to not fit it 6345 if (scale > 1 && !opts.fit) { 6346 scale = 1; 6347 } 6348 } 6349 6350 this.exec('Image', 'resize', srcRect, scale, opts); 6351 } catch(ex) { 6352 // for now simply trigger error event 6353 self.trigger('error', ex.code); 6354 } 6355 }, 6356 6357 /** 5761 6358 Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions. 5762 6359 5763 6360 @method downsize 5764 @param {Object} opts 5765 @param {Number} opts.width Resulting width 5766 @param {Number} [opts.height=width] Resulting height (optional, if not supplied will default to width) 5767 @param {Boolean} [opts.crop=false] Whether to crop the image to exact dimensions 5768 @param {Boolean} [opts.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) 5769 @param {String} [opts.resample=false] Resampling algorithm to use for resizing 6361 @deprecated use resize() 5770 6362 */ 5771 downsize: function(opt s) {6363 downsize: function(options) { 5772 6364 var defaults = { 5773 6365 width: this.width, 5774 6366 height: this.height, … … 5775 6367 type: this.type || 'image/jpeg', 5776 6368 quality: 90, 5777 6369 crop: false, 6370 fit: false, 5778 6371 preserveHeaders: true, 5779 resample: false5780 } ;6372 resample: 'default' 6373 }, opts; 5781 6374 5782 if (typeof(opt s) === 'object') {5783 opts = Basic.extend(defaults, opt s);6375 if (typeof(options) === 'object') { 6376 opts = Basic.extend(defaults, options); 5784 6377 } else { 5785 6378 // for backward compatibility 5786 6379 opts = Basic.extend(defaults, { … … 5791 6384 }); 5792 6385 } 5793 6386 5794 try { 5795 if (!this.size) { // only preloaded image objects can be used as source 5796 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5797 } 5798 5799 // no way to reliably intercept the crash due to high resolution, so we simply avoid it 5800 if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { 5801 throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); 5802 } 5803 5804 this.exec('Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders); 5805 } catch(ex) { 5806 // for now simply trigger error event 5807 this.trigger('error', ex.code); 5808 } 6387 this.resize(opts); 5809 6388 }, 5810 6389 5811 6390 /** 5812 6391 Alias for downsize(width, height, true). (see downsize) 5813 6392 5814 6393 @method crop 5815 6394 @param {Number} width Resulting width 5816 6395 @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) … … 5824 6403 if (!Env.can('create_canvas')) { 5825 6404 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); 5826 6405 } 5827 5828 var runtime = this.connectRuntime(this.ruid); 5829 return runtime.exec.call(this, 'Image', 'getAsCanvas'); 6406 return this.exec('Image', 'getAsCanvas'); 5830 6407 }, 5831 6408 5832 6409 /** 5833 Retrieves image in it's current state as m Oxie.Blob object. Cannot be run on empty or image in progress (throws6410 Retrieves image in it's current state as moxie.file.Blob object. Cannot be run on empty or image in progress (throws 5834 6411 DOMException.INVALID_STATE_ERR). 5835 6412 5836 6413 @method getAsBlob … … 5876 6453 }, 5877 6454 5878 6455 /** 5879 Embeds a visual representation of the image into the specified node. Depending on the runtime, 5880 it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare, 6456 Embeds a visual representation of the image into the specified node. Depending on the runtime, 6457 it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare, 5881 6458 can be used in legacy browsers that do not have canvas or proper dataURI support). 5882 6459 5883 6460 @method embed 5884 6461 @param {DOMElement} el DOM element to insert the image object into 5885 @param {Object} [opts] 5886 @param {Number} [opts.width] The width of an embed (defaults to the image width) 5887 @param {Number} [opts.height] The height of an embed (defaults to the image height) 5888 @param {String} [type="image/jpeg"] Mime type 5889 @param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg 5890 @param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions 6462 @param {Object} [options] 6463 @param {Number} [options.width] The width of an embed (defaults to the image width) 6464 @param {Number} [options.height] The height of an embed (defaults to the image height) 6465 @param {String} [options.type="image/jpeg"] Mime type 6466 @param {Number} [options.quality=90] Quality of an embed, if mime type is image/jpeg 6467 @param {Boolean} [options.crop=false] Whether to crop an embed to the specified dimensions 6468 @param {Boolean} [options.fit=true] By default thumbs will be up- or downscaled as necessary to fit the dimensions 5891 6469 */ 5892 embed: function(el, opt s) {6470 embed: function(el, options) { 5893 6471 var self = this 5894 6472 , runtime // this has to be outside of all the closures to contain proper runtime 5895 6473 ; 5896 6474 5897 opts = Basic.extend({6475 var opts = Basic.extend({ 5898 6476 width: this.width, 5899 6477 height: this.height, 5900 6478 type: this.type || 'image/jpeg', 5901 quality: 90 5902 }, opts || {}); 5903 6479 quality: 90, 6480 fit: true, 6481 resample: 'nearest' 6482 }, options); 5904 6483 6484 5905 6485 function render(type, quality) { 5906 6486 var img = this; 5907 6487 … … 5923 6503 } 5924 6504 5925 6505 if (Env.can('use_data_uri_of', dataUrl.length)) { 5926 el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" />';6506 el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" alt="" />'; 5927 6507 img.destroy(); 5928 6508 self.trigger('embedded'); 5929 6509 } else { … … 5976 6556 if (!this.size) { // only preloaded image objects can be used as source 5977 6557 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5978 6558 } 5979 6559 5980 6560 // high-resolution images cannot be consistently handled across the runtimes 5981 6561 if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { 5982 6562 //throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); … … 5989 6569 }); 5990 6570 5991 6571 imgCopy.bind("Load", function() { 5992 imgCopy.downsize(opts);6572 this.downsize(opts); 5993 6573 }); 5994 6574 5995 6575 // if embedded thumb data is available and dimensions are big enough, use it … … 6007 6587 }, 6008 6588 6009 6589 /** 6010 Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object. 6590 Properly destroys the image and frees resources in use. If any. Recommended way to dispose 6591 moxie.image.Image object. 6011 6592 6012 6593 @method destroy 6013 6594 */ … … 6016 6597 this.getRuntime().exec.call(this, 'Image', 'destroy'); 6017 6598 this.disconnectRuntime(); 6018 6599 } 6600 if (this.meta && this.meta.thumb) { 6601 // thumb is blob, make sure we destroy it first 6602 this.meta.thumb.data.destroy(); 6603 } 6019 6604 this.unbindAll(); 6020 6605 } 6021 6606 }); … … 6025 6610 this.handleEventProps(dispatches); 6026 6611 6027 6612 this.bind('Load Resize', function() { 6028 _updateInfo.call(this);6613 return _updateInfo.call(this); // if operation fails (e.g. image is neither PNG nor JPEG) cancel all pending events 6029 6614 }, 999); 6030 6615 6031 6616 6032 6617 function _updateInfo(info) { 6033 if (!info) { 6034 info = this.exec('Image', 'getInfo'); 6035 } 6618 try { 6619 if (!info) { 6620 info = this.exec('Image', 'getInfo'); 6621 } 6036 6622 6037 this.size = info.size;6038 this.width = info.width;6039 this.height = info.height;6040 this.type = info.type;6041 this.meta = info.meta;6623 this.size = info.size; 6624 this.width = info.width; 6625 this.height = info.height; 6626 this.type = info.type; 6627 this.meta = info.meta; 6042 6628 6043 // update file name, only if empty 6044 if (this.name === '') { 6045 this.name = info.name; 6629 // update file name, only if empty 6630 if (this.name === '') { 6631 this.name = info.name; 6632 } 6633 6634 return true; 6635 } catch(ex) { 6636 this.trigger('error', ex.code); 6637 return false; 6046 6638 } 6047 6639 } 6048 6049 6640 6641 6050 6642 function _load(src) { 6051 6643 var srcType = Basic.typeOf(src); 6052 6644 … … 6167 6759 6168 6760 // virtual world will crash on you if image has a resolution higher than this: 6169 6761 Image.MAX_RESIZE_WIDTH = 8192; 6170 Image.MAX_RESIZE_HEIGHT = 8192; 6762 Image.MAX_RESIZE_HEIGHT = 8192; 6171 6763 6172 6764 Image.prototype = EventTarget.instance; 6173 6765 … … 6214 6806 access_image_binary: function() { 6215 6807 return I.can('access_binary') && !!extensions.Image; 6216 6808 }, 6217 display_media: Test(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')), 6809 display_media: Test( 6810 (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && 6811 defined('moxie/image/Image') 6812 ), 6218 6813 do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()), 6219 6814 drag_and_drop: Test(function() { 6220 6815 // this comes directly from Modernizr: http://www.modernizr.com/ … … 6224 6819 (Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>')); 6225 6820 }()), 6226 6821 filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest 6227 return (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '>=')) || 6228 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || 6229 (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '>=')); 6822 return !( 6823 (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || 6824 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || 6825 (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) || 6826 (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<')) 6827 ); 6230 6828 }()), 6231 6829 return_response_headers: True, 6232 6830 return_response_type: function(responseType) { … … 6244 6842 return Env.can('use_fileinput') && window.File; 6245 6843 }, 6246 6844 select_folder: function() { 6247 return I.can('select_file') && Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>='); 6845 return I.can('select_file') && ( 6846 Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=') || 6847 Env.browser === 'Firefox' && Env.verComp(Env.version, 42, '>=') // https://developer.mozilla.org/en-US/Firefox/Releases/42 6848 ); 6248 6849 }, 6249 6850 select_multiple: function() { 6250 6851 // it is buggy on Safari Windows and iOS … … 6262 6863 return I.can('slice_blob') && I.can('send_multipart'); 6263 6864 }, 6264 6865 summon_file_dialog: function() { // yeah... some dirty sniffing here... 6265 return I.can('select_file') && ( 6266 (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '>=')) || 6267 (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '>=')) || 6268 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || 6269 !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']) 6866 return I.can('select_file') && !( 6867 (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) || 6868 (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) || 6869 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) 6270 6870 ); 6271 6871 }, 6272 upload_filesize: True 6872 upload_filesize: True, 6873 use_http_method: True 6273 6874 }, 6274 6875 arguments[2] 6275 6876 ); … … 6299 6900 return extensions; 6300 6901 }); 6301 6902 6903 // Included from: src/javascript/runtime/html5/file/Blob.js 6904 6905 /** 6906 * Blob.js 6907 * 6908 * Copyright 2013, Moxiecode Systems AB 6909 * Released under GPL License. 6910 * 6911 * License: http://www.plupload.com/license 6912 * Contributing: http://www.plupload.com/contributing 6913 */ 6914 6915 /** 6916 @class moxie/runtime/html5/file/Blob 6917 @private 6918 */ 6919 define("moxie/runtime/html5/file/Blob", [ 6920 "moxie/runtime/html5/Runtime", 6921 "moxie/file/Blob" 6922 ], function(extensions, Blob) { 6923 6924 function HTML5Blob() { 6925 function w3cBlobSlice(blob, start, end) { 6926 var blobSlice; 6927 6928 if (window.File.prototype.slice) { 6929 try { 6930 blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception 6931 return blob.slice(start, end); 6932 } catch (e) { 6933 // depricated slice method 6934 return blob.slice(start, end - start); 6935 } 6936 // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672 6937 } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) { 6938 return blobSlice.call(blob, start, end); 6939 } else { 6940 return null; // or throw some exception 6941 } 6942 } 6943 6944 this.slice = function() { 6945 return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments)); 6946 }; 6947 6948 this.destroy = function() { 6949 this.getRuntime().getShim().removeInstance(this.uid); 6950 }; 6951 } 6952 6953 return (extensions.Blob = HTML5Blob); 6954 }); 6955 6302 6956 // Included from: src/javascript/core/utils/Events.js 6303 6957 6304 6958 /** … … 6311 6965 * Contributing: http://www.plupload.com/contributing 6312 6966 */ 6313 6967 6968 /** 6969 @class moxie/core/utils/Events 6970 @public 6971 @static 6972 */ 6973 6314 6974 define('moxie/core/utils/Events', [ 6315 6975 'moxie/core/utils/Basic' 6316 6976 ], function(Basic) { … … 6330 6990 in objects internal Plupload registry (@see removeEvent). 6331 6991 6332 6992 @method addEvent 6333 @for Utils6334 6993 @static 6335 6994 @param {Object} obj DOM element like object to add handler to. 6336 6995 @param {String} name Name to add event listener to. … … 6499 7158 ], function(extensions, File, Basic, Dom, Events, Mime, Env) { 6500 7159 6501 7160 function FileInput() { 6502 var _options ;7161 var _options, _browseBtnZIndex; // save original z-index 6503 7162 6504 7163 Basic.extend(this, { 6505 7164 init: function(options) { … … 6508 7167 _options = options; 6509 7168 6510 7169 // figure out accept string 6511 mimes = _options.accept.mimes ||Mime.extList2mimes(_options.accept, I.can('filter_by_extension'));7170 mimes = Mime.extList2mimes(_options.accept, I.can('filter_by_extension')); 6512 7171 6513 7172 shimContainer = I.getShimContainer(); 6514 7173 … … 6530 7189 6531 7190 6532 7191 browseButton = Dom.get(_options.browse_button); 7192 _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto'; 6533 7193 6534 7194 // Route click event to the input[type=file] element for browsers that support such behavior 6535 7195 if (I.can('summon_file_dialog')) { … … 6537 7197 browseButton.style.position = 'relative'; 6538 7198 } 6539 7199 6540 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;6541 6542 browseButton.style.zIndex = zIndex;6543 shimContainer.style.zIndex = zIndex - 1;6544 6545 7200 Events.addEvent(browseButton, 'click', function(e) { 6546 7201 var input = Dom.get(I.uid); 6547 7202 if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] … … 6549 7204 } 6550 7205 e.preventDefault(); 6551 7206 }, comp.uid); 7207 7208 comp.bind('Refresh', function() { 7209 zIndex = parseInt(_browseBtnZIndex, 10) || 1; 7210 7211 Dom.get(_options.browse_button).style.zIndex = zIndex; 7212 this.getRuntime().getShimContainer().style.zIndex = zIndex - 1; 7213 }); 6552 7214 } 6553 7215 6554 7216 /* Since we have to place input[type=file] on top of the browse_button for some browsers, … … 6571 7233 comp.trigger('mouseup'); 6572 7234 }, comp.uid); 6573 7235 7236 // it shouldn't be possible to tab into the hidden element 7237 (I.can('summon_file_dialog') ? input : browseButton).setAttribute('tabindex', -1); 6574 7238 6575 input.onchange = function onChange( e) { // there should be only one handler for this7239 input.onchange = function onChange() { // there should be only one handler for this 6576 7240 comp.files = []; 6577 7241 6578 7242 Basic.each(this.files, function(file) { … … 6621 7285 }, 6622 7286 6623 7287 7288 setOption: function(name, value) { 7289 var I = this.getRuntime(); 7290 var input = Dom.get(I.uid); 7291 7292 switch (name) { 7293 case 'accept': 7294 if (value) { 7295 var mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension')); 7296 input.setAttribute('accept', mimes.join(',')); 7297 } else { 7298 input.removeAttribute('accept'); 7299 } 7300 break; 7301 7302 case 'directory': 7303 if (value && I.can('select_folder')) { 7304 input.setAttribute('directory', ''); 7305 input.setAttribute('webkitdirectory', ''); 7306 } else { 7307 input.removeAttribute('directory'); 7308 input.removeAttribute('webkitdirectory'); 7309 } 7310 break; 7311 7312 case 'multiple': 7313 if (value && I.can('select_multiple')) { 7314 input.setAttribute('multiple', ''); 7315 } else { 7316 input.removeAttribute('multiple'); 7317 } 7318 7319 } 7320 }, 7321 7322 6624 7323 disable: function(state) { 6625 7324 var I = this.getRuntime(), input; 6626 7325 … … 6633 7332 var I = this.getRuntime() 6634 7333 , shim = I.getShim() 6635 7334 , shimContainer = I.getShimContainer() 7335 , container = _options && Dom.get(_options.container) 7336 , browseButton = _options && Dom.get(_options.browse_button) 6636 7337 ; 6637 7338 6638 Events.removeAllEvents(shimContainer, this.uid);6639 Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);6640 Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);7339 if (container) { 7340 Events.removeAllEvents(container, this.uid); 7341 } 6641 7342 7343 if (browseButton) { 7344 Events.removeAllEvents(browseButton, this.uid); 7345 browseButton.style.zIndex = _browseBtnZIndex; // reset to original value 7346 } 7347 6642 7348 if (shimContainer) { 7349 Events.removeAllEvents(shimContainer, this.uid); 6643 7350 shimContainer.innerHTML = ''; 6644 7351 } 6645 7352 6646 7353 shim.removeInstance(this.uid); 6647 7354 6648 _options = shimContainer = shim = null;7355 _options = shimContainer = container = browseButton = shim = null; 6649 7356 } 6650 7357 }); 6651 7358 } … … 6653 7360 return (extensions.FileInput = FileInput); 6654 7361 }); 6655 7362 6656 // Included from: src/javascript/runtime/html5/file/Blob.js6657 6658 /**6659 * Blob.js6660 *6661 * Copyright 2013, Moxiecode Systems AB6662 * Released under GPL License.6663 *6664 * License: http://www.plupload.com/license6665 * Contributing: http://www.plupload.com/contributing6666 */6667 6668 /**6669 @class moxie/runtime/html5/file/Blob6670 @private6671 */6672 define("moxie/runtime/html5/file/Blob", [6673 "moxie/runtime/html5/Runtime",6674 "moxie/file/Blob"6675 ], function(extensions, Blob) {6676 6677 function HTML5Blob() {6678 function w3cBlobSlice(blob, start, end) {6679 var blobSlice;6680 6681 if (window.File.prototype.slice) {6682 try {6683 blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception6684 return blob.slice(start, end);6685 } catch (e) {6686 // depricated slice method6687 return blob.slice(start, end - start);6688 }6689 // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=6496726690 } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) {6691 return blobSlice.call(blob, start, end);6692 } else {6693 return null; // or throw some exception6694 }6695 }6696 6697 this.slice = function() {6698 return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments));6699 };6700 }6701 6702 return (extensions.Blob = HTML5Blob);6703 });6704 6705 7363 // Included from: src/javascript/runtime/html5/file/FileDrop.js 6706 7364 6707 7365 /** … … 6782 7440 destroy: function() { 6783 7441 Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); 6784 7442 _ruid = _files = _allowedExts = _options = null; 7443 this.getRuntime().getShim().removeInstance(this.uid); 6785 7444 } 6786 7445 }); 6787 7446 … … 6974 7633 6975 7634 destroy: function() { 6976 7635 _fr = null; 7636 this.getRuntime().getShim().removeInstance(this.uid); 6977 7637 } 6978 7638 }); 6979 7639 … … 7141 7801 _xhr.onreadystatechange = function() {}; 7142 7802 7143 7803 // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout 7144 if (_xhr.status === 0) { 7145 target.trigger('error'); 7146 } else { 7147 target.trigger('load'); 7148 } 7804 try { 7805 if (_xhr.status >= 200 && _xhr.status < 400) { 7806 target.trigger('load'); 7807 break; 7808 } 7809 } catch(ex) {} 7810 7811 target.trigger('error'); 7149 7812 break; 7150 7813 } 7151 7814 }; … … 7256 7919 7257 7920 destroy: function() { 7258 7921 self = _filename = null; 7922 this.getRuntime().getShim().removeInstance(this.uid); 7259 7923 } 7260 7924 }); 7261 7925 … … 7388 8052 UTF16StringReader.apply(this, arguments); 7389 8053 } 7390 8054 } 7391 7392 8055 7393 8056 Basic.extend(BinaryReader.prototype, { 7394 8057 … … 8488 9151 */ 8489 9152 8490 9153 /** 9154 Optional image investigation tool for HTML5 runtime. Provides the following features: 9155 - ability to distinguish image type (JPEG or PNG) by signature 9156 - ability to extract image width/height directly from it's internals, without preloading in memory (fast) 9157 - ability to extract APP headers from JPEGs (Exif, GPS, etc) 9158 - ability to replace width/height tags in extracted JPEG headers 9159 - ability to restore APP headers, that were for example stripped during image manipulation 9160 8491 9161 @class moxie/runtime/html5/image/ImageInfo 8492 9162 @private 9163 @param {String} data Image source as binary string 8493 9164 */ 8494 9165 define("moxie/runtime/html5/image/ImageInfo", [ 8495 9166 "moxie/core/utils/Basic", … … 8497 9168 "moxie/runtime/html5/image/JPEG", 8498 9169 "moxie/runtime/html5/image/PNG" 8499 9170 ], function(Basic, x, JPEG, PNG) { 8500 /**8501 Optional image investigation tool for HTML5 runtime. Provides the following features:8502 - ability to distinguish image type (JPEG or PNG) by signature8503 - ability to extract image width/height directly from it's internals, without preloading in memory (fast)8504 - ability to extract APP headers from JPEGs (Exif, GPS, etc)8505 - ability to replace width/height tags in extracted JPEG headers8506 - ability to restore APP headers, that were for example stripped during image manipulation8507 9171 8508 @class ImageInfo8509 @constructor8510 @param {String} data Image source as binary string8511 */8512 9172 return function(data) { 8513 9173 var _cs = [JPEG, PNG], _img; 8514 9174 … … 8611 9271 }; 8612 9272 }); 8613 9273 8614 // Included from: src/javascript/runtime/html5/image/ MegaPixel.js9274 // Included from: src/javascript/runtime/html5/image/ResizerCanvas.js 8615 9275 8616 9276 /** 8617 (The MIT License) 9277 * ResizerCanvas.js 9278 * 9279 * Copyright 2013, Moxiecode Systems AB 9280 * Released under GPL License. 9281 * 9282 * License: http://www.plupload.com/license 9283 * Contributing: http://www.plupload.com/contributing 9284 */ 8618 9285 8619 Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>; 9286 /** 9287 * Resizes image/canvas using canvas 9288 */ 9289 define("moxie/runtime/html5/image/ResizerCanvas", [], function() { 8620 9290 8621 Permission is hereby granted, free of charge, to any person obtaining 8622 a copy of this software and associated documentation files (the 8623 'Software'), to deal in the Software without restriction, including 8624 without limitation the rights to use, copy, modify, merge, publish, 8625 distribute, sublicense, and/or sell copies of the Software, and to 8626 permit persons to whom the Software is furnished to do so, subject to 8627 the following conditions: 9291 function scale(image, ratio, resample) { 9292 var sD = image.width > image.height ? 'width' : 'height'; // take the largest side 9293 var dD = Math.round(image[sD] * ratio); 9294 var scaleCapped = false; 8628 9295 8629 The above copyright notice and this permission notice shall be 8630 included in all copies or substantial portions of the Software. 9296 if (resample !== 'nearest' && (ratio < 0.5 || ratio > 2)) { 9297 ratio = ratio < 0.5 ? 0.5 : 2; 9298 scaleCapped = true; 9299 } 8631 9300 8632 THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 8633 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 8634 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 8635 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 8636 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 8637 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 8638 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8639 */ 9301 var tCanvas = _scale(image, ratio); 8640 9302 8641 /** 8642 * Mega pixel image rendering library for iOS6 Safari 8643 * 8644 * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel), 8645 * which causes unexpected subsampling when drawing it in canvas. 8646 * By using this library, you can safely render the image with proper stretching. 8647 * 8648 * Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com> 8649 * Released under the MIT license 8650 */ 9303 if (scaleCapped) { 9304 return scale(tCanvas, dD / tCanvas[sD], resample); 9305 } else { 9306 return tCanvas; 9307 } 9308 } 8651 9309 8652 /**8653 @class moxie/runtime/html5/image/MegaPixel8654 @private8655 */8656 define("moxie/runtime/html5/image/MegaPixel", [], function() {8657 9310 8658 /** 8659 * Rendering image element (with resizing) into the canvas element 8660 */ 8661 function renderImageToCanvas(img, canvas, options) { 8662 var iw = img.naturalWidth, ih = img.naturalHeight; 8663 var width = options.width, height = options.height; 8664 var x = options.x || 0, y = options.y || 0; 8665 var ctx = canvas.getContext('2d'); 8666 if (detectSubsampling(img)) { 8667 iw /= 2; 8668 ih /= 2; 8669 } 8670 var d = 1024; // size of tiling canvas 8671 var tmpCanvas = document.createElement('canvas'); 8672 tmpCanvas.width = tmpCanvas.height = d; 8673 var tmpCtx = tmpCanvas.getContext('2d'); 8674 var vertSquashRatio = detectVerticalSquash(img, iw, ih); 8675 var sy = 0; 8676 while (sy < ih) { 8677 var sh = sy + d > ih ? ih - sy : d; 8678 var sx = 0; 8679 while (sx < iw) { 8680 var sw = sx + d > iw ? iw - sx : d; 8681 tmpCtx.clearRect(0, 0, d, d); 8682 tmpCtx.drawImage(img, -sx, -sy); 8683 var dx = (sx * width / iw + x) << 0; 8684 var dw = Math.ceil(sw * width / iw); 8685 var dy = (sy * height / ih / vertSquashRatio + y) << 0; 8686 var dh = Math.ceil(sh * height / ih / vertSquashRatio); 8687 ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh); 8688 sx += d; 8689 } 8690 sy += d; 8691 } 8692 tmpCanvas = tmpCtx = null; 8693 } 9311 function _scale(image, ratio) { 9312 var sW = image.width; 9313 var sH = image.height; 9314 var dW = Math.round(sW * ratio); 9315 var dH = Math.round(sH * ratio); 8694 9316 8695 /** 8696 * Detect subsampling in loaded image. 8697 * In iOS, larger images than 2M pixels may be subsampled in rendering. 8698 */ 8699 function detectSubsampling(img) { 8700 var iw = img.naturalWidth, ih = img.naturalHeight; 8701 if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image 8702 var canvas = document.createElement('canvas'); 8703 canvas.width = canvas.height = 1; 8704 var ctx = canvas.getContext('2d'); 8705 ctx.drawImage(img, -iw + 1, 0); 8706 // subsampled image becomes half smaller in rendering size. 8707 // check alpha channel value to confirm image is covering edge pixel or not. 8708 // if alpha value is 0 image is not covering, hence subsampled. 8709 return ctx.getImageData(0, 0, 1, 1).data[3] === 0; 8710 } else { 8711 return false; 8712 } 8713 } 9317 var canvas = document.createElement('canvas'); 9318 canvas.width = dW; 9319 canvas.height = dH; 9320 canvas.getContext("2d").drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH); 8714 9321 9322 image = null; // just in case 9323 return canvas; 9324 } 8715 9325 8716 /** 8717 * Detecting vertical squash in loaded image. 8718 * Fixes a bug which squash image vertically while drawing into canvas for some images. 8719 */ 8720 function detectVerticalSquash(img, iw, ih) { 8721 var canvas = document.createElement('canvas'); 8722 canvas.width = 1; 8723 canvas.height = ih; 8724 var ctx = canvas.getContext('2d'); 8725 ctx.drawImage(img, 0, 0); 8726 var data = ctx.getImageData(0, 0, 1, ih).data; 8727 // search image edge pixel position in case it is squashed vertically. 8728 var sy = 0; 8729 var ey = ih; 8730 var py = ih; 8731 while (py > sy) { 8732 var alpha = data[(py - 1) * 4 + 3]; 8733 if (alpha === 0) { 8734 ey = py; 8735 } else { 8736 sy = py; 8737 } 8738 py = (ey + sy) >> 1; 8739 } 8740 canvas = null; 8741 var ratio = (py / ih); 8742 return (ratio === 0) ? 1 : ratio; 8743 } 9326 return { 9327 scale: scale 9328 }; 8744 9329 8745 return {8746 isSubsampled: detectSubsampling,8747 renderTo: renderImageToCanvas8748 };8749 9330 }); 8750 9331 8751 9332 // Included from: src/javascript/runtime/html5/image/Image.js … … 8772 9353 "moxie/file/Blob", 8773 9354 "moxie/file/File", 8774 9355 "moxie/runtime/html5/image/ImageInfo", 8775 "moxie/runtime/html5/image/ MegaPixel",9356 "moxie/runtime/html5/image/ResizerCanvas", 8776 9357 "moxie/core/utils/Mime", 8777 9358 "moxie/core/utils/Env" 8778 ], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, MegaPixel, Mime, Env) {8779 9359 ], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) { 9360 8780 9361 function HTML5Image() { 8781 9362 var me = this 8782 9363 , _img, _imgInfo, _canvas, _binStr, _blob … … 8786 9367 8787 9368 Basic.extend(this, { 8788 9369 loadFromBlob: function(blob) { 8789 var comp = this, I = comp.getRuntime()9370 var I = this.getRuntime() 8790 9371 , asBinary = arguments.length > 1 ? arguments[1] : true 8791 9372 ; 8792 9373 … … 8805 9386 if (asBinary) { 8806 9387 _binStr = _toBinary(dataUrl); 8807 9388 } 8808 _preload.call( comp, dataUrl);9389 _preload.call(this, dataUrl); 8809 9390 }); 8810 9391 } 8811 9392 }, … … 8829 9410 _imgInfo = new ImageInfo(_binStr); 8830 9411 } 8831 9412 9413 // this stuff below is definitely having fun with itself 8832 9414 info = { 8833 9415 width: _getImg().width || 0, 8834 9416 height: _getImg().height || 0, … … 8835 9417 type: _blob.type || Mime.getFileMime(_blob.name), 8836 9418 size: _binStr && _binStr.length || _blob.size || 0, 8837 9419 name: _blob.name || '', 8838 meta: _imgInfo && _imgInfo.meta || this.meta || {}9420 meta: null 8839 9421 }; 8840 9422 8841 // store thumbnail data as blob 8842 if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) { 8843 info.meta.thumb.data = new Blob(null, { 8844 type: 'image/jpeg', 8845 data: info.meta.thumb.data 8846 }); 9423 if (_preserveHeaders) { 9424 info.meta = _imgInfo && _imgInfo.meta || this.meta || {}; 9425 9426 // if data was taken from ImageInfo it will be a binary string, so we convert it to blob 9427 if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) { 9428 info.meta.thumb.data = new Blob(null, { 9429 type: 'image/jpeg', 9430 data: info.meta.thumb.data 9431 }); 9432 } 8847 9433 } 8848 9434 8849 9435 return info; 8850 9436 }, 8851 9437 8852 downsize: function() { 8853 _downsize.apply(this, arguments); 9438 9439 resize: function(rect, ratio, options) { 9440 var canvas = document.createElement('canvas'); 9441 canvas.width = rect.width; 9442 canvas.height = rect.height; 9443 9444 canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height); 9445 9446 _canvas = ResizerCanvas.scale(canvas, ratio); 9447 9448 _preserveHeaders = options.preserveHeaders; 9449 9450 // rotate if required, according to orientation tag 9451 if (!_preserveHeaders) { 9452 var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1; 9453 _canvas = _rotateToOrientaion(_canvas, orientation); 9454 } 9455 9456 this.width = _canvas.width; 9457 this.height = _canvas.height; 9458 9459 _modified = true; 9460 9461 this.trigger('Resize'); 8854 9462 }, 8855 9463 8856 9464 getAsCanvas: function() { 8857 if ( _canvas) {8858 _canvas .id = this.uid + '_canvas';9465 if (!_canvas) { 9466 _canvas = _getCanvas(); 8859 9467 } 9468 _canvas.id = this.uid + '_canvas'; 8860 9469 return _canvas; 8861 9470 }, 8862 9471 8863 9472 getAsBlob: function(type, quality) { 8864 9473 if (type !== this.type) { 8865 // if different mime type requested prepare image for conversion 8866 _downsize.call(this, this.width, this.height, false); 9474 _modified = true; // reconsider the state 9475 return new File(null, { 9476 name: _blob.name || '', 9477 type: type, 9478 data: me.getAsDataURL(type, quality) 9479 }); 8867 9480 } 8868 9481 return new File(null, { 8869 9482 name: _blob.name || '', 8870 9483 type: type, 8871 data: me.getAsBinaryString .call(this,type, quality)9484 data: me.getAsBinaryString(type, quality) 8872 9485 }); 8873 9486 }, 8874 9487 … … 8880 9493 return _img.src; 8881 9494 } 8882 9495 9496 // make sure we have a canvas to work with 9497 _getCanvas(); 9498 8883 9499 if ('image/jpeg' !== type) { 8884 9500 return _canvas.toDataURL('image/png'); 8885 9501 } else { … … 8912 9528 quality = 90; 8913 9529 } 8914 9530 9531 // make sure we have a canvas to work with 9532 _getCanvas(); 9533 8915 9534 try { 8916 9535 // older Geckos used to result in an exception on quality argument 8917 9536 dataUrl = _canvas.toDataURL('image/jpeg', quality/100); … … 8964 9583 } 8965 9584 8966 9585 9586 function _getCanvas() { 9587 var canvas = _getImg(); 9588 if (canvas.nodeName.toLowerCase() == 'canvas') { 9589 return canvas; 9590 } 9591 _canvas = document.createElement('canvas'); 9592 _canvas.width = canvas.width; 9593 _canvas.height = canvas.height; 9594 _canvas.getContext("2d").drawImage(canvas, 0, 0); 9595 return _canvas; 9596 } 9597 9598 8967 9599 function _toBinary(str) { 8968 9600 return Encode.atob(str.substring(str.indexOf('base64,') + 7)); 8969 9601 } … … 8997 9629 if (window.FileReader) { 8998 9630 fr = new FileReader(); 8999 9631 fr.onload = function() { 9000 callback (this.result);9632 callback.call(comp, this.result); 9001 9633 }; 9002 9634 fr.onerror = function() { 9003 9635 comp.trigger('error', x.ImageError.WRONG_FORMAT); … … 9004 9636 }; 9005 9637 fr.readAsDataURL(file); 9006 9638 } else { 9007 return callback (file.getAsDataURL());9639 return callback.call(this, file.getAsDataURL()); 9008 9640 } 9009 9641 } 9010 9642 9011 function _downsize(width, height, crop, preserveHeaders) {9012 var self = this9013 , scale9014 , mathFn9015 , x = 09016 , y = 09017 , img9018 , destWidth9019 , destHeight9020 , orientation9021 ;9022 9023 _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString())9024 9025 // take into account orientation tag9026 orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;9027 9028 if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation9029 // swap dimensions9030 var tmp = width;9031 width = height;9032 height = tmp;9033 }9034 9035 img = _getImg();9036 9037 // unify dimensions9038 if (!crop) {9039 scale = Math.min(width/img.width, height/img.height);9040 } else {9041 // one of the dimensions may exceed the actual image dimensions - we need to take the smallest value9042 width = Math.min(width, img.width);9043 height = Math.min(height, img.height);9044 9045 scale = Math.max(width/img.width, height/img.height);9046 }9047 9048 // we only downsize here9049 if (scale > 1 && !crop && preserveHeaders) {9050 this.trigger('Resize');9051 return;9052 }9053 9054 // prepare canvas if necessary9055 if (!_canvas) {9056 _canvas = document.createElement("canvas");9057 }9058 9059 // calculate dimensions of proportionally resized image9060 destWidth = Math.round(img.width * scale);9061 destHeight = Math.round(img.height * scale);9062 9063 // scale image and canvas9064 if (crop) {9065 _canvas.width = width;9066 _canvas.height = height;9067 9068 // if dimensions of the resulting image still larger than canvas, center it9069 if (destWidth > width) {9070 x = Math.round((destWidth - width) / 2);9071 }9072 9073 if (destHeight > height) {9074 y = Math.round((destHeight - height) / 2);9075 }9076 } else {9077 _canvas.width = destWidth;9078 _canvas.height = destHeight;9079 }9080 9081 // rotate if required, according to orientation tag9082 if (!_preserveHeaders) {9083 _rotateToOrientaion(_canvas.width, _canvas.height, orientation);9084 }9085 9086 _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight);9087 9088 this.width = _canvas.width;9089 this.height = _canvas.height;9090 9091 _modified = true;9092 self.trigger('Resize');9093 }9094 9095 9096 function _drawToCanvas(img, canvas, x, y, w, h) {9097 if (Env.OS === 'iOS') {9098 // avoid squish bug in iOS69099 MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });9100 } else {9101 var ctx = canvas.getContext('2d');9102 ctx.drawImage(img, x, y, w, h);9103 }9104 }9105 9106 9107 9643 /** 9108 9644 * Transform canvas coordination according to specified frame size and orientation 9109 9645 * Orientation value is from EXIF tag 9110 9646 * @author Shinichi Tomita <shinichi.tomita@gmail.com> 9111 9647 */ 9112 function _rotateToOrientaion(width, height, orientation) { 9113 switch (orientation) { 9114 case 5: 9115 case 6: 9116 case 7: 9117 case 8: 9118 _canvas.width = height; 9119 _canvas.height = width; 9120 break; 9121 default: 9122 _canvas.width = width; 9123 _canvas.height = height; 9648 function _rotateToOrientaion(img, orientation) { 9649 var RADIANS = Math.PI/180; 9650 var canvas = document.createElement('canvas'); 9651 var ctx = canvas.getContext('2d'); 9652 var width = img.width; 9653 var height = img.height; 9654 9655 if (Basic.inArray(orientation, [5,6,7,8]) > -1) { 9656 canvas.width = height; 9657 canvas.height = width; 9658 } else { 9659 canvas.width = width; 9660 canvas.height = height; 9124 9661 } 9125 9662 9126 9663 /** … … 9133 9670 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. 9134 9671 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. 9135 9672 */ 9136 9137 var ctx = _canvas.getContext('2d');9138 9673 switch (orientation) { 9139 9674 case 2: 9140 9675 // horizontal flip … … 9144 9679 case 3: 9145 9680 // 180 rotate left 9146 9681 ctx.translate(width, height); 9147 ctx.rotate( Math.PI);9682 ctx.rotate(180 * RADIANS); 9148 9683 break; 9149 9684 case 4: 9150 9685 // vertical flip … … 9153 9688 break; 9154 9689 case 5: 9155 9690 // vertical flip + 90 rotate right 9156 ctx.rotate( 0.5 * Math.PI);9691 ctx.rotate(90 * RADIANS); 9157 9692 ctx.scale(1, -1); 9158 9693 break; 9159 9694 case 6: 9160 9695 // 90 rotate right 9161 ctx.rotate( 0.5 * Math.PI);9696 ctx.rotate(90 * RADIANS); 9162 9697 ctx.translate(0, -height); 9163 9698 break; 9164 9699 case 7: 9165 9700 // horizontal flip + 90 rotate right 9166 ctx.rotate( 0.5 * Math.PI);9701 ctx.rotate(90 * RADIANS); 9167 9702 ctx.translate(width, -height); 9168 9703 ctx.scale(-1, 1); 9169 9704 break; 9170 9705 case 8: 9171 9706 // 90 rotate left 9172 ctx.rotate(- 0.5 * Math.PI);9707 ctx.rotate(-90 * RADIANS); 9173 9708 ctx.translate(-width, 0); 9174 9709 break; 9175 9710 } 9711 9712 ctx.drawImage(img, 0, 0, width, height); 9713 return canvas; 9176 9714 } 9177 9715 9178 9716 … … 9181 9719 _imgInfo.purge(); 9182 9720 _imgInfo = null; 9183 9721 } 9722 9184 9723 _binStr = _img = _canvas = _blob = null; 9185 9724 _modified = false; 9186 9725 } … … 9189 9728 return (extensions.Image = HTML5Image); 9190 9729 }); 9191 9730 9731 // Included from: src/javascript/runtime/flash/Runtime.js 9732 9192 9733 /** 9193 * Stub for moxie/runtime/flash/Runtime 9194 * @private 9734 * Runtime.js 9735 * 9736 * Copyright 2013, Moxiecode Systems AB 9737 * Released under GPL License. 9738 * 9739 * License: http://www.plupload.com/license 9740 * Contributing: http://www.plupload.com/contributing 9195 9741 */ 9742 9743 /*global ActiveXObject:true */ 9744 9745 /** 9746 Defines constructor for Flash runtime. 9747 9748 @class moxie/runtime/flash/Runtime 9749 @private 9750 */ 9196 9751 define("moxie/runtime/flash/Runtime", [ 9197 ], function() { 9198 return {}; 9752 "moxie/core/utils/Basic", 9753 "moxie/core/utils/Env", 9754 "moxie/core/utils/Dom", 9755 "moxie/core/Exceptions", 9756 "moxie/runtime/Runtime" 9757 ], function(Basic, Env, Dom, x, Runtime) { 9758 9759 var type = 'flash', extensions = {}; 9760 9761 /** 9762 Get the version of the Flash Player 9763 9764 @method getShimVersion 9765 @private 9766 @return {Number} Flash Player version 9767 */ 9768 function getShimVersion() { 9769 var version; 9770 9771 try { 9772 version = navigator.plugins['Shockwave Flash']; 9773 version = version.description; 9774 } catch (e1) { 9775 try { 9776 version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); 9777 } catch (e2) { 9778 version = '0.0'; 9779 } 9780 } 9781 version = version.match(/\d+/g); 9782 return parseFloat(version[0] + '.' + version[1]); 9783 } 9784 9785 9786 /** 9787 Cross-browser SWF removal 9788 - Especially needed to safely and completely remove a SWF in Internet Explorer 9789 9790 Originated from SWFObject v2.2 <http://code.google.com/p/swfobject/> 9791 */ 9792 function removeSWF(id) { 9793 var obj = Dom.get(id); 9794 if (obj && obj.nodeName == "OBJECT") { 9795 if (Env.browser === 'IE') { 9796 obj.style.display = "none"; 9797 (function onInit(){ 9798 // http://msdn.microsoft.com/en-us/library/ie/ms534360(v=vs.85).aspx 9799 if (obj.readyState == 4) { 9800 removeObjectInIE(id); 9801 } 9802 else { 9803 setTimeout(onInit, 10); 9804 } 9805 })(); 9806 } 9807 else { 9808 obj.parentNode.removeChild(obj); 9809 } 9810 } 9811 } 9812 9813 9814 function removeObjectInIE(id) { 9815 var obj = Dom.get(id); 9816 if (obj) { 9817 for (var i in obj) { 9818 if (typeof obj[i] == "function") { 9819 obj[i] = null; 9820 } 9821 } 9822 obj.parentNode.removeChild(obj); 9823 } 9824 } 9825 9826 /** 9827 Constructor for the Flash Runtime 9828 */ 9829 function FlashRuntime(options) { 9830 var I = this, initTimer; 9831 9832 options = Basic.extend({ swf_url: Env.swf_url }, options); 9833 9834 Runtime.call(this, options, type, { 9835 access_binary: function(value) { 9836 return value && I.mode === 'browser'; 9837 }, 9838 access_image_binary: function(value) { 9839 return value && I.mode === 'browser'; 9840 }, 9841 display_media: Runtime.capTest(defined('moxie/image/Image')), 9842 do_cors: Runtime.capTrue, 9843 drag_and_drop: false, 9844 report_upload_progress: function() { 9845 return I.mode === 'client'; 9846 }, 9847 resize_image: Runtime.capTrue, 9848 return_response_headers: false, 9849 return_response_type: function(responseType) { 9850 if (responseType === 'json' && !!window.JSON) { 9851 return true; 9852 } 9853 return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser'; 9854 }, 9855 return_status_code: function(code) { 9856 return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]); 9857 }, 9858 select_file: Runtime.capTrue, 9859 select_multiple: Runtime.capTrue, 9860 send_binary_string: function(value) { 9861 return value && I.mode === 'browser'; 9862 }, 9863 send_browser_cookies: function(value) { 9864 return value && I.mode === 'browser'; 9865 }, 9866 send_custom_headers: function(value) { 9867 return value && I.mode === 'browser'; 9868 }, 9869 send_multipart: Runtime.capTrue, 9870 slice_blob: function(value) { 9871 return value && I.mode === 'browser'; 9872 }, 9873 stream_upload: function(value) { 9874 return value && I.mode === 'browser'; 9875 }, 9876 summon_file_dialog: false, 9877 upload_filesize: function(size) { 9878 return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client'; 9879 }, 9880 use_http_method: function(methods) { 9881 return !Basic.arrayDiff(methods, ['GET', 'POST']); 9882 } 9883 }, { 9884 // capabilities that require specific mode 9885 access_binary: function(value) { 9886 return value ? 'browser' : 'client'; 9887 }, 9888 access_image_binary: function(value) { 9889 return value ? 'browser' : 'client'; 9890 }, 9891 report_upload_progress: function(value) { 9892 return value ? 'browser' : 'client'; 9893 }, 9894 return_response_type: function(responseType) { 9895 return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser']; 9896 }, 9897 return_status_code: function(code) { 9898 return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser']; 9899 }, 9900 send_binary_string: function(value) { 9901 return value ? 'browser' : 'client'; 9902 }, 9903 send_browser_cookies: function(value) { 9904 return value ? 'browser' : 'client'; 9905 }, 9906 send_custom_headers: function(value) { 9907 return value ? 'browser' : 'client'; 9908 }, 9909 slice_blob: function(value) { 9910 return value ? 'browser' : 'client'; 9911 }, 9912 stream_upload: function(value) { 9913 return value ? 'client' : 'browser'; 9914 }, 9915 upload_filesize: function(size) { 9916 return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser'; 9917 } 9918 }, 'client'); 9919 9920 9921 // minimal requirement for Flash Player version 9922 if (getShimVersion() < 11.3) { 9923 if (MXI_DEBUG && Env.debug.runtime) { 9924 Env.log("\tFlash didn't meet minimal version requirement (11.3)."); 9925 } 9926 9927 this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before 9928 } 9929 9930 9931 Basic.extend(this, { 9932 9933 getShim: function() { 9934 return Dom.get(this.uid); 9935 }, 9936 9937 shimExec: function(component, action) { 9938 var args = [].slice.call(arguments, 2); 9939 return I.getShim().exec(this.uid, component, action, args); 9940 }, 9941 9942 init: function() { 9943 var html, el, container; 9944 9945 container = this.getShimContainer(); 9946 9947 // if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc) 9948 Basic.extend(container.style, { 9949 position: 'absolute', 9950 top: '-8px', 9951 left: '-8px', 9952 width: '9px', 9953 height: '9px', 9954 overflow: 'hidden' 9955 }); 9956 9957 // insert flash object 9958 html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' + options.swf_url + '" '; 9959 9960 if (Env.browser === 'IE') { 9961 html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '; 9962 } 9963 9964 html += 'width="100%" height="100%" style="outline:0">' + 9965 '<param name="movie" value="' + options.swf_url + '" />' + 9966 '<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Runtime.getGlobalEventTarget() + '" />' + 9967 '<param name="wmode" value="transparent" />' + 9968 '<param name="allowscriptaccess" value="always" />' + 9969 '</object>'; 9970 9971 if (Env.browser === 'IE') { 9972 el = document.createElement('div'); 9973 container.appendChild(el); 9974 el.outerHTML = html; 9975 el = container = null; // just in case 9976 } else { 9977 container.innerHTML = html; 9978 } 9979 9980 // Init is dispatched by the shim 9981 initTimer = setTimeout(function() { 9982 if (I && !I.initialized) { // runtime might be already destroyed by this moment 9983 I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); 9984 9985 if (MXI_DEBUG && Env.debug.runtime) { 9986 Env.log("\tFlash failed to initialize within a specified period of time (typically 5s)."); 9987 } 9988 } 9989 }, 5000); 9990 }, 9991 9992 destroy: (function(destroy) { // extend default destroy method 9993 return function() { 9994 removeSWF(I.uid); // SWF removal requires special care in IE 9995 9996 destroy.call(I); 9997 clearTimeout(initTimer); // initialization check might be still onwait 9998 options = initTimer = destroy = I = null; 9999 }; 10000 }(this.destroy)) 10001 10002 }, extensions); 10003 } 10004 10005 Runtime.addConstructor(type, FlashRuntime); 10006 10007 return extensions; 9199 10008 }); 9200 10009 10010 // Included from: src/javascript/runtime/flash/file/Blob.js 10011 9201 10012 /** 9202 * Stub for moxie/runtime/silverlight/Runtime 9203 * @private 10013 * Blob.js 10014 * 10015 * Copyright 2013, Moxiecode Systems AB 10016 * Released under GPL License. 10017 * 10018 * License: http://www.plupload.com/license 10019 * Contributing: http://www.plupload.com/contributing 9204 10020 */ 10021 10022 /** 10023 @class moxie/runtime/flash/file/Blob 10024 @private 10025 */ 10026 define("moxie/runtime/flash/file/Blob", [ 10027 "moxie/runtime/flash/Runtime", 10028 "moxie/file/Blob" 10029 ], function(extensions, Blob) { 10030 10031 var FlashBlob = { 10032 slice: function(blob, start, end, type) { 10033 var self = this.getRuntime(); 10034 10035 if (start < 0) { 10036 start = Math.max(blob.size + start, 0); 10037 } else if (start > 0) { 10038 start = Math.min(start, blob.size); 10039 } 10040 10041 if (end < 0) { 10042 end = Math.max(blob.size + end, 0); 10043 } else if (end > 0) { 10044 end = Math.min(end, blob.size); 10045 } 10046 10047 blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || ''); 10048 10049 if (blob) { 10050 blob = new Blob(self.uid, blob); 10051 } 10052 return blob; 10053 } 10054 }; 10055 10056 return (extensions.Blob = FlashBlob); 10057 }); 10058 10059 // Included from: src/javascript/runtime/flash/file/FileInput.js 10060 10061 /** 10062 * FileInput.js 10063 * 10064 * Copyright 2013, Moxiecode Systems AB 10065 * Released under GPL License. 10066 * 10067 * License: http://www.plupload.com/license 10068 * Contributing: http://www.plupload.com/contributing 10069 */ 10070 10071 /** 10072 @class moxie/runtime/flash/file/FileInput 10073 @private 10074 */ 10075 define("moxie/runtime/flash/file/FileInput", [ 10076 "moxie/runtime/flash/Runtime", 10077 "moxie/file/File", 10078 "moxie/core/utils/Dom", 10079 "moxie/core/utils/Basic" 10080 ], function(extensions, File, Dom, Basic) { 10081 10082 var FileInput = { 10083 init: function(options) { 10084 var comp = this, I = this.getRuntime(); 10085 var browseButton = Dom.get(options.browse_button); 10086 10087 if (browseButton) { 10088 browseButton.setAttribute('tabindex', -1); 10089 browseButton = null; 10090 } 10091 10092 this.bind("Change", function() { 10093 var files = I.shimExec.call(comp, 'FileInput', 'getFiles'); 10094 comp.files = []; 10095 Basic.each(files, function(file) { 10096 comp.files.push(new File(I.uid, file)); 10097 }); 10098 }, 999); 10099 10100 this.getRuntime().shimExec.call(this, 'FileInput', 'init', { 10101 accept: options.accept, 10102 multiple: options.multiple 10103 }); 10104 10105 this.trigger('ready'); 10106 } 10107 }; 10108 10109 return (extensions.FileInput = FileInput); 10110 }); 10111 10112 // Included from: src/javascript/runtime/flash/file/FileReader.js 10113 10114 /** 10115 * FileReader.js 10116 * 10117 * Copyright 2013, Moxiecode Systems AB 10118 * Released under GPL License. 10119 * 10120 * License: http://www.plupload.com/license 10121 * Contributing: http://www.plupload.com/contributing 10122 */ 10123 10124 /** 10125 @class moxie/runtime/flash/file/FileReader 10126 @private 10127 */ 10128 define("moxie/runtime/flash/file/FileReader", [ 10129 "moxie/runtime/flash/Runtime", 10130 "moxie/core/utils/Encode" 10131 ], function(extensions, Encode) { 10132 10133 function _formatData(data, op) { 10134 switch (op) { 10135 case 'readAsText': 10136 return Encode.atob(data, 'utf8'); 10137 case 'readAsBinaryString': 10138 return Encode.atob(data); 10139 case 'readAsDataURL': 10140 return data; 10141 } 10142 return null; 10143 } 10144 10145 var FileReader = { 10146 read: function(op, blob) { 10147 var comp = this; 10148 10149 comp.result = ''; 10150 10151 // special prefix for DataURL read mode 10152 if (op === 'readAsDataURL') { 10153 comp.result = 'data:' + (blob.type || '') + ';base64,'; 10154 } 10155 10156 comp.bind('Progress', function(e, data) { 10157 if (data) { 10158 comp.result += _formatData(data, op); 10159 } 10160 }, 999); 10161 10162 return comp.getRuntime().shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid); 10163 } 10164 }; 10165 10166 return (extensions.FileReader = FileReader); 10167 }); 10168 10169 // Included from: src/javascript/runtime/flash/file/FileReaderSync.js 10170 10171 /** 10172 * FileReaderSync.js 10173 * 10174 * Copyright 2013, Moxiecode Systems AB 10175 * Released under GPL License. 10176 * 10177 * License: http://www.plupload.com/license 10178 * Contributing: http://www.plupload.com/contributing 10179 */ 10180 10181 /** 10182 @class moxie/runtime/flash/file/FileReaderSync 10183 @private 10184 */ 10185 define("moxie/runtime/flash/file/FileReaderSync", [ 10186 "moxie/runtime/flash/Runtime", 10187 "moxie/core/utils/Encode" 10188 ], function(extensions, Encode) { 10189 10190 function _formatData(data, op) { 10191 switch (op) { 10192 case 'readAsText': 10193 return Encode.atob(data, 'utf8'); 10194 case 'readAsBinaryString': 10195 return Encode.atob(data); 10196 case 'readAsDataURL': 10197 return data; 10198 } 10199 return null; 10200 } 10201 10202 var FileReaderSync = { 10203 read: function(op, blob) { 10204 var result, self = this.getRuntime(); 10205 10206 result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid); 10207 if (!result) { 10208 return null; // or throw ex 10209 } 10210 10211 // special prefix for DataURL read mode 10212 if (op === 'readAsDataURL') { 10213 result = 'data:' + (blob.type || '') + ';base64,' + result; 10214 } 10215 10216 return _formatData(result, op, blob.type); 10217 } 10218 }; 10219 10220 return (extensions.FileReaderSync = FileReaderSync); 10221 }); 10222 10223 // Included from: src/javascript/runtime/flash/runtime/Transporter.js 10224 10225 /** 10226 * Transporter.js 10227 * 10228 * Copyright 2013, Moxiecode Systems AB 10229 * Released under GPL License. 10230 * 10231 * License: http://www.plupload.com/license 10232 * Contributing: http://www.plupload.com/contributing 10233 */ 10234 10235 /** 10236 @class moxie/runtime/flash/runtime/Transporter 10237 @private 10238 */ 10239 define("moxie/runtime/flash/runtime/Transporter", [ 10240 "moxie/runtime/flash/Runtime", 10241 "moxie/file/Blob" 10242 ], function(extensions, Blob) { 10243 10244 var Transporter = { 10245 getAsBlob: function(type) { 10246 var self = this.getRuntime() 10247 , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type) 10248 ; 10249 if (blob) { 10250 return new Blob(self.uid, blob); 10251 } 10252 return null; 10253 } 10254 }; 10255 10256 return (extensions.Transporter = Transporter); 10257 }); 10258 10259 // Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js 10260 10261 /** 10262 * XMLHttpRequest.js 10263 * 10264 * Copyright 2013, Moxiecode Systems AB 10265 * Released under GPL License. 10266 * 10267 * License: http://www.plupload.com/license 10268 * Contributing: http://www.plupload.com/contributing 10269 */ 10270 10271 /** 10272 @class moxie/runtime/flash/xhr/XMLHttpRequest 10273 @private 10274 */ 10275 define("moxie/runtime/flash/xhr/XMLHttpRequest", [ 10276 "moxie/runtime/flash/Runtime", 10277 "moxie/core/utils/Basic", 10278 "moxie/file/Blob", 10279 "moxie/file/File", 10280 "moxie/file/FileReaderSync", 10281 "moxie/runtime/flash/file/FileReaderSync", 10282 "moxie/xhr/FormData", 10283 "moxie/runtime/Transporter", 10284 "moxie/runtime/flash/runtime/Transporter" 10285 ], function(extensions, Basic, Blob, File, FileReaderSync, FileReaderSyncFlash, FormData, Transporter, TransporterFlash) { 10286 10287 var XMLHttpRequest = { 10288 10289 send: function(meta, data) { 10290 var target = this, self = target.getRuntime(); 10291 10292 function send() { 10293 meta.transport = self.mode; 10294 self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data); 10295 } 10296 10297 10298 function appendBlob(name, blob) { 10299 self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid); 10300 data = null; 10301 send(); 10302 } 10303 10304 10305 function attachBlob(blob, cb) { 10306 var tr = new Transporter(); 10307 10308 tr.bind("TransportingComplete", function() { 10309 cb(this.result); 10310 }); 10311 10312 tr.transport(blob.getSource(), blob.type, { 10313 ruid: self.uid 10314 }); 10315 } 10316 10317 // copy over the headers if any 10318 if (!Basic.isEmptyObj(meta.headers)) { 10319 Basic.each(meta.headers, function(value, header) { 10320 self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object 10321 }); 10322 } 10323 10324 // transfer over multipart params and blob itself 10325 if (data instanceof FormData) { 10326 var blobField; 10327 data.each(function(value, name) { 10328 if (value instanceof Blob) { 10329 blobField = name; 10330 } else { 10331 self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value); 10332 } 10333 }); 10334 10335 if (!data.hasBlob()) { 10336 data = null; 10337 send(); 10338 } else { 10339 var blob = data.getBlob(); 10340 if (blob.isDetached()) { 10341 attachBlob(blob, function(attachedBlob) { 10342 blob.destroy(); 10343 appendBlob(blobField, attachedBlob); 10344 }); 10345 } else { 10346 appendBlob(blobField, blob); 10347 } 10348 } 10349 } else if (data instanceof Blob) { 10350 if (data.isDetached()) { 10351 attachBlob(data, function(attachedBlob) { 10352 data.destroy(); 10353 data = attachedBlob.uid; 10354 send(); 10355 }); 10356 } else { 10357 data = data.uid; 10358 send(); 10359 } 10360 } else { 10361 send(); 10362 } 10363 }, 10364 10365 getResponse: function(responseType) { 10366 var frs, blob, self = this.getRuntime(); 10367 10368 blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob'); 10369 10370 if (blob) { 10371 blob = new File(self.uid, blob); 10372 10373 if ('blob' === responseType) { 10374 return blob; 10375 } 10376 10377 try { 10378 frs = new FileReaderSync(); 10379 10380 if (!!~Basic.inArray(responseType, ["", "text"])) { 10381 return frs.readAsText(blob); 10382 } else if ('json' === responseType && !!window.JSON) { 10383 return JSON.parse(frs.readAsText(blob)); 10384 } 10385 } finally { 10386 blob.destroy(); 10387 } 10388 } 10389 return null; 10390 }, 10391 10392 abort: function(upload_complete_flag) { 10393 var self = this.getRuntime(); 10394 10395 self.shimExec.call(this, 'XMLHttpRequest', 'abort'); 10396 10397 this.dispatchEvent('readystatechange'); 10398 // this.dispatchEvent('progress'); 10399 this.dispatchEvent('abort'); 10400 10401 //if (!upload_complete_flag) { 10402 // this.dispatchEvent('uploadprogress'); 10403 //} 10404 } 10405 }; 10406 10407 return (extensions.XMLHttpRequest = XMLHttpRequest); 10408 }); 10409 10410 // Included from: src/javascript/runtime/flash/image/Image.js 10411 10412 /** 10413 * Image.js 10414 * 10415 * Copyright 2013, Moxiecode Systems AB 10416 * Released under GPL License. 10417 * 10418 * License: http://www.plupload.com/license 10419 * Contributing: http://www.plupload.com/contributing 10420 */ 10421 10422 /** 10423 @class moxie/runtime/flash/image/Image 10424 @private 10425 */ 10426 define("moxie/runtime/flash/image/Image", [ 10427 "moxie/runtime/flash/Runtime", 10428 "moxie/core/utils/Basic", 10429 "moxie/runtime/Transporter", 10430 "moxie/file/Blob", 10431 "moxie/file/FileReaderSync" 10432 ], function(extensions, Basic, Transporter, Blob, FileReaderSync) { 10433 10434 var Image = { 10435 loadFromBlob: function(blob) { 10436 var comp = this, self = comp.getRuntime(); 10437 10438 function exec(srcBlob) { 10439 self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid); 10440 comp = self = null; 10441 } 10442 10443 if (blob.isDetached()) { // binary string 10444 var tr = new Transporter(); 10445 tr.bind("TransportingComplete", function() { 10446 exec(tr.result.getSource()); 10447 }); 10448 tr.transport(blob.getSource(), blob.type, { ruid: self.uid }); 10449 } else { 10450 exec(blob.getSource()); 10451 } 10452 }, 10453 10454 loadFromImage: function(img) { 10455 var self = this.getRuntime(); 10456 return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid); 10457 }, 10458 10459 getInfo: function() { 10460 var self = this.getRuntime() 10461 , info = self.shimExec.call(this, 'Image', 'getInfo') 10462 ; 10463 10464 if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) { 10465 info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data); 10466 } 10467 return info; 10468 }, 10469 10470 getAsBlob: function(type, quality) { 10471 var self = this.getRuntime() 10472 , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality) 10473 ; 10474 if (blob) { 10475 return new Blob(self.uid, blob); 10476 } 10477 return null; 10478 }, 10479 10480 getAsDataURL: function() { 10481 var self = this.getRuntime() 10482 , blob = self.Image.getAsBlob.apply(this, arguments) 10483 , frs 10484 ; 10485 if (!blob) { 10486 return null; 10487 } 10488 frs = new FileReaderSync(); 10489 return frs.readAsDataURL(blob); 10490 } 10491 }; 10492 10493 return (extensions.Image = Image); 10494 }); 10495 10496 // Included from: src/javascript/runtime/silverlight/Runtime.js 10497 10498 /** 10499 * RunTime.js 10500 * 10501 * Copyright 2013, Moxiecode Systems AB 10502 * Released under GPL License. 10503 * 10504 * License: http://www.plupload.com/license 10505 * Contributing: http://www.plupload.com/contributing 10506 */ 10507 10508 /*global ActiveXObject:true */ 10509 10510 /** 10511 Defines constructor for Silverlight runtime. 10512 10513 @class moxie/runtime/silverlight/Runtime 10514 @private 10515 */ 9205 10516 define("moxie/runtime/silverlight/Runtime", [ 9206 ], function() { 9207 return {}; 10517 "moxie/core/utils/Basic", 10518 "moxie/core/utils/Env", 10519 "moxie/core/utils/Dom", 10520 "moxie/core/Exceptions", 10521 "moxie/runtime/Runtime" 10522 ], function(Basic, Env, Dom, x, Runtime) { 10523 10524 var type = "silverlight", extensions = {}; 10525 10526 function isInstalled(version) { 10527 var isVersionSupported = false, control = null, actualVer, 10528 actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0; 10529 10530 try { 10531 try { 10532 control = new ActiveXObject('AgControl.AgControl'); 10533 10534 if (control.IsVersionSupported(version)) { 10535 isVersionSupported = true; 10536 } 10537 10538 control = null; 10539 } catch (e) { 10540 var plugin = navigator.plugins["Silverlight Plug-In"]; 10541 10542 if (plugin) { 10543 actualVer = plugin.description; 10544 10545 if (actualVer === "1.0.30226.2") { 10546 actualVer = "2.0.30226.2"; 10547 } 10548 10549 actualVerArray = actualVer.split("."); 10550 10551 while (actualVerArray.length > 3) { 10552 actualVerArray.pop(); 10553 } 10554 10555 while ( actualVerArray.length < 4) { 10556 actualVerArray.push(0); 10557 } 10558 10559 reqVerArray = version.split("."); 10560 10561 while (reqVerArray.length > 4) { 10562 reqVerArray.pop(); 10563 } 10564 10565 do { 10566 requiredVersionPart = parseInt(reqVerArray[index], 10); 10567 actualVersionPart = parseInt(actualVerArray[index], 10); 10568 index++; 10569 } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart); 10570 10571 if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) { 10572 isVersionSupported = true; 10573 } 10574 } 10575 } 10576 } catch (e2) { 10577 isVersionSupported = false; 10578 } 10579 10580 return isVersionSupported; 10581 } 10582 10583 /** 10584 Constructor for the Silverlight Runtime 10585 */ 10586 function SilverlightRuntime(options) { 10587 var I = this, initTimer; 10588 10589 options = Basic.extend({ xap_url: Env.xap_url }, options); 10590 10591 Runtime.call(this, options, type, { 10592 access_binary: Runtime.capTrue, 10593 access_image_binary: Runtime.capTrue, 10594 display_media: Runtime.capTest(defined('moxie/image/Image')), 10595 do_cors: Runtime.capTrue, 10596 drag_and_drop: false, 10597 report_upload_progress: Runtime.capTrue, 10598 resize_image: Runtime.capTrue, 10599 return_response_headers: function(value) { 10600 return value && I.mode === 'client'; 10601 }, 10602 return_response_type: function(responseType) { 10603 if (responseType !== 'json') { 10604 return true; 10605 } else { 10606 return !!window.JSON; 10607 } 10608 }, 10609 return_status_code: function(code) { 10610 return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]); 10611 }, 10612 select_file: Runtime.capTrue, 10613 select_multiple: Runtime.capTrue, 10614 send_binary_string: Runtime.capTrue, 10615 send_browser_cookies: function(value) { 10616 return value && I.mode === 'browser'; 10617 }, 10618 send_custom_headers: function(value) { 10619 return value && I.mode === 'client'; 10620 }, 10621 send_multipart: Runtime.capTrue, 10622 slice_blob: Runtime.capTrue, 10623 stream_upload: true, 10624 summon_file_dialog: false, 10625 upload_filesize: Runtime.capTrue, 10626 use_http_method: function(methods) { 10627 return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']); 10628 } 10629 }, { 10630 // capabilities that require specific mode 10631 return_response_headers: function(value) { 10632 return value ? 'client' : 'browser'; 10633 }, 10634 return_status_code: function(code) { 10635 return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser']; 10636 }, 10637 send_browser_cookies: function(value) { 10638 return value ? 'browser' : 'client'; 10639 }, 10640 send_custom_headers: function(value) { 10641 return value ? 'client' : 'browser'; 10642 }, 10643 use_http_method: function(methods) { 10644 return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser']; 10645 } 10646 }); 10647 10648 10649 // minimal requirement 10650 if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') { 10651 if (MXI_DEBUG && Env.debug.runtime) { 10652 Env.log("\tSilverlight is not installed or minimal version (2.0.31005.0) requirement not met (not likely)."); 10653 } 10654 10655 this.mode = false; 10656 } 10657 10658 10659 Basic.extend(this, { 10660 getShim: function() { 10661 return Dom.get(this.uid).content.Moxie; 10662 }, 10663 10664 shimExec: function(component, action) { 10665 var args = [].slice.call(arguments, 2); 10666 return I.getShim().exec(this.uid, component, action, args); 10667 }, 10668 10669 init : function() { 10670 var container; 10671 10672 container = this.getShimContainer(); 10673 10674 container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' + 10675 '<param name="source" value="' + options.xap_url + '"/>' + 10676 '<param name="background" value="Transparent"/>' + 10677 '<param name="windowless" value="true"/>' + 10678 '<param name="enablehtmlaccess" value="true"/>' + 10679 '<param name="initParams" value="uid=' + this.uid + ',target=' + Runtime.getGlobalEventTarget() + '"/>' + 10680 '</object>'; 10681 10682 // Init is dispatched by the shim 10683 initTimer = setTimeout(function() { 10684 if (I && !I.initialized) { // runtime might be already destroyed by this moment 10685 I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); 10686 10687 if (MXI_DEBUG && Env.debug.runtime) { 10688 Env.log("\Silverlight failed to initialize within a specified period of time (5-10s)."); 10689 } 10690 } 10691 }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac) 10692 }, 10693 10694 destroy: (function(destroy) { // extend default destroy method 10695 return function() { 10696 destroy.call(I); 10697 clearTimeout(initTimer); // initialization check might be still onwait 10698 options = initTimer = destroy = I = null; 10699 }; 10700 }(this.destroy)) 10701 10702 }, extensions); 10703 } 10704 10705 Runtime.addConstructor(type, SilverlightRuntime); 10706 10707 return extensions; 9208 10708 }); 9209 10709 10710 // Included from: src/javascript/runtime/silverlight/file/Blob.js 10711 10712 /** 10713 * Blob.js 10714 * 10715 * Copyright 2013, Moxiecode Systems AB 10716 * Released under GPL License. 10717 * 10718 * License: http://www.plupload.com/license 10719 * Contributing: http://www.plupload.com/contributing 10720 */ 10721 10722 /** 10723 @class moxie/runtime/silverlight/file/Blob 10724 @private 10725 */ 10726 define("moxie/runtime/silverlight/file/Blob", [ 10727 "moxie/runtime/silverlight/Runtime", 10728 "moxie/core/utils/Basic", 10729 "moxie/runtime/flash/file/Blob" 10730 ], function(extensions, Basic, Blob) { 10731 return (extensions.Blob = Basic.extend({}, Blob)); 10732 }); 10733 10734 // Included from: src/javascript/runtime/silverlight/file/FileInput.js 10735 10736 /** 10737 * FileInput.js 10738 * 10739 * Copyright 2013, Moxiecode Systems AB 10740 * Released under GPL License. 10741 * 10742 * License: http://www.plupload.com/license 10743 * Contributing: http://www.plupload.com/contributing 10744 */ 10745 10746 /** 10747 @class moxie/runtime/silverlight/file/FileInput 10748 @private 10749 */ 10750 define("moxie/runtime/silverlight/file/FileInput", [ 10751 "moxie/runtime/silverlight/Runtime", 10752 "moxie/file/File", 10753 "moxie/core/utils/Dom", 10754 "moxie/core/utils/Basic" 10755 ], function(extensions, File, Dom, Basic) { 10756 10757 function toFilters(accept) { 10758 var filter = ''; 10759 for (var i = 0; i < accept.length; i++) { 10760 filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.'); 10761 } 10762 return filter; 10763 } 10764 10765 10766 var FileInput = { 10767 init: function(options) { 10768 var comp = this, I = this.getRuntime(); 10769 var browseButton = Dom.get(options.browse_button); 10770 10771 if (browseButton) { 10772 browseButton.setAttribute('tabindex', -1); 10773 browseButton = null; 10774 } 10775 10776 this.bind("Change", function() { 10777 var files = I.shimExec.call(comp, 'FileInput', 'getFiles'); 10778 comp.files = []; 10779 Basic.each(files, function(file) { 10780 comp.files.push(new File(I.uid, file)); 10781 }); 10782 }, 999); 10783 10784 I.shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.multiple); 10785 this.trigger('ready'); 10786 }, 10787 10788 setOption: function(name, value) { 10789 if (name == 'accept') { 10790 value = toFilters(value); 10791 } 10792 this.getRuntime().shimExec.call(this, 'FileInput', 'setOption', name, value); 10793 } 10794 }; 10795 10796 return (extensions.FileInput = FileInput); 10797 }); 10798 10799 // Included from: src/javascript/runtime/silverlight/file/FileDrop.js 10800 10801 /** 10802 * FileDrop.js 10803 * 10804 * Copyright 2013, Moxiecode Systems AB 10805 * Released under GPL License. 10806 * 10807 * License: http://www.plupload.com/license 10808 * Contributing: http://www.plupload.com/contributing 10809 */ 10810 10811 /** 10812 @class moxie/runtime/silverlight/file/FileDrop 10813 @private 10814 */ 10815 define("moxie/runtime/silverlight/file/FileDrop", [ 10816 "moxie/runtime/silverlight/Runtime", 10817 "moxie/core/utils/Dom", 10818 "moxie/core/utils/Events" 10819 ], function(extensions, Dom, Events) { 10820 10821 // not exactly useful, since works only in safari (...crickets...) 10822 var FileDrop = { 10823 init: function() { 10824 var comp = this, self = comp.getRuntime(), dropZone; 10825 10826 dropZone = self.getShimContainer(); 10827 10828 Events.addEvent(dropZone, 'dragover', function(e) { 10829 e.preventDefault(); 10830 e.stopPropagation(); 10831 e.dataTransfer.dropEffect = 'copy'; 10832 }, comp.uid); 10833 10834 Events.addEvent(dropZone, 'dragenter', function(e) { 10835 e.preventDefault(); 10836 var flag = Dom.get(self.uid).dragEnter(e); 10837 // If handled, then stop propagation of event in DOM 10838 if (flag) { 10839 e.stopPropagation(); 10840 } 10841 }, comp.uid); 10842 10843 Events.addEvent(dropZone, 'drop', function(e) { 10844 e.preventDefault(); 10845 var flag = Dom.get(self.uid).dragDrop(e); 10846 // If handled, then stop propagation of event in DOM 10847 if (flag) { 10848 e.stopPropagation(); 10849 } 10850 }, comp.uid); 10851 10852 return self.shimExec.call(this, 'FileDrop', 'init'); 10853 } 10854 }; 10855 10856 return (extensions.FileDrop = FileDrop); 10857 }); 10858 10859 // Included from: src/javascript/runtime/silverlight/file/FileReader.js 10860 10861 /** 10862 * FileReader.js 10863 * 10864 * Copyright 2013, Moxiecode Systems AB 10865 * Released under GPL License. 10866 * 10867 * License: http://www.plupload.com/license 10868 * Contributing: http://www.plupload.com/contributing 10869 */ 10870 10871 /** 10872 @class moxie/runtime/silverlight/file/FileReader 10873 @private 10874 */ 10875 define("moxie/runtime/silverlight/file/FileReader", [ 10876 "moxie/runtime/silverlight/Runtime", 10877 "moxie/core/utils/Basic", 10878 "moxie/runtime/flash/file/FileReader" 10879 ], function(extensions, Basic, FileReader) { 10880 return (extensions.FileReader = Basic.extend({}, FileReader)); 10881 }); 10882 10883 // Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js 10884 10885 /** 10886 * FileReaderSync.js 10887 * 10888 * Copyright 2013, Moxiecode Systems AB 10889 * Released under GPL License. 10890 * 10891 * License: http://www.plupload.com/license 10892 * Contributing: http://www.plupload.com/contributing 10893 */ 10894 10895 /** 10896 @class moxie/runtime/silverlight/file/FileReaderSync 10897 @private 10898 */ 10899 define("moxie/runtime/silverlight/file/FileReaderSync", [ 10900 "moxie/runtime/silverlight/Runtime", 10901 "moxie/core/utils/Basic", 10902 "moxie/runtime/flash/file/FileReaderSync" 10903 ], function(extensions, Basic, FileReaderSync) { 10904 return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync)); 10905 }); 10906 10907 // Included from: src/javascript/runtime/silverlight/runtime/Transporter.js 10908 10909 /** 10910 * Transporter.js 10911 * 10912 * Copyright 2013, Moxiecode Systems AB 10913 * Released under GPL License. 10914 * 10915 * License: http://www.plupload.com/license 10916 * Contributing: http://www.plupload.com/contributing 10917 */ 10918 10919 /** 10920 @class moxie/runtime/silverlight/runtime/Transporter 10921 @private 10922 */ 10923 define("moxie/runtime/silverlight/runtime/Transporter", [ 10924 "moxie/runtime/silverlight/Runtime", 10925 "moxie/core/utils/Basic", 10926 "moxie/runtime/flash/runtime/Transporter" 10927 ], function(extensions, Basic, Transporter) { 10928 return (extensions.Transporter = Basic.extend({}, Transporter)); 10929 }); 10930 10931 // Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js 10932 10933 /** 10934 * XMLHttpRequest.js 10935 * 10936 * Copyright 2013, Moxiecode Systems AB 10937 * Released under GPL License. 10938 * 10939 * License: http://www.plupload.com/license 10940 * Contributing: http://www.plupload.com/contributing 10941 */ 10942 10943 /** 10944 @class moxie/runtime/silverlight/xhr/XMLHttpRequest 10945 @private 10946 */ 10947 define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [ 10948 "moxie/runtime/silverlight/Runtime", 10949 "moxie/core/utils/Basic", 10950 "moxie/runtime/flash/xhr/XMLHttpRequest", 10951 "moxie/runtime/silverlight/file/FileReaderSync", 10952 "moxie/runtime/silverlight/runtime/Transporter" 10953 ], function(extensions, Basic, XMLHttpRequest, FileReaderSyncSilverlight, TransporterSilverlight) { 10954 return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest)); 10955 }); 10956 10957 // Included from: src/javascript/runtime/silverlight/image/Image.js 10958 10959 /** 10960 * Image.js 10961 * 10962 * Copyright 2013, Moxiecode Systems AB 10963 * Released under GPL License. 10964 * 10965 * License: http://www.plupload.com/license 10966 * Contributing: http://www.plupload.com/contributing 10967 */ 10968 10969 /** 10970 @class moxie/runtime/silverlight/image/Image 10971 @private 10972 */ 10973 define("moxie/runtime/silverlight/image/Image", [ 10974 "moxie/runtime/silverlight/Runtime", 10975 "moxie/core/utils/Basic", 10976 "moxie/file/Blob", 10977 "moxie/runtime/flash/image/Image" 10978 ], function(extensions, Basic, Blob, Image) { 10979 return (extensions.Image = Basic.extend({}, Image, { 10980 10981 getInfo: function() { 10982 var self = this.getRuntime() 10983 , grps = ['tiff', 'exif', 'gps', 'thumb'] 10984 , info = { meta: {} } 10985 , rawInfo = self.shimExec.call(this, 'Image', 'getInfo') 10986 ; 10987 10988 if (rawInfo.meta) { 10989 Basic.each(grps, function(grp) { 10990 var meta = rawInfo.meta[grp] 10991 , tag 10992 , i 10993 , length 10994 , value 10995 ; 10996 if (meta && meta.keys) { 10997 info.meta[grp] = {}; 10998 for (i = 0, length = meta.keys.length; i < length; i++) { 10999 tag = meta.keys[i]; 11000 value = meta[tag]; 11001 if (value) { 11002 // convert numbers 11003 if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero) 11004 value = parseInt(value, 10); 11005 } else if (/^\d*\.\d+$/.test(value)) { // double 11006 value = parseFloat(value); 11007 } 11008 info.meta[grp][tag] = value; 11009 } 11010 } 11011 } 11012 }); 11013 11014 // save thumb data as blob 11015 if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) { 11016 info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data); 11017 } 11018 } 11019 11020 info.width = parseInt(rawInfo.width, 10); 11021 info.height = parseInt(rawInfo.height, 10); 11022 info.size = parseInt(rawInfo.size, 10); 11023 info.type = rawInfo.type; 11024 info.name = rawInfo.name; 11025 11026 return info; 11027 }, 11028 11029 resize: function(rect, ratio, opts) { 11030 this.getRuntime().shimExec.call(this, 'Image', 'resize', rect.x, rect.y, rect.width, rect.height, ratio, opts.preserveHeaders, opts.resample); 11031 } 11032 })); 11033 }); 11034 9210 11035 // Included from: src/javascript/runtime/html4/Runtime.js 9211 11036 9212 11037 /** … … 9245 11070 Runtime.call(this, options, type, { 9246 11071 access_binary: Test(window.FileReader || window.File && File.getAsDataURL), 9247 11072 access_image_binary: false, 9248 display_media: Test(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))), 11073 display_media: Test( 11074 (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && 11075 defined('moxie/image/Image') 11076 ), 9249 11077 do_cors: false, 9250 11078 drag_and_drop: false, 9251 11079 filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest 9252 return (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '>=')) || 9253 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || 9254 (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '>=')); 11080 return !( 11081 (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || 11082 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || 11083 (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '<')) || 11084 (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<')) 11085 ); 9255 11086 }()), 9256 11087 resize_image: function() { 9257 11088 return extensions.Image && I.can('access_binary') && Env.can('create_canvas'); … … 9279 11110 return I.can('select_file'); 9280 11111 }, 9281 11112 summon_file_dialog: function() { // yeah... some dirty sniffing here... 9282 return I.can('select_file') && ( 9283 (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '>=')) || 9284 (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '>=')) || 9285 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || 9286 !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']) 11113 return I.can('select_file') && !( 11114 (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) || 11115 (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) || 11116 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) 9287 11117 ); 9288 11118 }, 9289 11119 upload_filesize: True, … … 9341 11171 ], function(extensions, File, Basic, Dom, Events, Mime, Env) { 9342 11172 9343 11173 function FileInput() { 9344 var _uid, _mimes = [], _options ;11174 var _uid, _mimes = [], _options, _browseBtnZIndex; // save original z-index; 9345 11175 9346 11176 function addInput() { 9347 11177 var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid; … … 9348 11178 9349 11179 uid = Basic.guid('uid_'); 9350 11180 9351 shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE11181 shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE 9352 11182 9353 11183 if (_uid) { // move previous form out of the view 9354 11184 currForm = Dom.get(_uid + '_form'); 9355 11185 if (currForm) { 9356 11186 Basic.extend(currForm.style, { top: '100%' }); 11187 // it shouldn't be possible to tab into the hidden element 11188 currForm.firstChild.setAttribute('tabindex', -1); 9357 11189 } 9358 11190 } 9359 11191 … … 9376 11208 input = document.createElement('input'); 9377 11209 input.setAttribute('id', uid); 9378 11210 input.setAttribute('type', 'file'); 9379 input.setAttribute('name', _options.name || 'Filedata');9380 11211 input.setAttribute('accept', _mimes.join(',')); 9381 11212 11213 if (I.can('summon_file_dialog')) { 11214 input.setAttribute('tabindex', -1); 11215 } 11216 9382 11217 Basic.extend(input.style, { 9383 11218 fontSize: '999px', 9384 11219 opacity: 0 … … 9411 11246 9412 11247 if (this.files) { // check if browser is fresh enough 9413 11248 file = this.files[0]; 9414 9415 // ignore empty files (IE10 for example hangs if you try to send them via XHR)9416 if (file.size === 0) {9417 form.parentNode.removeChild(form);9418 return;9419 }9420 11249 } else { 9421 11250 file = { 9422 11251 name: this.value … … 9464 11293 9465 11294 // figure out accept string 9466 11295 _options = options; 9467 _mimes = options.accept.mimes ||Mime.extList2mimes(options.accept, I.can('filter_by_extension'));11296 _mimes = Mime.extList2mimes(options.accept, I.can('filter_by_extension')); 9468 11297 9469 11298 shimContainer = I.getShimContainer(); 9470 11299 … … 9472 11301 var browseButton, zIndex, top; 9473 11302 9474 11303 browseButton = Dom.get(options.browse_button); 11304 _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto'; 9475 11305 9476 11306 // Route click event to the input[type=file] element for browsers that support such behavior 9477 11307 if (I.can('summon_file_dialog')) { 9478 11308 if (Dom.getStyle(browseButton, 'position') === 'static') { 9479 11309 browseButton.style.position = 'relative'; 9480 } 11310 } 9481 11311 9482 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; 11312 comp.bind('Refresh', function() { 11313 zIndex = parseInt(_browseBtnZIndex, 10) || 1; 9483 11314 9484 browseButton.style.zIndex = zIndex; 9485 shimContainer.style.zIndex = zIndex - 1; 11315 Dom.get(_options.browse_button).style.zIndex = zIndex; 11316 this.getRuntime().getShimContainer().style.zIndex = zIndex - 1; 11317 }); 11318 } else { 11319 // it shouldn't be possible to tab into the hidden element 11320 browseButton.setAttribute('tabindex', -1); 9486 11321 } 9487 11322 9488 11323 /* Since we have to place input[type=file] on top of the browse_button for some browsers, … … 9519 11354 }); 9520 11355 }, 9521 11356 11357 setOption: function(name, value) { 11358 var I = this.getRuntime(); 11359 var input; 9522 11360 11361 if (name == 'accept') { 11362 _mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension')); 11363 } 11364 11365 // update current input 11366 input = Dom.get(_uid) 11367 if (input) { 11368 input.setAttribute('accept', _mimes.join(',')); 11369 } 11370 }, 11371 11372 9523 11373 disable: function(state) { 9524 11374 var input; 9525 11375 … … 9532 11382 var I = this.getRuntime() 9533 11383 , shim = I.getShim() 9534 11384 , shimContainer = I.getShimContainer() 11385 , container = _options && Dom.get(_options.container) 11386 , browseButton = _options && Dom.get(_options.browse_button) 9535 11387 ; 9536 11388 9537 Events.removeAllEvents(shimContainer, this.uid);9538 Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);9539 Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);11389 if (container) { 11390 Events.removeAllEvents(container, this.uid); 11391 } 9540 11392 11393 if (browseButton) { 11394 Events.removeAllEvents(browseButton, this.uid); 11395 browseButton.style.zIndex = _browseBtnZIndex; // reset to original value 11396 } 11397 9541 11398 if (shimContainer) { 11399 Events.removeAllEvents(shimContainer, this.uid); 9542 11400 shimContainer.innerHTML = ''; 9543 11401 } 9544 11402 9545 11403 shim.removeInstance(this.uid); 9546 11404 9547 _uid = _mimes = _options = shimContainer = shim = null;11405 _uid = _mimes = _options = shimContainer = container = browseButton = shim = null; 9548 11406 } 9549 11407 }); 9550 11408 } … … 9817 11675 // target.dispatchEvent('readystatechange'); 9818 11676 target.dispatchEvent('abort'); 9819 11677 }); 11678 }, 11679 11680 destroy: function() { 11681 this.getRuntime().getShim().removeInstance(this.uid); 9820 11682 } 9821 11683 }); 9822 11684 } … … 9847 11709 return (extensions.Image = Image); 9848 11710 }); 9849 11711 9850 expose(["moxie/core/utils/Basic","moxie/core/utils/En v","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/FileInput","moxie/core/utils/Encode","moxie/file/Blob","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]);11712 expose(["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Dom","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/core/I18n","moxie/core/utils/Mime","moxie/file/FileInput","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/image/Image","moxie/core/utils/Events","moxie/runtime/html5/image/ResizerCanvas"]); 9851 11713 })(this); 9852 /** 9853 * o.js 9854 * 9855 * Copyright 2013, Moxiecode Systems AB 9856 * Released under GPL License. 9857 * 9858 * License: http://www.plupload.com/license 9859 * Contributing: http://www.plupload.com/contributing 9860 */ 9861 9862 /*global moxie:true */ 9863 9864 /** 9865 Globally exposed namespace with the most frequently used public classes and handy methods. 9866 9867 @class o 9868 @static 9869 @private 9870 */ 9871 (function(exports) { 9872 "use strict"; 9873 9874 var o = {}, inArray = exports.moxie.core.utils.Basic.inArray; 9875 9876 // directly add some public classes 9877 // (we do it dynamically here, since for custom builds we cannot know beforehand what modules were included) 9878 (function addAlias(ns) { 9879 var name, itemType; 9880 for (name in ns) { 9881 itemType = typeof(ns[name]); 9882 if (itemType === 'object' && !~inArray(name, ['Exceptions', 'Env', 'Mime'])) { 9883 addAlias(ns[name]); 9884 } else if (itemType === 'function') { 9885 o[name] = ns[name]; 9886 } 9887 } 9888 })(exports.moxie); 9889 9890 // add some manually 9891 o.Env = exports.moxie.core.utils.Env; 9892 o.Mime = exports.moxie.core.utils.Mime; 9893 o.Exceptions = exports.moxie.core.Exceptions; 9894 9895 // expose globally 9896 exports.mOxie = o; 9897 if (!exports.o) { 9898 exports.o = o; 9899 } 9900 return o; 9901 })(this); 11714 })); 11715 No newline at end of file -
src/js/_enqueues/vendor/plupload/plupload.js
1 1 /** 2 2 * Plupload - multi-runtime File Uploader 3 * v2. 1.93 * v2.3.6 4 4 * 5 5 * Copyright 2013, Moxiecode Systems AB 6 6 * Released under GPL License. … … 8 8 * License: http://www.plupload.com/license 9 9 * Contributing: http://www.plupload.com/contributing 10 10 * 11 * Date: 201 6-05-1511 * Date: 2017-11-03 12 12 */ 13 /** 14 * Plupload.js 15 * 16 * Copyright 2013, Moxiecode Systems AB 17 * Released under GPL License. 18 * 19 * License: http://www.plupload.com/license 20 * Contributing: http://www.plupload.com/contributing 21 */ 13 ; 14 (function(global, factory) { 15 var extract = function() { 16 var ctx = {}; 17 factory.apply(ctx, arguments); 18 return ctx.plupload; 19 }; 22 20 23 /** 24 * Modified for WordPress, Silverlight and Flash runtimes support was removed. 25 * See https://core.trac.wordpress.org/ticket/41755. 26 */ 21 if (typeof define === "function" && define.amd) { 22 define("plupload", ['./moxie'], extract); 23 } else if (typeof module === "object" && module.exports) { 24 module.exports = extract(require('./moxie')); 25 } else { 26 global.plupload = extract(global.moxie); 27 } 28 }(this || window, function(moxie) { 29 /** 30 * Plupload.js 31 * 32 * Copyright 2013, Moxiecode Systems AB 33 * Released under GPL License. 34 * 35 * License: http://www.plupload.com/license 36 * Contributing: http://www.plupload.com/contributing 37 */ 27 38 28 /*global mOxie:true */ 39 ; 40 (function(exports, o, undef) { 29 41 30 ;(function(window, o, undef) { 42 var delay = window.setTimeout; 43 var fileFilters = {}; 44 var u = o.core.utils; 45 var Runtime = o.runtime.Runtime; 31 46 32 var delay = window.setTimeout 33 , fileFilters = {} 34 ; 47 // convert plupload features to caps acceptable by mOxie 48 function normalizeCaps(settings) { 49 var features = settings.required_features, 50 caps = {}; 35 51 36 // convert plupload features to caps acceptable by mOxie 37 function normalizeCaps(settings) { 38 var features = settings.required_features, caps = {}; 52 function resolve(feature, value, strict) { 53 // Feature notation is deprecated, use caps (this thing here is required for backward compatibility) 54 var map = { 55 chunks: 'slice_blob', 56 jpgresize: 'send_binary_string', 57 pngresize: 'send_binary_string', 58 progress: 'report_upload_progress', 59 multi_selection: 'select_multiple', 60 dragdrop: 'drag_and_drop', 61 drop_element: 'drag_and_drop', 62 headers: 'send_custom_headers', 63 urlstream_upload: 'send_binary_string', 64 canSendBinary: 'send_binary', 65 triggerDialog: 'summon_file_dialog' 66 }; 39 67 40 function resolve(feature, value, strict) { 41 // Feature notation is deprecated, use caps (this thing here is required for backward compatibility) 42 var map = { 43 chunks: 'slice_blob', 44 jpgresize: 'send_binary_string', 45 pngresize: 'send_binary_string', 46 progress: 'report_upload_progress', 47 multi_selection: 'select_multiple', 48 dragdrop: 'drag_and_drop', 49 drop_element: 'drag_and_drop', 50 headers: 'send_custom_headers', 51 urlstream_upload: 'send_binary_string', 52 canSendBinary: 'send_binary', 53 triggerDialog: 'summon_file_dialog' 54 }; 68 if (map[feature]) { 69 caps[map[feature]] = value; 70 } else if (!strict) { 71 caps[feature] = value; 72 } 73 } 55 74 56 if (map[feature]) { 57 caps[map[feature]] = value; 58 } else if (!strict) { 59 caps[feature] = value; 60 } 61 } 75 if (typeof(features) === 'string') { 76 plupload.each(features.split(/\s*,\s*/), function(feature) { 77 resolve(feature, true); 78 }); 79 } else if (typeof(features) === 'object') { 80 plupload.each(features, function(value, feature) { 81 resolve(feature, value); 82 }); 83 } else if (features === true) { 84 // check settings for required features 85 if (settings.chunk_size && settings.chunk_size > 0) { 86 caps.slice_blob = true; 87 } 62 88 63 if (typeof(features) === 'string') { 64 plupload.each(features.split(/\s*,\s*/), function(feature) { 65 resolve(feature, true); 66 }); 67 } else if (typeof(features) === 'object') { 68 plupload.each(features, function(value, feature) { 69 resolve(feature, value); 70 }); 71 } else if (features === true) { 72 // check settings for required features 73 if (settings.chunk_size > 0) { 74 caps.slice_blob = true; 75 } 89 if (!plupload.isEmptyObj(settings.resize) || settings.multipart === false) { 90 caps.send_binary_string = true; 91 } 76 92 77 if (settings.resize.enabled || !settings.multipart) { 78 caps.send_binary_string = true; 93 if (settings.http_method) { 94 caps.use_http_method = settings.http_method; 95 } 96 97 plupload.each(settings, function(value, feature) { 98 resolve(feature, !!value, true); // strict check 99 }); 100 } 101 102 return caps; 79 103 } 80 81 plupload.each(settings, function(value, feature) {82 resolve(feature, !!value, true); // strict check83 });84 }85 104 86 // WP: only html runtimes. 87 settings.runtimes = 'html5,html4'; 105 /** 106 * @module plupload 107 * @static 108 */ 109 var plupload = { 110 /** 111 * Plupload version will be replaced on build. 112 * 113 * @property VERSION 114 * @for Plupload 115 * @static 116 * @final 117 */ 118 VERSION: '2.3.6', 88 119 89 return caps; 90 } 120 /** 121 * The state of the queue before it has started and after it has finished 122 * 123 * @property STOPPED 124 * @static 125 * @final 126 */ 127 STOPPED: 1, 91 128 92 /** 93 * @module plupload 94 * @static 95 */ 96 var plupload = { 97 /** 98 * Plupload version will be replaced on build. 99 * 100 * @property VERSION 101 * @for Plupload 102 * @static 103 * @final 104 */ 105 VERSION : '2.1.9', 129 /** 130 * Upload process is running 131 * 132 * @property STARTED 133 * @static 134 * @final 135 */ 136 STARTED: 2, 106 137 107 /**108 * The state of the queue before it has started and after it has finished109 *110 * @property STOPPED111 * @static112 * @final113 */114 STOPPED: 1,138 /** 139 * File is queued for upload 140 * 141 * @property QUEUED 142 * @static 143 * @final 144 */ 145 QUEUED: 1, 115 146 116 /**117 * Upload process is running118 *119 * @property STARTED120 * @static121 * @final122 */123 STARTED: 2,147 /** 148 * File is being uploaded 149 * 150 * @property UPLOADING 151 * @static 152 * @final 153 */ 154 UPLOADING: 2, 124 155 125 /**126 * File is queued for upload127 *128 * @property QUEUED129 * @static130 * @final131 */132 QUEUED : 1,156 /** 157 * File has failed to be uploaded 158 * 159 * @property FAILED 160 * @static 161 * @final 162 */ 163 FAILED: 4, 133 164 134 /**135 * File is being uploaded136 *137 * @property UPLOADING138 * @static139 * @final140 */141 UPLOADING : 2,165 /** 166 * File has been uploaded successfully 167 * 168 * @property DONE 169 * @static 170 * @final 171 */ 172 DONE: 5, 142 173 143 /** 144 * File has failed to be uploaded 145 * 146 * @property FAILED 147 * @static 148 * @final 149 */ 150 FAILED : 4, 174 // Error constants used by the Error event 151 175 152 /**153 * File has been uploaded successfully154 *155 * @property DONE156 * @static157 * @final158 */159 DONE : 5,176 /** 177 * Generic error for example if an exception is thrown inside Silverlight. 178 * 179 * @property GENERIC_ERROR 180 * @static 181 * @final 182 */ 183 GENERIC_ERROR: -100, 160 184 161 // Error constants used by the Error event 185 /** 186 * HTTP transport error. For example if the server produces a HTTP status other than 200. 187 * 188 * @property HTTP_ERROR 189 * @static 190 * @final 191 */ 192 HTTP_ERROR: -200, 162 193 163 /**164 * Generic error for example if an exception is thrown inside Silverlight.165 *166 * @property GENERIC_ERROR167 * @static168 * @final169 */170 GENERIC_ERROR : -100,194 /** 195 * Generic I/O error. For example if it wasn't possible to open the file stream on local machine. 196 * 197 * @property IO_ERROR 198 * @static 199 * @final 200 */ 201 IO_ERROR: -300, 171 202 172 /** 173 * HTTP transport error. For example if the server produces a HTTP status other than 200. 174 * 175 * @property HTTP_ERROR 176 * @static 177 * @final 178 */ 179 HTTP_ERROR : -200, 203 /** 204 * @property SECURITY_ERROR 205 * @static 206 * @final 207 */ 208 SECURITY_ERROR: -400, 180 209 181 /**182 * Generic I/O error. For example if it wasn't possible to open the file stream on local machine.183 *184 * @property IO_ERROR185 * @static186 * @final187 */188 IO_ERROR : -300,210 /** 211 * Initialization error. Will be triggered if no runtime was initialized. 212 * 213 * @property INIT_ERROR 214 * @static 215 * @final 216 */ 217 INIT_ERROR: -500, 189 218 190 /** 191 * @property SECURITY_ERROR 192 * @static 193 * @final 194 */ 195 SECURITY_ERROR : -400, 219 /** 220 * File size error. If the user selects a file that is too large or is empty it will be blocked and 221 * an error of this type will be triggered. 222 * 223 * @property FILE_SIZE_ERROR 224 * @static 225 * @final 226 */ 227 FILE_SIZE_ERROR: -600, 196 228 197 /**198 * Initialization error. Will be triggered if no runtime was initialized.199 *200 * @property INIT_ERROR201 * @static202 * @final203 */204 INIT_ERROR : -500,229 /** 230 * File extension error. If the user selects a file that isn't valid according to the filters setting. 231 * 232 * @property FILE_EXTENSION_ERROR 233 * @static 234 * @final 235 */ 236 FILE_EXTENSION_ERROR: -601, 205 237 206 /**207 * File size error. If the user selects a file that is too large it will be blocked and an error of this type will be triggered.208 *209 * @property FILE_SIZE_ERROR210 * @static211 * @final212 */213 FILE_SIZE_ERROR : -600,238 /** 239 * Duplicate file error. If prevent_duplicates is set to true and user selects the same file again. 240 * 241 * @property FILE_DUPLICATE_ERROR 242 * @static 243 * @final 244 */ 245 FILE_DUPLICATE_ERROR: -602, 214 246 215 /**216 * File extension error. If the user selects a file that isn't valid according to the filters setting.217 *218 * @property FILE_EXTENSION_ERROR219 * @static220 * @final221 */222 FILE_EXTENSION_ERROR : -601,247 /** 248 * Runtime will try to detect if image is proper one. Otherwise will throw this error. 249 * 250 * @property IMAGE_FORMAT_ERROR 251 * @static 252 * @final 253 */ 254 IMAGE_FORMAT_ERROR: -700, 223 255 224 /** 225 * Duplicate file error. If prevent_duplicates is set to true and user selects the same file again. 226 * 227 * @property FILE_DUPLICATE_ERROR 228 * @static 229 * @final 230 */ 231 FILE_DUPLICATE_ERROR : -602, 256 /** 257 * While working on files runtime may run out of memory and will throw this error. 258 * 259 * @since 2.1.2 260 * @property MEMORY_ERROR 261 * @static 262 * @final 263 */ 264 MEMORY_ERROR: -701, 232 265 233 /**234 * Runtime will try to detect if image is proper one. Otherwisewill throw this error.235 *236 * @property IMAGE_FORMAT_ERROR237 * @static238 * @final239 */240 IMAGE_FORMAT_ERROR : -700,266 /** 267 * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error. 268 * 269 * @property IMAGE_DIMENSIONS_ERROR 270 * @static 271 * @final 272 */ 273 IMAGE_DIMENSIONS_ERROR: -702, 241 274 242 /** 243 * While working on files runtime may run out of memory and will throw this error. 244 * 245 * @since 2.1.2 246 * @property MEMORY_ERROR 247 * @static 248 * @final 249 */ 250 MEMORY_ERROR : -701, 275 /** 276 * Expose whole moxie (#1469). 277 * 278 * @property moxie 279 * @type Object 280 * @final 281 */ 282 moxie: o, 251 283 252 /**253 * Each runtime has an upper limit on a dimension of the image it can handle. If bigger, will throw this error.254 *255 * @property IMAGE_DIMENSIONS_ERROR256 * @static257 * @final258 */259 IMAGE_DIMENSIONS_ERROR : -702,284 /** 285 * Mime type lookup table. 286 * 287 * @property mimeTypes 288 * @type Object 289 * @final 290 */ 291 mimeTypes: u.Mime.mimes, 260 292 261 /** 262 * Mime type lookup table. 263 * 264 * @property mimeTypes 265 * @type Object 266 * @final 267 */ 268 mimeTypes : o.mimes, 293 /** 294 * In some cases sniffing is the only way around :( 295 */ 296 ua: u.Env, 269 297 270 /** 271 * In some cases sniffing is the only way around :( 272 */ 273 ua: o.ua, 298 /** 299 * Gets the true type of the built-in object (better version of typeof). 300 * @credits Angus Croll (http://javascriptweblog.wordpress.com/) 301 * 302 * @method typeOf 303 * @static 304 * @param {Object} o Object to check. 305 * @return {String} Object [[Class]] 306 */ 307 typeOf: u.Basic.typeOf, 274 308 275 /**276 * Gets the true type of the built-in object (better version of typeof).277 * @credits Angus Croll (http://javascriptweblog.wordpress.com/)278 *279 * @method typeOf280 * @static281 * @param {Object} o Object to check.282 * @return {String} Object [[Class]]283 */284 typeOf: o.typeOf,309 /** 310 * Extends the specified object with another object. 311 * 312 * @method extend 313 * @static 314 * @param {Object} target Object to extend. 315 * @param {Object..} obj Multiple objects to extend with. 316 * @return {Object} Same as target, the extended object. 317 */ 318 extend: u.Basic.extend, 285 319 286 /** 287 * Extends the specified object with another object. 288 * 289 * @method extend 290 * @static 291 * @param {Object} target Object to extend. 292 * @param {Object..} obj Multiple objects to extend with. 293 * @return {Object} Same as target, the extended object. 294 */ 295 extend : o.extend, 320 /** 321 * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers. 322 * The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages 323 * to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique. 324 * It's more probable for the earth to be hit with an asteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property 325 * to an user unique key. 326 * 327 * @method guid 328 * @static 329 * @return {String} Virtually unique id. 330 */ 331 guid: u.Basic.guid, 296 332 297 /** 298 * Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers. 299 * The only way a user would be able to get the same ID is if the two persons at the same exact millisecond manages 300 * to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique. 301 * It's more probable for the earth to be hit with an asteriod. You can also if you want to be 100% sure set the plupload.guidPrefix property 302 * to an user unique key. 303 * 304 * @method guid 305 * @static 306 * @return {String} Virtually unique id. 307 */ 308 guid : o.guid, 333 /** 334 * Get array of DOM Elements by their ids. 335 * 336 * @method get 337 * @param {String} id Identifier of the DOM Element 338 * @return {Array} 339 */ 340 getAll: function get(ids) { 341 var els = [], 342 el; 309 343 310 /** 311 * Get array of DOM Elements by their ids. 312 * 313 * @method get 314 * @param {String} id Identifier of the DOM Element 315 * @return {Array} 316 */ 317 getAll : function get(ids) { 318 var els = [], el; 344 if (plupload.typeOf(ids) !== 'array') { 345 ids = [ids]; 346 } 319 347 320 if (plupload.typeOf(ids) !== 'array') { 321 ids = [ids]; 322 } 348 var i = ids.length; 349 while (i--) { 350 el = plupload.get(ids[i]); 351 if (el) { 352 els.push(el); 353 } 354 } 323 355 324 var i = ids.length; 325 while (i--) { 326 el = plupload.get(ids[i]); 327 if (el) { 328 els.push(el); 329 } 330 } 356 return els.length ? els : null; 357 }, 331 358 332 return els.length ? els : null;333 },359 /** 360 Get DOM element by id 334 361 335 /** 336 Get DOM element by id 362 @method get 363 @param {String} id Identifier of the DOM Element 364 @return {Node} 365 */ 366 get: u.Dom.get, 337 367 338 @method get 339 @param {String} id Identifier of the DOM Element 340 @return {Node} 341 */ 342 get: o.get, 368 /** 369 * Executes the callback function for each item in array/object. If you return false in the 370 * callback it will break the loop. 371 * 372 * @method each 373 * @static 374 * @param {Object} obj Object to iterate. 375 * @param {function} callback Callback function to execute for each item. 376 */ 377 each: u.Basic.each, 343 378 344 /**345 * Executes the callback function for each item in array/object. If you return false in the346 * callback it will break the loop.347 *348 * @method each349 * @static350 * @param {Object} obj Object to iterate.351 * @param {function} callback Callback function to execute for each item.352 */353 each : o.each,379 /** 380 * Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. 381 * 382 * @method getPos 383 * @static 384 * @param {Element} node HTML element or element id to get x, y position from. 385 * @param {Element} root Optional root element to stop calculations at. 386 * @return {object} Absolute position of the specified element object with x, y fields. 387 */ 388 getPos: u.Dom.getPos, 354 389 355 /** 356 * Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. 357 * 358 * @method getPos 359 * @static 360 * @param {Element} node HTML element or element id to get x, y position from. 361 * @param {Element} root Optional root element to stop calculations at. 362 * @return {object} Absolute position of the specified element object with x, y fields. 363 */ 364 getPos : o.getPos, 390 /** 391 * Returns the size of the specified node in pixels. 392 * 393 * @method getSize 394 * @static 395 * @param {Node} node Node to get the size of. 396 * @return {Object} Object with a w and h property. 397 */ 398 getSize: u.Dom.getSize, 365 399 366 /** 367 * Returns the size of the specified node in pixels. 368 * 369 * @method getSize 370 * @static 371 * @param {Node} node Node to get the size of. 372 * @return {Object} Object with a w and h property. 373 */ 374 getSize : o.getSize, 400 /** 401 * Encodes the specified string. 402 * 403 * @method xmlEncode 404 * @static 405 * @param {String} s String to encode. 406 * @return {String} Encoded string. 407 */ 408 xmlEncode: function(str) { 409 var xmlEncodeChars = { 410 '<': 'lt', 411 '>': 'gt', 412 '&': 'amp', 413 '"': 'quot', 414 '\'': '#39' 415 }, 416 xmlEncodeRegExp = /[<>&\"\']/g; 375 417 376 /** 377 * Encodes the specified string. 378 * 379 * @method xmlEncode 380 * @static 381 * @param {String} s String to encode. 382 * @return {String} Encoded string. 383 */ 384 xmlEncode : function(str) { 385 var xmlEncodeChars = {'<' : 'lt', '>' : 'gt', '&' : 'amp', '"' : 'quot', '\'' : '#39'}, xmlEncodeRegExp = /[<>&\"\']/g; 418 return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) { 419 return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr; 420 }) : str; 421 }, 386 422 387 return str ? ('' + str).replace(xmlEncodeRegExp, function(chr) { 388 return xmlEncodeChars[chr] ? '&' + xmlEncodeChars[chr] + ';' : chr; 389 }) : str; 390 }, 423 /** 424 * Forces anything into an array. 425 * 426 * @method toArray 427 * @static 428 * @param {Object} obj Object with length field. 429 * @return {Array} Array object containing all items. 430 */ 431 toArray: u.Basic.toArray, 391 432 392 /** 393 * Forces anything into an array. 394 * 395 * @method toArray 396 * @static 397 * @param {Object} obj Object with length field. 398 * @return {Array} Array object containing all items. 399 */ 400 toArray : o.toArray, 433 /** 434 * Find an element in array and return its index if present, otherwise return -1. 435 * 436 * @method inArray 437 * @static 438 * @param {mixed} needle Element to find 439 * @param {Array} array 440 * @return {Int} Index of the element, or -1 if not found 441 */ 442 inArray: u.Basic.inArray, 401 443 402 /** 403 * Find an element in array and return its index if present, otherwise return -1. 404 * 405 * @method inArray 406 * @static 407 * @param {mixed} needle Element to find 408 * @param {Array} array 409 * @return {Int} Index of the element, or -1 if not found 410 */ 411 inArray : o.inArray, 444 /** 445 Recieve an array of functions (usually async) to call in sequence, each function 446 receives a callback as first argument that it should call, when it completes. Finally, 447 after everything is complete, main callback is called. Passing truthy value to the 448 callback as a first argument will interrupt the sequence and invoke main callback 449 immediately. 412 450 413 /** 414 * Extends the language pack object with new items. 415 * 416 * @method addI18n 417 * @static 418 * @param {Object} pack Language pack items to add. 419 * @return {Object} Extended language pack object. 420 */ 421 addI18n : o.addI18n, 451 @method inSeries 452 @static 453 @param {Array} queue Array of functions to call in sequence 454 @param {Function} cb Main callback that is called in the end, or in case of error 455 */ 456 inSeries: u.Basic.inSeries, 422 457 423 /**424 * Translates the specified string by checking for the english string in the language pack lookup.425 *426 * @method translate427 * @static428 * @param {String} str String to look for.429 * @return {String} Translated string or the input string if it wasn't found.430 */431 translate : o.translate,458 /** 459 * Extends the language pack object with new items. 460 * 461 * @method addI18n 462 * @static 463 * @param {Object} pack Language pack items to add. 464 * @return {Object} Extended language pack object. 465 */ 466 addI18n: o.core.I18n.addI18n, 432 467 433 /**434 * Checks if object is empty.435 *436 * @method isEmptyObj437 * @static438 * @param {Object} obj Object to check.439 * @return {Boolean}440 */441 isEmptyObj : o.isEmptyObj,468 /** 469 * Translates the specified string by checking for the english string in the language pack lookup. 470 * 471 * @method translate 472 * @static 473 * @param {String} str String to look for. 474 * @return {String} Translated string or the input string if it wasn't found. 475 */ 476 translate: o.core.I18n.translate, 442 477 443 /** 444 * Checks if specified DOM element has specified class. 445 * 446 * @method hasClass 447 * @static 448 * @param {Object} obj DOM element like object to add handler to. 449 * @param {String} name Class name 450 */ 451 hasClass : o.hasClass, 478 /** 479 * Pseudo sprintf implementation - simple way to replace tokens with specified values. 480 * 481 * @param {String} str String with tokens 482 * @return {String} String with replaced tokens 483 */ 484 sprintf: u.Basic.sprintf, 452 485 453 /**454 * Adds specified className to specified DOM element.455 *456 * @method addClass457 * @static458 * @param {Object} obj DOM element like object to add handler to.459 * @param {String} name Class name460 */461 addClass : o.addClass,486 /** 487 * Checks if object is empty. 488 * 489 * @method isEmptyObj 490 * @static 491 * @param {Object} obj Object to check. 492 * @return {Boolean} 493 */ 494 isEmptyObj: u.Basic.isEmptyObj, 462 495 463 /**464 * Removes specified className from specified DOM element.465 *466 * @method removeClass467 * @static468 * @param {Object} obj DOM element like object to add handler to.469 * @param {String} name Class name470 */471 removeClass : o.removeClass,496 /** 497 * Checks if specified DOM element has specified class. 498 * 499 * @method hasClass 500 * @static 501 * @param {Object} obj DOM element like object to add handler to. 502 * @param {String} name Class name 503 */ 504 hasClass: u.Dom.hasClass, 472 505 473 /**474 * Returns a given computed style of aDOM element.475 *476 * @method getStyle477 * @static478 * @param {Object} obj DOM element like object.479 * @param {String} name Style you want to get from the DOM element480 */481 getStyle : o.getStyle,506 /** 507 * Adds specified className to specified DOM element. 508 * 509 * @method addClass 510 * @static 511 * @param {Object} obj DOM element like object to add handler to. 512 * @param {String} name Class name 513 */ 514 addClass: u.Dom.addClass, 482 515 483 /** 484 * Adds an event handler to the specified object and store reference to the handler 485 * in objects internal Plupload registry (@see removeEvent). 486 * 487 * @method addEvent 488 * @static 489 * @param {Object} obj DOM element like object to add handler to. 490 * @param {String} name Name to add event listener to. 491 * @param {Function} callback Function to call when event occurs. 492 * @param {String} (optional) key that might be used to add specifity to the event record. 493 */ 494 addEvent : o.addEvent, 516 /** 517 * Removes specified className from specified DOM element. 518 * 519 * @method removeClass 520 * @static 521 * @param {Object} obj DOM element like object to add handler to. 522 * @param {String} name Class name 523 */ 524 removeClass: u.Dom.removeClass, 495 525 496 /** 497 * Remove event handler from the specified object. If third argument (callback) 498 * is not specified remove all events with the specified name. 499 * 500 * @method removeEvent 501 * @static 502 * @param {Object} obj DOM element to remove event listener(s) from. 503 * @param {String} name Name of event listener to remove. 504 * @param {Function|String} (optional) might be a callback or unique key to match. 505 */ 506 removeEvent: o.removeEvent, 526 /** 527 * Returns a given computed style of a DOM element. 528 * 529 * @method getStyle 530 * @static 531 * @param {Object} obj DOM element like object. 532 * @param {String} name Style you want to get from the DOM element 533 */ 534 getStyle: u.Dom.getStyle, 507 535 508 /** 509 * Remove all kind of events from the specified object 510 * 511 * @method removeAllEvents 512 * @static 513 * @param {Object} obj DOM element to remove event listeners from. 514 * @param {String} (optional) unique key to match, when removing events. 515 */ 516 removeAllEvents: o.removeAllEvents, 536 /** 537 * Adds an event handler to the specified object and store reference to the handler 538 * in objects internal Plupload registry (@see removeEvent). 539 * 540 * @method addEvent 541 * @static 542 * @param {Object} obj DOM element like object to add handler to. 543 * @param {String} name Name to add event listener to. 544 * @param {Function} callback Function to call when event occurs. 545 * @param {String} (optional) key that might be used to add specifity to the event record. 546 */ 547 addEvent: u.Events.addEvent, 517 548 518 /** 519 * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _. 520 * 521 * @method cleanName 522 * @static 523 * @param {String} s String to clean up. 524 * @return {String} Cleaned string. 525 */ 526 cleanName : function(name) { 527 var i, lookup; 549 /** 550 * Remove event handler from the specified object. If third argument (callback) 551 * is not specified remove all events with the specified name. 552 * 553 * @method removeEvent 554 * @static 555 * @param {Object} obj DOM element to remove event listener(s) from. 556 * @param {String} name Name of event listener to remove. 557 * @param {Function|String} (optional) might be a callback or unique key to match. 558 */ 559 removeEvent: u.Events.removeEvent, 528 560 529 // Replace diacritics 530 lookup = [ 531 /[\300-\306]/g, 'A', /[\340-\346]/g, 'a', 532 /\307/g, 'C', /\347/g, 'c', 533 /[\310-\313]/g, 'E', /[\350-\353]/g, 'e', 534 /[\314-\317]/g, 'I', /[\354-\357]/g, 'i', 535 /\321/g, 'N', /\361/g, 'n', 536 /[\322-\330]/g, 'O', /[\362-\370]/g, 'o', 537 /[\331-\334]/g, 'U', /[\371-\374]/g, 'u' 538 ]; 561 /** 562 * Remove all kind of events from the specified object 563 * 564 * @method removeAllEvents 565 * @static 566 * @param {Object} obj DOM element to remove event listeners from. 567 * @param {String} (optional) unique key to match, when removing events. 568 */ 569 removeAllEvents: u.Events.removeAllEvents, 539 570 540 for (i = 0; i < lookup.length; i += 2) { 541 name = name.replace(lookup[i], lookup[i + 1]); 542 } 571 /** 572 * Cleans the specified name from national characters (diacritics). The result will be a name with only a-z, 0-9 and _. 573 * 574 * @method cleanName 575 * @static 576 * @param {String} s String to clean up. 577 * @return {String} Cleaned string. 578 */ 579 cleanName: function(name) { 580 var i, lookup; 543 581 544 // Replace whitespace 545 name = name.replace(/\s+/g, '_'); 582 // Replace diacritics 583 lookup = [ 584 /[\300-\306]/g, 'A', /[\340-\346]/g, 'a', 585 /\307/g, 'C', /\347/g, 'c', 586 /[\310-\313]/g, 'E', /[\350-\353]/g, 'e', 587 /[\314-\317]/g, 'I', /[\354-\357]/g, 'i', 588 /\321/g, 'N', /\361/g, 'n', 589 /[\322-\330]/g, 'O', /[\362-\370]/g, 'o', 590 /[\331-\334]/g, 'U', /[\371-\374]/g, 'u' 591 ]; 546 592 547 // Remove anything else 548 name = name.replace(/[^a-z0-9_\-\.]+/gi, ''); 593 for (i = 0; i < lookup.length; i += 2) { 594 name = name.replace(lookup[i], lookup[i + 1]); 595 } 549 596 550 return name;551 },597 // Replace whitespace 598 name = name.replace(/\s+/g, '_'); 552 599 553 /** 554 * Builds a full url out of a base URL and an object with items to append as query string items. 555 * 556 * @method buildUrl 557 * @static 558 * @param {String} url Base URL to append query string items to. 559 * @param {Object} items Name/value object to serialize as a querystring. 560 * @return {String} String with url + serialized query string items. 561 */ 562 buildUrl : function(url, items) { 563 var query = ''; 600 // Remove anything else 601 name = name.replace(/[^a-z0-9_\-\.]+/gi, ''); 564 602 565 plupload.each(items, function(value, name) { 566 query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value); 567 }); 603 return name; 604 }, 568 605 569 if (query) { 570 url += (url.indexOf('?') > 0 ? '&' : '?') + query; 571 } 606 /** 607 * Builds a full url out of a base URL and an object with items to append as query string items. 608 * 609 * @method buildUrl 610 * @static 611 * @param {String} url Base URL to append query string items to. 612 * @param {Object} items Name/value object to serialize as a querystring. 613 * @return {String} String with url + serialized query string items. 614 */ 615 buildUrl: function(url, items) { 616 var query = ''; 572 617 573 return url; 574 }, 618 plupload.each(items, function(value, name) { 619 query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value); 620 }); 575 621 576 /** 577 * Formats the specified number as a size string for example 1024 becomes 1 KB. 578 * 579 * @method formatSize 580 * @static 581 * @param {Number} size Size to format as string. 582 * @return {String} Formatted size string. 583 */ 584 formatSize : function(size) { 622 if (query) { 623 url += (url.indexOf('?') > 0 ? '&' : '?') + query; 624 } 585 625 586 if (size === undef || /\D/.test(size)) { 587 return plupload.translate('N/A'); 588 } 626 return url; 627 }, 589 628 590 function round(num, precision) { 591 return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision); 592 } 629 /** 630 * Formats the specified number as a size string for example 1024 becomes 1 KB. 631 * 632 * @method formatSize 633 * @static 634 * @param {Number} size Size to format as string. 635 * @return {String} Formatted size string. 636 */ 637 formatSize: function(size) { 593 638 594 var boundary = Math.pow(1024, 4); 639 if (size === undef || /\D/.test(size)) { 640 return plupload.translate('N/A'); 641 } 595 642 596 // TB 597 if (size > boundary) { 598 return round(size / boundary, 1) + " " + plupload.translate('tb'); 599 } 643 function round(num, precision) { 644 return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision); 645 } 600 646 601 // GB 602 if (size > (boundary/=1024)) { 603 return round(size / boundary, 1) + " " + plupload.translate('gb'); 604 } 647 var boundary = Math.pow(1024, 4); 605 648 606 // MB607 if (size > (boundary/=1024)) {608 return round(size / boundary, 1) + " " + plupload.translate('mb');609 }649 // TB 650 if (size > boundary) { 651 return round(size / boundary, 1) + " " + plupload.translate('tb'); 652 } 610 653 611 // KB612 if (size > 1024) {613 return Math.round(size / 1024) + " " + plupload.translate('kb');614 }654 // GB 655 if (size > (boundary /= 1024)) { 656 return round(size / boundary, 1) + " " + plupload.translate('gb'); 657 } 615 658 616 return size + " " + plupload.translate('b'); 617 }, 659 // MB 660 if (size > (boundary /= 1024)) { 661 return round(size / boundary, 1) + " " + plupload.translate('mb'); 662 } 618 663 664 // KB 665 if (size > 1024) { 666 return Math.round(size / 1024) + " " + plupload.translate('kb'); 667 } 619 668 620 /** 621 * Parses the specified size string into a byte value. For example 10kb becomes 10240. 622 * 623 * @method parseSize 624 * @static 625 * @param {String|Number} size String to parse or number to just pass through. 626 * @return {Number} Size in bytes. 627 */ 628 parseSize : o.parseSizeStr, 669 return size + " " + plupload.translate('b'); 670 }, 629 671 630 672 631 /** 632 * A way to predict what runtime will be choosen in the current environment with the 633 * specified settings. 634 * 635 * @method predictRuntime 636 * @static 637 * @param {Object|String} config Plupload settings to check 638 * @param {String} [runtimes] Comma-separated list of runtimes to check against 639 * @return {String} Type of compatible runtime 640 */ 641 predictRuntime : function(config, runtimes) { 642 var up, runtime; 673 /** 674 * Parses the specified size string into a byte value. For example 10kb becomes 10240. 675 * 676 * @method parseSize 677 * @static 678 * @param {String|Number} size String to parse or number to just pass through. 679 * @return {Number} Size in bytes. 680 */ 681 parseSize: u.Basic.parseSizeStr, 643 682 644 up = new plupload.Uploader(config);645 runtime = o.Runtime.thatCan(up.getOption().required_features, runtimes || config.runtimes);646 up.destroy();647 return runtime;648 },649 683 650 /** 651 * Registers a filter that will be executed for each file added to the queue. 652 * If callback returns false, file will not be added. 653 * 654 * Callback receives two arguments: a value for the filter as it was specified in settings.filters 655 * and a file to be filtered. Callback is executed in the context of uploader instance. 656 * 657 * @method addFileFilter 658 * @static 659 * @param {String} name Name of the filter by which it can be referenced in settings.filters 660 * @param {String} cb Callback - the actual routine that every added file must pass 661 */ 662 addFileFilter: function(name, cb) { 663 fileFilters[name] = cb; 664 } 665 }; 684 /** 685 * A way to predict what runtime will be choosen in the current environment with the 686 * specified settings. 687 * 688 * @method predictRuntime 689 * @static 690 * @param {Object|String} config Plupload settings to check 691 * @param {String} [runtimes] Comma-separated list of runtimes to check against 692 * @return {String} Type of compatible runtime 693 */ 694 predictRuntime: function(config, runtimes) { 695 var up, runtime; 666 696 697 up = new plupload.Uploader(config); 698 runtime = Runtime.thatCan(up.getOption().required_features, runtimes || config.runtimes); 699 up.destroy(); 700 return runtime; 701 }, 667 702 668 plupload.addFileFilter('mime_types', function(filters, file, cb) { 669 if (filters.length && !filters.regexp.test(file.name)) { 670 this.trigger('Error', { 671 code : plupload.FILE_EXTENSION_ERROR, 672 message : plupload.translate('File extension error.'), 673 file : file 703 /** 704 * Registers a filter that will be executed for each file added to the queue. 705 * If callback returns false, file will not be added. 706 * 707 * Callback receives two arguments: a value for the filter as it was specified in settings.filters 708 * and a file to be filtered. Callback is executed in the context of uploader instance. 709 * 710 * @method addFileFilter 711 * @static 712 * @param {String} name Name of the filter by which it can be referenced in settings.filters 713 * @param {String} cb Callback - the actual routine that every added file must pass 714 */ 715 addFileFilter: function(name, cb) { 716 fileFilters[name] = cb; 717 } 718 }; 719 720 721 plupload.addFileFilter('mime_types', function(filters, file, cb) { 722 if (filters.length && !filters.regexp.test(file.name)) { 723 this.trigger('Error', { 724 code: plupload.FILE_EXTENSION_ERROR, 725 message: plupload.translate('File extension error.'), 726 file: file 727 }); 728 cb(false); 729 } else { 730 cb(true); 731 } 674 732 }); 675 cb(false);676 } else {677 cb(true);678 }679 });680 733 681 734 682 plupload.addFileFilter('max_file_size', function(maxSize, file, cb) {683 var undef;735 plupload.addFileFilter('max_file_size', function(maxSize, file, cb) { 736 var undef; 684 737 685 maxSize = plupload.parseSize(maxSize);738 maxSize = plupload.parseSize(maxSize); 686 739 687 // Invalid file size 688 if (file.size !== undef && maxSize && file.size > maxSize) { 689 this.trigger('Error', { 690 code : plupload.FILE_SIZE_ERROR, 691 message : plupload.translate('File size error.'), 692 file : file 740 // Invalid file size 741 if (file.size !== undef && maxSize && file.size > maxSize) { 742 this.trigger('Error', { 743 code: plupload.FILE_SIZE_ERROR, 744 message: plupload.translate('File size error.'), 745 file: file 746 }); 747 cb(false); 748 } else { 749 cb(true); 750 } 693 751 }); 694 cb(false);695 } else {696 cb(true);697 }698 });699 752 700 753 701 plupload.addFileFilter('prevent_duplicates', function(value, file, cb) { 702 if (value) { 703 var ii = this.files.length; 704 while (ii--) { 705 // Compare by name and size (size might be 0 or undefined, but still equivalent for both) 706 if (file.name === this.files[ii].name && file.size === this.files[ii].size) { 754 plupload.addFileFilter('prevent_duplicates', function(value, file, cb) { 755 if (value) { 756 var ii = this.files.length; 757 while (ii--) { 758 // Compare by name and size (size might be 0 or undefined, but still equivalent for both) 759 if (file.name === this.files[ii].name && file.size === this.files[ii].size) { 760 this.trigger('Error', { 761 code: plupload.FILE_DUPLICATE_ERROR, 762 message: plupload.translate('Duplicate file error.'), 763 file: file 764 }); 765 cb(false); 766 return; 767 } 768 } 769 } 770 cb(true); 771 }); 772 773 plupload.addFileFilter('prevent_empty', function(value, file, cb) { 774 if (value && !file.size && file.size !== undef) { 707 775 this.trigger('Error', { 708 code : plupload.FILE_DUPLICATE_ERROR,709 message : plupload.translate('Duplicate file error.'),710 file 776 code: plupload.FILE_SIZE_ERROR, 777 message: plupload.translate('File size error.'), 778 file: file 711 779 }); 712 780 cb(false); 713 return; 781 } else { 782 cb(true); 714 783 } 715 } 716 } 717 cb(true); 718 }); 784 }); 719 785 720 786 721 /**722 @class Uploader723 @constructor787 /** 788 @class Uploader 789 @constructor 724 790 725 @param {Object} settings For detailed information about each option check documentation. 726 @param {String|DOMElement} settings.browse_button id of the DOM element or DOM element itself to use as file dialog trigger. 727 @param {String} settings.url URL of the server-side upload handler. 728 @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled. 729 @param {Boolean} [settings.send_chunk_number=true] Whether to send chunks and chunk numbers, or total and offset bytes. 730 @param {String|DOMElement} [settings.container] id of the DOM element or DOM element itself that will be used to wrap uploader structures. Defaults to immediate parent of the `browse_button` element. 731 @param {String|DOMElement} [settings.drop_element] id of the DOM element or DOM element itself to use as a drop zone for Drag-n-Drop. 732 @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message. 733 @param {Object} [settings.filters={}] Set of file type filters. 734 @param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR` 735 @param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`. 736 @param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`. 737 @param {String} [settings.flash_swf_url] URL of the Flash swf. (Not used in WordPress) 738 @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs. 739 @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event. 740 @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message. 741 @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload. 742 @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog. 743 @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess. 744 @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}` 745 @param {Number} [settings.resize.width] If image is bigger, it will be resized. 746 @param {Number} [settings.resize.height] If image is bigger, it will be resized. 747 @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100). 748 @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally. 749 @param {String} [settings.runtimes="html5,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails. 750 @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap. (Not used in WordPress) 751 @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files. 752 @param {Boolean} [settings.send_file_name=true] Whether to send file name as additional argument - 'name' (required for chunked uploads and some other cases where file name cannot be sent via normal ways). 753 */ 754 plupload.Uploader = function(options) { 755 /** 756 Fires when the current RunTime has been initialized. 757 758 @event Init 759 @param {plupload.Uploader} uploader Uploader instance sending the event. 760 */ 791 @param {Object} settings For detailed information about each option check documentation. 792 @param {String|DOMElement} settings.browse_button id of the DOM element or DOM element itself to use as file dialog trigger. 793 @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled. 794 @param {String|DOMElement} [settings.container] id of the DOM element or DOM element itself that will be used to wrap uploader structures. Defaults to immediate parent of the `browse_button` element. 795 @param {String|DOMElement} [settings.drop_element] id of the DOM element or DOM element itself to use as a drop zone for Drag-n-Drop. 796 @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message. 797 @param {Object} [settings.filters={}] Set of file type filters. 798 @param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`. 799 @param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR` 800 @param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`. 801 @param {Boolean} [settings.filters.prevent_empty=true] Do not let empty files into the queue (IE10 is known to hang for example when trying to upload such). Dispatches `plupload.FILE_SIZE_ERROR`. 802 @param {String} [settings.flash_swf_url] URL of the Flash swf. 803 @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs. 804 @param {String} [settings.http_method="POST"] HTTP method to use during upload (only PUT or POST allowed). 805 @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event. 806 @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message. 807 @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload. 808 @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog. 809 @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess. 810 @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}` 811 @param {Number} [settings.resize.width] If image is bigger, it will be resized. 812 @param {Number} [settings.resize.height] If image is bigger, it will be resized. 813 @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100). 814 @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally. 815 @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails. 816 @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap. 817 @param {Boolean} [settings.send_chunk_number=true] Whether to send chunks and chunk numbers, or total and offset bytes. 818 @param {Boolean} [settings.send_file_name=true] Whether to send file name as additional argument - 'name' (required for chunked uploads and some other cases where file name cannot be sent via normal ways). 819 @param {String} settings.url URL of the server-side upload handler. 820 @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files. 761 821 762 /** 763 Fires after the init event incase you need to perform actions there. 764 765 @event PostInit 766 @param {plupload.Uploader} uploader Uploader instance sending the event. 767 */ 822 */ 823 plupload.Uploader = function(options) { 824 /** 825 Fires when the current RunTime has been initialized. 768 826 769 /** 770 Fires when the option is changed in via uploader.setOption(). 771 772 @event OptionChanged 773 @since 2.1 774 @param {plupload.Uploader} uploader Uploader instance sending the event. 775 @param {String} name Name of the option that was changed 776 @param {Mixed} value New value for the specified option 777 @param {Mixed} oldValue Previous value of the option 778 */ 827 @event Init 828 @param {plupload.Uploader} uploader Uploader instance sending the event. 829 */ 779 830 780 /** 781 Fires when the silverlight/flash or other shim needs to move. 782 783 @event Refresh 784 @param {plupload.Uploader} uploader Uploader instance sending the event. 785 */ 831 /** 832 Fires after the init event incase you need to perform actions there. 786 833 787 /** 788 Fires when the overall state is being changed for the upload queue. 789 790 @event StateChanged 791 @param {plupload.Uploader} uploader Uploader instance sending the event. 792 */ 834 @event PostInit 835 @param {plupload.Uploader} uploader Uploader instance sending the event. 836 */ 793 837 794 /** 795 Fires when browse_button is clicked and browse dialog shows. 796 797 @event Browse 798 @since 2.1.2 799 @param {plupload.Uploader} uploader Uploader instance sending the event. 800 */ 838 /** 839 Fires when the option is changed in via uploader.setOption(). 801 840 802 /** 803 Fires for every filtered file before it is added to the queue. 804 805 @event FileFiltered 806 @since 2.1 807 @param {plupload.Uploader} uploader Uploader instance sending the event. 808 @param {plupload.File} file Another file that has to be added to the queue. 809 */ 841 @event OptionChanged 842 @since 2.1 843 @param {plupload.Uploader} uploader Uploader instance sending the event. 844 @param {String} name Name of the option that was changed 845 @param {Mixed} value New value for the specified option 846 @param {Mixed} oldValue Previous value of the option 847 */ 810 848 811 /** 812 Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance. 813 814 @event QueueChanged 815 @param {plupload.Uploader} uploader Uploader instance sending the event. 816 */ 849 /** 850 Fires when the silverlight/flash or other shim needs to move. 817 851 818 /** 819 Fires after files were filtered and added to the queue. 820 821 @event FilesAdded 822 @param {plupload.Uploader} uploader Uploader instance sending the event. 823 @param {Array} files Array of file objects that were added to queue by the user. 824 */ 852 @event Refresh 853 @param {plupload.Uploader} uploader Uploader instance sending the event. 854 */ 825 855 826 /** 827 Fires when file is removed from the queue. 828 829 @event FilesRemoved 830 @param {plupload.Uploader} uploader Uploader instance sending the event. 831 @param {Array} files Array of files that got removed. 832 */ 856 /** 857 Fires when the overall state is being changed for the upload queue. 833 858 834 /** 835 Fires just before a file is uploaded. Can be used to cancel the upload for the specified file 836 by returning false from the handler. 837 838 @event BeforeUpload 839 @param {plupload.Uploader} uploader Uploader instance sending the event. 840 @param {plupload.File} file File to be uploaded. 841 */ 859 @event StateChanged 860 @param {plupload.Uploader} uploader Uploader instance sending the event. 861 */ 842 862 843 /** 844 Fires when a file is to be uploaded by the runtime. 845 846 @event UploadFile 847 @param {plupload.Uploader} uploader Uploader instance sending the event. 848 @param {plupload.File} file File to be uploaded. 849 */ 863 /** 864 Fires when browse_button is clicked and browse dialog shows. 850 865 851 /** 852 Fires while a file is being uploaded. Use this event to update the current file upload progress. 853 854 @event UploadProgress 855 @param {plupload.Uploader} uploader Uploader instance sending the event. 856 @param {plupload.File} file File that is currently being uploaded. 857 */ 866 @event Browse 867 @since 2.1.2 868 @param {plupload.Uploader} uploader Uploader instance sending the event. 869 */ 858 870 859 /** 860 Fires when file chunk is uploaded. 861 862 @event ChunkUploaded 863 @param {plupload.Uploader} uploader Uploader instance sending the event. 864 @param {plupload.File} file File that the chunk was uploaded for. 865 @param {Object} result Object with response properties. 866 @param {Number} result.offset The amount of bytes the server has received so far, including this chunk. 867 @param {Number} result.total The size of the file. 868 @param {String} result.response The response body sent by the server. 869 @param {Number} result.status The HTTP status code sent by the server. 870 @param {String} result.responseHeaders All the response headers as a single string. 871 */ 871 /** 872 Fires for every filtered file before it is added to the queue. 872 873 873 /** 874 Fires when a file is successfully uploaded. 875 876 @event FileUploaded 877 @param {plupload.Uploader} uploader Uploader instance sending the event. 878 @param {plupload.File} file File that was uploaded. 879 @param {Object} result Object with response properties. 880 @param {String} result.response The response body sent by the server. 881 @param {Number} result.status The HTTP status code sent by the server. 882 @param {String} result.responseHeaders All the response headers as a single string. 883 */ 874 @event FileFiltered 875 @since 2.1 876 @param {plupload.Uploader} uploader Uploader instance sending the event. 877 @param {plupload.File} file Another file that has to be added to the queue. 878 */ 884 879 885 /** 886 Fires when all files in a queue are uploaded. 887 888 @event UploadComplete 889 @param {plupload.Uploader} uploader Uploader instance sending the event. 890 @param {Array} files Array of file objects that was added to queue/selected by the user. 891 */ 880 /** 881 Fires when the file queue is changed. In other words when files are added/removed to the files array of the uploader instance. 892 882 893 /** 894 Fires when a error occurs. 895 896 @event Error 897 @param {plupload.Uploader} uploader Uploader instance sending the event. 898 @param {Object} error Contains code, message and sometimes file and other details. 899 @param {Number} error.code The plupload error code. 900 @param {String} error.message Description of the error (uses i18n). 901 */ 883 @event QueueChanged 884 @param {plupload.Uploader} uploader Uploader instance sending the event. 885 */ 902 886 903 /** 904 Fires when destroy method is called. 905 906 @event Destroy 907 @param {plupload.Uploader} uploader Uploader instance sending the event. 908 */ 909 var uid = plupload.guid() 910 , settings 911 , files = [] 912 , preferred_caps = {} 913 , fileInputs = [] 914 , fileDrops = [] 915 , startTime 916 , total 917 , disabled = false 918 , xhr 919 ; 887 /** 888 Fires after files were filtered and added to the queue. 920 889 890 @event FilesAdded 891 @param {plupload.Uploader} uploader Uploader instance sending the event. 892 @param {Array} files Array of file objects that were added to queue by the user. 893 */ 921 894 922 // Private methods 923 function uploadNext() { 924 var file, count = 0, i; 895 /** 896 Fires when file is removed from the queue. 925 897 926 if (this.state == plupload.STARTED) { 927 // Find first QUEUED file 928 for (i = 0; i < files.length; i++) { 929 if (!file && files[i].status == plupload.QUEUED) { 930 file = files[i]; 931 if (this.trigger("BeforeUpload", file)) { 932 file.status = plupload.UPLOADING; 933 this.trigger("UploadFile", file); 898 @event FilesRemoved 899 @param {plupload.Uploader} uploader Uploader instance sending the event. 900 @param {Array} files Array of files that got removed. 901 */ 902 903 /** 904 Fires just before a file is uploaded. Can be used to cancel the upload for the specified file 905 by returning false from the handler. 906 907 @event BeforeUpload 908 @param {plupload.Uploader} uploader Uploader instance sending the event. 909 @param {plupload.File} file File to be uploaded. 910 */ 911 912 /** 913 Fires when a file is to be uploaded by the runtime. 914 915 @event UploadFile 916 @param {plupload.Uploader} uploader Uploader instance sending the event. 917 @param {plupload.File} file File to be uploaded. 918 */ 919 920 /** 921 Fires while a file is being uploaded. Use this event to update the current file upload progress. 922 923 @event UploadProgress 924 @param {plupload.Uploader} uploader Uploader instance sending the event. 925 @param {plupload.File} file File that is currently being uploaded. 926 */ 927 928 /** 929 * Fires just before a chunk is uploaded. This event enables you to override settings 930 * on the uploader instance before the chunk is uploaded. 931 * 932 * @event BeforeChunkUpload 933 * @param {plupload.Uploader} uploader Uploader instance sending the event. 934 * @param {plupload.File} file File to be uploaded. 935 * @param {Object} args POST params to be sent. 936 * @param {Blob} chunkBlob Current blob. 937 * @param {offset} offset Current offset. 938 */ 939 940 /** 941 Fires when file chunk is uploaded. 942 943 @event ChunkUploaded 944 @param {plupload.Uploader} uploader Uploader instance sending the event. 945 @param {plupload.File} file File that the chunk was uploaded for. 946 @param {Object} result Object with response properties. 947 @param {Number} result.offset The amount of bytes the server has received so far, including this chunk. 948 @param {Number} result.total The size of the file. 949 @param {String} result.response The response body sent by the server. 950 @param {Number} result.status The HTTP status code sent by the server. 951 @param {String} result.responseHeaders All the response headers as a single string. 952 */ 953 954 /** 955 Fires when a file is successfully uploaded. 956 957 @event FileUploaded 958 @param {plupload.Uploader} uploader Uploader instance sending the event. 959 @param {plupload.File} file File that was uploaded. 960 @param {Object} result Object with response properties. 961 @param {String} result.response The response body sent by the server. 962 @param {Number} result.status The HTTP status code sent by the server. 963 @param {String} result.responseHeaders All the response headers as a single string. 964 */ 965 966 /** 967 Fires when all files in a queue are uploaded. 968 969 @event UploadComplete 970 @param {plupload.Uploader} uploader Uploader instance sending the event. 971 @param {Array} files Array of file objects that was added to queue/selected by the user. 972 */ 973 974 /** 975 Fires when a error occurs. 976 977 @event Error 978 @param {plupload.Uploader} uploader Uploader instance sending the event. 979 @param {Object} error Contains code, message and sometimes file and other details. 980 @param {Number} error.code The plupload error code. 981 @param {String} error.message Description of the error (uses i18n). 982 */ 983 984 /** 985 Fires when destroy method is called. 986 987 @event Destroy 988 @param {plupload.Uploader} uploader Uploader instance sending the event. 989 */ 990 var uid = plupload.guid(), 991 settings, files = [], 992 preferred_caps = {}, 993 fileInputs = [], 994 fileDrops = [], 995 startTime, total, disabled = false, 996 xhr; 997 998 999 // Private methods 1000 function uploadNext() { 1001 var file, count = 0, 1002 i; 1003 1004 if (this.state == plupload.STARTED) { 1005 // Find first QUEUED file 1006 for (i = 0; i < files.length; i++) { 1007 if (!file && files[i].status == plupload.QUEUED) { 1008 file = files[i]; 1009 if (this.trigger("BeforeUpload", file)) { 1010 file.status = plupload.UPLOADING; 1011 this.trigger("UploadFile", file); 1012 } 1013 } else { 1014 count++; 1015 } 934 1016 } 935 } else { 936 count++; 1017 1018 // All files are DONE or FAILED 1019 if (count == files.length) { 1020 if (this.state !== plupload.STOPPED) { 1021 this.state = plupload.STOPPED; 1022 this.trigger("StateChanged"); 1023 } 1024 this.trigger("UploadComplete", files); 1025 } 937 1026 } 938 1027 } 939 1028 940 // All files are DONE or FAILED 941 if (count == files.length) { 942 if (this.state !== plupload.STOPPED) { 943 this.state = plupload.STOPPED; 944 this.trigger("StateChanged"); 945 } 946 this.trigger("UploadComplete", files); 1029 1030 function calcFile(file) { 1031 file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100; 1032 calc(); 947 1033 } 948 }949 }950 1034 951 1035 952 function calcFile(file) {953 file.percent = file.size > 0 ? Math.ceil(file.loaded / file.size * 100) : 100;954 calc();955 }1036 function calc() { 1037 var i, file; 1038 var loaded; 1039 var loadedDuringCurrentSession = 0; 956 1040 1041 // Reset stats 1042 total.reset(); 957 1043 958 function calc() { 959 var i, file; 1044 // Check status, size, loaded etc on all files 1045 for (i = 0; i < files.length; i++) { 1046 file = files[i]; 960 1047 961 // Reset stats 962 total.reset(); 1048 if (file.size !== undef) { 1049 // We calculate totals based on original file size 1050 total.size += file.origSize; 963 1051 964 // Check status, size, loaded etc on all files965 for (i = 0; i < files.length; i++) {966 file = files[i];1052 // Since we cannot predict file size after resize, we do opposite and 1053 // interpolate loaded amount to match magnitude of total 1054 loaded = file.loaded * file.origSize / file.size; 967 1055 968 if (file.size !== undef) {969 // We calculate totals based on original file size970 total.size += file.origSize;1056 if (!file.completeTimestamp || file.completeTimestamp > startTime) { 1057 loadedDuringCurrentSession += loaded; 1058 } 971 1059 972 // Since we cannot predict file size after resize, we do opposite and 973 // interpolate loaded amount to match magnitude of total 974 total.loaded += file.loaded * file.origSize / file.size; 975 } else { 976 total.size = undef; 1060 total.loaded += loaded; 1061 } else { 1062 total.size = undef; 1063 } 1064 1065 if (file.status == plupload.DONE) { 1066 total.uploaded++; 1067 } else if (file.status == plupload.FAILED) { 1068 total.failed++; 1069 } else { 1070 total.queued++; 1071 } 1072 } 1073 1074 // If we couldn't calculate a total file size then use the number of files to calc percent 1075 if (total.size === undef) { 1076 total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0; 1077 } else { 1078 total.bytesPerSec = Math.ceil(loadedDuringCurrentSession / ((+new Date() - startTime || 1) / 1000.0)); 1079 total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0; 1080 } 977 1081 } 978 1082 979 if (file.status == plupload.DONE) { 980 total.uploaded++; 981 } else if (file.status == plupload.FAILED) { 982 total.failed++; 983 } else { 984 total.queued++; 1083 1084 function getRUID() { 1085 var ctrl = fileInputs[0] || fileDrops[0]; 1086 if (ctrl) { 1087 return ctrl.getRuntime().uid; 1088 } 1089 return false; 985 1090 } 986 }987 1091 988 // If we couldn't calculate a total file size then use the number of files to calc percent989 if (total.size === undef) {990 total.percent = files.length > 0 ? Math.ceil(total.uploaded / files.length * 100) : 0;991 } else {992 total.bytesPerSec = Math.ceil(total.loaded / ((+new Date() - startTime || 1) / 1000.0));993 total.percent = total.size > 0 ? Math.ceil(total.loaded / total.size * 100) : 0;994 }995 }996 1092 1093 function bindEventListeners() { 1094 this.bind('FilesAdded FilesRemoved', function(up) { 1095 up.trigger('QueueChanged'); 1096 up.refresh(); 1097 }); 997 1098 998 function getRUID() { 999 var ctrl = fileInputs[0] || fileDrops[0]; 1000 if (ctrl) { 1001 return ctrl.getRuntime().uid; 1002 } 1003 return false; 1004 } 1099 this.bind('CancelUpload', onCancelUpload); 1005 1100 1101 this.bind('BeforeUpload', onBeforeUpload); 1006 1102 1007 function runtimeCan(file, cap) { 1008 if (file.ruid) { 1009 var info = o.Runtime.getInfo(file.ruid); 1010 if (info) { 1011 return info.can(cap); 1012 } 1013 } 1014 return false; 1015 } 1103 this.bind('UploadFile', onUploadFile); 1016 1104 1105 this.bind('UploadProgress', onUploadProgress); 1017 1106 1018 function bindEventListeners() { 1019 this.bind('FilesAdded FilesRemoved', function(up) { 1020 up.trigger('QueueChanged'); 1021 up.refresh(); 1022 }); 1107 this.bind('StateChanged', onStateChanged); 1023 1108 1024 this.bind('CancelUpload', onCancelUpload); 1025 1026 this.bind('BeforeUpload', onBeforeUpload); 1109 this.bind('QueueChanged', calc); 1027 1110 1028 this.bind('UploadFile', onUploadFile);1111 this.bind('Error', onError); 1029 1112 1030 this.bind('UploadProgress', onUploadProgress);1113 this.bind('FileUploaded', onFileUploaded); 1031 1114 1032 this.bind('StateChanged', onStateChanged); 1115 this.bind('Destroy', onDestroy); 1116 } 1033 1117 1034 this.bind('QueueChanged', calc);1035 1118 1036 this.bind('Error', onError); 1119 function initControls(settings, cb) { 1120 var self = this, 1121 inited = 0, 1122 queue = []; 1037 1123 1038 this.bind('FileUploaded', onFileUploaded); 1124 // common settings 1125 var options = { 1126 runtime_order: settings.runtimes, 1127 required_caps: settings.required_features, 1128 preferred_caps: preferred_caps, 1129 swf_url: settings.flash_swf_url, 1130 xap_url: settings.silverlight_xap_url 1131 }; 1039 1132 1040 this.bind('Destroy', onDestroy); 1041 } 1133 // add runtime specific options if any 1134 plupload.each(settings.runtimes.split(/\s*,\s*/), function(runtime) { 1135 if (settings[runtime]) { 1136 options[runtime] = settings[runtime]; 1137 } 1138 }); 1042 1139 1140 // initialize file pickers - there can be many 1141 if (settings.browse_button) { 1142 plupload.each(settings.browse_button, function(el) { 1143 queue.push(function(cb) { 1144 var fileInput = new o.file.FileInput(plupload.extend({}, options, { 1145 accept: settings.filters.mime_types, 1146 name: settings.file_data_name, 1147 multiple: settings.multi_selection, 1148 container: settings.container, 1149 browse_button: el 1150 })); 1043 1151 1044 function initControls(settings, cb) {1045 var self = this, inited = 0, queue = [];1152 fileInput.onready = function() { 1153 var info = Runtime.getInfo(this.ruid); 1046 1154 1047 // common settings1048 var options ={1049 runtime_order: settings.runtimes,1050 required_caps: settings.required_features,1051 preferred_caps: preferred_caps1052 };1155 // for backward compatibility 1156 plupload.extend(self.features, { 1157 chunks: info.can('slice_blob'), 1158 multipart: info.can('send_multipart'), 1159 multi_selection: info.can('select_multiple') 1160 }); 1053 1161 1054 // add runtime specific options if any 1055 plupload.each(settings.runtimes.split(/\s*,\s*/), function(runtime) { 1056 if (settings[runtime]) { 1057 options[runtime] = settings[runtime]; 1058 } 1059 }); 1162 inited++; 1163 fileInputs.push(this); 1164 cb(); 1165 }; 1060 1166 1061 // initialize file pickers - there can be many 1062 if (settings.browse_button) { 1063 plupload.each(settings.browse_button, function(el) { 1064 queue.push(function(cb) { 1065 var fileInput = new o.FileInput(plupload.extend({}, options, { 1066 accept: settings.filters.mime_types, 1067 name: settings.file_data_name, 1068 multiple: settings.multi_selection, 1069 container: settings.container, 1070 browse_button: el 1071 })); 1167 fileInput.onchange = function() { 1168 self.addFile(this.files); 1169 }; 1072 1170 1073 fileInput.onready = function() { 1074 var info = o.Runtime.getInfo(this.ruid); 1171 fileInput.bind('mouseenter mouseleave mousedown mouseup', function(e) { 1172 if (!disabled) { 1173 if (settings.browse_button_hover) { 1174 if ('mouseenter' === e.type) { 1175 plupload.addClass(el, settings.browse_button_hover); 1176 } else if ('mouseleave' === e.type) { 1177 plupload.removeClass(el, settings.browse_button_hover); 1178 } 1179 } 1075 1180 1076 // for backward compatibility 1077 o.extend(self.features, { 1078 chunks: info.can('slice_blob'), 1079 multipart: info.can('send_multipart'), 1080 multi_selection: info.can('select_multiple') 1181 if (settings.browse_button_active) { 1182 if ('mousedown' === e.type) { 1183 plupload.addClass(el, settings.browse_button_active); 1184 } else if ('mouseup' === e.type) { 1185 plupload.removeClass(el, settings.browse_button_active); 1186 } 1187 } 1188 } 1189 }); 1190 1191 fileInput.bind('mousedown', function() { 1192 self.trigger('Browse'); 1193 }); 1194 1195 fileInput.bind('error runtimeerror', function() { 1196 fileInput = null; 1197 cb(); 1198 }); 1199 1200 fileInput.init(); 1081 1201 }); 1202 }); 1203 } 1082 1204 1083 inited++; 1084 fileInputs.push(this); 1085 cb(); 1086 }; 1205 // initialize drop zones 1206 if (settings.drop_element) { 1207 plupload.each(settings.drop_element, function(el) { 1208 queue.push(function(cb) { 1209 var fileDrop = new o.file.FileDrop(plupload.extend({}, options, { 1210 drop_zone: el 1211 })); 1087 1212 1088 fileInput.onchange = function() { 1089 self.addFile(this.files); 1090 }; 1213 fileDrop.onready = function() { 1214 var info = Runtime.getInfo(this.ruid); 1091 1215 1092 fileInput.bind('mouseenter mouseleave mousedown mouseup', function(e) { 1093 if (!disabled) { 1094 if (settings.browse_button_hover) { 1095 if ('mouseenter' === e.type) { 1096 o.addClass(el, settings.browse_button_hover); 1097 } else if ('mouseleave' === e.type) { 1098 o.removeClass(el, settings.browse_button_hover); 1099 } 1100 } 1216 // for backward compatibility 1217 plupload.extend(self.features, { 1218 chunks: info.can('slice_blob'), 1219 multipart: info.can('send_multipart'), 1220 dragdrop: info.can('drag_and_drop') 1221 }); 1101 1222 1102 if (settings.browse_button_active) { 1103 if ('mousedown' === e.type) { 1104 o.addClass(el, settings.browse_button_active); 1105 } else if ('mouseup' === e.type) { 1106 o.removeClass(el, settings.browse_button_active); 1107 } 1108 } 1109 } 1110 }); 1223 inited++; 1224 fileDrops.push(this); 1225 cb(); 1226 }; 1111 1227 1112 fileInput.bind('mousedown',function() {1113 self.trigger('Browse');1114 });1228 fileDrop.ondrop = function() { 1229 self.addFile(this.files); 1230 }; 1115 1231 1116 fileInput.bind('error runtimeerror', function() { 1117 fileInput = null; 1118 cb(); 1232 fileDrop.bind('error runtimeerror', function() { 1233 fileDrop = null; 1234 cb(); 1235 }); 1236 1237 fileDrop.init(); 1238 }); 1119 1239 }); 1240 } 1120 1241 1121 fileInput.init(); 1242 1243 plupload.inSeries(queue, function() { 1244 if (typeof(cb) === 'function') { 1245 cb(inited); 1246 } 1122 1247 }); 1123 }); 1124 } 1248 } 1125 1249 1126 // initialize drop zones1127 if (settings.drop_element) {1128 plupload.each(settings.drop_element, function(el) {1129 queue.push(function(cb) {1130 var fileDrop = new o.FileDrop(plupload.extend({}, options, {1131 drop_zone: el1132 }));1133 1250 1134 fileDrop.onready = function() {1135 var info = o.Runtime.getInfo(this.ruid);1251 function resizeImage(blob, params, runtimeOptions, cb) { 1252 var img = new o.image.Image(); 1136 1253 1137 // for backward compatibility 1138 o.extend(self.features, { 1139 chunks: info.can('slice_blob'), 1140 multipart: info.can('send_multipart'), 1141 dragdrop: info.can('drag_and_drop') 1142 }); 1143 1144 inited++; 1145 fileDrops.push(this); 1146 cb(); 1254 try { 1255 img.onload = function() { 1256 // no manipulation required if... 1257 if (params.width > this.width && 1258 params.height > this.height && 1259 params.quality === undef && 1260 params.preserve_headers && 1261 !params.crop 1262 ) { 1263 this.destroy(); 1264 cb(blob); 1265 } else { 1266 // otherwise downsize 1267 img.downsize(params.width, params.height, params.crop, params.preserve_headers); 1268 } 1147 1269 }; 1148 1270 1149 fileDrop.ondrop = function() { 1150 self.addFile(this.files); 1271 img.onresize = function() { 1272 var resizedBlob = this.getAsBlob(blob.type, params.quality); 1273 this.destroy(); 1274 cb(resizedBlob); 1151 1275 }; 1152 1276 1153 fileDrop.bind('error runtimeerror', function() {1154 fileDrop = null;1155 cb( );1277 img.bind('error runtimeerror', function() { 1278 this.destroy(); 1279 cb(blob); 1156 1280 }); 1157 1281 1158 fileDrop.init(); 1159 }); 1160 }); 1161 } 1282 img.load(blob, runtimeOptions); 1283 } catch (ex) { 1284 cb(blob); 1285 } 1286 } 1162 1287 1163 1288 1164 o.inSeries(queue, function() { 1165 if (typeof(cb) === 'function') { 1166 cb(inited); 1167 } 1168 }); 1169 } 1289 function setOption(option, value, init) { 1290 var self = this, 1291 reinitRequired = false; 1170 1292 1293 function _setOption(option, value, init) { 1294 var oldValue = settings[option]; 1171 1295 1172 function resizeImage(blob, params, cb) { 1173 var img = new o.Image(); 1296 switch (option) { 1297 case 'max_file_size': 1298 if (option === 'max_file_size') { 1299 settings.max_file_size = settings.filters.max_file_size = value; 1300 } 1301 break; 1174 1302 1175 try { 1176 img.onload = function() { 1177 // no manipulation required if... 1178 if (params.width > this.width && 1179 params.height > this.height && 1180 params.quality === undef && 1181 params.preserve_headers && 1182 !params.crop 1183 ) { 1184 this.destroy(); 1185 return cb(blob); 1186 } 1187 // otherwise downsize 1188 img.downsize(params.width, params.height, params.crop, params.preserve_headers); 1189 }; 1303 case 'chunk_size': 1304 if (value = plupload.parseSize(value)) { 1305 settings[option] = value; 1306 settings.send_file_name = true; 1307 } 1308 break; 1190 1309 1191 img.onresize = function() { 1192 cb(this.getAsBlob(blob.type, params.quality)); 1193 this.destroy(); 1194 }; 1310 case 'multipart': 1311 settings[option] = value; 1312 if (!value) { 1313 settings.send_file_name = true; 1314 } 1315 break; 1195 1316 1196 img.onerror = function() {1197 cb(blob);1198 };1317 case 'http_method': 1318 settings[option] = value.toUpperCase() === 'PUT' ? 'PUT' : 'POST'; 1319 break; 1199 1320 1200 img.load(blob); 1201 } catch(ex) { 1202 cb(blob); 1203 } 1204 } 1321 case 'unique_names': 1322 settings[option] = value; 1323 if (value) { 1324 settings.send_file_name = true; 1325 } 1326 break; 1205 1327 1328 case 'filters': 1329 // for sake of backward compatibility 1330 if (plupload.typeOf(value) === 'array') { 1331 value = { 1332 mime_types: value 1333 }; 1334 } 1206 1335 1207 function setOption(option, value, init) { 1208 var self = this, reinitRequired = false; 1336 if (init) { 1337 plupload.extend(settings.filters, value); 1338 } else { 1339 settings.filters = value; 1340 } 1209 1341 1210 function _setOption(option, value, init) { 1211 var oldValue = settings[option]; 1342 // if file format filters are being updated, regenerate the matching expressions 1343 if (value.mime_types) { 1344 if (plupload.typeOf(value.mime_types) === 'string') { 1345 value.mime_types = o.core.utils.Mime.mimes2extList(value.mime_types); 1346 } 1212 1347 1213 switch (option) { 1214 case 'max_file_size': 1215 if (option === 'max_file_size') { 1216 settings.max_file_size = settings.filters.max_file_size = value; 1217 } 1218 break; 1348 value.mime_types.regexp = (function(filters) { 1349 var extensionsRegExp = []; 1219 1350 1220 case 'chunk_size': 1221 if (value = plupload.parseSize(value)) { 1222 settings[option] = value; 1223 settings.send_file_name = true; 1224 } 1225 break; 1351 plupload.each(filters, function(filter) { 1352 plupload.each(filter.extensions.split(/,/), function(ext) { 1353 if (/^\s*\*\s*$/.test(ext)) { 1354 extensionsRegExp.push('\\.*'); 1355 } else { 1356 extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&')); 1357 } 1358 }); 1359 }); 1226 1360 1227 case 'multipart': 1228 settings[option] = value; 1229 if (!value) { 1230 settings.send_file_name = true; 1231 } 1232 break; 1361 return new RegExp('(' + extensionsRegExp.join('|') + ')$', 'i'); 1362 }(value.mime_types)); 1233 1363 1234 case 'unique_names': 1235 settings[option] = value; 1236 if (value) { 1237 settings.send_file_name = true; 1238 } 1239 break; 1364 settings.filters.mime_types = value.mime_types; 1365 } 1366 break; 1240 1367 1241 case 'filters': 1242 // for sake of backward compatibility 1243 if (plupload.typeOf(value) === 'array') { 1244 value = { 1245 mime_types: value 1246 }; 1247 } 1368 case 'resize': 1369 if (value) { 1370 settings.resize = plupload.extend({ 1371 preserve_headers: true, 1372 crop: false 1373 }, value); 1374 } else { 1375 settings.resize = false; 1376 } 1377 break; 1248 1378 1249 if (init) { 1250 plupload.extend(settings.filters, value); 1251 } else { 1252 settings.filters = value; 1253 } 1379 case 'prevent_duplicates': 1380 settings.prevent_duplicates = settings.filters.prevent_duplicates = !!value; 1381 break; 1254 1382 1255 // if file format filters are being updated, regenerate the matching expressions 1256 if (value.mime_types) { 1257 settings.filters.mime_types.regexp = (function(filters) { 1258 var extensionsRegExp = []; 1383 // options that require reinitialisation 1384 case 'container': 1385 case 'browse_button': 1386 case 'drop_element': 1387 value = 'container' === option ? 1388 plupload.get(value) : 1389 plupload.getAll(value); 1259 1390 1260 plupload.each(filters, function(filter) {1261 plupload.each(filter.extensions.split(/,/), function(ext) {1262 if (/^\s*\*\s*$/.test(ext)) {1263 extensionsRegExp.push('\\.*');1264 } else {1265 extensionsRegExp.push('\\.' + ext.replace(new RegExp('[' + ('/^$.*+?|()[]{}\\'.replace(/./g, '\\$&')) + ']', 'g'), '\\$&'));1266 }1267 });1268 });1391 case 'runtimes': 1392 case 'multi_selection': 1393 case 'flash_swf_url': 1394 case 'silverlight_xap_url': 1395 settings[option] = value; 1396 if (!init) { 1397 reinitRequired = true; 1398 } 1399 break; 1269 1400 1270 return new RegExp('(' + extensionsRegExp.join('|') + ')$', 'i');1271 }(settings.filters.mime_types));1401 default: 1402 settings[option] = value; 1272 1403 } 1273 break;1274 1275 case 'resize':1276 if (init) {1277 plupload.extend(settings.resize, value, {1278 enabled: true1279 });1280 } else {1281 settings.resize = value;1282 }1283 break;1284 1404 1285 case 'prevent_duplicates':1286 settings.prevent_duplicates = settings.filters.prevent_duplicates = !!value;1287 break;1288 1289 // options that require reinitialisation1290 case 'container':1291 case 'browse_button':1292 case 'drop_element':1293 value = 'container' === option1294 ? plupload.get(value)1295 : plupload.getAll(value)1296 ;1297 1298 case 'runtimes':1299 case 'multi_selection':1300 settings[option] = value;1301 1405 if (!init) { 1302 reinitRequired = true;1406 self.trigger('OptionChanged', option, value, oldValue); 1303 1407 } 1304 break;1408 } 1305 1409 1306 default: 1307 settings[option] = value; 1308 } 1410 if (typeof(option) === 'object') { 1411 plupload.each(option, function(value, option) { 1412 _setOption(option, value, init); 1413 }); 1414 } else { 1415 _setOption(option, value, init); 1416 } 1309 1417 1310 if (!init) { 1311 self.trigger('OptionChanged', option, value, oldValue); 1312 } 1313 } 1418 if (init) { 1419 // Normalize the list of required capabilities 1420 settings.required_features = normalizeCaps(plupload.extend({}, settings)); 1314 1421 1315 if (typeof(option) === 'object') { 1316 plupload.each(option, function(value, option) { 1317 _setOption(option, value, init); 1318 }); 1319 } else { 1320 _setOption(option, value, init); 1321 } 1422 // Come up with the list of capabilities that can affect default mode in a multi-mode runtimes 1423 preferred_caps = normalizeCaps(plupload.extend({}, settings, { 1424 required_features: true 1425 })); 1426 } else if (reinitRequired) { 1427 self.trigger('Destroy'); 1322 1428 1323 if (init) { 1324 // Normalize the list of required capabilities 1325 settings.required_features = normalizeCaps(plupload.extend({}, settings)); 1326 1327 // Come up with the list of capabilities that can affect default mode in a multi-mode runtimes 1328 preferred_caps = normalizeCaps(plupload.extend({}, settings, { 1329 required_features: true 1330 })); 1331 } else if (reinitRequired) { 1332 self.trigger('Destroy'); 1333 1334 initControls.call(self, settings, function(inited) { 1335 if (inited) { 1336 self.runtime = o.Runtime.getInfo(getRUID()).type; 1337 self.trigger('Init', { runtime: self.runtime }); 1338 self.trigger('PostInit'); 1339 } else { 1340 self.trigger('Error', { 1341 code : plupload.INIT_ERROR, 1342 message : plupload.translate('Init error.') 1429 initControls.call(self, settings, function(inited) { 1430 if (inited) { 1431 self.runtime = Runtime.getInfo(getRUID()).type; 1432 self.trigger('Init', { 1433 runtime: self.runtime 1434 }); 1435 self.trigger('PostInit'); 1436 } else { 1437 self.trigger('Error', { 1438 code: plupload.INIT_ERROR, 1439 message: plupload.translate('Init error.') 1440 }); 1441 } 1343 1442 }); 1344 1443 } 1345 }); 1346 } 1347 } 1444 } 1348 1445 1349 1446 1350 // Internal event handlers 1351 function onBeforeUpload(up, file) { 1352 // Generate unique target filenames 1353 if (up.settings.unique_names) { 1354 var matches = file.name.match(/\.([^.]+)$/), ext = "part"; 1355 if (matches) { 1356 ext = matches[1]; 1447 // Internal event handlers 1448 function onBeforeUpload(up, file) { 1449 // Generate unique target filenames 1450 if (up.settings.unique_names) { 1451 var matches = file.name.match(/\.([^.]+)$/), 1452 ext = "part"; 1453 if (matches) { 1454 ext = matches[1]; 1455 } 1456 file.target_name = file.id + '.' + ext; 1457 } 1357 1458 } 1358 file.target_name = file.id + '.' + ext;1359 }1360 }1361 1459 1362 1460 1363 function onUploadFile(up, file) { 1364 var url = up.settings.url 1365 , chunkSize = up.settings.chunk_size 1366 , retries = up.settings.max_retries 1367 , features = up.features 1368 , offset = 0 1369 , blob 1370 ; 1461 function onUploadFile(up, file) { 1462 var url = up.settings.url; 1463 var chunkSize = up.settings.chunk_size; 1464 var retries = up.settings.max_retries; 1465 var features = up.features; 1466 var offset = 0; 1467 var blob; 1371 1468 1372 // make sure we start at a predictable offset 1373 if (file.loaded) { 1374 offset = file.loaded = chunkSize ? chunkSize * Math.floor(file.loaded / chunkSize) : 0; 1375 } 1469 var runtimeOptions = { 1470 runtime_order: up.settings.runtimes, 1471 required_caps: up.settings.required_features, 1472 preferred_caps: preferred_caps, 1473 swf_url: up.settings.flash_swf_url, 1474 xap_url: up.settings.silverlight_xap_url 1475 }; 1376 1476 1377 function handleError() { 1378 if (retries-- > 0) { 1379 delay(uploadNextChunk, 1000); 1380 } else { 1381 file.loaded = offset; // reset all progress 1477 // make sure we start at a predictable offset 1478 if (file.loaded) { 1479 offset = file.loaded = chunkSize ? chunkSize * Math.floor(file.loaded / chunkSize) : 0; 1480 } 1382 1481 1383 up.trigger('Error', { 1384 code : plupload.HTTP_ERROR, 1385 message : plupload.translate('HTTP Error.'), 1386 file : file, 1387 response : xhr.responseText, 1388 status : xhr.status, 1389 responseHeaders: xhr.getAllResponseHeaders() 1390 }); 1391 } 1392 } 1482 function handleError() { 1483 if (retries-- > 0) { 1484 delay(uploadNextChunk, 1000); 1485 } else { 1486 file.loaded = offset; // reset all progress 1393 1487 1394 function uploadNextChunk() { 1395 var chunkBlob, formData, args = {}, curChunkSize; 1488 up.trigger('Error', { 1489 code: plupload.HTTP_ERROR, 1490 message: plupload.translate('HTTP Error.'), 1491 file: file, 1492 response: xhr.responseText, 1493 status: xhr.status, 1494 responseHeaders: xhr.getAllResponseHeaders() 1495 }); 1496 } 1497 } 1396 1498 1397 // make sure that file wasn't cancelled and upload is not stopped in general 1398 if (file.status !== plupload.UPLOADING || up.state === plupload.STOPPED) { 1399 return; 1400 } 1499 function uploadNextChunk() { 1500 var chunkBlob, args = {}, 1501 curChunkSize; 1401 1502 1402 // send additional 'name' parameter only if required1403 if (up.settings.send_file_name) {1404 args.name = file.target_name || file.name;1405 }1503 // make sure that file wasn't cancelled and upload is not stopped in general 1504 if (file.status !== plupload.UPLOADING || up.state === plupload.STOPPED) { 1505 return; 1506 } 1406 1507 1407 if (chunkSize && features.chunks && blob.size > chunkSize) { // blob will be of type string if it was loaded in memory 1408 curChunkSize = Math.min(chunkSize, blob.size - offset); 1409 chunkBlob = blob.slice(offset, offset + curChunkSize); 1410 } else { 1411 curChunkSize = blob.size; 1412 chunkBlob = blob; 1413 } 1508 // send additional 'name' parameter only if required 1509 if (up.settings.send_file_name) { 1510 args.name = file.target_name || file.name; 1511 } 1414 1512 1415 // If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller 1416 if (chunkSize && features.chunks) { 1417 // Setup query string arguments 1418 if (up.settings.send_chunk_number) { 1419 args.chunk = Math.ceil(offset / chunkSize); 1420 args.chunks = Math.ceil(blob.size / chunkSize); 1421 } else { // keep support for experimental chunk format, just in case 1422 args.offset = offset; 1423 args.total = blob.size; 1424 } 1425 } 1513 if (chunkSize && features.chunks && blob.size > chunkSize) { // blob will be of type string if it was loaded in memory 1514 curChunkSize = Math.min(chunkSize, blob.size - offset); 1515 chunkBlob = blob.slice(offset, offset + curChunkSize); 1516 } else { 1517 curChunkSize = blob.size; 1518 chunkBlob = blob; 1519 } 1426 1520 1427 xhr = new o.XMLHttpRequest(); 1521 // If chunking is enabled add corresponding args, no matter if file is bigger than chunk or smaller 1522 if (chunkSize && features.chunks) { 1523 // Setup query string arguments 1524 if (up.settings.send_chunk_number) { 1525 args.chunk = Math.ceil(offset / chunkSize); 1526 args.chunks = Math.ceil(blob.size / chunkSize); 1527 } else { // keep support for experimental chunk format, just in case 1528 args.offset = offset; 1529 args.total = blob.size; 1530 } 1531 } 1428 1532 1429 // Do we have upload progress support 1430 if (xhr.upload) { 1431 xhr.upload.onprogress = function(e) { 1432 file.loaded = Math.min(file.size, offset + e.loaded); 1433 up.trigger('UploadProgress', file); 1434 }; 1435 } 1436 1437 xhr.onload = function() { 1438 // check if upload made itself through 1439 if (xhr.status >= 400) { 1440 handleError(); 1441 return; 1533 if (up.trigger('BeforeChunkUpload', file, args, chunkBlob, offset)) { 1534 uploadChunk(args, chunkBlob, curChunkSize); 1535 } 1442 1536 } 1443 1537 1444 retries = up.settings.max_retries; // reset the counter 1538 function uploadChunk(args, chunkBlob, curChunkSize) { 1539 var formData; 1445 1540 1446 // Handle chunk response 1447 if (curChunkSize < blob.size) { 1448 chunkBlob.destroy(); 1541 xhr = new o.xhr.XMLHttpRequest(); 1449 1542 1450 offset += curChunkSize; 1451 file.loaded = Math.min(offset, blob.size); 1543 // Do we have upload progress support 1544 if (xhr.upload) { 1545 xhr.upload.onprogress = function(e) { 1546 file.loaded = Math.min(file.size, offset + e.loaded); 1547 up.trigger('UploadProgress', file); 1548 }; 1549 } 1452 1550 1453 up.trigger('ChunkUploaded', file, { 1454 offset : file.loaded, 1455 total : blob.size, 1456 response : xhr.responseText, 1457 status : xhr.status, 1458 responseHeaders: xhr.getAllResponseHeaders() 1459 }); 1551 xhr.onload = function() { 1552 // check if upload made itself through 1553 if (xhr.status < 200 || xhr.status >= 400) { 1554 handleError(); 1555 return; 1556 } 1460 1557 1461 // stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them 1462 if (o.Env.browser === 'Android Browser') { 1463 // doesn't harm in general, but is not required anywhere else 1464 up.trigger('UploadProgress', file); 1465 } 1466 } else { 1467 file.loaded = file.size; 1468 } 1558 retries = up.settings.max_retries; // reset the counter 1469 1559 1470 chunkBlob = formData = null; // Free memory 1560 // Handle chunk response 1561 if (curChunkSize < blob.size) { 1562 chunkBlob.destroy(); 1471 1563 1472 // Check if file is uploaded 1473 if (!offset || offset >= blob.size) { 1474 // If file was modified, destory the copy 1475 if (file.size != file.origSize) { 1476 blob.destroy(); 1477 blob = null; 1478 } 1564 offset += curChunkSize; 1565 file.loaded = Math.min(offset, blob.size); 1479 1566 1480 up.trigger('UploadProgress', file); 1567 up.trigger('ChunkUploaded', file, { 1568 offset: file.loaded, 1569 total: blob.size, 1570 response: xhr.responseText, 1571 status: xhr.status, 1572 responseHeaders: xhr.getAllResponseHeaders() 1573 }); 1481 1574 1482 file.status = plupload.DONE; 1575 // stock Android browser doesn't fire upload progress events, but in chunking mode we can fake them 1576 if (plupload.ua.browser === 'Android Browser') { 1577 // doesn't harm in general, but is not required anywhere else 1578 up.trigger('UploadProgress', file); 1579 } 1580 } else { 1581 file.loaded = file.size; 1582 } 1483 1583 1484 up.trigger('FileUploaded', file, { 1485 response : xhr.responseText, 1486 status : xhr.status, 1487 responseHeaders: xhr.getAllResponseHeaders() 1488 }); 1489 } else { 1490 // Still chunks left 1491 delay(uploadNextChunk, 1); // run detached, otherwise event handlers interfere 1492 } 1493 }; 1584 chunkBlob = formData = null; // Free memory 1494 1585 1495 xhr.onerror = function() { 1496 handleError(); 1497 }; 1586 // Check if file is uploaded 1587 if (!offset || offset >= blob.size) { 1588 // If file was modified, destory the copy 1589 if (file.size != file.origSize) { 1590 blob.destroy(); 1591 blob = null; 1592 } 1498 1593 1499 xhr.onloadend = function() { 1500 this.destroy(); 1501 xhr = null; 1502 }; 1594 up.trigger('UploadProgress', file); 1503 1595 1504 // Build multipart request 1505 if (up.settings.multipart && features.multipart) { 1506 xhr.open("post", url, true); 1596 file.status = plupload.DONE; 1597 file.completeTimestamp = +new Date(); 1507 1598 1508 // Set custom headers 1509 plupload.each(up.settings.headers, function(value, name) { 1510 xhr.setRequestHeader(name, value); 1511 }); 1599 up.trigger('FileUploaded', file, { 1600 response: xhr.responseText, 1601 status: xhr.status, 1602 responseHeaders: xhr.getAllResponseHeaders() 1603 }); 1604 } else { 1605 // Still chunks left 1606 delay(uploadNextChunk, 1); // run detached, otherwise event handlers interfere 1607 } 1608 }; 1512 1609 1513 formData = new o.FormData(); 1610 xhr.onerror = function() { 1611 handleError(); 1612 }; 1514 1613 1515 // Add multipart params 1516 plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) { 1517 formData.append(name, value); 1518 }); 1614 xhr.onloadend = function() { 1615 this.destroy(); 1616 }; 1519 1617 1520 // Add file and send it 1521 formData.append(up.settings.file_data_name, chunkBlob); 1522 xhr.send(formData, { 1523 runtime_order: up.settings.runtimes, 1524 required_caps: up.settings.required_features, 1525 preferred_caps: preferred_caps 1526 }); 1527 } else { 1528 // if no multipart, send as binary stream 1529 url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params)); 1618 // Build multipart request 1619 if (up.settings.multipart && features.multipart) { 1620 xhr.open(up.settings.http_method, url, true); 1530 1621 1531 xhr.open("post", url, true); 1622 // Set custom headers 1623 plupload.each(up.settings.headers, function(value, name) { 1624 xhr.setRequestHeader(name, value); 1625 }); 1532 1626 1533 xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header1627 formData = new o.xhr.FormData(); 1534 1628 1535 // Set custom headers1536 plupload.each(up.settings.headers, function(value, name) {1537 xhr.setRequestHeader(name, value);1538 });1629 // Add multipart params 1630 plupload.each(plupload.extend(args, up.settings.multipart_params), function(value, name) { 1631 formData.append(name, value); 1632 }); 1539 1633 1540 xhr.send(chunkBlob, { 1541 runtime_order: up.settings.runtimes, 1542 required_caps: up.settings.required_features, 1543 preferred_caps: preferred_caps 1544 }); 1545 } 1546 } 1634 // Add file and send it 1635 formData.append(up.settings.file_data_name, chunkBlob); 1636 xhr.send(formData, runtimeOptions); 1637 } else { 1638 // if no multipart, send as binary stream 1639 url = plupload.buildUrl(up.settings.url, plupload.extend(args, up.settings.multipart_params)); 1547 1640 1548 blob = file.getSource();1641 xhr.open(up.settings.http_method, url, true); 1549 1642 1550 // Start uploading chunks 1551 if (up.settings.resize.enabled && runtimeCan(blob, 'send_binary_string') && !!~o.inArray(blob.type, ['image/jpeg', 'image/png'])) { 1552 // Resize if required 1553 resizeImage.call(this, blob, up.settings.resize, function(resizedBlob) { 1554 blob = resizedBlob; 1555 file.size = resizedBlob.size; 1556 uploadNextChunk(); 1557 }); 1558 } else { 1559 uploadNextChunk(); 1560 } 1561 } 1643 // Set custom headers 1644 plupload.each(up.settings.headers, function(value, name) { 1645 xhr.setRequestHeader(name, value); 1646 }); 1562 1647 1648 // do not set Content-Type, if it was defined previously (see #1203) 1649 if (!xhr.hasRequestHeader('Content-Type')) { 1650 xhr.setRequestHeader('Content-Type', 'application/octet-stream'); // Binary stream header 1651 } 1563 1652 1564 function onUploadProgress(up, file) {1565 calcFile(file);1566 }1653 xhr.send(chunkBlob, runtimeOptions); 1654 } 1655 } 1567 1656 1568 1657 1569 function onStateChanged(up) { 1570 if (up.state == plupload.STARTED) { 1571 // Get start time to calculate bps 1572 startTime = (+new Date()); 1573 } else if (up.state == plupload.STOPPED) { 1574 // Reset currently uploading files 1575 for (var i = up.files.length - 1; i >= 0; i--) { 1576 if (up.files[i].status == plupload.UPLOADING) { 1577 up.files[i].status = plupload.QUEUED; 1578 calc(); 1658 blob = file.getSource(); 1659 1660 // Start uploading chunks 1661 if (!plupload.isEmptyObj(up.settings.resize) && plupload.inArray(blob.type, ['image/jpeg', 'image/png']) !== -1) { 1662 // Resize if required 1663 resizeImage(blob, up.settings.resize, runtimeOptions, function(resizedBlob) { 1664 blob = resizedBlob; 1665 file.size = resizedBlob.size; 1666 uploadNextChunk(); 1667 }); 1668 } else { 1669 uploadNextChunk(); 1579 1670 } 1580 1671 } 1581 }1582 }1583 1672 1584 1673 1585 function onCancelUpload() { 1586 if (xhr) { 1587 xhr.abort(); 1588 } 1589 } 1674 function onUploadProgress(up, file) { 1675 calcFile(file); 1676 } 1590 1677 1591 1678 1592 function onFileUploaded(up) { 1593 calc(); 1679 function onStateChanged(up) { 1680 if (up.state == plupload.STARTED) { 1681 // Get start time to calculate bps 1682 startTime = (+new Date()); 1683 } else if (up.state == plupload.STOPPED) { 1684 // Reset currently uploading files 1685 for (var i = up.files.length - 1; i >= 0; i--) { 1686 if (up.files[i].status == plupload.UPLOADING) { 1687 up.files[i].status = plupload.QUEUED; 1688 calc(); 1689 } 1690 } 1691 } 1692 } 1594 1693 1595 // Upload next file but detach it from the error event1596 // since other custom listeners might want to stop the queue1597 delay(function() {1598 uploadNext.call(up);1599 }, 1);1600 }1601 1694 1695 function onCancelUpload() { 1696 if (xhr) { 1697 xhr.abort(); 1698 } 1699 } 1602 1700 1603 function onError(up, err) {1604 if (err.code === plupload.INIT_ERROR) {1605 up.destroy();1606 }1607 // Set failed status if an error occured on a file1608 else if (err.code === plupload.HTTP_ERROR) {1609 err.file.status = plupload.FAILED;1610 calcFile(err.file);1611 1701 1612 // Upload next file but detach it from the error event 1613 // since other custom listeners might want to stop the queue 1614 if (up.state == plupload.STARTED) { // upload in progress 1615 up.trigger('CancelUpload'); 1702 function onFileUploaded(up) { 1703 calc(); 1704 1705 // Upload next file but detach it from the error event 1706 // since other custom listeners might want to stop the queue 1616 1707 delay(function() { 1617 1708 uploadNext.call(up); 1618 1709 }, 1); 1619 1710 } 1620 }1621 }1622 1711 1623 1712 1624 function onDestroy(up) { 1625 up.stop(); 1713 function onError(up, err) { 1714 if (err.code === plupload.INIT_ERROR) { 1715 up.destroy(); 1716 } 1717 // Set failed status if an error occured on a file 1718 else if (err.code === plupload.HTTP_ERROR) { 1719 err.file.status = plupload.FAILED; 1720 err.file.completeTimestamp = +new Date(); 1721 calcFile(err.file); 1626 1722 1627 // Purge the queue 1628 plupload.each(files, function(file) { 1629 file.destroy(); 1630 }); 1631 files = []; 1723 // Upload next file but detach it from the error event 1724 // since other custom listeners might want to stop the queue 1725 if (up.state == plupload.STARTED) { // upload in progress 1726 up.trigger('CancelUpload'); 1727 delay(function() { 1728 uploadNext.call(up); 1729 }, 1); 1730 } 1731 } 1732 } 1632 1733 1633 if (fileInputs.length) {1634 plupload.each(fileInputs, function(fileInput) {1635 fileInput.destroy();1636 });1637 fileInputs = [];1638 }1639 1734 1640 if (fileDrops.length) { 1641 plupload.each(fileDrops, function(fileDrop) { 1642 fileDrop.destroy(); 1643 }); 1644 fileDrops = []; 1645 } 1735 function onDestroy(up) { 1736 up.stop(); 1646 1737 1647 preferred_caps = {};1648 disabled = false;1649 startTime = xhr = null;1650 total.reset();1651 }1738 // Purge the queue 1739 plupload.each(files, function(file) { 1740 file.destroy(); 1741 }); 1742 files = []; 1652 1743 1744 if (fileInputs.length) { 1745 plupload.each(fileInputs, function(fileInput) { 1746 fileInput.destroy(); 1747 }); 1748 fileInputs = []; 1749 } 1653 1750 1654 // Default settings 1655 settings = { 1656 runtimes: o.Runtime.order, 1657 max_retries: 0, 1658 chunk_size: 0, 1659 multipart: true, 1660 multi_selection: true, 1661 file_data_name: 'file', 1662 filters: { 1663 mime_types: [], 1664 prevent_duplicates: false, 1665 max_file_size: 0 1666 }, 1667 resize: { 1668 enabled: false, 1669 preserve_headers: true, 1670 crop: false 1671 }, 1672 send_file_name: true, 1673 send_chunk_number: true 1674 }; 1751 if (fileDrops.length) { 1752 plupload.each(fileDrops, function(fileDrop) { 1753 fileDrop.destroy(); 1754 }); 1755 fileDrops = []; 1756 } 1675 1757 1676 1677 setOption.call(this, options, null, true); 1758 preferred_caps = {}; 1759 disabled = false; 1760 startTime = xhr = null; 1761 total.reset(); 1762 } 1678 1763 1679 // Inital total state1680 total = new plupload.QueueProgress();1681 1764 1682 // Add public methods 1683 plupload.extend(this, { 1765 // Default settings 1766 settings = { 1767 chunk_size: 0, 1768 file_data_name: 'file', 1769 filters: { 1770 mime_types: [], 1771 max_file_size: 0, 1772 prevent_duplicates: false, 1773 prevent_empty: true 1774 }, 1775 flash_swf_url: 'js/Moxie.swf', 1776 http_method: 'POST', 1777 max_retries: 0, 1778 multipart: true, 1779 multi_selection: true, 1780 resize: false, 1781 runtimes: Runtime.order, 1782 send_file_name: true, 1783 send_chunk_number: true, 1784 silverlight_xap_url: 'js/Moxie.xap' 1785 }; 1684 1786 1685 /**1686 * Unique id for the Uploader instance.1687 *1688 * @property id1689 * @type String1690 */1691 id : uid,1692 uid : uid, // mOxie uses this to differentiate between event targets1693 1787 1694 /** 1695 * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED. 1696 * These states are controlled by the stop/start methods. The default value is STOPPED. 1697 * 1698 * @property state 1699 * @type Number 1700 */ 1701 state : plupload.STOPPED, 1788 setOption.call(this, options, null, true); 1702 1789 1703 /** 1704 * Map of features that are available for the uploader runtime. Features will be filled 1705 * before the init event is called, these features can then be used to alter the UI for the end user. 1706 * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize. 1707 * 1708 * @property features 1709 * @type Object 1710 */ 1711 features : {}, 1790 // Inital total state 1791 total = new plupload.QueueProgress(); 1712 1792 1713 /** 1714 * Current runtime name. 1715 * 1716 * @property runtime 1717 * @type String 1718 */ 1719 runtime : null, 1793 // Add public methods 1794 plupload.extend(this, { 1720 1795 1721 /**1722 * Current upload queue, an array of File instances.1723 *1724 * @property files1725 * @type Array1726 * @see plupload.File1727 */1728 files : files,1796 /** 1797 * Unique id for the Uploader instance. 1798 * 1799 * @property id 1800 * @type String 1801 */ 1802 id: uid, 1803 uid: uid, // mOxie uses this to differentiate between event targets 1729 1804 1730 /** 1731 * Object with name/value settings. 1732 * 1733 * @property settings 1734 * @type Object 1735 */ 1736 settings : settings, 1805 /** 1806 * Current state of the total uploading progress. This one can either be plupload.STARTED or plupload.STOPPED. 1807 * These states are controlled by the stop/start methods. The default value is STOPPED. 1808 * 1809 * @property state 1810 * @type Number 1811 */ 1812 state: plupload.STOPPED, 1737 1813 1738 /** 1739 * Total progess information. How many files has been uploaded, total percent etc. 1740 * 1741 * @property total 1742 * @type plupload.QueueProgress 1743 */ 1744 total : total, 1814 /** 1815 * Map of features that are available for the uploader runtime. Features will be filled 1816 * before the init event is called, these features can then be used to alter the UI for the end user. 1817 * Some of the current features that might be in this map is: dragdrop, chunks, jpgresize, pngresize. 1818 * 1819 * @property features 1820 * @type Object 1821 */ 1822 features: {}, 1745 1823 1824 /** 1825 * Current runtime name. 1826 * 1827 * @property runtime 1828 * @type String 1829 */ 1830 runtime: null, 1746 1831 1747 /** 1748 * Initializes the Uploader instance and adds internal event listeners. 1749 * 1750 * @method init 1751 */ 1752 init : function() { 1753 var self = this, opt, preinitOpt, err; 1754 1755 preinitOpt = self.getOption('preinit'); 1756 if (typeof(preinitOpt) == "function") { 1757 preinitOpt(self); 1758 } else { 1759 plupload.each(preinitOpt, function(func, name) { 1760 self.bind(name, func); 1761 }); 1762 } 1832 /** 1833 * Current upload queue, an array of File instances. 1834 * 1835 * @property files 1836 * @type Array 1837 * @see plupload.File 1838 */ 1839 files: files, 1763 1840 1764 bindEventListeners.call(self); 1841 /** 1842 * Object with name/value settings. 1843 * 1844 * @property settings 1845 * @type Object 1846 */ 1847 settings: settings, 1765 1848 1766 // Check for required options 1767 plupload.each(['container', 'browse_button', 'drop_element'], function(el) { 1768 if (self.getOption(el) === null) { 1769 err = { 1770 code : plupload.INIT_ERROR, 1771 message : plupload.translate("'%' specified, but cannot be found.") 1772 } 1773 return false; 1774 } 1775 }); 1849 /** 1850 * Total progess information. How many files has been uploaded, total percent etc. 1851 * 1852 * @property total 1853 * @type plupload.QueueProgress 1854 */ 1855 total: total, 1776 1856 1777 if (err) {1778 return self.trigger('Error', err);1779 }1780 1857 1858 /** 1859 * Initializes the Uploader instance and adds internal event listeners. 1860 * 1861 * @method init 1862 */ 1863 init: function() { 1864 var self = this, 1865 opt, preinitOpt, err; 1781 1866 1782 if (!settings.browse_button && !settings.drop_element) { 1783 return self.trigger('Error', { 1784 code : plupload.INIT_ERROR, 1785 message : plupload.translate("You must specify either 'browse_button' or 'drop_element'.") 1786 }); 1787 } 1867 preinitOpt = self.getOption('preinit'); 1868 if (typeof(preinitOpt) == "function") { 1869 preinitOpt(self); 1870 } else { 1871 plupload.each(preinitOpt, function(func, name) { 1872 self.bind(name, func); 1873 }); 1874 } 1788 1875 1876 bindEventListeners.call(self); 1789 1877 1790 initControls.call(self, settings, function(inited) { 1791 var initOpt = self.getOption('init'); 1792 if (typeof(initOpt) == "function") { 1793 initOpt(self); 1794 } else { 1795 plupload.each(initOpt, function(func, name) { 1796 self.bind(name, func); 1878 // Check for required options 1879 plupload.each(['container', 'browse_button', 'drop_element'], function(el) { 1880 if (self.getOption(el) === null) { 1881 err = { 1882 code: plupload.INIT_ERROR, 1883 message: plupload.sprintf(plupload.translate("%s specified, but cannot be found."), el) 1884 } 1885 return false; 1886 } 1797 1887 }); 1798 }1799 1888 1800 if (inited) { 1801 self.runtime = o.Runtime.getInfo(getRUID()).type; 1802 self.trigger('Init', { runtime: self.runtime }); 1803 self.trigger('PostInit'); 1804 } else { 1805 self.trigger('Error', { 1806 code : plupload.INIT_ERROR, 1807 message : plupload.translate('Init error.') 1808 }); 1809 } 1810 }); 1811 }, 1889 if (err) { 1890 return self.trigger('Error', err); 1891 } 1812 1892 1813 /**1814 * Set the value for the specified option(s).1815 *1816 * @method setOption1817 * @since 2.11818 * @param {String|Object} option Name of the option to change or the set of key/value pairs1819 * @param {Mixed} [value] Value for the option (is ignored, if first argument is object)1820 */1821 setOption: function(option, value) {1822 setOption.call(this, option, value, !this.runtime); // until runtime not set we do not need to reinitialize1823 },1824 1893 1825 /** 1826 * Get the value for the specified option or the whole configuration, if not specified. 1827 * 1828 * @method getOption 1829 * @since 2.1 1830 * @param {String} [option] Name of the option to get 1831 * @return {Mixed} Value for the option or the whole set 1832 */ 1833 getOption: function(option) { 1834 if (!option) { 1835 return settings; 1836 } 1837 return settings[option]; 1838 }, 1894 if (!settings.browse_button && !settings.drop_element) { 1895 return self.trigger('Error', { 1896 code: plupload.INIT_ERROR, 1897 message: plupload.translate("You must specify either browse_button or drop_element.") 1898 }); 1899 } 1839 1900 1840 /**1841 * Refreshes the upload instance by dispatching out a refresh event to all runtimes.1842 * This would for example reposition flash/silverlight shims on the page.1843 *1844 * @method refresh1845 */1846 refresh : function() {1847 if (fileInputs.length) {1848 plupload.each(fileInputs, function(fileInput) {1849 fileInput.trigger('Refresh');1850 });1851 }1852 this.trigger('Refresh');1853 },1854 1901 1855 /**1856 * Starts uploading the queued files.1857 *1858 * @method start1859 */1860 start : function() {1861 if (this.state != plupload.STARTED) {1862 this.state = plupload.STARTED;1863 this.trigger('StateChanged');1902 initControls.call(self, settings, function(inited) { 1903 var initOpt = self.getOption('init'); 1904 if (typeof(initOpt) == "function") { 1905 initOpt(self); 1906 } else { 1907 plupload.each(initOpt, function(func, name) { 1908 self.bind(name, func); 1909 }); 1910 } 1864 1911 1865 uploadNext.call(this); 1866 } 1867 }, 1912 if (inited) { 1913 self.runtime = Runtime.getInfo(getRUID()).type; 1914 self.trigger('Init', { 1915 runtime: self.runtime 1916 }); 1917 self.trigger('PostInit'); 1918 } else { 1919 self.trigger('Error', { 1920 code: plupload.INIT_ERROR, 1921 message: plupload.translate('Init error.') 1922 }); 1923 } 1924 }); 1925 }, 1868 1926 1869 /** 1870 * Stops the upload of the queued files. 1871 * 1872 * @method stop 1873 */ 1874 stop : function() { 1875 if (this.state != plupload.STOPPED) { 1876 this.state = plupload.STOPPED; 1877 this.trigger('StateChanged'); 1878 this.trigger('CancelUpload'); 1879 } 1880 }, 1927 /** 1928 * Set the value for the specified option(s). 1929 * 1930 * @method setOption 1931 * @since 2.1 1932 * @param {String|Object} option Name of the option to change or the set of key/value pairs 1933 * @param {Mixed} [value] Value for the option (is ignored, if first argument is object) 1934 */ 1935 setOption: function(option, value) { 1936 setOption.call(this, option, value, !this.runtime); // until runtime not set we do not need to reinitialize 1937 }, 1881 1938 1939 /** 1940 * Get the value for the specified option or the whole configuration, if not specified. 1941 * 1942 * @method getOption 1943 * @since 2.1 1944 * @param {String} [option] Name of the option to get 1945 * @return {Mixed} Value for the option or the whole set 1946 */ 1947 getOption: function(option) { 1948 if (!option) { 1949 return settings; 1950 } 1951 return settings[option]; 1952 }, 1882 1953 1883 /** 1884 * Disables/enables browse button on request. 1885 * 1886 * @method disableBrowse 1887 * @param {Boolean} disable Whether to disable or enable (default: true) 1888 */ 1889 disableBrowse : function() { 1890 disabled = arguments[0] !== undef ? arguments[0] : true; 1954 /** 1955 * Refreshes the upload instance by dispatching out a refresh event to all runtimes. 1956 * This would for example reposition flash/silverlight shims on the page. 1957 * 1958 * @method refresh 1959 */ 1960 refresh: function() { 1961 if (fileInputs.length) { 1962 plupload.each(fileInputs, function(fileInput) { 1963 fileInput.trigger('Refresh'); 1964 }); 1965 } 1966 this.trigger('Refresh'); 1967 }, 1891 1968 1892 if (fileInputs.length) { 1893 plupload.each(fileInputs, function(fileInput) { 1894 fileInput.disable(disabled); 1895 }); 1896 } 1969 /** 1970 * Starts uploading the queued files. 1971 * 1972 * @method start 1973 */ 1974 start: function() { 1975 if (this.state != plupload.STARTED) { 1976 this.state = plupload.STARTED; 1977 this.trigger('StateChanged'); 1897 1978 1898 this.trigger('DisableBrowse', disabled); 1899 }, 1979 uploadNext.call(this); 1980 } 1981 }, 1900 1982 1901 /** 1902 * Returns the specified file object by id. 1903 * 1904 * @method getFile 1905 * @param {String} id File id to look for. 1906 * @return {plupload.File} File object or undefined if it wasn't found; 1907 */ 1908 getFile : function(id) { 1909 var i; 1910 for (i = files.length - 1; i >= 0; i--) { 1911 if (files[i].id === id) { 1912 return files[i]; 1913 } 1914 } 1915 }, 1983 /** 1984 * Stops the upload of the queued files. 1985 * 1986 * @method stop 1987 */ 1988 stop: function() { 1989 if (this.state != plupload.STOPPED) { 1990 this.state = plupload.STOPPED; 1991 this.trigger('StateChanged'); 1992 this.trigger('CancelUpload'); 1993 } 1994 }, 1916 1995 1917 /**1918 * Adds file to the queue programmatically. Can be native file, instance of Plupload.File,1919 * instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded,1920 * if any files were added to the queue. Otherwise nothing happens.1921 *1922 * @method addFile1923 * @since 2.01924 * @param {plupload.File|mOxie.File|File|Node|Array} file File or files to add to the queue.1925 * @param {String} [fileName] If specified, will be used as a name for the file1926 */1927 addFile : function(file, fileName) {1928 var self = this1929 , queue = []1930 , filesAdded = []1931 , ruid1932 ;1933 1996 1934 function filterFile(file, cb) { 1935 var queue = []; 1936 o.each(self.settings.filters, function(rule, name) { 1937 if (fileFilters[name]) { 1938 queue.push(function(cb) { 1939 fileFilters[name].call(self, rule, file, function(res) { 1940 cb(!res); 1941 }); 1997 /** 1998 * Disables/enables browse button on request. 1999 * 2000 * @method disableBrowse 2001 * @param {Boolean} disable Whether to disable or enable (default: true) 2002 */ 2003 disableBrowse: function() { 2004 disabled = arguments[0] !== undef ? arguments[0] : true; 2005 2006 if (fileInputs.length) { 2007 plupload.each(fileInputs, function(fileInput) { 2008 fileInput.disable(disabled); 1942 2009 }); 1943 2010 } 1944 });1945 o.inSeries(queue, cb);1946 }1947 2011 1948 /** 1949 * @method resolveFile 1950 * @private 1951 * @param {o.File|o.Blob|plupload.File|File|Blob|input[type="file"]} file 1952 */ 1953 function resolveFile(file) { 1954 var type = o.typeOf(file); 2012 this.trigger('DisableBrowse', disabled); 2013 }, 1955 2014 1956 // o.File 1957 if (file instanceof o.File) { 1958 if (!file.ruid && !file.isDetached()) { 1959 if (!ruid) { // weird case 1960 return false; 2015 /** 2016 * Returns the specified file object by id. 2017 * 2018 * @method getFile 2019 * @param {String} id File id to look for. 2020 * @return {plupload.File} File object or undefined if it wasn't found; 2021 */ 2022 getFile: function(id) { 2023 var i; 2024 for (i = files.length - 1; i >= 0; i--) { 2025 if (files[i].id === id) { 2026 return files[i]; 1961 2027 } 1962 file.ruid = ruid;1963 file.connectRuntime(ruid);1964 2028 } 1965 resolveFile(new plupload.File(file)); 1966 } 1967 // o.Blob 1968 else if (file instanceof o.Blob) { 1969 resolveFile(file.getSource()); 1970 file.destroy(); 1971 } 1972 // plupload.File - final step for other branches 1973 else if (file instanceof plupload.File) { 1974 if (fileName) { 1975 file.name = fileName; 2029 }, 2030 2031 /** 2032 * Adds file to the queue programmatically. Can be native file, instance of Plupload.File, 2033 * instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded, 2034 * if any files were added to the queue. Otherwise nothing happens. 2035 * 2036 * @method addFile 2037 * @since 2.0 2038 * @param {plupload.File|mOxie.File|File|Node|Array} file File or files to add to the queue. 2039 * @param {String} [fileName] If specified, will be used as a name for the file 2040 */ 2041 addFile: function(file, fileName) { 2042 var self = this, 2043 queue = [], 2044 filesAdded = [], 2045 ruid; 2046 2047 function filterFile(file, cb) { 2048 var queue = []; 2049 plupload.each(self.settings.filters, function(rule, name) { 2050 if (fileFilters[name]) { 2051 queue.push(function(cb) { 2052 fileFilters[name].call(self, rule, file, function(res) { 2053 cb(!res); 2054 }); 2055 }); 2056 } 2057 }); 2058 plupload.inSeries(queue, cb); 1976 2059 } 1977 1978 queue.push(function(cb) {1979 // run through the internal and user-defined filters, if any1980 filterFile(file, function(err) {1981 if (!err) {1982 // make files available for the filters by updating the main queue directly1983 files.push(file);1984 // collect the files that will be passed to FilesAdded event1985 filesAdded.push(file);1986 2060 1987 self.trigger("FileFiltered", file); 2061 /** 2062 * @method resolveFile 2063 * @private 2064 * @param {moxie.file.File|moxie.file.Blob|plupload.File|File|Blob|input[type="file"]} file 2065 */ 2066 function resolveFile(file) { 2067 var type = plupload.typeOf(file); 2068 2069 // moxie.file.File 2070 if (file instanceof o.file.File) { 2071 if (!file.ruid && !file.isDetached()) { 2072 if (!ruid) { // weird case 2073 return false; 2074 } 2075 file.ruid = ruid; 2076 file.connectRuntime(ruid); 1988 2077 } 1989 delay(cb, 1); // do not build up recursions or eventually we might hit the limits 2078 resolveFile(new plupload.File(file)); 2079 } 2080 // moxie.file.Blob 2081 else if (file instanceof o.file.Blob) { 2082 resolveFile(file.getSource()); 2083 file.destroy(); 2084 } 2085 // plupload.File - final step for other branches 2086 else if (file instanceof plupload.File) { 2087 if (fileName) { 2088 file.name = fileName; 2089 } 2090 2091 queue.push(function(cb) { 2092 // run through the internal and user-defined filters, if any 2093 filterFile(file, function(err) { 2094 if (!err) { 2095 // make files available for the filters by updating the main queue directly 2096 files.push(file); 2097 // collect the files that will be passed to FilesAdded event 2098 filesAdded.push(file); 2099 2100 self.trigger("FileFiltered", file); 2101 } 2102 delay(cb, 1); // do not build up recursions or eventually we might hit the limits 2103 }); 2104 }); 2105 } 2106 // native File or blob 2107 else if (plupload.inArray(type, ['file', 'blob']) !== -1) { 2108 resolveFile(new o.file.File(null, file)); 2109 } 2110 // input[type="file"] 2111 else if (type === 'node' && plupload.typeOf(file.files) === 'filelist') { 2112 // if we are dealing with input[type="file"] 2113 plupload.each(file.files, resolveFile); 2114 } 2115 // mixed array of any supported types (see above) 2116 else if (type === 'array') { 2117 fileName = null; // should never happen, but unset anyway to avoid funny situations 2118 plupload.each(file, resolveFile); 2119 } 2120 } 2121 2122 ruid = getRUID(); 2123 2124 resolveFile(file); 2125 2126 if (queue.length) { 2127 plupload.inSeries(queue, function() { 2128 // if any files left after filtration, trigger FilesAdded 2129 if (filesAdded.length) { 2130 self.trigger("FilesAdded", filesAdded); 2131 } 1990 2132 }); 1991 }); 1992 } 1993 // native File or blob 1994 else if (o.inArray(type, ['file', 'blob']) !== -1) { 1995 resolveFile(new o.File(null, file)); 1996 } 1997 // input[type="file"] 1998 else if (type === 'node' && o.typeOf(file.files) === 'filelist') { 1999 // if we are dealing with input[type="file"] 2000 o.each(file.files, resolveFile); 2001 } 2002 // mixed array of any supported types (see above) 2003 else if (type === 'array') { 2004 fileName = null; // should never happen, but unset anyway to avoid funny situations 2005 o.each(file, resolveFile); 2006 } 2007 } 2133 } 2134 }, 2008 2135 2009 ruid = getRUID(); 2010 2011 resolveFile(file); 2136 /** 2137 * Removes a specific file. 2138 * 2139 * @method removeFile 2140 * @param {plupload.File|String} file File to remove from queue. 2141 */ 2142 removeFile: function(file) { 2143 var id = typeof(file) === 'string' ? file : file.id; 2012 2144 2013 if (queue.length) { 2014 o.inSeries(queue, function() { 2015 // if any files left after filtration, trigger FilesAdded 2016 if (filesAdded.length) { 2017 self.trigger("FilesAdded", filesAdded); 2145 for (var i = files.length - 1; i >= 0; i--) { 2146 if (files[i].id === id) { 2147 return this.splice(i, 1)[0]; 2148 } 2018 2149 } 2019 }); 2020 } 2021 }, 2150 }, 2022 2151 2023 /** 2024 * Removes a specific file. 2025 * 2026 * @method removeFile 2027 * @param {plupload.File|String} file File to remove from queue. 2028 */ 2029 removeFile : function(file) { 2030 var id = typeof(file) === 'string' ? file : file.id; 2152 /** 2153 * Removes part of the queue and returns the files removed. This will also trigger the 2154 * FilesRemoved and QueueChanged events. 2155 * 2156 * @method splice 2157 * @param {Number} [start=0] Start index to remove from. 2158 * @param {Number} [length] Number of files to remove (defaults to number of files in the queue). 2159 * @return {Array} Array of files that was removed. 2160 */ 2161 splice: function(start, length) { 2162 // Splice and trigger events 2163 var removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length); 2031 2164 2032 for (var i = files.length - 1; i >= 0; i--) { 2033 if (files[i].id === id) { 2034 return this.splice(i, 1)[0]; 2035 } 2036 } 2037 }, 2165 // if upload is in progress we need to stop it and restart after files are removed 2166 var restartRequired = false; 2167 if (this.state == plupload.STARTED) { // upload in progress 2168 plupload.each(removed, function(file) { 2169 if (file.status === plupload.UPLOADING) { 2170 restartRequired = true; // do not restart, unless file that is being removed is uploading 2171 return false; 2172 } 2173 }); 2038 2174 2039 /** 2040 * Removes part of the queue and returns the files removed. This will also trigger the FilesRemoved and QueueChanged events. 2041 * 2042 * @method splice 2043 * @param {Number} start (Optional) Start index to remove from. 2044 * @param {Number} length (Optional) Lengh of items to remove. 2045 * @return {Array} Array of files that was removed. 2046 */ 2047 splice : function(start, length) { 2048 // Splice and trigger events 2049 var removed = files.splice(start === undef ? 0 : start, length === undef ? files.length : length); 2175 if (restartRequired) { 2176 this.stop(); 2177 } 2178 } 2050 2179 2051 // if upload is in progress we need to stop it and restart after files are removed 2052 var restartRequired = false; 2053 if (this.state == plupload.STARTED) { // upload in progress 2054 plupload.each(removed, function(file) { 2055 if (file.status === plupload.UPLOADING) { 2056 restartRequired = true; // do not restart, unless file that is being removed is uploading 2057 return false; 2180 this.trigger("FilesRemoved", removed); 2181 2182 // Dispose any resources allocated by those files 2183 plupload.each(removed, function(file) { 2184 file.destroy(); 2185 }); 2186 2187 if (restartRequired) { 2188 this.start(); 2058 2189 } 2059 });2060 2061 if (restartRequired) {2062 this.stop();2063 }2064 }2065 2190 2066 this.trigger("FilesRemoved", removed); 2191 return removed; 2192 }, 2067 2193 2068 // Dispose any resources allocated by those files 2069 plupload.each(removed, function(file) { 2070 file.destroy(); 2071 }); 2072 2073 if (restartRequired) { 2074 this.start(); 2075 } 2194 /** 2195 Dispatches the specified event name and its arguments to all listeners. 2076 2196 2077 return removed; 2078 }, 2197 @method trigger 2198 @param {String} name Event name to fire. 2199 @param {Object..} Multiple arguments to pass along to the listener functions. 2200 */ 2079 2201 2080 /** 2081 Dispatches the specified event name and its arguments to all listeners. 2202 // override the parent method to match Plupload-like event logic 2203 dispatchEvent: function(type) { 2204 var list, args, result; 2082 2205 2083 @method trigger 2084 @param {String} name Event name to fire. 2085 @param {Object..} Multiple arguments to pass along to the listener functions. 2086 */ 2206 type = type.toLowerCase(); 2087 2207 2088 // override the parent method to match Plupload-like event logic 2089 dispatchEvent: function(type) { 2090 var list, args, result; 2091 2092 type = type.toLowerCase(); 2093 2094 list = this.hasEventListener(type); 2208 list = this.hasEventListener(type); 2095 2209 2096 if (list) { 2097 // sort event list by priority 2098 list.sort(function(a, b) { return b.priority - a.priority; }); 2099 2100 // first argument should be current plupload.Uploader instance 2101 args = [].slice.call(arguments); 2102 args.shift(); 2103 args.unshift(this); 2210 if (list) { 2211 // sort event list by priority 2212 list.sort(function(a, b) { 2213 return b.priority - a.priority; 2214 }); 2104 2215 2105 for (var i = 0; i < list.length; i++) { 2106 // Fire event, break chain if false is returned 2107 if (list[i].fn.apply(list[i].scope, args) === false) { 2108 return false; 2216 // first argument should be current plupload.Uploader instance 2217 args = [].slice.call(arguments); 2218 args.shift(); 2219 args.unshift(this); 2220 2221 for (var i = 0; i < list.length; i++) { 2222 // Fire event, break chain if false is returned 2223 if (list[i].fn.apply(list[i].scope, args) === false) { 2224 return false; 2225 } 2226 } 2109 2227 } 2110 } 2111 } 2112 return true; 2113 }, 2228 return true; 2229 }, 2114 2230 2115 /**2116 Check whether uploader has any listeners to the specified event.2231 /** 2232 Check whether uploader has any listeners to the specified event. 2117 2233 2118 @method hasEventListener2119 @param {String} name Event name to check for.2120 */2234 @method hasEventListener 2235 @param {String} name Event name to check for. 2236 */ 2121 2237 2122 2238 2123 /**2124 Adds an event listener by name.2239 /** 2240 Adds an event listener by name. 2125 2241 2126 @method bind2127 @param {String} name Event name to listen for.2128 @param {function} fn Function to call ones the event gets fired.2129 @param {Object} [scope] Optional scope to execute the specified function in.2130 @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first2131 */2132 bind: function(name, fn, scope, priority) {2133 // adapt moxie EventTarget style to Plupload-like2134 plupload.Uploader.prototype.bind.call(this, name, fn, priority, scope);2135 },2242 @method bind 2243 @param {String} name Event name to listen for. 2244 @param {function} fn Function to call ones the event gets fired. 2245 @param {Object} [scope] Optional scope to execute the specified function in. 2246 @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first 2247 */ 2248 bind: function(name, fn, scope, priority) { 2249 // adapt moxie EventTarget style to Plupload-like 2250 plupload.Uploader.prototype.bind.call(this, name, fn, priority, scope); 2251 }, 2136 2252 2137 /**2138 Removes the specified event listener.2253 /** 2254 Removes the specified event listener. 2139 2255 2140 @method unbind2141 @param {String} name Name of event to remove.2142 @param {function} fn Function to remove from listener.2143 */2256 @method unbind 2257 @param {String} name Name of event to remove. 2258 @param {function} fn Function to remove from listener. 2259 */ 2144 2260 2145 /**2146 Removes all event listeners.2261 /** 2262 Removes all event listeners. 2147 2263 2148 @method unbindAll2149 */2264 @method unbindAll 2265 */ 2150 2266 2151 2267 2268 /** 2269 * Destroys Plupload instance and cleans after itself. 2270 * 2271 * @method destroy 2272 */ 2273 destroy: function() { 2274 this.trigger('Destroy'); 2275 settings = total = null; // purge these exclusively 2276 this.unbindAll(); 2277 } 2278 }); 2279 }; 2280 2281 plupload.Uploader.prototype = o.core.EventTarget.instance; 2282 2152 2283 /** 2153 * Destroys Plupload instance and cleans after itself.2284 * Constructs a new file instance. 2154 2285 * 2155 * @method destroy 2286 * @class File 2287 * @constructor 2288 * 2289 * @param {Object} file Object containing file properties 2290 * @param {String} file.name Name of the file. 2291 * @param {Number} file.size File size. 2156 2292 */ 2157 destroy : function() { 2158 this.trigger('Destroy'); 2159 settings = total = null; // purge these exclusively 2160 this.unbindAll(); 2161 } 2162 }); 2163 }; 2293 plupload.File = (function() { 2294 var filepool = {}; 2164 2295 2165 plupload.Uploader.prototype = o.EventTarget.instance; 2296 function PluploadFile(file) { 2166 2297 2167 /** 2168 * Constructs a new file instance. 2169 * 2170 * @class File 2171 * @constructor 2172 * 2173 * @param {Object} file Object containing file properties 2174 * @param {String} file.name Name of the file. 2175 * @param {Number} file.size File size. 2176 */ 2177 plupload.File = (function() { 2178 var filepool = {}; 2298 plupload.extend(this, { 2179 2299 2180 function PluploadFile(file) { 2300 /** 2301 * File id this is a globally unique id for the specific file. 2302 * 2303 * @property id 2304 * @type String 2305 */ 2306 id: plupload.guid(), 2181 2307 2182 plupload.extend(this, { 2308 /** 2309 * File name for example "myfile.gif". 2310 * 2311 * @property name 2312 * @type String 2313 */ 2314 name: file.name || file.fileName, 2183 2315 2184 /**2185 * File id this is a globally unique id for the specific file.2186 *2187 * @property id2188 * @type String2189 */2190 id: plupload.guid(),2316 /** 2317 * File type, `e.g image/jpeg` 2318 * 2319 * @property type 2320 * @type String 2321 */ 2322 type: file.type || '', 2191 2323 2192 /** 2193 * File name for example "myfile.gif". 2194 * 2195 * @property name 2196 * @type String 2197 */ 2198 name: file.name || file.fileName, 2324 /** 2325 * Relative path to the file inside a directory 2326 * 2327 * @property relativePath 2328 * @type String 2329 * @default '' 2330 */ 2331 relativePath: file.relativePath || '', 2199 2332 2200 /**2201 * File type, `e.g image/jpeg`2202 *2203 * @property type2204 * @type String2205 */2206 type: file.type || '',2333 /** 2334 * File size in bytes (may change after client-side manupilation). 2335 * 2336 * @property size 2337 * @type Number 2338 */ 2339 size: file.fileSize || file.size, 2207 2340 2341 /** 2342 * Original file size in bytes. 2343 * 2344 * @property origSize 2345 * @type Number 2346 */ 2347 origSize: file.fileSize || file.size, 2348 2349 /** 2350 * Number of bytes uploaded of the files total size. 2351 * 2352 * @property loaded 2353 * @type Number 2354 */ 2355 loaded: 0, 2356 2357 /** 2358 * Number of percentage uploaded of the file. 2359 * 2360 * @property percent 2361 * @type Number 2362 */ 2363 percent: 0, 2364 2365 /** 2366 * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE. 2367 * 2368 * @property status 2369 * @type Number 2370 * @see plupload 2371 */ 2372 status: plupload.QUEUED, 2373 2374 /** 2375 * Date of last modification. 2376 * 2377 * @property lastModifiedDate 2378 * @type {String} 2379 */ 2380 lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString(), // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) 2381 2382 2383 /** 2384 * Set when file becomes plupload.DONE or plupload.FAILED. Is used to calculate proper plupload.QueueProgress.bytesPerSec. 2385 * @private 2386 * @property completeTimestamp 2387 * @type {Number} 2388 */ 2389 completeTimestamp: 0, 2390 2391 /** 2392 * Returns native window.File object, when it's available. 2393 * 2394 * @method getNative 2395 * @return {window.File} or null, if plupload.File is of different origin 2396 */ 2397 getNative: function() { 2398 var file = this.getSource().getSource(); 2399 return plupload.inArray(plupload.typeOf(file), ['blob', 'file']) !== -1 ? file : null; 2400 }, 2401 2402 /** 2403 * Returns mOxie.File - unified wrapper object that can be used across runtimes. 2404 * 2405 * @method getSource 2406 * @return {mOxie.File} or null 2407 */ 2408 getSource: function() { 2409 if (!filepool[this.id]) { 2410 return null; 2411 } 2412 return filepool[this.id]; 2413 }, 2414 2415 /** 2416 * Destroys plupload.File object. 2417 * 2418 * @method destroy 2419 */ 2420 destroy: function() { 2421 var src = this.getSource(); 2422 if (src) { 2423 src.destroy(); 2424 delete filepool[this.id]; 2425 } 2426 } 2427 }); 2428 2429 filepool[this.id] = file; 2430 } 2431 2432 return PluploadFile; 2433 }()); 2434 2435 2436 /** 2437 * Constructs a queue progress. 2438 * 2439 * @class QueueProgress 2440 * @constructor 2441 */ 2442 plupload.QueueProgress = function() { 2443 var self = this; // Setup alias for self to reduce code size when it's compressed 2444 2208 2445 /** 2209 * File size in bytes (may change after client-side manupilation).2446 * Total queue file size. 2210 2447 * 2211 2448 * @property size 2212 2449 * @type Number 2213 2450 */ 2214 s ize: file.size || file.fileSize,2451 self.size = 0; 2215 2452 2216 2453 /** 2217 * Original file size in bytes.2454 * Total bytes uploaded. 2218 2455 * 2219 * @property origSize2456 * @property loaded 2220 2457 * @type Number 2221 2458 */ 2222 origSize: file.size || file.fileSize,2459 self.loaded = 0; 2223 2460 2224 2461 /** 2225 * Number of bytes uploaded of the files total size.2462 * Number of files uploaded. 2226 2463 * 2227 * @property loaded2464 * @property uploaded 2228 2465 * @type Number 2229 2466 */ 2230 loaded: 0,2467 self.uploaded = 0; 2231 2468 2232 2469 /** 2233 * Number of percentage uploaded of the file.2470 * Number of files failed to upload. 2234 2471 * 2235 * @property percent2472 * @property failed 2236 2473 * @type Number 2237 2474 */ 2238 percent: 0,2475 self.failed = 0; 2239 2476 2240 2477 /** 2241 * Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.2478 * Number of files yet to be uploaded. 2242 2479 * 2243 * @property status2480 * @property queued 2244 2481 * @type Number 2245 * @see plupload2246 2482 */ 2247 s tatus: plupload.QUEUED,2483 self.queued = 0; 2248 2484 2249 2485 /** 2250 * Date of last modification.2486 * Total percent of the uploaded bytes. 2251 2487 * 2252 * @property lastModifiedDate2253 * @type {String}2488 * @property percent 2489 * @type Number 2254 2490 */ 2255 lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString(), // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)2491 self.percent = 0; 2256 2492 2257 2493 /** 2258 * Returns native window.File object, when it's available.2494 * Bytes uploaded per second. 2259 2495 * 2260 * @ method getNative2261 * @ return {window.File} or null, if plupload.File is of different origin2496 * @property bytesPerSec 2497 * @type Number 2262 2498 */ 2263 getNative: function() { 2264 var file = this.getSource().getSource(); 2265 return o.inArray(o.typeOf(file), ['blob', 'file']) !== -1 ? file : null; 2266 }, 2499 self.bytesPerSec = 0; 2267 2500 2268 2501 /** 2269 * Re turns mOxie.File - unified wrapper object that can be used across runtimes.2502 * Resets the progress to its initial values. 2270 2503 * 2271 * @method getSource 2272 * @return {mOxie.File} or null 2504 * @method reset 2273 2505 */ 2274 getSource: function() { 2275 if (!filepool[this.id]) { 2276 return null; 2277 } 2278 return filepool[this.id]; 2279 }, 2506 self.reset = function() { 2507 self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0; 2508 }; 2509 }; 2280 2510 2281 /** 2282 * Destroys plupload.File object. 2283 * 2284 * @method destroy 2285 */ 2286 destroy: function() { 2287 var src = this.getSource(); 2288 if (src) { 2289 src.destroy(); 2290 delete filepool[this.id]; 2291 } 2292 } 2293 }); 2511 exports.plupload = plupload; 2294 2512 2295 filepool[this.id] = file; 2296 } 2513 }(this, moxie)); 2297 2514 2298 return PluploadFile; 2299 }()); 2300 2301 2302 /** 2303 * Constructs a queue progress. 2304 * 2305 * @class QueueProgress 2306 * @constructor 2307 */ 2308 plupload.QueueProgress = function() { 2309 var self = this; // Setup alias for self to reduce code size when it's compressed 2310 2311 /** 2312 * Total queue file size. 2313 * 2314 * @property size 2315 * @type Number 2316 */ 2317 self.size = 0; 2318 2319 /** 2320 * Total bytes uploaded. 2321 * 2322 * @property loaded 2323 * @type Number 2324 */ 2325 self.loaded = 0; 2326 2327 /** 2328 * Number of files uploaded. 2329 * 2330 * @property uploaded 2331 * @type Number 2332 */ 2333 self.uploaded = 0; 2334 2335 /** 2336 * Number of files failed to upload. 2337 * 2338 * @property failed 2339 * @type Number 2340 */ 2341 self.failed = 0; 2342 2343 /** 2344 * Number of files yet to be uploaded. 2345 * 2346 * @property queued 2347 * @type Number 2348 */ 2349 self.queued = 0; 2350 2351 /** 2352 * Total percent of the uploaded bytes. 2353 * 2354 * @property percent 2355 * @type Number 2356 */ 2357 self.percent = 0; 2358 2359 /** 2360 * Bytes uploaded per second. 2361 * 2362 * @property bytesPerSec 2363 * @type Number 2364 */ 2365 self.bytesPerSec = 0; 2366 2367 /** 2368 * Resets the progress to its initial values. 2369 * 2370 * @method reset 2371 */ 2372 self.reset = function() { 2373 self.size = self.loaded = self.uploaded = self.failed = self.queued = self.percent = self.bytesPerSec = 0; 2374 }; 2375 }; 2376 2377 window.plupload = plupload; 2378 2379 }(window, mOxie)); 2515 })); 2516 No newline at end of file -
src/wp-includes/script-loader.php
1251 1251 'error_uploading' => __( '“%s” has failed to upload.' ), 1252 1252 ); 1253 1253 1254 $scripts->add( 'moxiejs', "/wp-includes/js/plupload/moxie$suffix.js", array(), '1. 3.5' );1255 $scripts->add( 'plupload', "/wp-includes/js/plupload/plupload$suffix.js", array( 'moxiejs' ), '2. 1.9' );1254 $scripts->add( 'moxiejs', "/wp-includes/js/plupload/moxie$suffix.js", array(), '1.5.7' ); 1255 $scripts->add( 'plupload', "/wp-includes/js/plupload/plupload$suffix.js", array( 'moxiejs' ), '2.3.6' ); 1256 1256 // Back compat handles: 1257 1257 foreach ( array( 'all', 'html5', 'flash', 'silverlight', 'html4' ) as $handle ) { 1258 1258 $scripts->add( "plupload-$handle", false, array( 'plupload' ), '2.1.1' );