Ticket #48277: 48277.2.diff
File 48277.2.diff, 788.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 4 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> 6 5 Everyone is permitted to copy and distribute verbatim copies 7 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 your12 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. 13 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. 20 19 21 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 this service if you wish), that you receive source code or can get it 25 if you want it, that you can change the software or use pieces of it 26 in new free programs; and that you know you can do these things. 27 28 To protect your rights, we need to make restrictions that forbid 29 anyone to deny you these rights or to ask you to surrender the rights. 30 These restrictions translate to certain responsibilities for you if you 31 distribute copies of the software, or if you modify it. 32 33 For example, if you distribute copies of such a program, whether 34 gratis or for a fee, you must give the recipients all the rights that 35 you have. You must make sure that they, too, receive or can get the 36 source code. And you must show them these terms so they know their 37 rights. 38 39 We protect your rights with two steps: (1) copyright the software, and 40 (2) offer you this license which gives you legal permission to copy, 41 distribute and/or modify the software. 42 43 Also, for each author's protection and ours, we want to make certain 44 that everyone understands that there is no warranty for this free 45 software. If the software is modified by someone else and passed on, we 46 want its recipients to know that what they have is not the original, so 47 that any problems introduced by others will not reflect on the original 48 authors' reputations. 49 50 Finally, any free program is threatened constantly by software 51 patents. We wish to avoid the danger that redistributors of a free 52 program will individually obtain patent licenses, in effect making the 53 program proprietary. To prevent this, we have made it clear that any 54 patent must be licensed for everyone's free use or not licensed at all. 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. 26 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. 31 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. 41 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. 49 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. 55 55 56 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". 71 72 Activities other than copying, distribution and modification are not 73 covered by this License; they are outside its scope. The act of 74 running the Program is not restricted, and the output from the Program 75 is covered only if its contents constitute a work based on the 76 Program (independent of having been made by running the Program). 77 Whether that is true depends on what the Program does. 78 79 1. You may copy and distribute verbatim copies of the Program's 80 source code as you receive it, in any medium, provided that you 81 conspicuously and appropriately publish on each copy an appropriate 82 copyright notice and disclaimer of warranty; keep intact all the 83 notices that refer to this License and to the absence of any warranty; 84 and give any other recipients of the Program a copy of this License 85 along with the Program. 86 87 You may charge a fee for the physical act of transferring a copy, and 88 you may at your option offer warranty protection in exchange for a fee. 89 90 2. You may modify your copy or copies of the Program or any portion 91 of it, thus forming a work based on the Program, and copy and 92 distribute such modifications or work under the terms of Section 1 93 above, provided that you also meet all of these conditions: 94 95 a) You must cause the modified files to carry prominent notices 96 stating that you changed the files and the date of any change. 97 98 b) You must cause any work that you distribute or publish, that in 99 whole or in part contains or is derived from the Program or any 100 part thereof, to be licensed as a whole at no charge to all third 101 parties under the terms of this License. 102 103 c) If the modified program normally reads commands interactively 104 when run, you must cause it, when started running for such 105 interactive use in the most ordinary way, to print or display an 106 announcement including an appropriate copyright notice and a 107 notice that there is no warranty (or else, saying that you provide 108 a warranty) and that users may redistribute the program under 109 these conditions, and telling the user how to view a copy of this 110 License. (Exception: if the Program itself is interactive but 111 does not normally print such an announcement, your work based on 112 the Program is not required to print an announcement.) 113 114 These requirements apply to the modified work as a whole. If 115 identifiable sections of that work are not derived from the Program, 116 and can be reasonably considered independent and separate works in 117 themselves, then this License, and its terms, do not apply to those 118 sections when you distribute them as separate works. But when you 119 distribute the same sections as part of a whole which is a work based 120 on the Program, the distribution of the whole must be on the terms of 121 this License, whose permissions for other licensees extend to the 122 entire whole, and thus to each and every part regardless of who wrote it. 123 124 Thus, it is not the intent of this section to claim rights or contest 125 your rights to work written entirely by you; rather, the intent is to 126 exercise the right to control the distribution of derivative or 127 collective works based on the Program. 128 129 In addition, mere aggregation of another work not based on the Program 130 with the Program (or with a work based on the Program) on a volume of 131 a storage or distribution medium does not bring the other work under 132 the scope of this License. 133 134 3. You may copy and distribute the Program (or a work based on it, 135 under Section 2) in object code or executable form under the terms of 136 Sections 1 and 2 above provided that you also do one of the following: 137 138 a) Accompany it with the complete corresponding machine-readable 139 source code, which must be distributed under the terms of Sections 140 1 and 2 above on a medium customarily used for software interchange; or, 141 142 b) Accompany it with a written offer, valid for at least three 143 years, to give any third party, for a charge no more than your 144 cost of physically performing source distribution, a complete 145 machine-readable copy of the corresponding source code, to be 146 distributed under the terms of Sections 1 and 2 above on a medium 147 customarily used for software interchange; or, 148 149 c) Accompany it with the information you received as to the offer 150 to distribute corresponding source code. (This alternative is 151 allowed only for noncommercial distribution and only if you 152 received the program in object code or executable form with such 153 an offer, in accord with Subsection b above.) 154 155 The source code for a work means the preferred form of the work for 156 making modifications to it. For an executable work, complete source 157 code means all the source code for all modules it contains, plus any 158 associated interface definition files, plus the scripts used to 159 control compilation and installation of the executable. However, as a 160 special exception, the source code distributed need not include 161 anything that is normally distributed (in either source or binary 162 form) with the major components (compiler, kernel, and so on) of the 163 operating system on which the executable runs, unless that component 164 itself accompanies the executable. 165 166 If distribution of executable or object code is made by offering 167 access to copy from a designated place, then offering equivalent 168 access to copy the source code from the same place counts as 169 distribution of the source code, even though third parties are not 170 compelled to copy the source along with the object code. 171 172 4. You may not copy, modify, sublicense, or distribute the Program 173 except as expressly provided under this License. Any attempt 174 otherwise to copy, modify, sublicense or distribute the Program is 175 void, and will automatically terminate your rights under this License. 176 However, parties who have received copies, or rights, from you under 177 this License will not have their licenses terminated so long as such 178 parties remain in full compliance. 179 180 5. You are not required to accept this License, since you have not 181 signed it. However, nothing else grants you permission to modify or 182 distribute the Program or its derivative works. These actions are 183 prohibited by law if you do not accept this License. Therefore, by 184 modifying or distributing the Program (or any work based on the 185 Program), you indicate your acceptance of this License to do so, and 186 all its terms and conditions for copying, distributing or modifying 187 the Program or works based on it. 188 189 6. Each time you redistribute the Program (or any work based on the 190 Program), the recipient automatically receives a license from the 191 original licensor to copy, distribute or modify the Program subject to 192 these terms and conditions. You may not impose any further 193 restrictions on the recipients' exercise of the rights granted herein. 194 You are not responsible for enforcing compliance by third parties to 61 0. Definitions. 62 63 "This License" refers to version 3 of the GNU Affero General Public License. 64 65 "Copyright" also means copyright-like laws that apply to other kinds of 66 works, such as semiconductor masks. 67 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. 71 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. 76 77 A "covered work" means either the unmodified Program or a work based 78 on the Program. 79 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. 86 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. 90 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. 99 100 1. Source Code. 101 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. 105 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. 110 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. 121 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. 134 135 The Corresponding Source need not include anything that users 136 can regenerate automatically from other parts of the Corresponding 137 Source. 138 139 The Corresponding Source for a work in source code form is that 140 same work. 141 142 2. Basic Permissions. 143 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. 151 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. 162 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. 209 210 If any portion of this section is held invalid or unenforceable under 211 any particular circumstance, the balance of the section is intended to 212 apply and the section as a whole is intended to apply in other 213 circumstances. 214 215 It is not the purpose of this section to induce you to infringe any 216 patents or other property right claims or to contest validity of any 217 such claims; this section has the sole purpose of protecting the 218 integrity of the free software distribution system, which is 219 implemented by public license practices. Many people have made 220 generous contributions to the wide range of software distributed 221 through that system in reliance on consistent application of that 222 system; it is up to the author/donor to decide if he or she is willing 223 to distribute software through any other system and a licensee cannot 224 impose that choice. 225 226 This section is intended to make thoroughly clear what is believed to 227 be a consequence of the rest of this License. 228 229 8. If the distribution and/or use of the Program is restricted in 230 certain countries either by patents or by copyrighted interfaces, the 231 original copyright holder who places the Program under this License 232 may add an explicit geographical distribution limitation excluding 233 those countries, so that distribution is permitted only in or among 234 countries not thus excluded. In such case, this License incorporates 235 the limitation as if written in the body of this License. 236 237 9. The Free Software Foundation may publish revised and/or new versions 238 of the General Public License from time to time. Such new versions will 239 be similar in spirit to the present version, but may differ in detail to 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. 539 540 13. Remote Network Interaction; Use with the GNU General Public License. 541 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. 552 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. 560 561 14. Revised Versions of this License. 562 563 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. 249 250 10. If you wish to incorporate parts of the Program into other free 251 programs whose distribution conditions are different, write to the author 252 to ask for permission. For software which is copyrighted by the Free 253 Software Foundation, write to the Free Software Foundation; we sometimes 254 make exceptions for this. Our decision will be guided by the two goals 255 of preserving the free status of all derivatives of our free software and 256 of promoting the sharing and reuse of software generally. 257 258 NO WARRANTY 259 260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 REPAIR OR CORRECTION. 269 270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 POSSIBILITY OF SUCH DAMAGES. 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. 576 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. 581 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. 586 587 15. Disclaimer of Warranty. 588 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. 597 598 16. Limitation of Liability. 599 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. 609 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. 279 618 280 619 END OF TERMS AND CONDITIONS 281 620 282 621 How to Apply These Terms to Your New Programs 283 622 284 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 … … 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 632 <one line to give the program's name and a brief idea of what it does.> 294 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 GNU General Public License as published by298 the Free Software Foundation ; either version 2of the License, or635 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 299 638 (at your option) any later version. 300 639 301 640 This program is distributed in the hope that it will be useful, 302 641 but WITHOUT ANY WARRANTY; without even the implied warranty of 303 642 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 GNU General Public License for more details.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: 314 315 Gnomovision version 69, Copyright (C) year name of author 316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 This is free software, and you are welcome to redistribute it 318 under certain conditions; type `show c' for details. 319 320 The hypothetical commands `show w' and `show c' should show the appropriate 321 parts of the General Public License. Of course, the commands you use may 322 be called something other than `show w' and `show c'; they could even be 323 mouse-clicks or menu items--whatever suits your program. 324 325 You should also get your employer (if you work as a programmer) or your 326 school, if any, to sign a "copyright disclaimer" for the program, if 327 necessary. Here is a sample; alter the names: 328 329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 332 <signature of Ty Coon>, 1 April 1989 333 Ty Coon, President of Vice 334 335 This General Public License does not permit incorporating your program into 336 proprietary programs. If your program is a subroutine library, you may 337 consider it more useful to permit linking proprietary applications with the 338 library. If this is what you want to do, use the GNU Lesser General 339 Public License instead of this License. 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. 657 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.8 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: 2016-05-15 13 */ 14 /** 15 * Compiled inline version. (Library mode) 12 * Date: 2018-02-19 16 13 */ 14 ;(function (global, factory) { 15 var extract = function() { 16 var ctx = {}; 17 factory.apply(ctx, arguments); 18 return ctx.moxie; 19 }; 17 20 18 /** 19 * Modified for WordPress, Silverlight and Flash runtimes support was removed. 20 * See https://core.trac.wordpress.org/ticket/41755. 21 */ 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() { 29 /** 30 * Compiled inline version. (Library mode) 31 */ 22 32 23 /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */24 /*globals $code */33 /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ 34 /*globals $code */ 25 35 26 (function(exports, undefined) {27 "use strict";36 (function(exports, undefined) { 37 "use strict"; 28 38 29 var modules = {};39 var modules = {}; 30 40 31 function require(ids, callback) {32 var module, defs = [];41 function require(ids, callback) { 42 var module, defs = []; 33 43 34 for (var i = 0; i < ids.length; ++i) { 35 module = modules[ids[i]] || resolve(ids[i]); 36 if (!module) { 37 throw 'module definition dependecy not found: ' + ids[i]; 44 for (var i = 0; i < ids.length; ++i) { 45 module = modules[ids[i]] || resolve(ids[i]); 46 if (!module) { 47 throw 'module definition dependecy not found: ' + ids[i]; 48 } 49 50 defs.push(module); 38 51 } 39 52 40 defs.push(module);53 callback.apply(null, defs); 41 54 } 42 55 43 callback.apply(null, defs); 44 } 56 function define(id, dependencies, definition) { 57 if (typeof id !== 'string') { 58 throw 'invalid module definition, module id must be defined and be a string'; 59 } 45 60 46 function define(id, dependencies, definition) { 47 if (typeof id !== 'string') { 48 throw 'invalid module definition, module id must be defined and be a string'; 49 } 61 if (dependencies === undefined) { 62 throw 'invalid module definition, dependencies must be specified'; 63 } 50 64 51 if (dependencies=== undefined) {52 throw 'invalid module definition, dependenciesmust be specified';53 }65 if (definition === undefined) { 66 throw 'invalid module definition, definition function must be specified'; 67 } 54 68 55 if (definition === undefined) { 56 throw 'invalid module definition, definition function must be specified'; 69 require(dependencies, function() { 70 modules[id] = definition.apply(null, arguments); 71 }); 57 72 } 58 73 59 require(dependencies, function() { 60 modules[id] = definition.apply(null, arguments); 61 }); 62 } 74 function defined(id) { 75 return !!modules[id]; 76 } 63 77 64 function defined(id) {65 return !!modules[id];66 }78 function resolve(id) { 79 var target = exports; 80 var fragments = id.split(/[.\/]/); 67 81 68 function resolve(id) { 69 var target = exports; 70 var fragments = id.split(/[.\/]/); 82 for (var fi = 0; fi < fragments.length; ++fi) { 83 if (!target[fragments[fi]]) { 84 return; 85 } 71 86 72 for (var fi = 0; fi < fragments.length; ++fi) { 73 if (!target[fragments[fi]]) { 74 return; 87 target = target[fragments[fi]]; 75 88 } 76 89 77 target = target[fragments[fi]];90 return target; 78 91 } 79 92 80 return target; 81 } 93 function expose(ids) { 94 for (var i = 0; i < ids.length; i++) { 95 var target = exports; 96 var id = ids[i]; 97 var fragments = id.split(/[.\/]/); 82 98 83 function expose(ids) { 84 for (var i = 0; i < ids.length; i++) { 85 var target = exports; 86 var id = ids[i]; 87 var fragments = id.split(/[.\/]/); 99 for (var fi = 0; fi < fragments.length - 1; ++fi) { 100 if (target[fragments[fi]] === undefined) { 101 target[fragments[fi]] = {}; 102 } 88 103 89 for (var fi = 0; fi < fragments.length - 1; ++fi) { 90 if (target[fragments[fi]] === undefined) { 91 target[fragments[fi]] = {}; 104 target = target[fragments[fi]]; 92 105 } 93 106 94 target = target[fragments[fi]];107 target[fragments[fragments.length - 1]] = modules[id]; 95 108 } 96 97 target[fragments[fragments.length - 1]] = modules[id];98 109 } 99 }100 110 101 111 // Included from: src/javascript/core/utils/Basic.js 102 112 103 /**104 * Basic.js105 *106 * Copyright 2013, Moxiecode Systems AB107 * Released under GPL License.108 *109 * License: http://www.plupload.com/license110 * Contributing: http://www.plupload.com/contributing111 */113 /** 114 * Basic.js 115 * 116 * Copyright 2013, Moxiecode Systems AB 117 * Released under GPL License. 118 * 119 * License: http://www.plupload.com/license 120 * Contributing: http://www.plupload.com/contributing 121 */ 112 122 113 define('moxie/core/utils/Basic', [], function() { 114 /** 123 /** 124 @class moxie/core/utils/Basic 125 @public 126 @static 127 */ 128 129 define('moxie/core/utils/Basic', [], function() { 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 */ 124 var typeOf = function(o) { 125 var undef; 126 127 if (o === undef) { 128 return 'undefined'; 129 } else if (o === null) { 130 return 'null'; 131 } else if (o.nodeType) { 132 return 'node'; 133 } 138 */ 139 function typeOf(o) { 140 var undef; 134 141 135 // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8 136 return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); 137 }; 138 139 /** 140 Extends the specified object with another object. 142 if (o === undef) { 143 return 'undefined'; 144 } else if (o === null) { 145 return 'null'; 146 } else if (o.nodeType) { 147 return 'node'; 148 } 149 150 // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8 151 return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); 152 } 153 154 /** 155 Extends the specified object with another object(s). 141 156 142 157 @method extend 143 158 @static 144 159 @param {Object} target Object to extend. 145 160 @param {Object} [obj]* Multiple objects to extend with. 146 161 @return {Object} Same as target, the extended object. 147 */ 148 var extend = function(target) { 149 var undef; 150 151 each(arguments, function(arg, i) { 152 if (i > 0) { 153 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 } 162 */ 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) { 219 var undef; 220 var target = args[0]; 221 222 each(args, function(arg, i) { 223 if (i > 0) { 224 each(arg, function(value, key) { 225 var isComplex = inArray(typeOf(value), ['array', 'object']) !== -1; 226 227 if (value === undef || strict && target[key] === undef) { 228 return true; 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 } 240 }); 160 241 } 161 242 }); 243 244 return target; 162 245 } 163 }); 164 return target; 165 }; 166 167 /** 246 247 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 … … 172 293 @static 173 294 @param {Object} obj Object to iterate. 174 295 @param {function} callback Callback function to execute for each item. 175 */ 176 var each = function(obj, callback) { 177 var length, key, i, undef; 178 179 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; 296 */ 297 function each(obj, callback) { 298 var length, key, i, undef; 299 300 if (obj) { 301 try { 302 length = obj.length; 303 } catch(ex) { 304 length = undef; 185 305 } 186 } 187 } else if (typeOf(obj) === 'object') { 188 // Loop object items 189 for (key in obj) { 190 if (obj.hasOwnProperty(key)) { 191 if (callback(obj[key], key) === false) { 192 return; 306 307 if (length === undef || typeof(length) !== 'number') { 308 // Loop object items 309 for (key in obj) { 310 if (obj.hasOwnProperty(key)) { 311 if (callback(obj[key], key) === false) { 312 return; 313 } 314 } 315 } 316 } else { 317 // Loop array items 318 for (i = 0; i < length; i++) { 319 if (callback(obj[i], i) === false) { 320 return; 321 } 193 322 } 194 323 } 195 324 } 196 325 } 197 }198 };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 */208 var isEmptyObj = function(obj) {209 var prop;334 */ 335 function isEmptyObj(obj) { 336 var prop; 210 337 211 if (!obj || typeOf(obj) !== 'object') {212 return true;213 }338 if (!obj || typeOf(obj) !== 'object') { 339 return true; 340 } 214 341 215 for (prop in obj) {216 return false;217 }342 for (prop in obj) { 343 return false; 344 } 218 345 219 return true;220 };346 return true; 347 } 221 348 222 /**349 /** 223 350 Recieve an array of functions (usually async) to call in sequence, each function 224 351 receives a callback as first argument that it should call, when it completes. Finally, 225 352 after everything is complete, main callback is called. Passing truthy value to the … … 230 357 @static 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 */234 var inSeries = function(queue, cb) {235 var i = 0, length = queue.length;360 */ 361 function inSeries(queue, cb) { 362 var i = 0, length = queue.length; 236 363 237 if (typeOf(cb) !== 'function') {238 cb = function() {};239 }364 if (typeOf(cb) !== 'function') { 365 cb = function() {}; 366 } 240 367 241 if (!queue || !queue.length) {242 cb();243 }368 if (!queue || !queue.length) { 369 cb(); 370 } 244 371 245 function callNext(i) { 246 if (typeOf(queue[i]) === 'function') { 247 queue[i](function(error) { 248 /*jshint expr:true */ 249 ++i < length && !error ? callNext(i) : cb(error); 250 }); 372 function callNext(i) { 373 if (typeOf(queue[i]) === 'function') { 374 queue[i](function(error) { 375 /*jshint expr:true */ 376 ++i < length && !error ? callNext(i) : cb(error); 377 }); 378 } 379 } 380 callNext(i); 251 381 } 252 }253 callNext(i);254 };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 r268 */269 var inParallel = function(queue, cb) {270 var count = 0, num = queue.length, cbArgs = new Array(num);271 272 each(queue, function(fn, i) {273 fn(function(error) {274 if (error) {275 return cb(error);276 }277 278 var args = [].slice.call(arguments);279 args.shift(); // strip error - undefined or not280 281 cbArgs[i] = args;282 count++;283 284 if (count === num) {285 cbArgs.unshift(null);286 cb.apply(this, cbArgs);287 }288 });289 });290 };291 292 293 /**394 @param {Function} cb Main callback that is called in the end, or in case of erro 395 */ 396 function inParallel(queue, cb) { 397 var count = 0, num = queue.length, cbArgs = new Array(num); 398 399 each(queue, function(fn, i) { 400 fn(function(error) { 401 if (error) { 402 return cb(error); 403 } 404 405 var args = [].slice.call(arguments); 406 args.shift(); // strip error - undefined or not 407 408 cbArgs[i] = args; 409 count++; 410 411 if (count === num) { 412 cbArgs.unshift(null); 413 cb.apply(this, cbArgs); 414 } 415 }); 416 }); 417 } 418 419 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 */ 302 var inArray = function(needle, array) { 303 if (array) { 304 if (Array.prototype.indexOf) { 305 return Array.prototype.indexOf.call(array, needle); 306 } 307 308 for (var i = 0, length = array.length; i < length; i++) { 309 if (array[i] === needle) { 310 return i; 428 */ 429 function inArray(needle, array) { 430 if (array) { 431 if (Array.prototype.indexOf) { 432 return Array.prototype.indexOf.call(array, needle); 433 } 434 435 for (var i = 0, length = array.length; i < length; i++) { 436 if (array[i] === needle) { 437 return i; 438 } 439 } 311 440 } 441 return -1; 312 442 } 313 }314 return -1;315 };316 443 317 444 318 /**445 /** 319 446 Returns elements of first array if they are not present in second. And false - otherwise. 320 447 321 448 @private … … 323 450 @param {Array} needles 324 451 @param {Array} array 325 452 @return {Array|Boolean} 326 */327 var arrayDiff = function(needles, array) {328 var diff = [];453 */ 454 function arrayDiff(needles, array) { 455 var diff = []; 329 456 330 if (typeOf(needles) !== 'array') {331 needles = [needles];332 }457 if (typeOf(needles) !== 'array') { 458 needles = [needles]; 459 } 333 460 334 if (typeOf(array) !== 'array') {335 array = [array];336 }461 if (typeOf(array) !== 'array') { 462 array = [array]; 463 } 337 464 338 for (var i in needles) {339 if (inArray(needles[i], array) === -1) {340 diff.push(needles[i]);341 }342 }343 return diff.length ? diff : false;344 };465 for (var i in needles) { 466 if (inArray(needles[i], array) === -1) { 467 diff.push(needles[i]); 468 } 469 } 470 return diff.length ? diff : false; 471 } 345 472 346 473 347 /**474 /** 348 475 Find intersection of two arrays. 349 476 350 477 @private … … 352 479 @param {Array} array1 353 480 @param {Array} array2 354 481 @return {Array} Intersection of two arrays or null if there is none 355 */ 356 var arrayIntersect = function(array1, array2) { 357 var result = []; 358 each(array1, function(item) { 359 if (inArray(item, array2) !== -1) { 360 result.push(item); 482 */ 483 function arrayIntersect(array1, array2) { 484 var result = []; 485 each(array1, function(item) { 486 if (inArray(item, array2) !== -1) { 487 result.push(item); 488 } 489 }); 490 return result.length ? result : null; 361 491 } 362 }); 363 return result.length ? result : null; 364 }; 365 366 367 /** 492 493 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 */375 var toArray = function(obj) {376 var i, arr = [];501 */ 502 function toArray(obj) { 503 var i, arr = []; 377 504 378 for (i = 0; i < obj.length; i++) {379 arr[i] = obj[i];380 }505 for (i = 0; i < obj.length; i++) { 506 arr[i] = obj[i]; 507 } 381 508 382 return arr;383 };384 385 386 /**509 return arr; 510 } 511 512 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). 395 522 @method guid 396 523 @return {String} Virtually unique id. 397 */ 398 var guid = (function() { 399 var counter = 0; 400 401 return function(prefix) { 402 var guid = new Date().getTime().toString(32), i; 403 404 for (i = 0; i < 5; i++) { 405 guid += Math.floor(Math.random() * 65535).toString(32); 406 } 407 408 return (prefix || 'o_') + guid + (counter++).toString(32); 409 }; 410 }()); 411 524 */ 525 var guid = (function() { 526 var counter = 0; 412 527 413 /** 528 return function(prefix) { 529 var guid = new Date().getTime().toString(32), i; 530 531 for (i = 0; i < 5; i++) { 532 guid += Math.floor(Math.random() * 65535).toString(32); 533 } 534 535 return (prefix || 'o_') + guid + (counter++).toString(32); 536 }; 537 }()); 538 539 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 */421 var trim = function(str) {422 if (!str) {423 return str;424 }425 return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, '');426 };547 */ 548 function trim(str) { 549 if (!str) { 550 return str; 551 } 552 return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, ''); 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 */ 437 var parseSizeStr = function(size) { 438 if (typeof(size) !== 'string') { 439 return size; 440 } 441 442 var muls = { 443 t: 1099511627776, 444 g: 1073741824, 445 m: 1048576, 446 k: 1024 447 }, 448 mul; 563 */ 564 function parseSizeStr(size) { 565 if (typeof(size) !== 'string') { 566 return size; 567 } 449 568 569 var muls = { 570 t: 1099511627776, 571 g: 1073741824, 572 m: 1048576, 573 k: 1024 574 }, 575 mul; 450 576 451 size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, '')); 452 mul = size[2]; 453 size = +size[1]; 454 455 if (muls.hasOwnProperty(mul)) { 456 size *= muls[mul]; 457 } 458 return Math.floor(size); 459 }; 577 size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, '')); 578 mul = size[2]; 579 size = +size[1]; 460 580 581 if (muls.hasOwnProperty(mul)) { 582 size *= muls[mul]; 583 } 584 return Math.floor(size); 585 } 461 586 462 /**463 * Pseudo sprintf implementation - simple way to replace tokens with specified values.464 *465 * @param {String} str String with tokens466 * @return {String} String with replaced tokens467 */468 var sprintf = function(str) {469 var args = [].slice.call(arguments, 1);470 587 471 return str.replace(/%[a-z]/g, function() { 472 var value = args.shift(); 473 return typeOf(value) !== 'undefined' ? value : ''; 474 }); 475 }; 476 588 /** 589 * Pseudo sprintf implementation - simple way to replace tokens with specified values. 590 * 591 * @param {String} str String with tokens 592 * @return {String} String with replaced tokens 593 */ 594 function sprintf(str) { 595 var args = [].slice.call(arguments, 1); 477 596 478 return { 479 guid: guid, 480 typeOf: typeOf, 481 extend: extend, 482 each: each, 483 isEmptyObj: isEmptyObj, 484 inSeries: inSeries, 485 inParallel: inParallel, 486 inArray: inArray, 487 arrayDiff: arrayDiff, 488 arrayIntersect: arrayIntersect, 489 toArray: toArray, 490 trim: trim, 491 sprintf: sprintf, 492 parseSizeStr: parseSizeStr 493 }; 494 }); 597 return str.replace(/%([a-z])/g, function($0, $1) { 598 var value = args.shift(); 495 599 496 // Included from: src/javascript/core/utils/Env.js 600 switch ($1) { 601 case 's': 602 return value + ''; 497 603 498 /** 499 * Env.js 500 * 501 * Copyright 2013, Moxiecode Systems AB 502 * Released under GPL License. 503 * 504 * License: http://www.plupload.com/license 505 * Contributing: http://www.plupload.com/contributing 506 */ 604 case 'd': 605 return parseInt(value, 10); 507 606 508 define("moxie/core/utils/Env", [ 509 "moxie/core/utils/Basic" 510 ], function(Basic) { 511 512 /** 513 * UAParser.js v0.7.7 514 * Lightweight JavaScript-based User-Agent string parser 515 * https://github.com/faisalman/ua-parser-js 516 * 517 * Copyright © 2012-2015 Faisal Salman <fyzlman@gmail.com> 518 * Dual licensed under GPLv2 & MIT 519 */ 520 var UAParser = (function (undefined) { 607 case 'f': 608 return parseFloat(value); 521 609 522 ////////////// 523 // Constants 524 ///////////// 525 526 527 var EMPTY = '', 528 UNKNOWN = '?', 529 FUNC_TYPE = 'function', 530 UNDEF_TYPE = 'undefined', 531 OBJ_TYPE = 'object', 532 MAJOR = 'major', 533 MODEL = 'model', 534 NAME = 'name', 535 TYPE = 'type', 536 VENDOR = 'vendor', 537 VERSION = 'version', 538 ARCHITECTURE= 'architecture', 539 CONSOLE = 'console', 540 MOBILE = 'mobile', 541 TABLET = 'tablet'; 542 543 544 /////////// 545 // Helper 546 ////////// 547 548 549 var util = { 550 has : function (str1, str2) { 551 return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; 552 }, 553 lowerize : function (str) { 554 return str.toLowerCase(); 555 } 556 }; 557 558 559 /////////////// 560 // Map helper 561 ////////////// 562 563 564 var mapper = { 565 566 rgx : function () { 567 568 // loop through all regexes maps 569 for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { 570 571 var regex = args[i], // even sequence (0,2,4,..) 572 props = args[i + 1]; // odd sequence (1,3,5,..) 573 574 // construct object barebones 575 if (typeof(result) === UNDEF_TYPE) { 576 result = {}; 577 for (p in props) { 578 q = props[p]; 579 if (typeof(q) === OBJ_TYPE) { 580 result[q[0]] = undefined; 581 } else { 582 result[q] = undefined; 583 } 584 } 585 } 586 587 // try matching uastring with regexes 588 for (j = k = 0; j < regex.length; j++) { 589 matches = regex[j].exec(this.getUA()); 590 if (!!matches) { 591 for (p = 0; p < props.length; p++) { 592 match = matches[++k]; 593 q = props[p]; 594 // check if given property is actually array 595 if (typeof(q) === OBJ_TYPE && q.length > 0) { 596 if (q.length == 2) { 597 if (typeof(q[1]) == FUNC_TYPE) { 598 // assign modified match 599 result[q[0]] = q[1].call(this, match); 600 } else { 601 // assign given value, ignore regex match 602 result[q[0]] = q[1]; 603 } 604 } else if (q.length == 3) { 605 // check whether function or regex 606 if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { 607 // call function (usually string mapper) 608 result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; 609 } else { 610 // sanitize match using given regex 611 result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; 612 } 613 } else if (q.length == 4) { 614 result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; 615 } 616 } else { 617 result[q] = match ? match : undefined; 618 } 619 } 620 break; 621 } 622 } 623 624 if(!!matches) break; // break the loop immediately if match found 625 } 626 return result; 627 }, 628 629 str : function (str, map) { 630 631 for (var i in map) { 632 // check if array 633 if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { 634 for (var j = 0; j < map[i].length; j++) { 635 if (util.has(map[i][j], str)) { 636 return (i === UNKNOWN) ? undefined : i; 637 } 638 } 639 } else if (util.has(map[i], str)) { 640 return (i === UNKNOWN) ? undefined : i; 641 } 642 } 643 return str; 644 } 645 }; 646 647 648 /////////////// 649 // String map 650 ////////////// 651 652 653 var maps = { 654 655 browser : { 656 oldsafari : { 657 major : { 658 '1' : ['/8', '/1', '/3'], 659 '2' : '/4', 660 '?' : '/' 661 }, 662 version : { 663 '1.0' : '/8', 664 '1.2' : '/1', 665 '1.3' : '/3', 666 '2.0' : '/412', 667 '2.0.2' : '/416', 668 '2.0.3' : '/417', 669 '2.0.4' : '/419', 670 '?' : '/' 671 } 672 } 673 }, 674 675 device : { 676 sprint : { 677 model : { 678 'Evo Shift 4G' : '7373KT' 679 }, 680 vendor : { 681 'HTC' : 'APA', 682 'Sprint' : 'Sprint' 683 } 684 } 685 }, 686 687 os : { 688 windows : { 689 version : { 690 'ME' : '4.90', 691 'NT 3.11' : 'NT3.51', 692 'NT 4.0' : 'NT4.0', 693 '2000' : 'NT 5.0', 694 'XP' : ['NT 5.1', 'NT 5.2'], 695 'Vista' : 'NT 6.0', 696 '7' : 'NT 6.1', 697 '8' : 'NT 6.2', 698 '8.1' : 'NT 6.3', 699 'RT' : 'ARM' 700 } 701 } 702 } 703 }; 704 705 706 ////////////// 707 // Regex map 708 ///////////// 709 710 711 var regexes = { 712 713 browser : [[ 714 715 // Presto based 716 /(opera\smini)\/([\w\.-]+)/i, // Opera Mini 717 /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet 718 /(opera).+version\/([\w\.]+)/i, // Opera > 9.80 719 /(opera)[\/\s]+([\w\.]+)/i // Opera < 9.80 720 721 ], [NAME, VERSION], [ 722 723 /\s(opr)\/([\w\.]+)/i // Opera Webkit 724 ], [[NAME, 'Opera'], VERSION], [ 725 726 // Mixed 727 /(kindle)\/([\w\.]+)/i, // Kindle 728 /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i, 729 // Lunascape/Maxthon/Netfront/Jasmine/Blazer 730 731 // Trident based 732 /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i, 733 // Avant/IEMobile/SlimBrowser/Baidu 734 /(?:ms|\()(ie)\s([\w\.]+)/i, // Internet Explorer 735 736 // Webkit/KHTML based 737 /(rekonq)\/([\w\.]+)*/i, // Rekonq 738 /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i 739 // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron 740 ], [NAME, VERSION], [ 741 742 /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i // IE11 743 ], [[NAME, 'IE'], VERSION], [ 744 745 /(edge)\/((\d+)?[\w\.]+)/i // Microsoft Edge 746 ], [NAME, VERSION], [ 747 748 /(yabrowser)\/([\w\.]+)/i // Yandex 749 ], [[NAME, 'Yandex'], VERSION], [ 750 751 /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon 752 ], [[NAME, /_/g, ' '], VERSION], [ 753 754 /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i, 755 // Chrome/OmniWeb/Arora/Tizen/Nokia 756 /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i 757 // UCBrowser/QQBrowser 758 ], [NAME, VERSION], [ 759 760 /(dolfin)\/([\w\.]+)/i // Dolphin 761 ], [[NAME, 'Dolphin'], VERSION], [ 762 763 /((?:android.+)crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS 764 ], [[NAME, 'Chrome'], VERSION], [ 765 766 /XiaoMi\/MiuiBrowser\/([\w\.]+)/i // MIUI Browser 767 ], [VERSION, [NAME, 'MIUI Browser']], [ 768 769 /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i // Android Browser 770 ], [VERSION, [NAME, 'Android Browser']], [ 771 772 /FBAV\/([\w\.]+);/i // Facebook App for iOS 773 ], [VERSION, [NAME, 'Facebook']], [ 774 775 /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari 776 ], [VERSION, [NAME, 'Mobile Safari']], [ 777 778 /version\/([\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile 779 ], [VERSION, NAME], [ 780 781 /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 782 ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [ 783 784 /(konqueror)\/([\w\.]+)/i, // Konqueror 785 /(webkit|khtml)\/([\w\.]+)/i 786 ], [NAME, VERSION], [ 787 788 // Gecko based 789 /(navigator|netscape)\/([\w\.-]+)/i // Netscape 790 ], [[NAME, 'Netscape'], VERSION], [ 791 /(swiftfox)/i, // Swiftfox 792 /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i, 793 // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror 794 /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i, 795 // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix 796 /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla 797 798 // Other 799 /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i, 800 // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf 801 /(links)\s\(([\w\.]+)/i, // Links 802 /(gobrowser)\/?([\w\.]+)*/i, // GoBrowser 803 /(ice\s?browser)\/v?([\w\._]+)/i, // ICE Browser 804 /(mosaic)[\/\s]([\w\.]+)/i // Mosaic 805 ], [NAME, VERSION] 806 ], 807 808 engine : [[ 809 810 /windows.+\sedge\/([\w\.]+)/i // EdgeHTML 811 ], [VERSION, [NAME, 'EdgeHTML']], [ 812 813 /(presto)\/([\w\.]+)/i, // Presto 814 /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m 815 /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links 816 /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab 817 ], [NAME, VERSION], [ 818 819 /rv\:([\w\.]+).*(gecko)/i // Gecko 820 ], [VERSION, NAME] 821 ], 822 823 os : [[ 824 825 // Windows based 826 /microsoft\s(windows)\s(vista|xp)/i // Windows (iTunes) 827 ], [NAME, VERSION], [ 828 /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT 829 /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i 830 ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ 831 /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i 832 ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ 833 834 // Mobile/Embedded OS 835 /\((bb)(10);/i // BlackBerry 10 836 ], [[NAME, 'BlackBerry'], VERSION], [ 837 /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry 838 /(tizen)[\/\s]([\w\.]+)/i, // Tizen 839 /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i, 840 // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki 841 /linux;.+(sailfish);/i // Sailfish OS 842 ], [NAME, VERSION], [ 843 /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian 844 ], [[NAME, 'Symbian'], VERSION], [ 845 /\((series40);/i // Series 40 846 ], [NAME], [ 847 /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS 848 ], [[NAME, 'Firefox OS'], VERSION], [ 849 850 // Console 851 /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation 852 853 // GNU/Linux based 854 /(mint)[\/\s\(]?(\w+)*/i, // Mint 855 /(mageia|vectorlinux)[;\s]/i, // Mageia/VectorLinux 856 /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i, 857 // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware 858 // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus 859 /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux 860 /(gnu)\s?([\w\.]+)*/i // GNU 861 ], [NAME, VERSION], [ 862 863 /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS 864 ], [[NAME, 'Chromium OS'], VERSION],[ 865 866 // Solaris 867 /(sunos)\s?([\w\.]+\d)*/i // Solaris 868 ], [[NAME, 'Solaris'], VERSION], [ 869 870 // BSD based 871 /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly 872 ], [NAME, VERSION],[ 873 874 /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS 875 ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ 876 877 /(mac\sos\sx)\s?([\w\s\.]+\w)*/i, 878 /(macintosh|mac(?=_powerpc)\s)/i // Mac OS 879 ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [ 880 881 // Other 882 /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i, // Solaris 883 /(haiku)\s(\w+)/i, // Haiku 884 /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX 885 /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i, 886 // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS 887 /(unix)\s?([\w\.]+)*/i // UNIX 888 ], [NAME, VERSION] 889 ] 890 }; 891 892 893 ///////////////// 894 // Constructor 895 //////////////// 896 897 898 var UAParser = function (uastring) { 899 900 var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); 901 902 this.getBrowser = function () { 903 return mapper.rgx.apply(this, regexes.browser); 904 }; 905 this.getEngine = function () { 906 return mapper.rgx.apply(this, regexes.engine); 907 }; 908 this.getOS = function () { 909 return mapper.rgx.apply(this, regexes.os); 910 }; 911 this.getResult = function() { 912 return { 913 ua : this.getUA(), 914 browser : this.getBrowser(), 915 engine : this.getEngine(), 916 os : this.getOS() 917 }; 918 }; 919 this.getUA = function () { 920 return ua; 921 }; 922 this.setUA = function (uastring) { 923 ua = uastring; 924 return this; 925 }; 926 this.setUA(ua); 927 }; 928 929 return UAParser; 930 })(); 931 932 933 function version_compare(v1, v2, operator) { 934 // From: http://phpjs.org/functions 935 // + original by: Philippe Jausions (http://pear.php.net/user/jausions) 936 // + original by: Aidan Lister (http://aidanlister.com/) 937 // + reimplemented by: Kankrelune (http://www.webfaktory.info/) 938 // + improved by: Brett Zamir (http://brett-zamir.me) 939 // + improved by: Scott Baker 940 // + improved by: Theriault 941 // * example 1: version_compare('8.2.5rc', '8.2.5a'); 942 // * returns 1: 1 943 // * example 2: version_compare('8.2.50', '8.2.52', '<'); 944 // * returns 2: true 945 // * example 3: version_compare('5.3.0-dev', '5.3.0'); 946 // * returns 3: -1 947 // * example 4: version_compare('4.1.0.52','4.01.0.51'); 948 // * returns 4: 1 949 950 // Important: compare must be initialized at 0. 951 var i = 0, 952 x = 0, 953 compare = 0, 954 // vm maps textual PHP versions to negatives so they're less than 0. 955 // PHP currently defines these as CASE-SENSITIVE. It is important to 956 // leave these as negatives so that they can come before numerical versions 957 // and as if no letters were there to begin with. 958 // (1alpha is < 1 and < 1.1 but > 1dev1) 959 // If a non-numerical value can't be mapped to this table, it receives 960 // -7 as its value. 961 vm = { 962 'dev': -6, 963 'alpha': -5, 964 'a': -5, 965 'beta': -4, 966 'b': -4, 967 'RC': -3, 968 'rc': -3, 969 '#': -2, 970 'p': 1, 971 'pl': 1 972 }, 973 // This function will be called to prepare each version argument. 974 // It replaces every _, -, and + with a dot. 975 // It surrounds any nonsequence of numbers/dots with dots. 976 // It replaces sequences of dots with a single dot. 977 // version_compare('4..0', '4.0') == 0 978 // Important: A string of 0 length needs to be converted into a value 979 // even less than an unexisting value in vm (-7), hence [-8]. 980 // It's also important to not strip spaces because of this. 981 // version_compare('', ' ') == 1 982 prepVersion = function (v) { 983 v = ('' + v).replace(/[_\-+]/g, '.'); 984 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 985 return (!v.length ? [-8] : v.split('.')); 986 }, 987 // This converts a version component to a number. 988 // Empty component becomes 0. 989 // Non-numerical component becomes a negative number. 990 // Numerical component becomes itself as an integer. 991 numVersion = function (v) { 992 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 993 }; 994 995 v1 = prepVersion(v1); 996 v2 = prepVersion(v2); 997 x = Math.max(v1.length, v2.length); 998 for (i = 0; i < x; i++) { 999 if (v1[i] == v2[i]) { 1000 continue; 1001 } 1002 v1[i] = numVersion(v1[i]); 1003 v2[i] = numVersion(v2[i]); 1004 if (v1[i] < v2[i]) { 1005 compare = -1; 1006 break; 1007 } else if (v1[i] > v2[i]) { 1008 compare = 1; 1009 break; 1010 } 1011 } 1012 if (!operator) { 1013 return compare; 1014 } 1015 1016 // Important: operator is CASE-SENSITIVE. 1017 // "No operator" seems to be treated as "<." 1018 // Any other values seem to make the function return null. 1019 switch (operator) { 1020 case '>': 1021 case 'gt': 1022 return (compare > 0); 1023 case '>=': 1024 case 'ge': 1025 return (compare >= 0); 1026 case '<=': 1027 case 'le': 1028 return (compare <= 0); 1029 case '==': 1030 case '=': 1031 case 'eq': 1032 return (compare === 0); 1033 case '<>': 1034 case '!=': 1035 case 'ne': 1036 return (compare !== 0); 1037 case '': 1038 case '<': 1039 case 'lt': 1040 return (compare < 0); 1041 default: 1042 return null; 1043 } 1044 } 610 case 'c': 611 return ''; 1045 612 613 default: 614 return value; 615 } 616 }); 617 } 1046 618 1047 var can = (function() {1048 var caps = {1049 define_property: (function() {1050 /* // currently too much extra code required, not exactly worth it1051 try { // as of IE8, getters/setters are supported only on DOM elements1052 var obj = {};1053 if (Object.defineProperty) {1054 Object.defineProperty(obj, 'prop', {1055 enumerable: true,1056 configurable: true1057 });1058 return true;1059 }1060 } catch(ex) {}1061 619 1062 if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {1063 return true;1064 }*/1065 return false;1066 }()),1067 620 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 }()), 621 function delay(cb, timeout) { 622 var self = this; 623 setTimeout(function() { 624 cb.call(self); 625 }, timeout || 1); 626 } 1075 627 1076 return_response_type: function(responseType) {1077 try {1078 if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {1079 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 }1092 } catch (ex) {}1093 return false;1094 },1095 628 1096 // ideas for this heavily come from Modernizr (http://modernizr.com/) 1097 use_data_uri: (function() { 1098 var du = new Image(); 629 return { 630 guid: guid, 631 typeOf: typeOf, 632 extend: extend, 633 extendIf: extendIf, 634 extendImmutable: extendImmutable, 635 extendImmutableIf: extendImmutableIf, 636 clone: clone, 637 inherit: inherit, 638 each: each, 639 isEmptyObj: isEmptyObj, 640 inSeries: inSeries, 641 inParallel: inParallel, 642 inArray: inArray, 643 arrayDiff: arrayDiff, 644 arrayIntersect: arrayIntersect, 645 toArray: toArray, 646 trim: trim, 647 sprintf: sprintf, 648 parseSizeStr: parseSizeStr, 649 delay: delay 650 }; 651 }); 1099 652 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 }()), 653 // Included from: src/javascript/core/utils/Encode.js 1109 654 1110 use_data_uri_over32kb: function() { // IE8 1111 return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9); 1112 }, 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 */ 1113 664 1114 use_data_uri_of: function(bytes) { 1115 return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); 1116 }, 665 /** 666 @class moxie/core/utils/Encode 667 @public 668 @static 669 */ 1117 670 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 } 671 define('moxie/core/utils/Encode', [], function() { 1122 672 1123 var el = document.createElement('input'); 1124 el.setAttribute('type', 'file'); 1125 return !el.disabled; 1126 } 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)); 1127 683 }; 1128 684 1129 return function(cap) { 1130 var args = [].slice.call(arguments); 1131 args.shift(); // shift of cap 1132 return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap]; 1133 }; 1134 }()); 685 /** 686 Decode UTF-8 encoded string 1135 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 }; 1136 696 1137 var uaResult = new UAParser().getResult(); 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 1138 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); 1139 760 1140 var Env = { 1141 can: can, 761 dec = tmp_arr.join(''); 1142 762 1143 uaParser: UAParser, 1144 1145 browser: uaResult.browser.name, 1146 version: uaResult.browser.version, 1147 os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason 1148 osVersion: uaResult.os.version, 763 return utf8 ? utf8_decode(dec) : dec; 764 }; 1149 765 1150 verComp: version_compare, 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 1151 769 1152 global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent" 1153 }; 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); 1154 821 1155 // for backward compatibility 1156 // @deprecated Use `Env.os` instead 1157 Env.OS = Env.os; 1158 1159 if (MXI_DEBUG) { 1160 Env.debug = { 1161 runtime: true, 1162 events: false 1163 }; 1164 1165 Env.log = function() { 1166 1167 function logObj(data) { 1168 // TODO: this should recursively print out the object in a pretty way 1169 console.appendChild(document.createTextNode(data + "\n")); 1170 } 1171 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); 1180 } else if (document) { 1181 var console = document.getElementById('moxie-console'); 1182 if (!console) { 1183 console = document.createElement('pre'); 1184 console.id = 'moxie-console'; 1185 //console.style.display = 'none'; 1186 document.body.appendChild(console); 1187 } 822 enc = tmp_arr.join(''); 1188 823 1189 if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) { 1190 logObj(data); 1191 } else { 1192 console.appendChild(document.createTextNode(data + "\n")); 1193 } 1194 } 1195 }; 1196 } 824 var r = data.length % 3; 1197 825 1198 return Env;1199 });826 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); 827 }; 1200 828 1201 // Included from: src/javascript/core/I18n.js1202 829 1203 /** 1204 * I18n.js 1205 * 1206 * Copyright 2013, Moxiecode Systems AB 1207 * Released under GPL License. 1208 * 1209 * License: http://www.plupload.com/license 1210 * Contributing: http://www.plupload.com/contributing 1211 */ 830 return { 831 utf8_encode: utf8_encode, 832 utf8_decode: utf8_decode, 833 atob: atob, 834 btoa: btoa 835 }; 836 }); 1212 837 1213 define("moxie/core/I18n", [ 1214 "moxie/core/utils/Basic" 1215 ], function(Basic) { 1216 var i18n = {}; 838 // Included from: src/javascript/core/utils/Env.js 1217 839 1218 return {1219 840 /** 1220 * E xtends the language pack object with new items.841 * Env.js 1221 842 * 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 }, 1228 1229 /** 1230 * Translates the specified string by checking for the english string in the language pack lookup. 843 * Copyright 2013, Moxiecode Systems AB 844 * Released under GPL License. 1231 845 * 1232 * @param {String} str String to look for.1233 * @return {String} Translated string or the input string if it wasn't found.846 * License: http://www.plupload.com/license 847 * Contributing: http://www.plupload.com/contributing 1234 848 */ 1235 translate: function(str) {1236 return i18n[str] || str;1237 },1238 849 1239 850 /** 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. 851 @class moxie/core/utils/Env 852 @public 853 @static 1244 854 */ 1245 _: function(str) {1246 return this.translate(str);1247 },1248 855 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); 856 define("moxie/core/utils/Env", [ 857 "moxie/core/utils/Basic" 858 ], function(Basic) { 859 860 /** 861 * UAParser.js v0.7.7 862 * Lightweight JavaScript-based User-Agent string parser 863 * https://github.com/faisalman/ua-parser-js 864 * 865 * Copyright © 2012-2015 Faisal Salman <fyzlman@gmail.com> 866 * Dual licensed under GPLv2 & MIT 867 */ 868 var UAParser = (function (undefined) { 869 870 ////////////// 871 // Constants 872 ///////////// 873 874 875 var EMPTY = '', 876 UNKNOWN = '?', 877 FUNC_TYPE = 'function', 878 UNDEF_TYPE = 'undefined', 879 OBJ_TYPE = 'object', 880 MAJOR = 'major', 881 MODEL = 'model', 882 NAME = 'name', 883 TYPE = 'type', 884 VENDOR = 'vendor', 885 VERSION = 'version', 886 ARCHITECTURE= 'architecture', 887 CONSOLE = 'console', 888 MOBILE = 'mobile', 889 TABLET = 'tablet'; 890 891 892 /////////// 893 // Helper 894 ////////// 895 896 897 var util = { 898 has : function (str1, str2) { 899 return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; 900 }, 901 lowerize : function (str) { 902 return str.toLowerCase(); 903 } 904 }; 1257 905 1258 return str.replace(/%[a-z]/g, function() {1259 var value = args.shift();1260 return Basic.typeOf(value) !== 'undefined' ? value : '';1261 });1262 }1263 };1264 });1265 906 1266 // Included from: src/javascript/core/utils/Mime.js 907 /////////////// 908 // Map helper 909 ////////////// 910 911 912 var mapper = { 913 914 rgx : function () { 915 916 // loop through all regexes maps 917 for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { 918 919 var regex = args[i], // even sequence (0,2,4,..) 920 props = args[i + 1]; // odd sequence (1,3,5,..) 921 922 // construct object barebones 923 if (typeof(result) === UNDEF_TYPE) { 924 result = {}; 925 for (p in props) { 926 q = props[p]; 927 if (typeof(q) === OBJ_TYPE) { 928 result[q[0]] = undefined; 929 } else { 930 result[q] = undefined; 931 } 932 } 933 } 1267 934 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 */ 935 // try matching uastring with regexes 936 for (j = k = 0; j < regex.length; j++) { 937 matches = regex[j].exec(this.getUA()); 938 if (!!matches) { 939 for (p = 0; p < props.length; p++) { 940 match = matches[++k]; 941 q = props[p]; 942 // check if given property is actually array 943 if (typeof(q) === OBJ_TYPE && q.length > 0) { 944 if (q.length == 2) { 945 if (typeof(q[1]) == FUNC_TYPE) { 946 // assign modified match 947 result[q[0]] = q[1].call(this, match); 948 } else { 949 // assign given value, ignore regex match 950 result[q[0]] = q[1]; 951 } 952 } else if (q.length == 3) { 953 // check whether function or regex 954 if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { 955 // call function (usually string mapper) 956 result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; 957 } else { 958 // sanitize match using given regex 959 result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; 960 } 961 } else if (q.length == 4) { 962 result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; 963 } 964 } else { 965 result[q] = match ? match : undefined; 966 } 967 } 968 break; 969 } 970 } 1277 971 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; 1358 } 1359 }, 1360 1361 1362 extList2mimes: function (filters, addMissingExtensions) { 1363 var self = this, ext, i, ii, type, mimes = []; 1364 1365 // convert extensions to mime types list 1366 for (i = 0; i < filters.length; i++) { 1367 ext = filters[i].extensions.split(/\s*,\s*/); 1368 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 } 1375 1376 type = self.mimes[ext[ii]]; 1377 if (type && Basic.inArray(type, mimes) === -1) { 1378 mimes.push(type); 1379 } 1380 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 } 1389 } 1390 return mimes; 1391 }, 1392 1393 1394 mimes2exts: function(mimes) { 1395 var self = this, exts = []; 1396 1397 Basic.each(mimes, function(mime) { 1398 if (mime === '*') { 1399 exts = []; 1400 return false; 1401 } 972 if(!!matches) break; // break the loop immediately if match found 973 } 974 return result; 975 }, 1402 976 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]); 977 str : function (str, map) { 978 979 for (var i in map) { 980 // check if array 981 if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { 982 for (var j = 0; j < map[i].length; j++) { 983 if (util.has(map[i][j], str)) { 984 return (i === UNKNOWN) ? undefined : i; 985 } 986 } 987 } else if (util.has(map[i], str)) { 988 return (i === UNKNOWN) ? undefined : i; 1411 989 } 1412 }); 1413 } else if (self.extensions[mime]) { 1414 [].push.apply(exts, self.extensions[mime]); 990 } 991 return str; 1415 992 } 1416 } 1417 }); 1418 return exts; 1419 }, 993 }; 1420 994 1421 995 1422 mimes2extList: function(mimes) { 1423 var accept = [], exts = []; 996 /////////////// 997 // String map 998 ////////////// 1424 999 1425 if (Basic.typeOf(mimes) === 'string') {1426 mimes = Basic.trim(mimes).split(/\s*,\s*/);1427 }1428 1000 1429 exts = this.mimes2exts(mimes); 1430 1431 accept.push({ 1432 title: I18n.translate('Files'), 1433 extensions: exts.length ? exts.join(',') : '*' 1434 }); 1435 1436 // save original mimes string 1437 accept.mimes = mimes; 1001 var maps = { 1002 1003 browser : { 1004 oldsafari : { 1005 major : { 1006 '1' : ['/8', '/1', '/3'], 1007 '2' : '/4', 1008 '?' : '/' 1009 }, 1010 version : { 1011 '1.0' : '/8', 1012 '1.2' : '/1', 1013 '1.3' : '/3', 1014 '2.0' : '/412', 1015 '2.0.2' : '/416', 1016 '2.0.3' : '/417', 1017 '2.0.4' : '/419', 1018 '?' : '/' 1019 } 1020 } 1021 }, 1438 1022 1439 return accept; 1440 }, 1023 device : { 1024 sprint : { 1025 model : { 1026 'Evo Shift 4G' : '7373KT' 1027 }, 1028 vendor : { 1029 'HTC' : 'APA', 1030 'Sprint' : 'Sprint' 1031 } 1032 } 1033 }, 1441 1034 1035 os : { 1036 windows : { 1037 version : { 1038 'ME' : '4.90', 1039 'NT 3.11' : 'NT3.51', 1040 'NT 4.0' : 'NT4.0', 1041 '2000' : 'NT 5.0', 1042 'XP' : ['NT 5.1', 'NT 5.2'], 1043 'Vista' : 'NT 6.0', 1044 '7' : 'NT 6.1', 1045 '8' : 'NT 6.2', 1046 '8.1' : 'NT 6.3', 1047 'RT' : 'ARM' 1048 } 1049 } 1050 } 1051 }; 1442 1052 1443 getFileExtension: function(fileName) {1444 var matches = fileName && fileName.match(/\.([^.]+)$/);1445 if (matches) {1446 return matches[1].toLowerCase();1447 }1448 return '';1449 },1450 1053 1451 getFileMime: function(fileName) { 1452 return this.mimes[this.getFileExtension(fileName)] || ''; 1453 } 1454 }; 1054 ////////////// 1055 // Regex map 1056 ///////////// 1057 1058 1059 var regexes = { 1060 1061 browser : [[ 1062 1063 // Presto based 1064 /(opera\smini)\/([\w\.-]+)/i, // Opera Mini 1065 /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet 1066 /(opera).+version\/([\w\.]+)/i, // Opera > 9.80 1067 /(opera)[\/\s]+([\w\.]+)/i // Opera < 9.80 1068 1069 ], [NAME, VERSION], [ 1070 1071 /\s(opr)\/([\w\.]+)/i // Opera Webkit 1072 ], [[NAME, 'Opera'], VERSION], [ 1073 1074 // Mixed 1075 /(kindle)\/([\w\.]+)/i, // Kindle 1076 /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i, 1077 // Lunascape/Maxthon/Netfront/Jasmine/Blazer 1078 1079 // Trident based 1080 /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i, 1081 // Avant/IEMobile/SlimBrowser/Baidu 1082 /(?:ms|\()(ie)\s([\w\.]+)/i, // Internet Explorer 1083 1084 // Webkit/KHTML based 1085 /(rekonq)\/([\w\.]+)*/i, // Rekonq 1086 /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i 1087 // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron 1088 ], [NAME, VERSION], [ 1089 1090 /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i // IE11 1091 ], [[NAME, 'IE'], VERSION], [ 1092 1093 /(edge)\/((\d+)?[\w\.]+)/i // Microsoft Edge 1094 ], [NAME, VERSION], [ 1095 1096 /(yabrowser)\/([\w\.]+)/i // Yandex 1097 ], [[NAME, 'Yandex'], VERSION], [ 1098 1099 /(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon 1100 ], [[NAME, /_/g, ' '], VERSION], [ 1101 1102 /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i, 1103 // Chrome/OmniWeb/Arora/Tizen/Nokia 1104 /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i 1105 // UCBrowser/QQBrowser 1106 ], [NAME, VERSION], [ 1107 1108 /(dolfin)\/([\w\.]+)/i // Dolphin 1109 ], [[NAME, 'Dolphin'], VERSION], [ 1110 1111 /((?:android.+)crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS 1112 ], [[NAME, 'Chrome'], VERSION], [ 1113 1114 /XiaoMi\/MiuiBrowser\/([\w\.]+)/i // MIUI Browser 1115 ], [VERSION, [NAME, 'MIUI Browser']], [ 1116 1117 /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i // Android Browser 1118 ], [VERSION, [NAME, 'Android Browser']], [ 1119 1120 /FBAV\/([\w\.]+);/i // Facebook App for iOS 1121 ], [VERSION, [NAME, 'Facebook']], [ 1122 1123 /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari 1124 ], [VERSION, [NAME, 'Mobile Safari']], [ 1125 1126 /version\/([\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile 1127 ], [VERSION, NAME], [ 1128 1129 /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Safari < 3.0 1130 ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [ 1131 1132 /(konqueror)\/([\w\.]+)/i, // Konqueror 1133 /(webkit|khtml)\/([\w\.]+)/i 1134 ], [NAME, VERSION], [ 1135 1136 // Gecko based 1137 /(navigator|netscape)\/([\w\.-]+)/i // Netscape 1138 ], [[NAME, 'Netscape'], VERSION], [ 1139 /(swiftfox)/i, // Swiftfox 1140 /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i, 1141 // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror 1142 /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i, 1143 // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix 1144 /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla 1145 1146 // Other 1147 /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i, 1148 // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf 1149 /(links)\s\(([\w\.]+)/i, // Links 1150 /(gobrowser)\/?([\w\.]+)*/i, // GoBrowser 1151 /(ice\s?browser)\/v?([\w\._]+)/i, // ICE Browser 1152 /(mosaic)[\/\s]([\w\.]+)/i // Mosaic 1153 ], [NAME, VERSION] 1154 ], 1155 1156 engine : [[ 1157 1158 /windows.+\sedge\/([\w\.]+)/i // EdgeHTML 1159 ], [VERSION, [NAME, 'EdgeHTML']], [ 1160 1161 /(presto)\/([\w\.]+)/i, // Presto 1162 /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m 1163 /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links 1164 /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab 1165 ], [NAME, VERSION], [ 1166 1167 /rv\:([\w\.]+).*(gecko)/i // Gecko 1168 ], [VERSION, NAME] 1169 ], 1170 1171 os : [[ 1172 1173 // Windows based 1174 /microsoft\s(windows)\s(vista|xp)/i // Windows (iTunes) 1175 ], [NAME, VERSION], [ 1176 /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT 1177 /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i 1178 ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ 1179 /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i 1180 ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ 1181 1182 // Mobile/Embedded OS 1183 /\((bb)(10);/i // BlackBerry 10 1184 ], [[NAME, 'BlackBerry'], VERSION], [ 1185 /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry 1186 /(tizen)[\/\s]([\w\.]+)/i, // Tizen 1187 /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i, 1188 // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki 1189 /linux;.+(sailfish);/i // Sailfish OS 1190 ], [NAME, VERSION], [ 1191 /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian 1192 ], [[NAME, 'Symbian'], VERSION], [ 1193 /\((series40);/i // Series 40 1194 ], [NAME], [ 1195 /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS 1196 ], [[NAME, 'Firefox OS'], VERSION], [ 1197 1198 // Console 1199 /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation 1200 1201 // GNU/Linux based 1202 /(mint)[\/\s\(]?(\w+)*/i, // Mint 1203 /(mageia|vectorlinux)[;\s]/i, // Mageia/VectorLinux 1204 /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i, 1205 // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware 1206 // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus 1207 /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux 1208 /(gnu)\s?([\w\.]+)*/i // GNU 1209 ], [NAME, VERSION], [ 1210 1211 /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS 1212 ], [[NAME, 'Chromium OS'], VERSION],[ 1213 1214 // Solaris 1215 /(sunos)\s?([\w\.]+\d)*/i // Solaris 1216 ], [[NAME, 'Solaris'], VERSION], [ 1217 1218 // BSD based 1219 /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly 1220 ], [NAME, VERSION],[ 1221 1222 /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS 1223 ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ 1224 1225 /(mac\sos\sx)\s?([\w\s\.]+\w)*/i, 1226 /(macintosh|mac(?=_powerpc)\s)/i // Mac OS 1227 ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [ 1228 1229 // Other 1230 /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i, // Solaris 1231 /(haiku)\s(\w+)/i, // Haiku 1232 /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX 1233 /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i, 1234 // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS 1235 /(unix)\s?([\w\.]+)*/i // UNIX 1236 ], [NAME, VERSION] 1237 ] 1238 }; 1455 1239 1456 Mime.addMimeType(mimeData);1457 1240 1458 return Mime; 1459 }); 1241 ///////////////// 1242 // Constructor 1243 //////////////// 1460 1244 1461 // Included from: src/javascript/core/utils/Dom.js1462 1245 1463 /** 1464 * Dom.js 1465 * 1466 * Copyright 2013, Moxiecode Systems AB 1467 * Released under GPL License. 1468 * 1469 * License: http://www.plupload.com/license 1470 * Contributing: http://www.plupload.com/contributing 1471 */ 1246 var UAParser = function (uastring) { 1472 1247 1473 define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) { 1248 var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); 1474 1249 1475 /** 1476 Get DOM Element by it's id. 1250 this.getBrowser = function () { 1251 return mapper.rgx.apply(this, regexes.browser); 1252 }; 1253 this.getEngine = function () { 1254 return mapper.rgx.apply(this, regexes.engine); 1255 }; 1256 this.getOS = function () { 1257 return mapper.rgx.apply(this, regexes.os); 1258 }; 1259 this.getResult = function() { 1260 return { 1261 ua : this.getUA(), 1262 browser : this.getBrowser(), 1263 engine : this.getEngine(), 1264 os : this.getOS() 1265 }; 1266 }; 1267 this.getUA = function () { 1268 return ua; 1269 }; 1270 this.setUA = function (uastring) { 1271 ua = uastring; 1272 return this; 1273 }; 1274 this.setUA(ua); 1275 }; 1477 1276 1478 @method get 1479 @for Utils 1480 @param {String} id Identifier of the DOM Element 1481 @return {DOMElement} 1482 */ 1483 var get = function(id) { 1484 if (typeof id !== 'string') { 1485 return id; 1486 } 1487 return document.getElementById(id); 1488 }; 1277 return UAParser; 1278 })(); 1489 1279 1490 /**1491 Checks if specified DOM element has specified class.1492 1280 1493 @method hasClass 1494 @static 1495 @param {Object} obj DOM element like object to add handler to. 1496 @param {String} name Class name 1497 */ 1498 var hasClass = function(obj, name) { 1499 if (!obj.className) { 1500 return false; 1501 } 1281 function version_compare(v1, v2, operator) { 1282 // From: http://phpjs.org/functions 1283 // + original by: Philippe Jausions (http://pear.php.net/user/jausions) 1284 // + original by: Aidan Lister (http://aidanlister.com/) 1285 // + reimplemented by: Kankrelune (http://www.webfaktory.info/) 1286 // + improved by: Brett Zamir (http://brett-zamir.me) 1287 // + improved by: Scott Baker 1288 // + improved by: Theriault 1289 // * example 1: version_compare('8.2.5rc', '8.2.5a'); 1290 // * returns 1: 1 1291 // * example 2: version_compare('8.2.50', '8.2.52', '<'); 1292 // * returns 2: true 1293 // * example 3: version_compare('5.3.0-dev', '5.3.0'); 1294 // * returns 3: -1 1295 // * example 4: version_compare('4.1.0.52','4.01.0.51'); 1296 // * returns 4: 1 1297 1298 // Important: compare must be initialized at 0. 1299 var i = 0, 1300 x = 0, 1301 compare = 0, 1302 // vm maps textual PHP versions to negatives so they're less than 0. 1303 // PHP currently defines these as CASE-SENSITIVE. It is important to 1304 // leave these as negatives so that they can come before numerical versions 1305 // and as if no letters were there to begin with. 1306 // (1alpha is < 1 and < 1.1 but > 1dev1) 1307 // If a non-numerical value can't be mapped to this table, it receives 1308 // -7 as its value. 1309 vm = { 1310 'dev': -6, 1311 'alpha': -5, 1312 'a': -5, 1313 'beta': -4, 1314 'b': -4, 1315 'RC': -3, 1316 'rc': -3, 1317 '#': -2, 1318 'p': 1, 1319 'pl': 1 1320 }, 1321 // This function will be called to prepare each version argument. 1322 // It replaces every _, -, and + with a dot. 1323 // It surrounds any nonsequence of numbers/dots with dots. 1324 // It replaces sequences of dots with a single dot. 1325 // version_compare('4..0', '4.0') == 0 1326 // Important: A string of 0 length needs to be converted into a value 1327 // even less than an unexisting value in vm (-7), hence [-8]. 1328 // It's also important to not strip spaces because of this. 1329 // version_compare('', ' ') == 1 1330 prepVersion = function (v) { 1331 v = ('' + v).replace(/[_\-+]/g, '.'); 1332 v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); 1333 return (!v.length ? [-8] : v.split('.')); 1334 }, 1335 // This converts a version component to a number. 1336 // Empty component becomes 0. 1337 // Non-numerical component becomes a negative number. 1338 // Numerical component becomes itself as an integer. 1339 numVersion = function (v) { 1340 return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); 1341 }; 1502 1342 1503 var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); 1504 return regExp.test(obj.className); 1505 }; 1343 v1 = prepVersion(v1); 1344 v2 = prepVersion(v2); 1345 x = Math.max(v1.length, v2.length); 1346 for (i = 0; i < x; i++) { 1347 if (v1[i] == v2[i]) { 1348 continue; 1349 } 1350 v1[i] = numVersion(v1[i]); 1351 v2[i] = numVersion(v2[i]); 1352 if (v1[i] < v2[i]) { 1353 compare = -1; 1354 break; 1355 } else if (v1[i] > v2[i]) { 1356 compare = 1; 1357 break; 1358 } 1359 } 1360 if (!operator) { 1361 return compare; 1362 } 1506 1363 1507 /** 1508 Adds specified className to specified DOM element. 1364 // Important: operator is CASE-SENSITIVE. 1365 // "No operator" seems to be treated as "<." 1366 // Any other values seem to make the function return null. 1367 switch (operator) { 1368 case '>': 1369 case 'gt': 1370 return (compare > 0); 1371 case '>=': 1372 case 'ge': 1373 return (compare >= 0); 1374 case '<=': 1375 case 'le': 1376 return (compare <= 0); 1377 case '==': 1378 case '=': 1379 case 'eq': 1380 return (compare === 0); 1381 case '<>': 1382 case '!=': 1383 case 'ne': 1384 return (compare !== 0); 1385 case '': 1386 case '<': 1387 case 'lt': 1388 return (compare < 0); 1389 default: 1390 return null; 1391 } 1392 } 1509 1393 1510 @method addClass1511 @static1512 @param {Object} obj DOM element like object to add handler to.1513 @param {String} name Class name1514 */1515 var addClass = function(obj, name) {1516 if (!hasClass(obj, name)) {1517 obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;1518 }1519 };1520 1394 1521 /** 1522 Removes specified className from specified DOM element. 1395 var can = (function() { 1396 var caps = { 1397 access_global_ns: function () { 1398 return !!window.moxie; 1399 }, 1400 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 }); 1410 return true; 1411 } 1412 } catch(ex) {} 1523 1413 1524 @method removeClass 1525 @static 1526 @param {Object} obj DOM element like object to add handler to. 1527 @param {String} name Class name 1528 */ 1529 var removeClass = function(obj, name) { 1530 if (obj.className) { 1531 var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); 1532 obj.className = obj.className.replace(regExp, function($0, $1, $2) { 1533 return $1 === ' ' && $2 === ' ' ? ' ' : ''; 1534 }); 1535 } 1536 }; 1414 if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { 1415 return true; 1416 }*/ 1417 return false; 1418 }()), 1537 1419 1538 /** 1539 Returns a given computed style of a DOM element. 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 }, 1540 1429 1541 @method getStyle 1542 @static 1543 @param {Object} obj DOM element like object. 1544 @param {String} name Style you want to get from the DOM element 1545 */ 1546 var getStyle = function(obj, name) { 1547 if (obj.currentStyle) { 1548 return obj.currentStyle[name]; 1549 } else if (window.getComputedStyle) { 1550 return window.getComputedStyle(obj, null)[name]; 1551 } 1552 }; 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 } 1443 return true; 1444 } 1445 } 1446 } catch (ex) {} 1447 return false; 1448 }, 1553 1449 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 }, 1459 1460 // ideas for this heavily come from Modernizr (http://modernizr.com/) 1461 use_data_uri: (function() { 1462 var du = new Image(); 1463 1464 du.onload = function() { 1465 caps.use_data_uri = (du.width === 1 && du.height === 1); 1466 }; 1554 1467 1555 /** 1556 Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. 1468 setTimeout(function() { 1469 du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; 1470 }, 1); 1471 return false; 1472 }()), 1557 1473 1558 @method getPos 1559 @static 1560 @param {Element} node HTML element or element id to get x, y position from. 1561 @param {Element} root Optional root element to stop calculations at. 1562 @return {object} Absolute position of the specified element object with x, y fields. 1563 */ 1564 var getPos = function(node, root) { 1565 var x = 0, y = 0, parent, doc = document, nodeRect, rootRect; 1566 1567 node = node; 1568 root = root || doc.body; 1569 1570 // Returns the x, y cordinate for an element on IE 6 and IE 7 1571 function getIEPos(node) { 1572 var bodyElm, rect, x = 0, y = 0; 1573 1574 if (node) { 1575 rect = node.getBoundingClientRect(); 1576 bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body; 1577 x = rect.left + bodyElm.scrollLeft; 1578 y = rect.top + bodyElm.scrollTop; 1579 } 1474 use_data_uri_over32kb: function() { // IE8 1475 return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9); 1476 }, 1477 1478 use_data_uri_of: function(bytes) { 1479 return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); 1480 }, 1580 1481 1581 return { 1582 x : x, 1583 y : y 1584 }; 1585 } 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; 1485 } 1586 1486 1587 // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode 1588 if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) { 1589 nodeRect = getIEPos(node); 1590 rootRect = getIEPos(root); 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) {} 1591 1499 1592 return { 1593 x : nodeRect.x - rootRect.x, 1594 y : nodeRect.y - rootRect.y 1595 }; 1596 } 1500 if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context 1501 gl = null; 1502 } 1597 1503 1598 parent = node;1599 while (parent && parent != root && parent.nodeType) {1600 x += parent.offsetLeft || 0;1601 y += parent.offsetTop || 0;1602 parent = parent.offsetParent;1603 }1504 isSupported = !!gl; 1505 caps.use_webgl = isSupported; // save result of our check 1506 canvas = undefined; 1507 return isSupported; 1508 } 1509 }; 1604 1510 1605 parent = node.parentNode;1606 while (parent && parent != root && parent.nodeType) {1607 x -= parent.scrollLeft || 0;1608 y -= parent.scrollTop || 0;1609 parent = parent.parentNode;1610 }1511 return function(cap) { 1512 var args = [].slice.call(arguments); 1513 args.shift(); // shift of cap 1514 return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap]; 1515 }; 1516 }()); 1611 1517 1612 return {1613 x : x,1614 y : y1615 };1616 };1617 1518 1618 /** 1619 Returns the size of the specified node in pixels. 1519 var uaResult = new UAParser().getResult(); 1620 1520 1621 @method getSize1622 @static1623 @param {Node} node Node to get the size of.1624 @return {Object} Object with a w and h property.1625 */1626 var getSize = function(node) {1627 return {1628 w : node.offsetWidth || node.clientWidth,1629 h : node.offsetHeight || node.clientHeight1630 };1631 };1632 1521 1633 return { 1634 get: get, 1635 hasClass: hasClass, 1636 addClass: addClass, 1637 removeClass: removeClass, 1638 getStyle: getStyle, 1639 getPos: getPos, 1640 getSize: getSize 1641 }; 1642 }); 1522 var Env = { 1523 can: can, 1643 1524 1644 // Included from: src/javascript/core/Exceptions.js 1525 uaParser: UAParser, 1645 1526 1646 /** 1647 * Exceptions.js 1648 * 1649 * Copyright 2013, Moxiecode Systems AB 1650 * Released under GPL License. 1651 * 1652 * License: http://www.plupload.com/license 1653 * Contributing: http://www.plupload.com/contributing 1654 */ 1527 browser: uaResult.browser.name, 1528 version: uaResult.browser.version, 1529 os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason 1530 osVersion: uaResult.os.version, 1655 1531 1656 define('moxie/core/Exceptions', [ 1657 '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; 1667 } 1532 verComp: version_compare, 1668 1533 1669 return { 1670 RuntimeError: (function() { 1671 var namecodes = { 1672 NOT_INIT_ERR: 1, 1673 NOT_SUPPORTED_ERR: 9, 1674 JS_ERR: 4 1675 }; 1676 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 }()), 1703 1704 ImageError: (function() { 1705 var namecodes = { 1706 WRONG_FORMAT: 1, 1707 MAX_RESOLUTION_ERR: 2, 1708 INVALID_META_ERR: 3 1709 }; 1710 1711 function ImageError(code) { 1712 this.code = code; 1713 this.name = _findKey(namecodes, code); 1714 this.message = this.name + ": ImageError " + this.code; 1715 } 1716 1717 Basic.extend(ImageError, namecodes); 1718 ImageError.prototype = Error.prototype; 1719 1720 return ImageError; 1721 }()), 1722 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 }; 1734 1735 function FileException(code) { 1736 this.code = code; 1737 this.name = _findKey(namecodes, code); 1738 this.message = this.name + ": FileException " + this.code; 1739 } 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: 25 1773 }; 1774 1775 function DOMException(code) { 1776 this.code = code; 1777 this.name = _findKey(namecodes, code); 1778 this.message = this.name + ": DOMException " + this.code; 1779 } 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: 0 1794 }); 1795 1796 EventException.prototype = Error.prototype; 1797 1798 return EventException; 1799 }()) 1800 }; 1801 }); 1534 swf_url: "../flash/Moxie.swf", 1535 xap_url: "../silverlight/Moxie.xap", 1536 global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent" 1537 }; 1802 1538 1803 // Included from: src/javascript/core/EventTarget.js 1539 // for backward compatibility 1540 // @deprecated Use `Env.os` instead 1541 Env.OS = Env.os; 1542 1543 if (MXI_DEBUG) { 1544 Env.debug = { 1545 runtime: true, 1546 events: false 1547 }; 1804 1548 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 */ 1549 Env.log = function() { 1814 1550 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 1551 function logObj(data) { 1552 // TODO: this should recursively print out the object in a pretty way 1553 console.appendChild(document.createTextNode(data + "\n")); 1554 } 1555 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); 1559 } else if (document) { 1560 var console = document.getElementById('moxie-console'); 1561 if (!console) { 1562 console = document.createElement('pre'); 1563 console.id = 'moxie-console'; 1564 //console.style.display = 'none'; 1565 document.body.appendChild(console); 1566 } 1822 1567 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 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) { 1572 logObj(data); 1573 return; 1574 } 1834 1575 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 1576 console.appendChild(document.createTextNode(data + "\n")); 1577 } 1578 }; 1579 } 1842 1580 1843 @method init 1844 */ 1845 init: function() { 1846 if (!this.uid) { 1847 this.uid = Basic.guid('uid_'); 1848 } 1849 }, 1581 return Env; 1582 }); 1850 1583 1851 /** 1852 Register a handler to a specific event dispatched by the object 1584 // Included from: src/javascript/core/Exceptions.js 1853 1585 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; 1862 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 1586 /** 1587 * Exceptions.js 1588 * 1589 * Copyright 2013, Moxiecode Systems AB 1590 * Released under GPL License. 1591 * 1592 * License: http://www.plupload.com/license 1593 * Contributing: http://www.plupload.com/contributing 1594 */ 1892 1595 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 1596 define('moxie/core/Exceptions', [ 1597 'moxie/core/utils/Basic' 1598 ], function(Basic) { 1904 1599 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 } 1921 } 1922 } else { 1923 list = []; 1924 } 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 } 1600 function _findKey(obj, value) { 1601 var key; 1602 for (key in obj) { 1603 if (obj[key] === value) { 1604 return key; 1934 1605 } 1935 1606 } 1936 }, 1937 1938 /** 1939 Remove all event handlers from the object 1607 return null; 1608 } 1940 1609 1941 @method removeAllEventListeners1942 */1943 removeAllEventListeners: function() {1944 if (eventpool[this.uid]) {1945 delete eventpool[this.uid];1946 }1947 },1948 1949 1610 /** 1950 Dispatch the event 1611 @class moxie/core/Exception 1612 */ 1613 return { 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 }; 1951 1621 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; 1963 1964 if (Basic.typeOf(tmpEvt.type) === 'string') { 1965 type = tmpEvt.type; 1966 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); 1622 function RuntimeError(code, message) { 1623 this.code = code; 1624 this.name = _findKey(namecodes, code); 1625 this.message = this.name + (message || ": RuntimeError " + this.code); 1974 1626 } 1975 }1976 1977 // check if event is meant to be dispatched on an object having specific uid1978 if (type.indexOf('::') !== -1) {1979 (function(arr) {1980 uid = arr[0];1981 type = arr[1];1982 }(type.split('::')));1983 } else {1984 uid = this.uid;1985 }1986 1987 type = type.toLowerCase();1988 1989 list = eventpool[uid] && eventpool[uid][type];1990 1991 if (list) {1992 // sort event list by prority1993 list.sort(function(a, b) { return b.priority - a.priority; });1994 1995 args = [].slice.call(arguments);1996 1997 // first argument will be pseudo-event object1998 args.shift();1999 evt.type = type;2000 args.unshift(evt);2001 1627 2002 if (MXI_DEBUG && Env.debug.events) { 2003 Env.log("Event '%s' fired on %u", evt.type, uid); 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'; 2004 1638 } 2005 1639 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 } 1640 Basic.extend(OperationNotAllowedException, { 1641 NOT_ALLOWED_ERR: 1 2023 1642 }); 2024 if (queue.length) {2025 Basic.inSeries(queue, function(err) {2026 result = !err;2027 });2028 }2029 }2030 return result;2031 },2032 2033 /**2034 Alias for addEventListener2035 1643 2036 @method bind 2037 @protected 2038 */ 2039 bind: function() { 2040 this.addEventListener.apply(this, arguments); 2041 }, 2042 2043 /** 2044 Alias for removeEventListener 1644 OperationNotAllowedException.prototype = Error.prototype; 2045 1645 2046 @method unbind 2047 @protected 2048 */ 2049 unbind: function() { 2050 this.removeEventListener.apply(this, arguments); 2051 }, 2052 2053 /** 2054 Alias for removeAllEventListeners 1646 return OperationNotAllowedException; 1647 }()), 2055 1648 2056 @method unbindAll 2057 @protected 2058 */ 2059 unbindAll: function() { 2060 this.removeAllEventListeners.apply(this, arguments); 2061 }, 2062 2063 /** 2064 Alias for dispatchEvent 1649 ImageError: (function() { 1650 var namecodes = { 1651 WRONG_FORMAT: 1, 1652 MAX_RESOLUTION_ERR: 2, 1653 INVALID_META_ERR: 3 1654 }; 2065 1655 2066 @method trigger 2067 @protected 2068 */ 2069 trigger: function() { 2070 return this.dispatchEvent.apply(this, arguments); 2071 }, 2072 1656 function ImageError(code) { 1657 this.code = code; 1658 this.name = _findKey(namecodes, code); 1659 this.message = this.name + ": ImageError " + this.code; 1660 } 2073 1661 2074 /**2075 Handle properties of on[event] type.1662 Basic.extend(ImageError, namecodes); 1663 ImageError.prototype = Error.prototype; 2076 1664 2077 @method handleEventProps 2078 @private 2079 */ 2080 handleEventProps: function(dispatches) { 2081 var self = this; 1665 return ImageError; 1666 }()), 2082 1667 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 }); 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 }; 2089 1679 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; 1680 function FileException(code) { 1681 this.code = code; 1682 this.name = _findKey(namecodes, code); 1683 this.message = this.name + ": FileException " + this.code; 2095 1684 } 2096 });2097 }2098 2099 });2100 }2101 1685 2102 EventTarget.instance = new EventTarget(); 1686 Basic.extend(FileException, namecodes); 1687 FileException.prototype = Error.prototype; 1688 return FileException; 1689 }()), 2103 1690 2104 return EventTarget; 2105 }); 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 }; 2106 1719 2107 // Included from: src/javascript/runtime/Runtime.js 1720 function DOMException(code) { 1721 this.code = code; 1722 this.name = _findKey(namecodes, code); 1723 this.message = this.name + ": DOMException " + this.code; 1724 } 2108 1725 2109 /** 2110 * Runtime.js 2111 * 2112 * Copyright 2013, Moxiecode Systems AB 2113 * Released under GPL License. 2114 * 2115 * License: http://www.plupload.com/license 2116 * Contributing: http://www.plupload.com/contributing 2117 */ 1726 Basic.extend(DOMException, namecodes); 1727 DOMException.prototype = Error.prototype; 1728 return DOMException; 1729 }()), 2118 1730 2119 define('moxie/runtime/Runtime', [ 2120 "moxie/core/utils/Env", 2121 "moxie/core/utils/Basic", 2122 "moxie/core/utils/Dom", 2123 "moxie/core/EventTarget" 2124 ], function(Env, Basic, Dom, EventTarget) { 2125 var runtimeConstructors = {}, runtimes = {}; 1731 EventException: (function() { 1732 function EventException(code) { 1733 this.code = code; 1734 this.name = 'EventException'; 1735 } 2126 1736 2127 /** 2128 Common set of methods and properties for every runtime instance 1737 Basic.extend(EventException, { 1738 UNSPECIFIED_EVENT_TYPE_ERR: 0 1739 }); 2129 1740 2130 @class Runtime1741 EventException.prototype = Error.prototype; 2131 1742 2132 @param {Object} options 2133 @param {String} type Sanitized name of the runtime 2134 @param {Object} [caps] Set of capabilities that differentiate specified runtime 2135 @param {Object} [modeCaps] Set of capabilities that do require specific operational mode 2136 @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested 2137 */ 2138 function Runtime(options, type, caps, modeCaps, preferredMode) { 2139 /** 2140 Dispatched when runtime is initialized and ready. 2141 Results in RuntimeInit on a connected component. 1743 return EventException; 1744 }()) 1745 }; 1746 }); 2142 1747 2143 @event Init 2144 */ 1748 // Included from: src/javascript/core/utils/Dom.js 2145 1749 2146 1750 /** 2147 Dispatched when runtime fails to initialize. 2148 Results in RuntimeError on a connected component. 2149 2150 @event Error 2151 */ 2152 2153 var self = this 2154 , _shim 2155 , _uid = Basic.guid(type + '_') 2156 , defaultMode = preferredMode || 'browser' 2157 ; 2158 2159 options = options || {}; 2160 2161 // register runtime in private hash 2162 runtimes[_uid] = this; 1751 * Dom.js 1752 * 1753 * Copyright 2013, Moxiecode Systems AB 1754 * Released under GPL License. 1755 * 1756 * License: http://www.plupload.com/license 1757 * Contributing: http://www.plupload.com/contributing 1758 */ 2163 1759 2164 1760 /** 2165 Default set of capabilities, which can be redifined later by specific runtime 2166 2167 @private 2168 @property caps 2169 @type Object 2170 */ 2171 caps = Basic.extend({ 2172 // Runtime can: 2173 // provide access to raw binary data of the file 2174 access_binary: false, 2175 // provide access to raw binary data of the image (image extension is optional) 2176 access_image_binary: false, 2177 // display binary data as thumbs for example 2178 display_media: false, 2179 // make cross-domain requests 2180 do_cors: false, 2181 // accept files dragged and dropped from the desktop 2182 drag_and_drop: false, 2183 // filter files in selection dialog by their extensions 2184 filter_by_extension: true, 2185 // resize image (and manipulate it raw data of any file in general) 2186 resize_image: false, 2187 // periodically report how many bytes of total in the file were uploaded (loaded) 2188 report_upload_progress: false, 2189 // provide access to the headers of http response 2190 return_response_headers: false, 2191 // support response of specific type, which should be passed as an argument 2192 // e.g. runtime.can('return_response_type', 'blob') 2193 return_response_type: false, 2194 // return http status code of the response 2195 return_status_code: true, 2196 // send custom http header with the request 2197 send_custom_headers: false, 2198 // pick up the files from a dialog 2199 select_file: false, 2200 // select whole folder in file browse dialog 2201 select_folder: false, 2202 // select multiple files at once in file browse dialog 2203 select_multiple: true, 2204 // send raw binary data, that is generated after image resizing or manipulation of other kind 2205 send_binary_string: false, 2206 // send cookies with http request and therefore retain session 2207 send_browser_cookies: true, 2208 // send data formatted as multipart/form-data 2209 send_multipart: true, 2210 // slice the file or blob to smaller parts 2211 slice_blob: false, 2212 // upload file without preloading it to memory, stream it out directly from disk 2213 stream_upload: false, 2214 // programmatically trigger file browse dialog 2215 summon_file_dialog: false, 2216 // upload file of specific size, size should be passed as argument 2217 // e.g. runtime.can('upload_filesize', '500mb') 2218 upload_filesize: true, 2219 // initiate http request with specific http method, method should be passed as argument 2220 // e.g. runtime.can('use_http_method', 'put') 2221 use_http_method: true 2222 }, caps); 2223 2224 2225 // default to the mode that is compatible with preferred caps 2226 if (options.preferred_caps) { 2227 defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode); 2228 } 1761 @class moxie/core/utils/Dom 1762 @public 1763 @static 1764 */ 2229 1765 2230 if (MXI_DEBUG && Env.debug.runtime) { 2231 Env.log("\tdefault mode: %s", defaultMode); 2232 } 2233 2234 // small extension factory here (is meant to be extended with actual extensions constructors) 2235 _shim = (function() { 2236 var objpool = {}; 2237 return { 2238 exec: function(uid, comp, fn, args) { 2239 if (_shim[comp]) { 2240 if (!objpool[uid]) { 2241 objpool[uid] = { 2242 context: this, 2243 instance: new _shim[comp]() 2244 }; 2245 } 2246 if (objpool[uid].instance[fn]) { 2247 return objpool[uid].instance[fn].apply(this, args); 2248 } 2249 } 2250 }, 1766 define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) { 2251 1767 2252 removeInstance: function(uid) { 2253 delete objpool[uid]; 2254 }, 1768 /** 1769 Get DOM Element by it's id. 2255 1770 2256 removeAllInstances: function() { 2257 var self = this; 2258 Basic.each(objpool, function(obj, uid) { 2259 if (Basic.typeOf(obj.instance.destroy) === 'function') { 2260 obj.instance.destroy.call(obj.context); 2261 } 2262 self.removeInstance(uid); 2263 }); 1771 @method get 1772 @param {String} id Identifier of the DOM Element 1773 @return {DOMElement} 1774 */ 1775 var get = function(id) { 1776 if (typeof id !== 'string') { 1777 return id; 2264 1778 } 1779 return document.getElementById(id); 2265 1780 }; 2266 }());2267 1781 2268 2269 // public methods2270 Basic.extend(this, {2271 1782 /** 2272 Specifies whether runtime instance was initialized or not 2273 2274 @property initialized 2275 @type {Boolean} 2276 @default false 2277 */ 2278 initialized: false, // shims require this flag to stop initialization retries 1783 Checks if specified DOM element has specified class. 2279 1784 2280 /** 2281 Unique ID of the runtime 1785 @method hasClass 1786 @static 1787 @param {Object} obj DOM element like object to add handler to. 1788 @param {String} name Class name 1789 */ 1790 var hasClass = function(obj, name) { 1791 if (!obj.className) { 1792 return false; 1793 } 2282 1794 2283 @property uid 2284 @type {String} 2285 */ 2286 uid: _uid, 1795 var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); 1796 return regExp.test(obj.className); 1797 }; 2287 1798 2288 1799 /** 2289 Runtime type (e.g. flash, html5, etc)1800 Adds specified className to specified DOM element. 2290 1801 2291 @property type 2292 @type {String} 2293 */ 2294 type: type, 1802 @method addClass 1803 @static 1804 @param {Object} obj DOM element like object to add handler to. 1805 @param {String} name Class name 1806 */ 1807 var addClass = function(obj, name) { 1808 if (!hasClass(obj, name)) { 1809 obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name; 1810 } 1811 }; 2295 1812 2296 1813 /** 2297 Runtime (not native one) may operate in browser or client mode.1814 Removes specified className from specified DOM element. 2298 1815 2299 @property mode 2300 @private 2301 @type {String|Boolean} current mode or false, if none possible 2302 */ 2303 mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode), 1816 @method removeClass 1817 @static 1818 @param {Object} obj DOM element like object to add handler to. 1819 @param {String} name Class name 1820 */ 1821 var removeClass = function(obj, name) { 1822 if (obj.className) { 1823 var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); 1824 obj.className = obj.className.replace(regExp, function($0, $1, $2) { 1825 return $1 === ' ' && $2 === ' ' ? ' ' : ''; 1826 }); 1827 } 1828 }; 2304 1829 2305 1830 /** 2306 id of the DOM container for the runtime (if available) 2307 2308 @property shimid 2309 @type {String} 2310 */ 2311 shimid: _uid + '_container', 1831 Returns a given computed style of a DOM element. 2312 1832 2313 /** 2314 Number of connected clients. If equal to zero, runtime can be destroyed 1833 @method getStyle 1834 @static 1835 @param {Object} obj DOM element like object. 1836 @param {String} name Style you want to get from the DOM element 1837 */ 1838 var getStyle = function(obj, name) { 1839 if (obj.currentStyle) { 1840 return obj.currentStyle[name]; 1841 } else if (window.getComputedStyle) { 1842 return window.getComputedStyle(obj, null)[name]; 1843 } 1844 }; 2315 1845 2316 @property clients2317 @type {Number}2318 */2319 clients: 0,2320 1846 2321 1847 /** 2322 Runtime initialization options 2323 2324 @property options 2325 @type {Object} 2326 */ 2327 options: options, 1848 Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. 2328 1849 2329 /** 2330 Checks if the runtime has specific capability 1850 @method getPos 1851 @static 1852 @param {Element} node HTML element or element id to get x, y position from. 1853 @param {Element} root Optional root element to stop calculations at. 1854 @return {object} Absolute position of the specified element object with x, y fields. 1855 */ 1856 var getPos = function(node, root) { 1857 var x = 0, y = 0, parent, doc = document, nodeRect, rootRect; 1858 1859 node = node; 1860 root = root || doc.body; 1861 1862 // Returns the x, y cordinate for an element on IE 6 and IE 7 1863 function getIEPos(node) { 1864 var bodyElm, rect, x = 0, y = 0; 1865 1866 if (node) { 1867 rect = node.getBoundingClientRect(); 1868 bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body; 1869 x = rect.left + bodyElm.scrollLeft; 1870 y = rect.top + bodyElm.scrollTop; 1871 } 2331 1872 2332 @method can 2333 @param {String} cap Name of capability to check 2334 @param {Mixed} [value] If passed, capability should somehow correlate to the value 2335 @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set) 2336 @return {Boolean} true if runtime has such capability and false, if - not 2337 */ 2338 can: function(cap, value) { 2339 var refCaps = arguments[2] || caps; 2340 2341 // if cap var is a comma-separated list of caps, convert it to object (key/value) 2342 if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') { 2343 cap = Runtime.parseCaps(cap); 1873 return { 1874 x : x, 1875 y : y 1876 }; 2344 1877 } 2345 1878 2346 if (Basic.typeOf(cap) === 'object') { 2347 for (var key in cap) { 2348 if (!this.can(key, cap[key], refCaps)) { 2349 return false; 2350 } 2351 } 2352 return true; 1879 // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode 1880 if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) { 1881 nodeRect = getIEPos(node); 1882 rootRect = getIEPos(root); 1883 1884 return { 1885 x : nodeRect.x - rootRect.x, 1886 y : nodeRect.y - rootRect.y 1887 }; 2353 1888 } 2354 1889 2355 // check the individual cap 2356 if (Basic.typeOf(refCaps[cap]) === 'function') { 2357 return refCaps[cap].call(this, value); 2358 } else { 2359 return (value === refCaps[cap]); 1890 parent = node; 1891 while (parent && parent != root && parent.nodeType) { 1892 x += parent.offsetLeft || 0; 1893 y += parent.offsetTop || 0; 1894 parent = parent.offsetParent; 1895 } 1896 1897 parent = node.parentNode; 1898 while (parent && parent != root && parent.nodeType) { 1899 x -= parent.scrollLeft || 0; 1900 y -= parent.scrollTop || 0; 1901 parent = parent.parentNode; 2360 1902 } 2361 }, 1903 1904 return { 1905 x : x, 1906 y : y 1907 }; 1908 }; 2362 1909 2363 1910 /** 2364 Returns container for the runtime as DOM element1911 Returns the size of the specified node in pixels. 2365 1912 2366 @method getShimContainer 2367 @return {DOMElement} 2368 */ 2369 getShimContainer: function() { 2370 var container, shimContainer = Dom.get(this.shimid); 2371 2372 // if no container for shim, create one 2373 if (!shimContainer) { 2374 container = this.options.container ? Dom.get(this.options.container) : document.body; 2375 2376 // create shim container and insert it at an absolute position into the outer container 2377 shimContainer = document.createElement('div'); 2378 shimContainer.id = this.shimid; 2379 shimContainer.className = 'moxie-shim moxie-shim-' + this.type; 1913 @method getSize 1914 @static 1915 @param {Node} node Node to get the size of. 1916 @return {Object} Object with a w and h property. 1917 */ 1918 var getSize = function(node) { 1919 return { 1920 w : node.offsetWidth || node.clientWidth, 1921 h : node.offsetHeight || node.clientHeight 1922 }; 1923 }; 2380 1924 2381 Basic.extend(shimContainer.style, { 2382 position: 'absolute', 2383 top: '0px', 2384 left: '0px', 2385 width: '1px', 2386 height: '1px', 2387 overflow: 'hidden' 2388 }); 1925 return { 1926 get: get, 1927 hasClass: hasClass, 1928 addClass: addClass, 1929 removeClass: removeClass, 1930 getStyle: getStyle, 1931 getPos: getPos, 1932 getSize: getSize 1933 }; 1934 }); 2389 1935 2390 container.appendChild(shimContainer); 2391 container = null; 2392 } 1936 // Included from: src/javascript/core/EventTarget.js 2393 1937 2394 return shimContainer; 2395 }, 1938 /** 1939 * EventTarget.js 1940 * 1941 * Copyright 2013, Moxiecode Systems AB 1942 * Released under GPL License. 1943 * 1944 * License: http://www.plupload.com/license 1945 * Contributing: http://www.plupload.com/contributing 1946 */ 2396 1947 2397 /** 2398 Returns runtime as DOM element (if appropriate) 1948 define('moxie/core/EventTarget', [ 1949 'moxie/core/utils/Env', 1950 'moxie/core/Exceptions', 1951 'moxie/core/utils/Basic' 1952 ], function(Env, x, Basic) { 2399 1953 2400 @method getShim 2401 @return {DOMElement} 2402 */ 2403 getShim: function() { 2404 return _shim; 2405 }, 1954 // hash of event listeners by object uid 1955 var eventpool = {}; 2406 1956 2407 1957 /** 2408 Invokes a method within the runtime itself (might differ across the runtimes)1958 Parent object for all event dispatching components and objects 2409 1959 2410 @method shimExec 2411 @param {Mixed} [] 2412 @protected 2413 @return {Mixed} Depends on the action and component 2414 */ 2415 shimExec: function(component, action) { 2416 var args = [].slice.call(arguments, 2); 2417 return self.getShim().exec.call(this, this.uid, component, action, args); 2418 }, 1960 @class moxie/core/EventTarget 1961 @constructor EventTarget 1962 */ 1963 function EventTarget() { 1964 /** 1965 Unique id of the event dispatcher, usually overriden by children 2419 1966 2420 /** 2421 Operaional interface that is used by components to invoke specific actions on the runtime 2422 (is invoked in the scope of component) 1967 @property uid 1968 @type String 1969 */ 1970 this.uid = Basic.guid(); 1971 } 2423 1972 2424 @method exec2425 @param {Mixed} []*2426 @protected2427 @return {Mixed} Depends on the action and component2428 */2429 exec: function(component, action) { // this is called in the context of component, not runtime2430 var args = [].slice.call(arguments, 2);2431 1973 2432 if (self[component] && self[component][action]) { 2433 return self[component][action].apply(this, args); 2434 } 2435 return self.shimExec.apply(this, arguments); 2436 }, 1974 Basic.extend(EventTarget.prototype, { 2437 1975 2438 /**2439 Destroys the runtime (removes all events and deletes DOM structures)1976 /** 1977 Can be called from within a child in order to acquire uniqie id in automated manner 2440 1978 2441 @method destroy 2442 */ 2443 destroy: function() { 2444 if (!self) { 2445 return; // obviously already destroyed 2446 } 1979 @method init 1980 */ 1981 init: function() { 1982 if (!this.uid) { 1983 this.uid = Basic.guid('uid_'); 1984 } 1985 }, 2447 1986 2448 var shimContainer = Dom.get(this.shimid); 2449 if (shimContainer) { 2450 shimContainer.parentNode.removeChild(shimContainer); 2451 } 1987 /** 1988 Register a handler to a specific event dispatched by the object 2452 1989 2453 if (_shim) { 2454 _shim.removeAllInstances(); 2455 } 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; 1998 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_'); 2002 } 2003 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; 2012 } 2456 2013 2457 this.unbindAll(); 2458 delete runtimes[this.uid]; 2459 this.uid = null; // mark this runtime as destroyed 2460 _uid = self = _shim = shimContainer = null; 2461 } 2462 }); 2014 type = type.toLowerCase(); 2015 priority = parseInt(priority, 10) || 0; 2463 2016 2464 // once we got the mode, test against all caps 2465 if (this.mode && options.required_caps && !this.can(options.required_caps)) { 2466 this.mode = false; 2467 } 2468 } 2017 list = eventpool[this.uid] && eventpool[this.uid][type] || []; 2018 list.push({fn : fn, priority : priority, scope : scope || this}); 2469 2019 2020 if (!eventpool[this.uid]) { 2021 eventpool[this.uid] = {}; 2022 } 2023 eventpool[this.uid][type] = list; 2024 }, 2470 2025 2471 /**2472 Default order to try different runtime types2026 /** 2027 Check if any handlers were registered to the specified event 2473 2028 2474 @property order 2475 @type String 2476 @static 2477 */ 2478 Runtime.order = 'html5,html4'; 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 }, 2479 2043 2044 /** 2045 Unregister the handler from the event, or if former was not specified - unregister all handlers 2480 2046 2481 /** 2482 Retrieves runtime from private hash by it's uid 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; 2053 2054 type = type.toLowerCase(); 2055 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 } 2483 2063 2484 @method getRuntime 2485 @private 2486 @static 2487 @param {String} uid Unique identifier of the runtime 2488 @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not 2489 */ 2490 Runtime.getRuntime = function(uid) { 2491 return runtimes[uid] ? runtimes[uid] : false; 2492 }; 2064 list = eventpool[this.uid] && eventpool[this.uid][type]; 2493 2065 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; 2072 } 2073 } 2074 } else { 2075 list = []; 2076 } 2494 2077 2495 /** 2496 Register constructor for the Runtime of new (or perhaps modified) type 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 } 2086 } 2087 } 2088 }, 2497 2089 2498 @method addConstructor 2499 @static 2500 @param {String} type Runtime type (e.g. flash, html5, etc) 2501 @param {Function} construct Constructor for the Runtime type 2502 */ 2503 Runtime.addConstructor = function(type, constructor) { 2504 constructor.prototype = EventTarget.instance; 2505 runtimeConstructors[type] = constructor; 2506 }; 2090 /** 2091 Remove all event handlers from the object 2507 2092 2093 @method removeAllEventListeners 2094 */ 2095 removeAllEventListeners: function() { 2096 if (eventpool[this.uid]) { 2097 delete eventpool[this.uid]; 2098 } 2099 }, 2508 2100 2509 /**2510 Get the constructor for the specified type.2101 /** 2102 Dispatch the event 2511 2103 2512 method getConstructor 2513 @static 2514 @param {String} type Runtime type (e.g. flash, html5, etc) 2515 @return {Function} Constructor for the Runtime type 2516 */ 2517 Runtime.getConstructor = function(type) { 2518 return runtimeConstructors[type] || null; 2519 }; 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; 2122 } 2123 evt.async = tmpEvt.async || false; 2124 } else { 2125 throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR); 2126 } 2127 } 2520 2128 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 } 2521 2138 2522 /** 2523 Get info about the runtime (uid, type, capabilities) 2139 type = type.toLowerCase(); 2524 2140 2525 @method getInfo 2526 @static 2527 @param {String} uid Unique identifier of the runtime 2528 @return {Mixed} Info object or null if runtime doesn't exist 2529 */ 2530 Runtime.getInfo = function(uid) { 2531 var runtime = Runtime.getRuntime(uid); 2141 list = eventpool[uid] && eventpool[uid][type]; 2532 2142 2533 if (runtime) { 2534 return { 2535 uid: runtime.uid, 2536 type: runtime.type, 2537 mode: runtime.mode, 2538 can: function() { 2539 return runtime.can.apply(runtime, arguments); 2540 } 2541 }; 2542 } 2543 return null; 2544 }; 2143 if (list) { 2144 // sort event list by prority 2145 list.sort(function(a, b) { return b.priority - a.priority; }); 2545 2146 2147 args = [].slice.call(arguments); 2546 2148 2547 /** 2548 Convert caps represented by a comma-separated string to the object representation. 2149 // first argument will be pseudo-event object 2150 args.shift(); 2151 evt.type = type; 2152 args.unshift(evt); 2549 2153 2550 @method parseCaps 2551 @static 2552 @param {String} capStr Comma-separated list of capabilities 2553 @return {Object} 2554 */ 2555 Runtime.parseCaps = function(capStr) { 2556 var capObj = {}; 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 } 2557 2157 2558 if (Basic.typeOf(capStr) !== 'string') { 2559 return capStr || {}; 2560 } 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); 2169 }); 2170 } else { 2171 queue.push(function(cb) { 2172 cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation 2173 }); 2174 } 2175 }); 2176 if (queue.length) { 2177 Basic.inSeries(queue, function(err) { 2178 result = !err; 2179 }); 2180 } 2181 } 2182 return result; 2183 }, 2561 2184 2562 Basic.each(capStr.split(','), function(key) { 2563 capObj[key] = true; // we assume it to be - true 2564 }); 2185 /** 2186 Register a handler to the event type that will run only once 2565 2187 2566 return capObj; 2567 }; 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 }, 2568 2202 2569 /**2570 Test the specified runtime for specific capabilities.2203 /** 2204 Alias for addEventListener 2571 2205 2572 @method can 2573 @static 2574 @param {String} type Runtime type (e.g. flash, html5, etc) 2575 @param {String|Object} caps Set of capabilities to check 2576 @return {Boolean} Result of the test 2577 */ 2578 Runtime.can = function(type, caps) { 2579 var runtime 2580 , constructor = Runtime.getConstructor(type) 2581 , mode 2582 ; 2583 if (constructor) { 2584 runtime = new constructor({ 2585 required_caps: caps 2586 }); 2587 mode = runtime.mode; 2588 runtime.destroy(); 2589 return !!mode; 2590 } 2591 return false; 2592 }; 2206 @method bind 2207 @protected 2208 */ 2209 bind: function() { 2210 this.addEventListener.apply(this, arguments); 2211 }, 2212 2213 /** 2214 Alias for removeEventListener 2593 2215 2216 @method unbind 2217 @protected 2218 */ 2219 unbind: function() { 2220 this.removeEventListener.apply(this, arguments); 2221 }, 2594 2222 2595 /**2596 Figure out a runtime that supports specified capabilities.2223 /** 2224 Alias for removeAllEventListeners 2597 2225 2598 @method thatCan 2599 @static 2600 @param {String|Object} caps Set of capabilities to check 2601 @param {String} [runtimeOrder] Comma-separated list of runtimes to check against 2602 @return {String} Usable runtime identifier or null 2603 */ 2604 Runtime.thatCan = function(caps, runtimeOrder) { 2605 var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/); 2606 for (var i in types) { 2607 if (Runtime.can(types[i], caps)) { 2608 return types[i]; 2609 } 2610 } 2611 return null; 2612 }; 2226 @method unbindAll 2227 @protected 2228 */ 2229 unbindAll: function() { 2230 this.removeAllEventListeners.apply(this, arguments); 2231 }, 2613 2232 2233 /** 2234 Alias for dispatchEvent 2614 2235 2615 /** 2616 Figure out an operational mode for the specified set of capabilities. 2236 @method trigger 2237 @protected 2238 */ 2239 trigger: function() { 2240 return this.dispatchEvent.apply(this, arguments); 2241 }, 2617 2242 2618 @method getMode2619 @static2620 @param {Object} modeCaps Set of capabilities that depend on particular runtime mode2621 @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for2622 @param {String|Boolean} [defaultMode='browser'] Default mode to use2623 @return {String|Boolean} Compatible operational mode2624 */2625 Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {2626 var mode = null;2627 2243 2628 if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified 2629 defaultMode = 'browser'; 2630 } 2244 /** 2245 Handle properties of on[event] type. 2631 2246 2632 if (requiredCaps && !Basic.isEmptyObj(modeCaps)) { 2633 // loop over required caps and check if they do require the same mode 2634 Basic.each(requiredCaps, function(value, cap) { 2635 if (modeCaps.hasOwnProperty(cap)) { 2636 var capMode = modeCaps[cap](value); 2637 2638 // make sure we always have an array 2639 if (typeof(capMode) === 'string') { 2640 capMode = [capMode]; 2641 } 2642 2643 if (!mode) { 2644 mode = capMode; 2645 } else if (!(mode = Basic.arrayIntersect(mode, capMode))) { 2646 // if cap requires conflicting mode - runtime cannot fulfill required caps 2247 @method handleEventProps 2248 @private 2249 */ 2250 handleEventProps: function(dispatches) { 2251 var self = this; 2647 2252 2648 if (MXI_DEBUG && Env.debug.runtime) { 2649 Env.log("\t\t%c: %v (conflicting mode requested: %s)", cap, value, capMode); 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); 2650 2257 } 2258 }); 2651 2259 2652 return (mode = false); 2653 } 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 }); 2654 2267 } 2655 2268 2656 if (MXI_DEBUG && Env.debug.runtime) {2657 Env.log("\t\t%c: %v (compatible modes: %s)", cap, value, mode);2658 }2659 2269 }); 2660 2270 2661 if (mode) {2662 return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];2663 } else if (mode === false) {2664 return false;2665 }2666 }2667 return defaultMode;2668 };2669 2271 2272 EventTarget.instance = new EventTarget(); 2670 2273 2671 /**2672 Capability check that always returns true2274 return EventTarget; 2275 }); 2673 2276 2674 @private 2675 @static 2676 @return {True} 2677 */ 2678 Runtime.capTrue = function() { 2679 return true; 2680 }; 2277 // Included from: src/javascript/runtime/Runtime.js 2681 2278 2682 /** 2683 Capability check that always returns false 2279 /** 2280 * Runtime.js 2281 * 2282 * Copyright 2013, Moxiecode Systems AB 2283 * Released under GPL License. 2284 * 2285 * License: http://www.plupload.com/license 2286 * Contributing: http://www.plupload.com/contributing 2287 */ 2684 2288 2685 @private2686 @static2687 @return {False}2688 */2689 Runtime.capFalse = function() {2690 return false;2691 };2289 define('moxie/runtime/Runtime', [ 2290 "moxie/core/utils/Env", 2291 "moxie/core/utils/Basic", 2292 "moxie/core/utils/Dom", 2293 "moxie/core/EventTarget" 2294 ], function(Env, Basic, Dom, EventTarget) { 2295 var runtimeConstructors = {}, runtimes = {}; 2692 2296 2693 /**2694 Evaluate the expression to boolean value and create a function that always returns it.2297 /** 2298 Common set of methods and properties for every runtime instance 2695 2299 2696 @private 2697 @static 2698 @param {Mixed} expr Expression to evaluate 2699 @return {Function} Function returning the result of evaluation 2700 */ 2701 Runtime.capTest = function(expr) { 2702 return function() { 2703 return !!expr; 2704 }; 2705 }; 2300 @class moxie/runtime/Runtime 2706 2301 2707 return Runtime; 2708 }); 2302 @param {Object} options 2303 @param {String} type Sanitized name of the runtime 2304 @param {Object} [caps] Set of capabilities that differentiate specified runtime 2305 @param {Object} [modeCaps] Set of capabilities that do require specific operational mode 2306 @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested 2307 */ 2308 function Runtime(options, type, caps, modeCaps, preferredMode) { 2309 /** 2310 Dispatched when runtime is initialized and ready. 2311 Results in RuntimeInit on a connected component. 2312 2313 @event Init 2314 */ 2315 2316 /** 2317 Dispatched when runtime fails to initialize. 2318 Results in RuntimeError on a connected component. 2319 2320 @event Error 2321 */ 2322 2323 var self = this 2324 , _shim 2325 , _uid = Basic.guid(type + '_') 2326 , defaultMode = preferredMode || 'browser' 2327 ; 2328 2329 options = options || {}; 2330 2331 // register runtime in private hash 2332 runtimes[_uid] = this; 2333 2334 /** 2335 Default set of capabilities, which can be redifined later by specific runtime 2336 2337 @private 2338 @property caps 2339 @type Object 2340 */ 2341 caps = Basic.extend({ 2342 // Runtime can: 2343 // provide access to raw binary data of the file 2344 access_binary: false, 2345 // provide access to raw binary data of the image (image extension is optional) 2346 access_image_binary: false, 2347 // display binary data as thumbs for example 2348 display_media: false, 2349 // make cross-domain requests 2350 do_cors: false, 2351 // accept files dragged and dropped from the desktop 2352 drag_and_drop: false, 2353 // filter files in selection dialog by their extensions 2354 filter_by_extension: true, 2355 // resize image (and manipulate it raw data of any file in general) 2356 resize_image: false, 2357 // periodically report how many bytes of total in the file were uploaded (loaded) 2358 report_upload_progress: false, 2359 // provide access to the headers of http response 2360 return_response_headers: false, 2361 // support response of specific type, which should be passed as an argument 2362 // e.g. runtime.can('return_response_type', 'blob') 2363 return_response_type: false, 2364 // return http status code of the response 2365 return_status_code: true, 2366 // send custom http header with the request 2367 send_custom_headers: false, 2368 // pick up the files from a dialog 2369 select_file: false, 2370 // select whole folder in file browse dialog 2371 select_folder: false, 2372 // select multiple files at once in file browse dialog 2373 select_multiple: true, 2374 // send raw binary data, that is generated after image resizing or manipulation of other kind 2375 send_binary_string: false, 2376 // send cookies with http request and therefore retain session 2377 send_browser_cookies: true, 2378 // send data formatted as multipart/form-data 2379 send_multipart: true, 2380 // slice the file or blob to smaller parts 2381 slice_blob: false, 2382 // upload file without preloading it to memory, stream it out directly from disk 2383 stream_upload: false, 2384 // programmatically trigger file browse dialog 2385 summon_file_dialog: false, 2386 // upload file of specific size, size should be passed as argument 2387 // e.g. runtime.can('upload_filesize', '500mb') 2388 upload_filesize: true, 2389 // initiate http request with specific http method, method should be passed as argument 2390 // e.g. runtime.can('use_http_method', 'put') 2391 use_http_method: true 2392 }, caps); 2393 2394 2395 // default to the mode that is compatible with preferred caps 2396 if (options.preferred_caps) { 2397 defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode); 2398 } 2399 2400 if (MXI_DEBUG && Env.debug.runtime) { 2401 Env.log("\tdefault mode: %s", defaultMode); 2402 } 2403 2404 // small extension factory here (is meant to be extended with actual extensions constructors) 2405 _shim = (function() { 2406 var objpool = {}; 2407 return { 2408 exec: function(uid, comp, fn, args) { 2409 if (_shim[comp]) { 2410 if (!objpool[uid]) { 2411 objpool[uid] = { 2412 context: this, 2413 instance: new _shim[comp]() 2414 }; 2415 } 2416 if (objpool[uid].instance[fn]) { 2417 return objpool[uid].instance[fn].apply(this, args); 2418 } 2419 } 2420 }, 2421 2422 removeInstance: function(uid) { 2423 delete objpool[uid]; 2424 }, 2425 2426 removeAllInstances: function() { 2427 var self = this; 2428 Basic.each(objpool, function(obj, uid) { 2429 if (Basic.typeOf(obj.instance.destroy) === 'function') { 2430 obj.instance.destroy.call(obj.context); 2431 } 2432 self.removeInstance(uid); 2433 }); 2434 } 2435 }; 2436 }()); 2437 2438 2439 // public methods 2440 Basic.extend(this, { 2441 /** 2442 Specifies whether runtime instance was initialized or not 2443 2444 @property initialized 2445 @type {Boolean} 2446 @default false 2447 */ 2448 initialized: false, // shims require this flag to stop initialization retries 2449 2450 /** 2451 Unique ID of the runtime 2452 2453 @property uid 2454 @type {String} 2455 */ 2456 uid: _uid, 2457 2458 /** 2459 Runtime type (e.g. flash, html5, etc) 2460 2461 @property type 2462 @type {String} 2463 */ 2464 type: type, 2465 2466 /** 2467 Runtime (not native one) may operate in browser or client mode. 2468 2469 @property mode 2470 @private 2471 @type {String|Boolean} current mode or false, if none possible 2472 */ 2473 mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode), 2474 2475 /** 2476 id of the DOM container for the runtime (if available) 2477 2478 @property shimid 2479 @type {String} 2480 */ 2481 shimid: _uid + '_container', 2482 2483 /** 2484 Number of connected clients. If equal to zero, runtime can be destroyed 2485 2486 @property clients 2487 @type {Number} 2488 */ 2489 clients: 0, 2490 2491 /** 2492 Runtime initialization options 2493 2494 @property options 2495 @type {Object} 2496 */ 2497 options: options, 2498 2499 /** 2500 Checks if the runtime has specific capability 2501 2502 @method can 2503 @param {String} cap Name of capability to check 2504 @param {Mixed} [value] If passed, capability should somehow correlate to the value 2505 @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set) 2506 @return {Boolean} true if runtime has such capability and false, if - not 2507 */ 2508 can: function(cap, value) { 2509 var refCaps = arguments[2] || caps; 2510 2511 // if cap var is a comma-separated list of caps, convert it to object (key/value) 2512 if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') { 2513 cap = Runtime.parseCaps(cap); 2514 } 2515 2516 if (Basic.typeOf(cap) === 'object') { 2517 for (var key in cap) { 2518 if (!this.can(key, cap[key], refCaps)) { 2519 return false; 2520 } 2521 } 2522 return true; 2523 } 2524 2525 // check the individual cap 2526 if (Basic.typeOf(refCaps[cap]) === 'function') { 2527 return refCaps[cap].call(this, value); 2528 } else { 2529 return (value === refCaps[cap]); 2530 } 2531 }, 2532 2533 /** 2534 Returns container for the runtime as DOM element 2535 2536 @method getShimContainer 2537 @return {DOMElement} 2538 */ 2539 getShimContainer: function() { 2540 var container, shimContainer = Dom.get(this.shimid); 2541 2542 // if no container for shim, create one 2543 if (!shimContainer) { 2544 container = Dom.get(this.options.container) || document.body; 2545 2546 // create shim container and insert it at an absolute position into the outer container 2547 shimContainer = document.createElement('div'); 2548 shimContainer.id = this.shimid; 2549 shimContainer.className = 'moxie-shim moxie-shim-' + this.type; 2550 2551 Basic.extend(shimContainer.style, { 2552 position: 'absolute', 2553 top: '0px', 2554 left: '0px', 2555 width: '1px', 2556 height: '1px', 2557 overflow: 'hidden' 2558 }); 2559 2560 container.appendChild(shimContainer); 2561 container = null; 2562 } 2563 2564 return shimContainer; 2565 }, 2566 2567 /** 2568 Returns runtime as DOM element (if appropriate) 2569 2570 @method getShim 2571 @return {DOMElement} 2572 */ 2573 getShim: function() { 2574 return _shim; 2575 }, 2576 2577 /** 2578 Invokes a method within the runtime itself (might differ across the runtimes) 2579 2580 @method shimExec 2581 @param {Mixed} [] 2582 @protected 2583 @return {Mixed} Depends on the action and component 2584 */ 2585 shimExec: function(component, action) { 2586 var args = [].slice.call(arguments, 2); 2587 return self.getShim().exec.call(this, this.uid, component, action, args); 2588 }, 2589 2590 /** 2591 Operaional interface that is used by components to invoke specific actions on the runtime 2592 (is invoked in the scope of component) 2593 2594 @method exec 2595 @param {Mixed} []* 2596 @protected 2597 @return {Mixed} Depends on the action and component 2598 */ 2599 exec: function(component, action) { // this is called in the context of component, not runtime 2600 var args = [].slice.call(arguments, 2); 2601 2602 if (self[component] && self[component][action]) { 2603 return self[component][action].apply(this, args); 2604 } 2605 return self.shimExec.apply(this, arguments); 2606 }, 2607 2608 /** 2609 Destroys the runtime (removes all events and deletes DOM structures) 2610 2611 @method destroy 2612 */ 2613 destroy: function() { 2614 if (!self) { 2615 return; // obviously already destroyed 2616 } 2617 2618 var shimContainer = Dom.get(this.shimid); 2619 if (shimContainer) { 2620 shimContainer.parentNode.removeChild(shimContainer); 2621 } 2622 2623 if (_shim) { 2624 _shim.removeAllInstances(); 2625 } 2626 2627 this.unbindAll(); 2628 delete runtimes[this.uid]; 2629 this.uid = null; // mark this runtime as destroyed 2630 _uid = self = _shim = shimContainer = null; 2631 } 2632 }); 2633 2634 // once we got the mode, test against all caps 2635 if (this.mode && options.required_caps && !this.can(options.required_caps)) { 2636 this.mode = false; 2637 } 2638 } 2639 2640 2641 /** 2642 Default order to try different runtime types 2643 2644 @property order 2645 @type String 2646 @static 2647 */ 2648 Runtime.order = 'html5,flash,silverlight,html4'; 2649 2650 2651 /** 2652 Retrieves runtime from private hash by it's uid 2653 2654 @method getRuntime 2655 @private 2656 @static 2657 @param {String} uid Unique identifier of the runtime 2658 @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not 2659 */ 2660 Runtime.getRuntime = function(uid) { 2661 return runtimes[uid] ? runtimes[uid] : false; 2662 }; 2663 2664 2665 /** 2666 Register constructor for the Runtime of new (or perhaps modified) type 2667 2668 @method addConstructor 2669 @static 2670 @param {String} type Runtime type (e.g. flash, html5, etc) 2671 @param {Function} construct Constructor for the Runtime type 2672 */ 2673 Runtime.addConstructor = function(type, constructor) { 2674 constructor.prototype = EventTarget.instance; 2675 runtimeConstructors[type] = constructor; 2676 }; 2677 2678 2679 /** 2680 Get the constructor for the specified type. 2681 2682 method getConstructor 2683 @static 2684 @param {String} type Runtime type (e.g. flash, html5, etc) 2685 @return {Function} Constructor for the Runtime type 2686 */ 2687 Runtime.getConstructor = function(type) { 2688 return runtimeConstructors[type] || null; 2689 }; 2690 2691 2692 /** 2693 Get info about the runtime (uid, type, capabilities) 2694 2695 @method getInfo 2696 @static 2697 @param {String} uid Unique identifier of the runtime 2698 @return {Mixed} Info object or null if runtime doesn't exist 2699 */ 2700 Runtime.getInfo = function(uid) { 2701 var runtime = Runtime.getRuntime(uid); 2702 2703 if (runtime) { 2704 return { 2705 uid: runtime.uid, 2706 type: runtime.type, 2707 mode: runtime.mode, 2708 can: function() { 2709 return runtime.can.apply(runtime, arguments); 2710 } 2711 }; 2712 } 2713 return null; 2714 }; 2715 2716 2717 /** 2718 Convert caps represented by a comma-separated string to the object representation. 2719 2720 @method parseCaps 2721 @static 2722 @param {String} capStr Comma-separated list of capabilities 2723 @return {Object} 2724 */ 2725 Runtime.parseCaps = function(capStr) { 2726 var capObj = {}; 2727 2728 if (Basic.typeOf(capStr) !== 'string') { 2729 return capStr || {}; 2730 } 2731 2732 Basic.each(capStr.split(','), function(key) { 2733 capObj[key] = true; // we assume it to be - true 2734 }); 2735 2736 return capObj; 2737 }; 2738 2739 /** 2740 Test the specified runtime for specific capabilities. 2741 2742 @method can 2743 @static 2744 @param {String} type Runtime type (e.g. flash, html5, etc) 2745 @param {String|Object} caps Set of capabilities to check 2746 @return {Boolean} Result of the test 2747 */ 2748 Runtime.can = function(type, caps) { 2749 var runtime 2750 , constructor = Runtime.getConstructor(type) 2751 , mode 2752 ; 2753 if (constructor) { 2754 runtime = new constructor({ 2755 required_caps: caps 2756 }); 2757 mode = runtime.mode; 2758 runtime.destroy(); 2759 return !!mode; 2760 } 2761 return false; 2762 }; 2763 2764 2765 /** 2766 Figure out a runtime that supports specified capabilities. 2767 2768 @method thatCan 2769 @static 2770 @param {String|Object} caps Set of capabilities to check 2771 @param {String} [runtimeOrder] Comma-separated list of runtimes to check against 2772 @return {String} Usable runtime identifier or null 2773 */ 2774 Runtime.thatCan = function(caps, runtimeOrder) { 2775 var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/); 2776 for (var i in types) { 2777 if (Runtime.can(types[i], caps)) { 2778 return types[i]; 2779 } 2780 } 2781 return null; 2782 }; 2783 2784 2785 /** 2786 Figure out an operational mode for the specified set of capabilities. 2787 2788 @method getMode 2789 @static 2790 @param {Object} modeCaps Set of capabilities that depend on particular runtime mode 2791 @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for 2792 @param {String|Boolean} [defaultMode='browser'] Default mode to use 2793 @return {String|Boolean} Compatible operational mode 2794 */ 2795 Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) { 2796 var mode = null; 2797 2798 if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified 2799 defaultMode = 'browser'; 2800 } 2801 2802 if (requiredCaps && !Basic.isEmptyObj(modeCaps)) { 2803 // loop over required caps and check if they do require the same mode 2804 Basic.each(requiredCaps, function(value, cap) { 2805 if (modeCaps.hasOwnProperty(cap)) { 2806 var capMode = modeCaps[cap](value); 2807 2808 // make sure we always have an array 2809 if (typeof(capMode) === 'string') { 2810 capMode = [capMode]; 2811 } 2812 2813 if (!mode) { 2814 mode = capMode; 2815 } else if (!(mode = Basic.arrayIntersect(mode, capMode))) { 2816 // if cap requires conflicting mode - runtime cannot fulfill required caps 2817 2818 if (MXI_DEBUG && Env.debug.runtime) { 2819 Env.log("\t\t%s: %s (conflicting mode requested: %s)", cap, value, capMode); 2820 } 2821 2822 return (mode = false); 2823 } 2824 } 2825 2826 if (MXI_DEBUG && Env.debug.runtime) { 2827 Env.log("\t\t%s: %s (compatible modes: %s)", cap, value, mode); 2828 } 2829 }); 2830 2831 if (mode) { 2832 return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0]; 2833 } else if (mode === false) { 2834 return false; 2835 } 2836 } 2837 return defaultMode; 2838 }; 2839 2840 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 /** 2866 Capability check that always returns true 2867 2868 @private 2869 @static 2870 @return {True} 2871 */ 2872 Runtime.capTrue = function() { 2873 return true; 2874 }; 2875 2876 /** 2877 Capability check that always returns false 2878 2879 @private 2880 @static 2881 @return {False} 2882 */ 2883 Runtime.capFalse = function() { 2884 return false; 2885 }; 2886 2887 /** 2888 Evaluate the expression to boolean value and create a function that always returns it. 2889 2890 @private 2891 @static 2892 @param {Mixed} expr Expression to evaluate 2893 @return {Function} Function returning the result of evaluation 2894 */ 2895 Runtime.capTest = function(expr) { 2896 return function() { 2897 return !!expr; 2898 }; 2899 }; 2900 2901 return Runtime; 2902 }); 2903 2904 // Included from: src/javascript/runtime/RuntimeClient.js 2905 2906 /** 2907 * RuntimeClient.js 2908 * 2909 * Copyright 2013, Moxiecode Systems AB 2910 * Released under GPL License. 2911 * 2912 * License: http://www.plupload.com/license 2913 * Contributing: http://www.plupload.com/contributing 2914 */ 2915 2916 define('moxie/runtime/RuntimeClient', [ 2917 'moxie/core/utils/Env', 2918 'moxie/core/Exceptions', 2919 'moxie/core/utils/Basic', 2920 'moxie/runtime/Runtime' 2921 ], function(Env, x, Basic, Runtime) { 2922 /** 2923 Set of methods and properties, required by a component to acquire ability to connect to a runtime 2924 2925 @class moxie/runtime/RuntimeClient 2926 */ 2927 return function RuntimeClient() { 2928 var runtime; 2929 2930 Basic.extend(this, { 2931 /** 2932 Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one. 2933 Increments number of clients connected to the specified runtime. 2934 2935 @private 2936 @method connectRuntime 2937 @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites 2938 */ 2939 connectRuntime: function(options) { 2940 var comp = this, ruid; 2941 2942 function initialize(items) { 2943 var type, constructor; 2944 2945 // if we ran out of runtimes 2946 if (!items.length) { 2947 comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); 2948 runtime = null; 2949 return; 2950 } 2951 2952 type = items.shift().toLowerCase(); 2953 constructor = Runtime.getConstructor(type); 2954 if (!constructor) { 2955 if (MXI_DEBUG && Env.debug.runtime) { 2956 Env.log("Constructor for '%s' runtime is not available.", type); 2957 } 2958 initialize(items); 2959 return; 2960 } 2961 2962 if (MXI_DEBUG && Env.debug.runtime) { 2963 Env.log("Trying runtime: %s", type); 2964 Env.log(options); 2965 } 2966 2967 // try initializing the runtime 2968 runtime = new constructor(options); 2969 2970 runtime.bind('Init', function() { 2971 // mark runtime as initialized 2972 runtime.initialized = true; 2973 2974 if (MXI_DEBUG && Env.debug.runtime) { 2975 Env.log("Runtime '%s' initialized", runtime.type); 2976 } 2977 2978 // jailbreak ... 2979 setTimeout(function() { 2980 runtime.clients++; 2981 comp.ruid = runtime.uid; 2982 // this will be triggered on component 2983 comp.trigger('RuntimeInit', runtime); 2984 }, 1); 2985 }); 2986 2987 runtime.bind('Error', function() { 2988 if (MXI_DEBUG && Env.debug.runtime) { 2989 Env.log("Runtime '%s' failed to initialize", runtime.type); 2990 } 2991 2992 runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here 2993 initialize(items); 2994 }); 2995 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 }); 3004 3005 if (MXI_DEBUG && Env.debug.runtime) { 3006 Env.log("\tselected mode: %s", runtime.mode); 3007 } 3008 3009 // check if runtime managed to pick-up operational mode 3010 if (!runtime.mode) { 3011 runtime.trigger('Error'); 3012 return; 3013 } 3014 3015 runtime.init(); 3016 } 3017 3018 // check if a particular runtime was requested 3019 if (Basic.typeOf(options) === 'string') { 3020 ruid = options; 3021 } else if (Basic.typeOf(options.ruid) === 'string') { 3022 ruid = options.ruid; 3023 } 3024 3025 if (ruid) { 3026 runtime = Runtime.getRuntime(ruid); 3027 if (runtime) { 3028 comp.ruid = ruid; 3029 runtime.clients++; 3030 return runtime; 3031 } else { 3032 // there should be a runtime and there's none - weird case 3033 throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR); 3034 } 3035 } 3036 3037 // initialize a fresh one, that fits runtime list and required features best 3038 initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/)); 3039 }, 3040 3041 3042 /** 3043 Disconnects from the runtime. Decrements number of clients connected to the specified runtime. 3044 3045 @private 3046 @method disconnectRuntime 3047 */ 3048 disconnectRuntime: function() { 3049 if (runtime && --runtime.clients <= 0) { 3050 runtime.destroy(); 3051 } 3052 3053 // once the component is disconnected, it shouldn't have access to the runtime 3054 runtime = null; 3055 }, 3056 3057 3058 /** 3059 Returns the runtime to which the client is currently connected. 3060 3061 @method getRuntime 3062 @return {Runtime} Runtime or null if client is not connected 3063 */ 3064 getRuntime: function() { 3065 if (runtime && runtime.uid) { 3066 return runtime; 3067 } 3068 return runtime = null; // make sure we do not leave zombies rambling around 3069 }, 3070 3071 3072 /** 3073 Handy shortcut to safely invoke runtime extension methods. 3074 3075 @private 3076 @method exec 3077 @return {Mixed} Whatever runtime extension method returns 3078 */ 3079 exec: function() { 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); 3201 } 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]; 3265 } 3266 }); 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 } 3529 }); 3530 return exts; 3531 }; 3532 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 } 3592 }); 3593 3594 // Included from: src/javascript/file/FileInput.js 3595 3596 /** 3597 * FileInput.js 3598 * 3599 * Copyright 2013, Moxiecode Systems AB 3600 * Released under GPL License. 3601 * 3602 * License: http://www.plupload.com/license 3603 * Contributing: http://www.plupload.com/contributing 3604 */ 3605 3606 define('moxie/file/FileInput', [ 3607 'moxie/core/utils/Basic', 3608 'moxie/core/utils/Env', 3609 'moxie/core/utils/Mime', 3610 'moxie/core/utils/Dom', 3611 'moxie/core/Exceptions', 3612 'moxie/core/EventTarget', 3613 'moxie/core/I18n', 3614 'moxie/runtime/Runtime', 3615 'moxie/runtime/RuntimeClient' 3616 ], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) { 3617 /** 3618 Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click, 3619 converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory 3620 with _FileReader_ or uploaded to a server through _XMLHttpRequest_. 3621 3622 @class moxie/file/FileInput 3623 @constructor 3624 @extends EventTarget 3625 @uses RuntimeClient 3626 @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_. 3627 @param {String|DOMElement} options.browse_button DOM Element to turn into file picker. 3628 @param {Array} [options.accept] Array of mime types to accept. By default accepts all. 3629 @param {Boolean} [options.multiple=false] Enable selection of multiple files. 3630 @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time). 3631 @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode 3632 for _browse\_button_. 3633 @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support. 3634 3635 @example 3636 <div id="container"> 3637 <a id="file-picker" href="javascript:;">Browse...</a> 3638 </div> 3639 3640 <script> 3641 var fileInput = new moxie.file.FileInput({ 3642 browse_button: 'file-picker', // or document.getElementById('file-picker') 3643 container: 'container', 3644 accept: [ 3645 {title: "Image files", extensions: "jpg,gif,png"} // accept only images 3646 ], 3647 multiple: true // allow multiple file selection 3648 }); 3649 3650 fileInput.onchange = function(e) { 3651 // do something to files array 3652 console.info(e.target.files); // or this.files or fileInput.files 3653 }; 3654 3655 fileInput.init(); // initialize 3656 </script> 3657 */ 3658 var dispatches = [ 3659 /** 3660 Dispatched when runtime is connected and file-picker is ready to be used. 3661 3662 @event ready 3663 @param {Object} event 3664 */ 3665 'ready', 3666 3667 /** 3668 Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. 3669 Check [corresponding documentation entry](#method_refresh) for more info. 3670 3671 @event refresh 3672 @param {Object} event 3673 */ 3674 3675 /** 3676 Dispatched when selection of files in the dialog is complete. 3677 3678 @event change 3679 @param {Object} event 3680 */ 3681 'change', 3682 3683 'cancel', // TODO: might be useful 3684 3685 /** 3686 Dispatched when mouse cursor enters file-picker area. Can be used to style element 3687 accordingly. 3688 3689 @event mouseenter 3690 @param {Object} event 3691 */ 3692 'mouseenter', 3693 3694 /** 3695 Dispatched when mouse cursor leaves file-picker area. Can be used to style element 3696 accordingly. 3697 3698 @event mouseleave 3699 @param {Object} event 3700 */ 3701 'mouseleave', 3702 3703 /** 3704 Dispatched when functional mouse button is pressed on top of file-picker area. 3705 3706 @event mousedown 3707 @param {Object} event 3708 */ 3709 'mousedown', 3710 3711 /** 3712 Dispatched when functional mouse button is released on top of file-picker area. 3713 3714 @event mouseup 3715 @param {Object} event 3716 */ 3717 'mouseup' 3718 ]; 3719 3720 function FileInput(options) { 3721 if (MXI_DEBUG) { 3722 Env.log("Instantiating FileInput..."); 3723 } 3724 3725 var container, browseButton, defaults; 3726 3727 // if flat argument passed it should be browse_button id 3728 if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) { 3729 options = { browse_button : options }; 3730 } 3731 3732 // this will help us to find proper default container 3733 browseButton = Dom.get(options.browse_button); 3734 if (!browseButton) { 3735 // browse button is required 3736 throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); 3737 } 3738 3739 // figure out the options 3740 defaults = { 3741 accept: [{ 3742 title: I18n.translate('All Files'), 3743 extensions: '*' 3744 }], 3745 multiple: false, 3746 required_caps: false, 3747 container: browseButton.parentNode || document.body 3748 }; 3749 3750 options = Basic.extend({}, defaults, options); 3751 3752 // convert to object representation 3753 if (typeof(options.required_caps) === 'string') { 3754 options.required_caps = Runtime.parseCaps(options.required_caps); 3755 } 3756 3757 // normalize accept option (could be list of mime types or array of title/extensions pairs) 3758 if (typeof(options.accept) === 'string') { 3759 options.accept = Mime.mimes2extList(options.accept); 3760 } 3761 3762 container = Dom.get(options.container); 3763 // make sure we have container 3764 if (!container) { 3765 container = document.body; 3766 } 3767 3768 // make container relative, if it's not 3769 if (Dom.getStyle(container, 'position') === 'static') { 3770 container.style.position = 'relative'; 3771 } 3772 3773 container = browseButton = null; // IE 3774 3775 RuntimeClient.call(this); 3776 3777 Basic.extend(this, { 3778 /** 3779 Unique id of the component 3780 3781 @property uid 3782 @protected 3783 @readOnly 3784 @type {String} 3785 @default UID 3786 */ 3787 uid: Basic.guid('uid_'), 3788 3789 /** 3790 Unique id of the connected runtime, if any. 3791 3792 @property ruid 3793 @protected 3794 @type {String} 3795 */ 3796 ruid: null, 3797 3798 /** 3799 Unique id of the runtime container. Useful to get hold of it for various manipulations. 3800 3801 @property shimid 3802 @protected 3803 @type {String} 3804 */ 3805 shimid: null, 3806 3807 /** 3808 Array of selected moxie.file.File objects 3809 3810 @property files 3811 @type {Array} 3812 @default null 3813 */ 3814 files: null, 3815 3816 /** 3817 Initializes the file-picker, connects it to runtime and dispatches event ready when done. 3818 3819 @method init 3820 */ 3821 init: function() { 3822 var self = this; 3823 3824 self.bind('RuntimeInit', function(e, runtime) { 3825 self.ruid = runtime.uid; 3826 self.shimid = runtime.shimid; 3827 3828 self.bind("Ready", function() { 3829 self.trigger("Refresh"); 3830 }, 999); 3831 3832 // re-position and resize shim container 3833 self.bind('Refresh', function() { 3834 var pos, size, browseButton, shimContainer, zIndex; 3835 3836 browseButton = Dom.get(options.browse_button); 3837 shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist 3838 3839 if (browseButton) { 3840 pos = Dom.getPos(browseButton, Dom.get(options.container)); 3841 size = Dom.getSize(browseButton); 3842 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 0; 3843 3844 if (shimContainer) { 3845 Basic.extend(shimContainer.style, { 3846 top: pos.y + 'px', 3847 left: pos.x + 'px', 3848 width: size.w + 'px', 3849 height: size.h + 'px', 3850 zIndex: zIndex + 1 3851 }); 3852 } 3853 } 3854 shimContainer = browseButton = null; 3855 }); 3856 3857 runtime.exec.call(self, 'FileInput', 'init', options); 3858 }); 3859 3860 // runtime needs: options.required_features, options.runtime_order and options.container 3861 self.connectRuntime(Basic.extend({}, options, { 3862 required_caps: { 3863 select_file: true 3864 } 3865 })); 3866 }, 3867 3868 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 /** 3914 Disables file-picker element, so that it doesn't react to mouse clicks. 3915 3916 @method disable 3917 @param {Boolean} [state=true] Disable component if - true, enable if - false 3918 */ 3919 disable: function(state) { 3920 var runtime = this.getRuntime(); 3921 if (runtime) { 3922 this.exec('FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state); 3923 } 3924 }, 3925 3926 3927 /** 3928 Reposition and resize dialog trigger to match the position and size of browse_button element. 3929 3930 @method refresh 3931 */ 3932 refresh: function() { 3933 this.trigger("Refresh"); 3934 }, 3935 3936 3937 /** 3938 Destroy component. 3939 3940 @method destroy 3941 */ 3942 destroy: function() { 3943 var runtime = this.getRuntime(); 3944 if (runtime) { 3945 runtime.exec.call(this, 'FileInput', 'destroy'); 3946 this.disconnectRuntime(); 3947 } 3948 3949 if (Basic.typeOf(this.files) === 'array') { 3950 // no sense in leaving associated files behind 3951 Basic.each(this.files, function(file) { 3952 file.destroy(); 3953 }); 3954 } 3955 this.files = null; 3956 3957 this.unbindAll(); 3958 } 3959 }); 3960 3961 this.handleEventProps(dispatches); 3962 } 3963 3964 FileInput.prototype = EventTarget.instance; 3965 3966 return FileInput; 3967 }); 3968 3969 // Included from: src/javascript/file/File.js 3970 3971 /** 3972 * File.js 3973 * 3974 * Copyright 2013, Moxiecode Systems AB 3975 * Released under GPL License. 3976 * 3977 * License: http://www.plupload.com/license 3978 * Contributing: http://www.plupload.com/contributing 3979 */ 3980 3981 define('moxie/file/File', [ 3982 'moxie/core/utils/Basic', 3983 'moxie/core/utils/Mime', 3984 'moxie/file/Blob' 3985 ], function(Basic, Mime, Blob) { 3986 /** 3987 @class moxie/file/File 3988 @extends Blob 3989 @constructor 3990 @param {String} ruid Unique id of the runtime, to which this blob belongs to 3991 @param {Object} file Object "Native" file object, as it is represented in the runtime 3992 */ 3993 function File(ruid, file) { 3994 if (!file) { // avoid extra errors in case we overlooked something 3995 file = {}; 3996 } 3997 3998 Blob.apply(this, arguments); 3999 4000 if (!this.type) { 4001 this.type = Mime.getFileMime(file.name); 4002 } 4003 4004 // sanitize file name or generate new one 4005 var name; 4006 if (file.name) { 4007 name = file.name.replace(/\\/g, '/'); 4008 name = name.substr(name.lastIndexOf('/') + 1); 4009 } else if (this.type) { 4010 var prefix = this.type.split('/')[0]; 4011 name = Basic.guid((prefix !== '' ? prefix : 'file') + '_'); 4012 4013 if (Mime.extensions[this.type]) { 4014 name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible 4015 } 4016 } 4017 4018 4019 Basic.extend(this, { 4020 /** 4021 File name 4022 4023 @property name 4024 @type {String} 4025 @default UID 4026 */ 4027 name: name || Basic.guid('file_'), 4028 4029 /** 4030 Relative path to the file inside a directory 4031 4032 @property relativePath 4033 @type {String} 4034 @default '' 4035 */ 4036 relativePath: '', 4037 4038 /** 4039 Date of last modification 4040 4041 @property lastModifiedDate 4042 @type {String} 4043 @default now 4044 */ 4045 lastModifiedDate: file.lastModified ? new Date(file.lastModified) : file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) 4046 }); 4047 } 4048 4049 File.prototype = Blob.prototype; 4050 4051 return File; 4052 }); 4053 4054 // Included from: src/javascript/file/FileDrop.js 4055 4056 /** 4057 * FileDrop.js 4058 * 4059 * Copyright 2013, Moxiecode Systems AB 4060 * Released under GPL License. 4061 * 4062 * License: http://www.plupload.com/license 4063 * Contributing: http://www.plupload.com/contributing 4064 */ 4065 4066 define('moxie/file/FileDrop', [ 4067 'moxie/core/I18n', 4068 'moxie/core/utils/Dom', 4069 'moxie/core/Exceptions', 4070 'moxie/core/utils/Basic', 4071 'moxie/core/utils/Env', 4072 'moxie/file/File', 4073 'moxie/runtime/RuntimeClient', 4074 'moxie/core/EventTarget', 4075 'moxie/core/utils/Mime' 4076 ], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) { 4077 /** 4078 Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used 4079 in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through 4080 _XMLHttpRequest_. 4081 4082 @example 4083 <div id="drop_zone"> 4084 Drop files here 4085 </div> 4086 <br /> 4087 <div id="filelist"></div> 4088 4089 <script type="text/javascript"> 4090 var fileDrop = new moxie.file.FileDrop('drop_zone'), fileList = moxie.utils.Dom.get('filelist'); 4091 4092 fileDrop.ondrop = function() { 4093 moxie.utils.Basic.each(this.files, function(file) { 4094 fileList.innerHTML += '<div>' + file.name + '</div>'; 4095 }); 4096 }; 4097 4098 fileDrop.init(); 4099 </script> 4100 4101 @class moxie/file/FileDrop 4102 @constructor 4103 @extends EventTarget 4104 @uses RuntimeClient 4105 @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone 4106 @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone 4107 @param {Array} [options.accept] Array of mime types to accept. By default accepts all 4108 @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support 4109 */ 4110 var dispatches = [ 4111 /** 4112 Dispatched when runtime is connected and drop zone is ready to accept files. 4113 4114 @event ready 4115 @param {Object} event 4116 */ 4117 'ready', 4118 4119 /** 4120 Dispatched when dragging cursor enters the drop zone. 4121 4122 @event dragenter 4123 @param {Object} event 4124 */ 4125 'dragenter', 4126 4127 /** 4128 Dispatched when dragging cursor leaves the drop zone. 4129 4130 @event dragleave 4131 @param {Object} event 4132 */ 4133 'dragleave', 4134 4135 /** 4136 Dispatched when file is dropped onto the drop zone. 4137 4138 @event drop 4139 @param {Object} event 4140 */ 4141 'drop', 4142 4143 /** 4144 Dispatched if error occurs. 4145 4146 @event error 4147 @param {Object} event 4148 */ 4149 'error' 4150 ]; 4151 4152 function FileDrop(options) { 4153 if (MXI_DEBUG) { 4154 Env.log("Instantiating FileDrop..."); 4155 } 4156 4157 var self = this, defaults; 4158 4159 // if flat argument passed it should be drop_zone id 4160 if (typeof(options) === 'string') { 4161 options = { drop_zone : options }; 4162 } 4163 4164 // figure out the options 4165 defaults = { 4166 accept: [{ 4167 title: I18n.translate('All Files'), 4168 extensions: '*' 4169 }], 4170 required_caps: { 4171 drag_and_drop: true 4172 } 4173 }; 4174 4175 options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults; 4176 4177 // this will help us to find proper default container 4178 options.container = Dom.get(options.drop_zone) || document.body; 4179 4180 // make container relative, if it is not 4181 if (Dom.getStyle(options.container, 'position') === 'static') { 4182 options.container.style.position = 'relative'; 4183 } 4184 4185 // normalize accept option (could be list of mime types or array of title/extensions pairs) 4186 if (typeof(options.accept) === 'string') { 4187 options.accept = Mime.mimes2extList(options.accept); 4188 } 4189 4190 RuntimeClient.call(self); 4191 4192 Basic.extend(self, { 4193 uid: Basic.guid('uid_'), 4194 4195 ruid: null, 4196 4197 files: null, 4198 4199 init: function() { 4200 self.bind('RuntimeInit', function(e, runtime) { 4201 self.ruid = runtime.uid; 4202 runtime.exec.call(self, 'FileDrop', 'init', options); 4203 self.dispatchEvent('ready'); 4204 }); 4205 4206 // runtime needs: options.required_features, options.runtime_order and options.container 4207 self.connectRuntime(options); // throws RuntimeError 4208 }, 4209 4210 destroy: function() { 4211 var runtime = this.getRuntime(); 4212 if (runtime) { 4213 runtime.exec.call(this, 'FileDrop', 'destroy'); 4214 this.disconnectRuntime(); 4215 } 4216 this.files = null; 4217 4218 this.unbindAll(); 4219 } 4220 }); 4221 4222 this.handleEventProps(dispatches); 4223 } 4224 4225 FileDrop.prototype = EventTarget.instance; 4226 4227 return FileDrop; 4228 }); 4229 4230 // Included from: src/javascript/file/FileReader.js 4231 4232 /** 4233 * FileReader.js 4234 * 4235 * Copyright 2013, Moxiecode Systems AB 4236 * Released under GPL License. 4237 * 4238 * License: http://www.plupload.com/license 4239 * Contributing: http://www.plupload.com/contributing 4240 */ 4241 4242 define('moxie/file/FileReader', [ 4243 'moxie/core/utils/Basic', 4244 'moxie/core/utils/Encode', 4245 'moxie/core/Exceptions', 4246 'moxie/core/EventTarget', 4247 'moxie/file/Blob', 4248 'moxie/runtime/RuntimeClient' 4249 ], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) { 4250 /** 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) 4252 interface. Where possible uses native FileReader, where - not falls back to shims. 4253 4254 @class moxie/file/FileReader 4255 @constructor FileReader 4256 @extends EventTarget 4257 @uses RuntimeClient 4258 */ 4259 var dispatches = [ 4260 4261 /** 4262 Dispatched when the read starts. 4263 4264 @event loadstart 4265 @param {Object} event 4266 */ 4267 'loadstart', 4268 4269 /** 4270 Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total). 4271 4272 @event progress 4273 @param {Object} event 4274 */ 4275 'progress', 4276 4277 /** 4278 Dispatched when the read has successfully completed. 4279 4280 @event load 4281 @param {Object} event 4282 */ 4283 'load', 4284 4285 /** 4286 Dispatched when the read has been aborted. For instance, by invoking the abort() method. 4287 4288 @event abort 4289 @param {Object} event 4290 */ 4291 'abort', 4292 4293 /** 4294 Dispatched when the read has failed. 4295 4296 @event error 4297 @param {Object} event 4298 */ 4299 'error', 4300 4301 /** 4302 Dispatched when the request has completed (either in success or failure). 4303 4304 @event loadend 4305 @param {Object} event 4306 */ 4307 'loadend' 4308 ]; 4309 4310 function FileReader() { 4311 4312 RuntimeClient.call(this); 4313 4314 Basic.extend(this, { 4315 /** 4316 UID of the component instance. 4317 4318 @property uid 4319 @type {String} 4320 */ 4321 uid: Basic.guid('uid_'), 4322 4323 /** 4324 Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING 4325 and FileReader.DONE. 4326 4327 @property readyState 4328 @type {Number} 4329 @default FileReader.EMPTY 4330 */ 4331 readyState: FileReader.EMPTY, 4332 4333 /** 4334 Result of the successful read operation. 4335 4336 @property result 4337 @type {String} 4338 */ 4339 result: null, 4340 4341 /** 4342 Stores the error of failed asynchronous read operation. 4343 4344 @property error 4345 @type {DOMError} 4346 */ 4347 error: null, 4348 4349 /** 4350 Initiates reading of File/Blob object contents to binary string. 4351 4352 @method readAsBinaryString 4353 @param {Blob|File} blob Object to preload 4354 */ 4355 readAsBinaryString: function(blob) { 4356 _read.call(this, 'readAsBinaryString', blob); 4357 }, 4358 4359 /** 4360 Initiates reading of File/Blob object contents to dataURL string. 4361 4362 @method readAsDataURL 4363 @param {Blob|File} blob Object to preload 4364 */ 4365 readAsDataURL: function(blob) { 4366 _read.call(this, 'readAsDataURL', blob); 4367 }, 4368 4369 /** 4370 Initiates reading of File/Blob object contents to string. 4371 4372 @method readAsText 4373 @param {Blob|File} blob Object to preload 4374 */ 4375 readAsText: function(blob) { 4376 _read.call(this, 'readAsText', blob); 4377 }, 4378 4379 /** 4380 Aborts preloading process. 4381 4382 @method abort 4383 */ 4384 abort: function() { 4385 this.result = null; 4386 4387 if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) { 4388 return; 4389 } else if (this.readyState === FileReader.LOADING) { 4390 this.readyState = FileReader.DONE; 4391 } 4392 4393 this.exec('FileReader', 'abort'); 4394 4395 this.trigger('abort'); 4396 this.trigger('loadend'); 4397 }, 4398 4399 /** 4400 Destroy component and release resources. 4401 4402 @method destroy 4403 */ 4404 destroy: function() { 4405 this.abort(); 4406 this.exec('FileReader', 'destroy'); 4407 this.disconnectRuntime(); 4408 this.unbindAll(); 4409 } 4410 }); 4411 4412 // uid must already be assigned 4413 this.handleEventProps(dispatches); 4414 4415 this.bind('Error', function(e, err) { 4416 this.readyState = FileReader.DONE; 4417 this.error = err; 4418 }, 999); 4419 4420 this.bind('Load', function(e) { 4421 this.readyState = FileReader.DONE; 4422 }, 999); 4423 4424 4425 function _read(op, blob) { 4426 var self = this; 4427 4428 this.trigger('loadstart'); 4429 4430 if (this.readyState === FileReader.LOADING) { 4431 this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR)); 4432 this.trigger('loadend'); 4433 return; 4434 } 4435 4436 // if source is not o.Blob/o.File 4437 if (!(blob instanceof Blob)) { 4438 this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR)); 4439 this.trigger('loadend'); 4440 return; 4441 } 4442 4443 this.result = null; 4444 this.readyState = FileReader.LOADING; 4445 4446 if (blob.isDetached()) { 4447 var src = blob.getSource(); 4448 switch (op) { 4449 case 'readAsText': 4450 case 'readAsBinaryString': 4451 this.result = src; 4452 break; 4453 case 'readAsDataURL': 4454 this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src); 4455 break; 4456 } 4457 this.readyState = FileReader.DONE; 4458 this.trigger('load'); 4459 this.trigger('loadend'); 4460 } else { 4461 this.connectRuntime(blob.ruid); 4462 this.exec('FileReader', 'read', op, blob); 4463 } 4464 } 4465 } 4466 4467 /** 4468 Initial FileReader state 4469 4470 @property EMPTY 4471 @type {Number} 4472 @final 4473 @static 4474 @default 0 4475 */ 4476 FileReader.EMPTY = 0; 2709 4477 2710 // Included from: src/javascript/runtime/RuntimeClient.js 4478 /** 4479 FileReader switches to this state when it is preloading the source 2711 4480 2712 /** 2713 * RuntimeClient.js 2714 * 2715 * Copyright 2013, Moxiecode Systems AB 2716 * Released under GPL License. 2717 * 2718 * License: http://www.plupload.com/license 2719 * Contributing: http://www.plupload.com/contributing 2720 */ 4481 @property LOADING 4482 @type {Number} 4483 @final 4484 @static 4485 @default 1 4486 */ 4487 FileReader.LOADING = 1; 2721 4488 2722 define('moxie/runtime/RuntimeClient', [ 2723 'moxie/core/utils/Env', 2724 'moxie/core/Exceptions', 2725 'moxie/core/utils/Basic', 2726 'moxie/runtime/Runtime' 2727 ], function(Env, x, Basic, Runtime) { 2728 /** 2729 Set of methods and properties, required by a component to acquire ability to connect to a runtime 4489 /** 4490 Preloading is complete, this is a final state 4491 4492 @property DONE 4493 @type {Number} 4494 @final 4495 @static 4496 @default 2 4497 */ 4498 FileReader.DONE = 2; 4499 4500 FileReader.prototype = EventTarget.instance; 4501 4502 return FileReader; 4503 }); 2730 4504 2731 @class RuntimeClient 2732 */ 2733 return function RuntimeClient() { 2734 var runtime; 4505 // Included from: src/javascript/core/utils/Url.js 4506 4507 /** 4508 * Url.js 4509 * 4510 * Copyright 2013, Moxiecode Systems AB 4511 * Released under GPL License. 4512 * 4513 * License: http://www.plupload.com/license 4514 * Contributing: http://www.plupload.com/contributing 4515 */ 4516 4517 /** 4518 @class moxie/core/utils/Url 4519 @public 4520 @static 4521 */ 2735 4522 2736 Basic.extend(this, { 4523 define('moxie/core/utils/Url', [ 4524 'moxie/core/utils/Basic' 4525 ], function(Basic) { 2737 4526 /** 2738 Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one.2739 Increments number of clients connected to the specified runtime.4527 Parse url into separate components and fill in absent parts with parts from current url, 4528 based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js 2740 4529 2741 @private 2742 @method connectRuntime 2743 @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites 2744 */ 2745 connectRuntime: function(options) { 2746 var comp = this, ruid; 2747 2748 function initialize(items) { 2749 var type, constructor; 2750 2751 // if we ran out of runtimes 2752 if (!items.length) { 2753 comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); 2754 runtime = null; 2755 return; 2756 } 4530 @method parseUrl 4531 @static 4532 @param {String} url Url to parse (defaults to empty string if undefined) 4533 @return {Object} Hash containing extracted uri components 4534 */ 4535 var parseUrl = function(url, currentUrl) { 4536 var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'] 4537 , i = key.length 4538 , ports = { 4539 http: 80, 4540 https: 443 4541 } 4542 , uri = {} 4543 , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/ 4544 , m = regex.exec(url || '') 4545 , isRelative 4546 , isSchemeLess = /^\/\/\w/.test(url) 4547 ; 2757 4548 2758 type = items.shift().toLowerCase(); 2759 constructor = Runtime.getConstructor(type); 2760 if (!constructor) { 2761 initialize(items); 2762 return; 2763 } 4549 switch (Basic.typeOf(currentUrl)) { 4550 case 'undefined': 4551 currentUrl = parseUrl(document.location.href, false); 4552 break; 2764 4553 2765 if (MXI_DEBUG && Env.debug.runtime) { 2766 Env.log("Trying runtime: %s", type); 2767 Env.log(options); 4554 case 'string': 4555 currentUrl = parseUrl(currentUrl, false); 4556 break; 4557 } 4558 4559 while (i--) { 4560 if (m[i]) { 4561 uri[key[i]] = m[i]; 2768 4562 } 4563 } 2769 4564 2770 // try initializing the runtime 2771 runtime = new constructor(options); 4565 isRelative = !isSchemeLess && !uri.scheme; 2772 4566 2773 runtime.bind('Init', function() {2774 // mark runtime as initialized2775 runtime.initialized = true;4567 if (isSchemeLess || isRelative) { 4568 uri.scheme = currentUrl.scheme; 4569 } 2776 4570 2777 if (MXI_DEBUG && Env.debug.runtime) { 2778 Env.log("Runtime '%s' initialized", runtime.type); 4571 // when url is relative, we set the origin and the path ourselves 4572 if (isRelative) { 4573 uri.host = currentUrl.host; 4574 uri.port = currentUrl.port; 4575 4576 var path = ''; 4577 // for urls without trailing slash we need to figure out the path 4578 if (/^[^\/]/.test(uri.path)) { 4579 path = currentUrl.path; 4580 // if path ends with a filename, strip it 4581 if (/\/[^\/]*\.[^\/]*$/.test(path)) { 4582 path = path.replace(/\/[^\/]+$/, '/'); 4583 } else { 4584 // avoid double slash at the end (see #127) 4585 path = path.replace(/\/?$/, '/'); 2779 4586 } 4587 } 4588 uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir 4589 } 2780 4590 2781 // jailbreak ... 2782 setTimeout(function() { 2783 runtime.clients++; 2784 // this will be triggered on component 2785 comp.trigger('RuntimeInit', runtime); 2786 }, 1); 2787 }); 4591 if (!uri.port) { 4592 uri.port = ports[uri.scheme] || 80; 4593 } 2788 4594 2789 runtime.bind('Error', function() { 2790 if (MXI_DEBUG && Env.debug.runtime) { 2791 Env.log("Runtime '%s' failed to initialize", runtime.type); 2792 } 4595 uri.port = parseInt(uri.port, 10); 2793 4596 2794 runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here2795 initialize(items);2796 });4597 if (!uri.path) { 4598 uri.path = "/"; 4599 } 2797 4600 2798 /*runtime.bind('Exception', function() { });*/4601 delete uri.source; 2799 4602 2800 if (MXI_DEBUG && Env.debug.runtime) { 2801 Env.log("\tselected mode: %s", runtime.mode); 2802 } 4603 return uri; 4604 }; 2803 4605 2804 // check if runtime managed to pick-up operational mode 2805 if (!runtime.mode) { 2806 runtime.trigger('Error'); 2807 return; 2808 } 4606 /** 4607 Resolve url - among other things will turn relative url to absolute 2809 4608 2810 runtime.init(); 4609 @method resolveUrl 4610 @static 4611 @param {String|Object} url Either absolute or relative, or a result of parseUrl call 4612 @return {String} Resolved, absolute url 4613 */ 4614 var resolveUrl = function(url) { 4615 var ports = { // we ignore default ports 4616 http: 80, 4617 https: 443 2811 4618 } 4619 , urlp = typeof(url) === 'object' ? url : parseUrl(url); 4620 ; 4621 4622 return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : ''); 4623 }; 4624 4625 /** 4626 Check if specified url has the same origin as the current document 2812 4627 2813 // check if a particular runtime was requested 2814 if (Basic.typeOf(options) === 'string') { 2815 ruid = options; 2816 } else if (Basic.typeOf(options.ruid) === 'string') { 2817 ruid = options.ruid; 4628 @method hasSameOrigin 4629 @static 4630 @param {String|Object} url 4631 @return {Boolean} 4632 */ 4633 var hasSameOrigin = function(url) { 4634 function origin(url) { 4635 return [url.scheme, url.host, url.port].join('/'); 2818 4636 } 2819 4637 2820 if (ruid) { 2821 runtime = Runtime.getRuntime(ruid); 2822 if (runtime) { 2823 runtime.clients++; 2824 return runtime; 2825 } else { 2826 // there should be a runtime and there's none - weird case 2827 throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR); 2828 } 4638 if (typeof url === 'string') { 4639 url = parseUrl(url); 2829 4640 } 2830 4641 2831 // initialize a fresh one, that fits runtime list and required features best 2832 initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/)); 2833 }, 4642 return origin(parseUrl()) === origin(url); 4643 }; 4644 4645 return { 4646 parseUrl: parseUrl, 4647 resolveUrl: resolveUrl, 4648 hasSameOrigin: hasSameOrigin 4649 }; 4650 }); 4651 4652 // Included from: src/javascript/runtime/RuntimeTarget.js 2834 4653 4654 /** 4655 * RuntimeTarget.js 4656 * 4657 * Copyright 2013, Moxiecode Systems AB 4658 * Released under GPL License. 4659 * 4660 * License: http://www.plupload.com/license 4661 * Contributing: http://www.plupload.com/contributing 4662 */ 2835 4663 4664 define('moxie/runtime/RuntimeTarget', [ 4665 'moxie/core/utils/Basic', 4666 'moxie/runtime/RuntimeClient', 4667 "moxie/core/EventTarget" 4668 ], function(Basic, RuntimeClient, EventTarget) { 2836 4669 /** 2837 Disconnects from the runtime. Decrements number of clients connected to the specified runtime. 4670 Instance of this class can be used as a target for the events dispatched by shims, 4671 when allowing them onto components is for either reason inappropriate 2838 4672 2839 @private2840 @method disconnectRuntime2841 */2842 disconnectRuntime: function() {2843 if (runtime && --runtime.clients <= 0) {2844 runtime.destroy();2845 }4673 @class moxie/runtime/RuntimeTarget 4674 @constructor 4675 @protected 4676 @extends EventTarget 4677 */ 4678 function RuntimeTarget() { 4679 this.uid = Basic.guid('uid_'); 2846 4680 2847 // once the component is disconnected, it shouldn't have access to the runtime 2848 runtime = null; 2849 }, 4681 RuntimeClient.call(this); 4682 4683 this.destroy = function() { 4684 this.disconnectRuntime(); 4685 this.unbindAll(); 4686 }; 4687 } 4688 4689 RuntimeTarget.prototype = EventTarget.instance; 4690 4691 return RuntimeTarget; 4692 }); 4693 4694 // Included from: src/javascript/file/FileReaderSync.js 2850 4695 4696 /** 4697 * FileReaderSync.js 4698 * 4699 * Copyright 2013, Moxiecode Systems AB 4700 * Released under GPL License. 4701 * 4702 * License: http://www.plupload.com/license 4703 * Contributing: http://www.plupload.com/contributing 4704 */ 2851 4705 4706 define('moxie/file/FileReaderSync', [ 4707 'moxie/core/utils/Basic', 4708 'moxie/runtime/RuntimeClient', 4709 'moxie/core/utils/Encode' 4710 ], function(Basic, RuntimeClient, Encode) { 2852 4711 /** 2853 Returns the runtime to which the client is currently connected. 4712 Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here 4713 it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be, 4714 but probably < 1mb). Not meant to be used directly by user. 2854 4715 2855 @method getRuntime 2856 @return {Runtime} Runtime or null if client is not connected 2857 */ 2858 getRuntime: function() { 2859 if (runtime && runtime.uid) { 2860 return runtime; 4716 @class moxie/file/FileReaderSync 4717 @private 4718 @constructor 4719 */ 4720 return function() { 4721 RuntimeClient.call(this); 4722 4723 Basic.extend(this, { 4724 uid: Basic.guid('uid_'), 4725 4726 readAsBinaryString: function(blob) { 4727 return _read.call(this, 'readAsBinaryString', blob); 4728 }, 4729 4730 readAsDataURL: function(blob) { 4731 return _read.call(this, 'readAsDataURL', blob); 4732 }, 4733 4734 /*readAsArrayBuffer: function(blob) { 4735 return _read.call(this, 'readAsArrayBuffer', blob); 4736 },*/ 4737 4738 readAsText: function(blob) { 4739 return _read.call(this, 'readAsText', blob); 4740 } 4741 }); 4742 4743 function _read(op, blob) { 4744 if (blob.isDetached()) { 4745 var src = blob.getSource(); 4746 switch (op) { 4747 case 'readAsBinaryString': 4748 return src; 4749 case 'readAsDataURL': 4750 return 'data:' + blob.type + ';base64,' + Encode.btoa(src); 4751 case 'readAsText': 4752 var txt = ''; 4753 for (var i = 0, length = src.length; i < length; i++) { 4754 txt += String.fromCharCode(src[i]); 4755 } 4756 return txt; 4757 } 4758 } else { 4759 var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob); 4760 this.disconnectRuntime(); 4761 return result; 4762 } 2861 4763 } 2862 return runtime = null; // make sure we do not leave zombies rambling around 2863 }, 4764 }; 4765 }); 4766 4767 // Included from: src/javascript/xhr/FormData.js 2864 4768 4769 /** 4770 * FormData.js 4771 * 4772 * Copyright 2013, Moxiecode Systems AB 4773 * Released under GPL License. 4774 * 4775 * License: http://www.plupload.com/license 4776 * Contributing: http://www.plupload.com/contributing 4777 */ 2865 4778 4779 define("moxie/xhr/FormData", [ 4780 "moxie/core/Exceptions", 4781 "moxie/core/utils/Basic", 4782 "moxie/file/Blob" 4783 ], function(x, Basic, Blob) { 2866 4784 /** 2867 Handy shortcut to safely invoke runtime extension methods. 2868 2869 @private 2870 @method exec 2871 @return {Mixed} Whatever runtime extension method returns 2872 */ 2873 exec: function() { 2874 if (runtime) { 2875 return runtime.exec.apply(this, arguments); 2876 } 2877 return null; 4785 FormData 4786 4787 @class moxie/xhr/FormData 4788 @constructor 4789 */ 4790 function FormData() { 4791 var _blob, _fields = []; 4792 4793 Basic.extend(this, { 4794 /** 4795 Append another key-value pair to the FormData object 4796 4797 @method append 4798 @param {String} name Name for the new field 4799 @param {String|Blob|Array|Object} value Value for the field 4800 */ 4801 append: function(name, value) { 4802 var self = this, valueType = Basic.typeOf(value); 4803 4804 // according to specs value might be either Blob or String 4805 if (value instanceof Blob) { 4806 _blob = { 4807 name: name, 4808 value: value // unfortunately we can only send single Blob in one FormData 4809 }; 4810 } else if ('array' === valueType) { 4811 name += '[]'; 4812 4813 Basic.each(value, function(value) { 4814 self.append(name, value); 4815 }); 4816 } else if ('object' === valueType) { 4817 Basic.each(value, function(value, key) { 4818 self.append(name + '[' + key + ']', value); 4819 }); 4820 } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) { 4821 self.append(name, "false"); 4822 } else { 4823 _fields.push({ 4824 name: name, 4825 value: value.toString() 4826 }); 4827 } 4828 }, 4829 4830 /** 4831 Checks if FormData contains Blob. 4832 4833 @method hasBlob 4834 @return {Boolean} 4835 */ 4836 hasBlob: function() { 4837 return !!this.getBlob(); 4838 }, 4839 4840 /** 4841 Retrieves blob. 4842 4843 @method getBlob 4844 @return {Object} Either Blob if found or null 4845 */ 4846 getBlob: function() { 4847 return _blob && _blob.value || null; 4848 }, 4849 4850 /** 4851 Retrieves blob field name. 4852 4853 @method getBlobName 4854 @return {String} Either Blob field name or null 4855 */ 4856 getBlobName: function() { 4857 return _blob && _blob.name || null; 4858 }, 4859 4860 /** 4861 Loop over the fields in FormData and invoke the callback for each of them. 4862 4863 @method each 4864 @param {Function} cb Callback to call for each field 4865 */ 4866 each: function(cb) { 4867 Basic.each(_fields, function(field) { 4868 cb(field.value, field.name); 4869 }); 4870 4871 if (_blob) { 4872 cb(_blob.value, _blob.name); 4873 } 4874 }, 4875 4876 destroy: function() { 4877 _blob = null; 4878 _fields = []; 4879 } 4880 }); 2878 4881 } 2879 4882 4883 return FormData; 2880 4884 }); 2881 };2882 4885 4886 // Included from: src/javascript/xhr/XMLHttpRequest.js 4887 4888 /** 4889 * XMLHttpRequest.js 4890 * 4891 * Copyright 2013, Moxiecode Systems AB 4892 * Released under GPL License. 4893 * 4894 * License: http://www.plupload.com/license 4895 * Contributing: http://www.plupload.com/contributing 4896 */ 2883 4897 2884 }); 4898 define("moxie/xhr/XMLHttpRequest", [ 4899 "moxie/core/utils/Basic", 4900 "moxie/core/Exceptions", 4901 "moxie/core/EventTarget", 4902 "moxie/core/utils/Encode", 4903 "moxie/core/utils/Url", 4904 "moxie/runtime/Runtime", 4905 "moxie/runtime/RuntimeTarget", 4906 "moxie/file/Blob", 4907 "moxie/file/FileReaderSync", 4908 "moxie/xhr/FormData", 4909 "moxie/core/utils/Env", 4910 "moxie/core/utils/Mime" 4911 ], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) { 4912 4913 var httpCode = { 4914 100: 'Continue', 4915 101: 'Switching Protocols', 4916 102: 'Processing', 4917 4918 200: 'OK', 4919 201: 'Created', 4920 202: 'Accepted', 4921 203: 'Non-Authoritative Information', 4922 204: 'No Content', 4923 205: 'Reset Content', 4924 206: 'Partial Content', 4925 207: 'Multi-Status', 4926 226: 'IM Used', 4927 4928 300: 'Multiple Choices', 4929 301: 'Moved Permanently', 4930 302: 'Found', 4931 303: 'See Other', 4932 304: 'Not Modified', 4933 305: 'Use Proxy', 4934 306: 'Reserved', 4935 307: 'Temporary Redirect', 4936 4937 400: 'Bad Request', 4938 401: 'Unauthorized', 4939 402: 'Payment Required', 4940 403: 'Forbidden', 4941 404: 'Not Found', 4942 405: 'Method Not Allowed', 4943 406: 'Not Acceptable', 4944 407: 'Proxy Authentication Required', 4945 408: 'Request Timeout', 4946 409: 'Conflict', 4947 410: 'Gone', 4948 411: 'Length Required', 4949 412: 'Precondition Failed', 4950 413: 'Request Entity Too Large', 4951 414: 'Request-URI Too Long', 4952 415: 'Unsupported Media Type', 4953 416: 'Requested Range Not Satisfiable', 4954 417: 'Expectation Failed', 4955 422: 'Unprocessable Entity', 4956 423: 'Locked', 4957 424: 'Failed Dependency', 4958 426: 'Upgrade Required', 4959 4960 500: 'Internal Server Error', 4961 501: 'Not Implemented', 4962 502: 'Bad Gateway', 4963 503: 'Service Unavailable', 4964 504: 'Gateway Timeout', 4965 505: 'HTTP Version Not Supported', 4966 506: 'Variant Also Negotiates', 4967 507: 'Insufficient Storage', 4968 510: 'Not Extended' 4969 }; 2885 4970 2886 // Included from: src/javascript/file/FileInput.js 4971 function XMLHttpRequestUpload() { 4972 this.uid = Basic.guid('uid_'); 4973 } 2887 4974 2888 /** 2889 * FileInput.js 2890 * 2891 * Copyright 2013, Moxiecode Systems AB 2892 * Released under GPL License. 2893 * 2894 * License: http://www.plupload.com/license 2895 * Contributing: http://www.plupload.com/contributing 2896 */ 4975 XMLHttpRequestUpload.prototype = EventTarget.instance; 2897 4976 2898 define('moxie/file/FileInput', [ 2899 'moxie/core/utils/Basic', 2900 'moxie/core/utils/Env', 2901 'moxie/core/utils/Mime', 2902 'moxie/core/utils/Dom', 2903 'moxie/core/Exceptions', 2904 'moxie/core/EventTarget', 2905 'moxie/core/I18n', 2906 'moxie/runtime/Runtime', 2907 'moxie/runtime/RuntimeClient' 2908 ], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) { 2909 /** 2910 Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click, 2911 converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory 2912 with _FileReader_ or uploaded to a server through _XMLHttpRequest_. 4977 /** 4978 Implementation of XMLHttpRequest 2913 4979 2914 @class FileInput4980 @class moxie/xhr/XMLHttpRequest 2915 4981 @constructor 2916 @extends EventTarget2917 4982 @uses RuntimeClient 2918 @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_. 2919 @param {String|DOMElement} options.browse_button DOM Element to turn into file picker. 2920 @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 @param {Boolean} [options.multiple=false] Enable selection of multiple files. 2923 @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 2925 for _browse\_button_. 2926 @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support. 4983 @extends EventTarget 4984 */ 4985 var dispatches = [ 4986 'loadstart', 4987 4988 'progress', 4989 4990 'abort', 4991 4992 'error', 4993 4994 'load', 2927 4995 2928 @example 2929 <div id="container"> 2930 <a id="file-picker" href="javascript:;">Browse...</a> 2931 </div> 4996 'timeout', 2932 4997 2933 <script> 2934 var fileInput = new mOxie.FileInput({ 2935 browse_button: 'file-picker', // or document.getElementById('file-picker') 2936 container: 'container', 2937 accept: [ 2938 {title: "Image files", extensions: "jpg,gif,png"} // accept only images 2939 ], 2940 multiple: true // allow multiple file selection 2941 }); 4998 'loadend' 2942 4999 2943 fileInput.onchange = function(e) { 2944 // do something to files array 2945 console.info(e.target.files); // or this.files or fileInput.files 2946 }; 5000 // readystatechange (for historical reasons) 5001 ]; 2947 5002 2948 fileInput.init(); // initialize 2949 </script> 2950 */ 2951 var dispatches = [ 2952 /** 2953 Dispatched when runtime is connected and file-picker is ready to be used. 5003 var NATIVE = 1, RUNTIME = 2; 2954 5004 2955 @event ready 2956 @param {Object} event 2957 */ 2958 'ready', 5005 function XMLHttpRequest() { 5006 var self = this, 5007 // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible 5008 props = { 5009 /** 5010 The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout. 2959 5011 2960 /** 2961 Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. 2962 Check [corresponding documentation entry](#method_refresh) for more info. 5012 @property timeout 5013 @type Number 5014 @default 0 5015 */ 5016 timeout: 0, 2963 5017 2964 @event refresh 2965 @param {Object} event 2966 */ 5018 /** 5019 Current state, can take following values: 5020 UNSENT (numeric value 0) 5021 The object has been constructed. 2967 5022 2968 /**2969 Dispatched when selection of files in the dialog is complete.5023 OPENED (numeric value 1) 5024 The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method. 2970 5025 2971 @event change 2972 @param {Object} event 2973 */ 2974 'change', 5026 HEADERS_RECEIVED (numeric value 2) 5027 All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available. 2975 5028 2976 'cancel', // TODO: might be useful 5029 LOADING (numeric value 3) 5030 The response entity body is being received. 2977 5031 2978 /** 2979 Dispatched when mouse cursor enters file-picker area. Can be used to style element 2980 accordingly. 5032 DONE (numeric value 4) 2981 5033 2982 @event mouseenter 2983 @param {Object} event 2984 */ 2985 'mouseenter', 5034 @property readyState 5035 @type Number 5036 @default 0 (UNSENT) 5037 */ 5038 readyState: XMLHttpRequest.UNSENT, 2986 5039 2987 /**2988 Dispatched when mouse cursor leaves file-picker area. Can be used to style element2989 accordingly.5040 /** 5041 True when user credentials are to be included in a cross-origin request. False when they are to be excluded 5042 in a cross-origin request and when cookies are to be ignored in its response. Initially false. 2990 5043 2991 @event mouseleave 2992 @param {Object} event 2993 */ 2994 'mouseleave', 5044 @property withCredentials 5045 @type Boolean 5046 @default false 5047 */ 5048 withCredentials: false, 2995 5049 2996 /**2997 Dispatched when functional mouse button is pressed on top of file-picker area.5050 /** 5051 Returns the HTTP status code. 2998 5052 2999 @event mousedown 3000 @param {Object} event 3001 */ 3002 'mousedown', 5053 @property status 5054 @type Number 5055 @default 0 5056 */ 5057 status: 0, 3003 5058 3004 /**3005 Dispatched when functional mouse button is released on top of file-picker area.5059 /** 5060 Returns the HTTP status text. 3006 5061 3007 @event mouseup 3008 @param {Object} event 3009 */ 3010 'mouseup' 3011 ]; 5062 @property statusText 5063 @type String 5064 */ 5065 statusText: "", 3012 5066 3013 function FileInput(options) { 3014 if (MXI_DEBUG) { 3015 Env.log("Instantiating FileInput..."); 3016 } 5067 /** 5068 Returns the response type. Can be set to change the response type. Values are: 5069 the empty string (default), "arraybuffer", "blob", "document", "json", and "text". 3017 5070 3018 var self = this, 3019 container, browseButton, defaults; 5071 @property responseType 5072 @type String 5073 */ 5074 responseType: "", 3020 5075 3021 // if flat argument passed it should be browse_button id 3022 if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) { 3023 options = { browse_button : options }; 3024 } 5076 /** 5077 Returns the document response entity body. 3025 5078 3026 // this will help us to find proper default container 3027 browseButton = Dom.get(options.browse_button); 3028 if (!browseButton) { 3029 // browse button is required 3030 throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); 3031 } 5079 Throws an "InvalidStateError" exception if responseType is not the empty string or "document". 3032 5080 3033 // figure out the options 3034 defaults = { 3035 accept: [{ 3036 title: I18n.translate('All Files'), 3037 extensions: '*' 3038 }], 3039 name: 'file', 3040 multiple: false, 3041 required_caps: false, 3042 container: browseButton.parentNode || document.body 3043 }; 3044 3045 options = Basic.extend({}, defaults, options); 3046 3047 // convert to object representation 3048 if (typeof(options.required_caps) === 'string') { 3049 options.required_caps = Runtime.parseCaps(options.required_caps); 3050 } 3051 3052 // normalize accept option (could be list of mime types or array of title/extensions pairs) 3053 if (typeof(options.accept) === 'string') { 3054 options.accept = Mime.mimes2extList(options.accept); 3055 } 5081 @property responseXML 5082 @type Document 5083 */ 5084 responseXML: null, 3056 5085 3057 container = Dom.get(options.container); 3058 // make sure we have container 3059 if (!container) { 3060 container = document.body; 3061 } 5086 /** 5087 Returns the text response entity body. 3062 5088 3063 // make container relative, if it's not 3064 if (Dom.getStyle(container, 'position') === 'static') { 3065 container.style.position = 'relative'; 3066 } 5089 Throws an "InvalidStateError" exception if responseType is not the empty string or "text". 3067 5090 3068 container = browseButton = null; // IE 3069 3070 RuntimeClient.call(self); 3071 3072 Basic.extend(self, { 3073 /** 5091 @property responseText 5092 @type String 5093 */ 5094 responseText: null, 5095 5096 /** 5097 Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body). 5098 Can become: ArrayBuffer, Blob, Document, JSON, Text 5099 5100 @property response 5101 @type Mixed 5102 */ 5103 response: null 5104 }, 5105 5106 _async = true, 5107 _url, 5108 _method, 5109 _headers = {}, 5110 _user, 5111 _password, 5112 _encoding = null, 5113 _mimeType = null, 5114 5115 // flags 5116 _sync_flag = false, 5117 _send_flag = false, 5118 _upload_events_flag = false, 5119 _upload_complete_flag = false, 5120 _error_flag = false, 5121 _same_origin_flag = false, 5122 5123 // times 5124 _start_time, 5125 _timeoutset_time, 5126 5127 _finalMime = null, 5128 _finalCharset = null, 5129 5130 _options = {}, 5131 _xhr, 5132 _responseHeaders = '', 5133 _responseHeadersBag 5134 ; 5135 5136 5137 Basic.extend(this, props, { 5138 /** 3074 5139 Unique id of the component 3075 5140 3076 5141 @property uid 3077 @protected 3078 @readOnly 3079 @type {String} 3080 @default UID 3081 */ 3082 uid: Basic.guid('uid_'), 3083 3084 /** 3085 Unique id of the connected runtime, if any. 5142 @type String 5143 */ 5144 uid: Basic.guid('uid_'), 3086 5145 3087 @property ruid 3088 @protected 3089 @type {String} 3090 */ 3091 ruid: null, 5146 /** 5147 Target for Upload events 3092 5148 3093 /** 3094 Unique id of the runtime container. Useful to get hold of it for various manipulations. 5149 @property upload 5150 @type XMLHttpRequestUpload 5151 */ 5152 upload: new XMLHttpRequestUpload(), 3095 5153 3096 @property shimid3097 @protected3098 @type {String}3099 */3100 shimid: null,3101 3102 /**3103 Array of selected mOxie.File objects3104 5154 3105 @property files 3106 @type {Array} 3107 @default null 3108 */ 3109 files: null, 5155 /** 5156 Sets the request method, request URL, synchronous flag, request username, and request password. 3110 5157 3111 /** 3112 Initializes the file-picker, connects it to runtime and dispatches event ready when done. 5158 Throws a "SyntaxError" exception if one of the following is true: 3113 5159 3114 @method init 3115 */ 3116 init: function() { 3117 self.bind('RuntimeInit', function(e, runtime) { 3118 self.ruid = runtime.uid; 3119 self.shimid = runtime.shimid; 5160 method is not a valid HTTP method. 5161 url cannot be resolved. 5162 url contains the "user:password" format in the userinfo production. 5163 Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK. 3120 5164 3121 self.bind("Ready", function() { 3122 self.trigger("Refresh"); 3123 }, 999); 5165 Throws an "InvalidAccessError" exception if one of the following is true: 3124 5166 3125 // re-position and resize shim container 3126 self.bind('Refresh', function() { 3127 var pos, size, browseButton, shimContainer; 3128 3129 browseButton = Dom.get(options.browse_button); 3130 shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist 5167 Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin. 5168 There is an associated XMLHttpRequest document and either the timeout attribute is not zero, 5169 the withCredentials attribute is true, or the responseType attribute is not the empty string. 3131 5170 3132 if (browseButton) {3133 pos = Dom.getPos(browseButton, Dom.get(options.container));3134 size = Dom.getSize(browseButton);3135 5171 3136 if (shimContainer) { 3137 Basic.extend(shimContainer.style, { 3138 top : pos.y + 'px', 3139 left : pos.x + 'px', 3140 width : size.w + 'px', 3141 height : size.h + 'px' 3142 }); 3143 } 5172 @method open 5173 @param {String} method HTTP method to use on request 5174 @param {String} url URL to request 5175 @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default. 5176 @param {String} [user] Username to use in HTTP authentication process on server-side 5177 @param {String} [password] Password to use in HTTP authentication process on server-side 5178 */ 5179 open: function(method, url, async, user, password) { 5180 var urlp; 5181 5182 // first two arguments are required 5183 if (!method || !url) { 5184 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 3144 5185 } 3145 shimContainer = browseButton = null;3146 });3147 3148 runtime.exec.call(self, 'FileInput', 'init', options);3149 });3150 5186 3151 // runtime needs: options.required_features, options.runtime_order and options.container 3152 self.connectRuntime(Basic.extend({}, options, { 3153 required_caps: { 3154 select_file: true 3155 } 3156 })); 3157 }, 5187 // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method 5188 if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) { 5189 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 5190 } 3158 5191 3159 /** 3160 Disables file-picker element, so that it doesn't react to mouse clicks. 5192 // 3 5193 if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) { 5194 _method = method.toUpperCase(); 5195 } 3161 5196 3162 @method disable3163 @param {Boolean} [state=true] Disable component if - true, enable if - false3164 */3165 disable: function(state) {3166 var runtime = this.getRuntime();3167 if (runtime) {3168 runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);3169 }3170 },3171 5197 5198 // 4 - allowing these methods poses a security risk 5199 if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) { 5200 throw new x.DOMException(x.DOMException.SECURITY_ERR); 5201 } 3172 5202 3173 /**3174 Reposition and resize dialog trigger to match the position and size of browse_button element.5203 // 5 5204 url = Encode.utf8_encode(url); 3175 5205 3176 @method refresh 3177 */ 3178 refresh: function() { 3179 self.trigger("Refresh"); 3180 }, 5206 // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError". 5207 urlp = Url.parseUrl(url); 3181 5208 5209 _same_origin_flag = Url.hasSameOrigin(urlp); 3182 5210 3183 /**3184 Destroy component.5211 // 7 - manually build up absolute url 5212 _url = Url.resolveUrl(url); 3185 5213 3186 @method destroy 3187 */ 3188 destroy: function() { 3189 var runtime = this.getRuntime(); 3190 if (runtime) { 3191 runtime.exec.call(this, 'FileInput', 'destroy'); 3192 this.disconnectRuntime(); 3193 } 5214 // 9-10, 12-13 5215 if ((user || password) && !_same_origin_flag) { 5216 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 5217 } 3194 5218 3195 if (Basic.typeOf(this.files) === 'array') { 3196 // no sense in leaving associated files behind 3197 Basic.each(this.files, function(file) { 3198 file.destroy(); 3199 }); 3200 } 3201 this.files = null; 5219 _user = user || urlp.user; 5220 _password = password || urlp.pass; 3202 5221 3203 this.unbindAll(); 3204 } 3205 }); 5222 // 11 5223 _async = async || true; 3206 5224 3207 this.handleEventProps(dispatches); 3208 } 5225 if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) { 5226 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 5227 } 3209 5228 3210 FileInput.prototype = EventTarget.instance;5229 // 14 - terminate abort() 3211 5230 3212 return FileInput; 3213 }); 5231 // 15 - terminate send() 3214 5232 3215 // Included from: src/javascript/core/utils/Encode.js 5233 // 18 5234 _sync_flag = !_async; 5235 _send_flag = false; 5236 _headers = {}; 5237 _reset.call(this); 3216 5238 3217 /** 3218 * Encode.js 3219 * 3220 * Copyright 2013, Moxiecode Systems AB 3221 * Released under GPL License. 3222 * 3223 * License: http://www.plupload.com/license 3224 * Contributing: http://www.plupload.com/contributing 3225 */ 5239 // 19 5240 _p('readyState', XMLHttpRequest.OPENED); 3226 5241 3227 define('moxie/core/utils/Encode', [], function() { 5242 // 20 5243 this.dispatchEvent('readystatechange'); 5244 }, 3228 5245 3229 /** 3230 Encode string with UTF-8 5246 /** 5247 Appends an header to the list of author request headers, or if header is already 5248 in the list of author request headers, combines its value with value. 3231 5249 3232 @method utf8_encode 3233 @for Utils 3234 @static 3235 @param {String} str String to encode 3236 @return {String} UTF-8 encoded string 3237 */ 3238 var utf8_encode = function(str) { 3239 return unescape(encodeURIComponent(str)); 3240 }; 3241 3242 /** 3243 Decode UTF-8 encoded string 5250 Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. 5251 Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value 5252 is not a valid HTTP header field value. 3244 5253 3245 @method utf8_decode 3246 @static 3247 @param {String} str String to decode 3248 @return {String} Decoded string 3249 */ 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.js 5254 @method setRequestHeader 5255 @param {String} header 5256 @param {String|Number} value 5257 */ 5258 setRequestHeader: function(header, value) { 5259 var uaHeaders = [ // these headers are controlled by the user agent 5260 "accept-charset", 5261 "accept-encoding", 5262 "access-control-request-headers", 5263 "access-control-request-method", 5264 "connection", 5265 "content-length", 5266 "cookie", 5267 "cookie2", 5268 "content-transfer-encoding", 5269 "date", 5270 "expect", 5271 "host", 5272 "keep-alive", 5273 "origin", 5274 "referer", 5275 "te", 5276 "trailer", 5277 "transfer-encoding", 5278 "upgrade", 5279 "user-agent", 5280 "via" 5281 ]; 5282 5283 // 1-2 5284 if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) { 5285 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5286 } 3257 5287 3258 @method atob 3259 @static 3260 @param {String} data String to decode 3261 @return {String} Decoded string 3262 */ 3263 var atob = function(data, utf8) { 3264 if (typeof(window.atob) === 'function') { 3265 return utf8 ? utf8_decode(window.atob(data)) : window.atob(data); 3266 } 5288 // 3 5289 if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) { 5290 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 5291 } 3267 5292 3268 // http://kevin.vanzonneveld.net 3269 // + original by: Tyler Akins (http://rumkin.com) 3270 // + improved by: Thunder.m 3271 // + input by: Aman Gupta 3272 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 3273 // + bugfixed by: Onno Marsman 3274 // + bugfixed by: Pellentesque Malesuada 3275 // + 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 native 3281 // - 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 = []; 5293 // 4 5294 /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values 5295 if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) { 5296 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 5297 }*/ 3290 5298 3291 if (!data) { 3292 return data; 3293 } 5299 header = Basic.trim(header).toLowerCase(); 3294 5300 3295 data += ''; 5301 // setting of proxy-* and sec-* headers is prohibited by spec 5302 if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) { 5303 return false; 5304 } 3296 5305 3297 do { // unpack four hexets into three octets using index points in b64 3298 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++)); 5306 // camelize 5307 // browsers lowercase header names (at least for custom ones) 5308 // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); }); 3302 5309 3303 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; 5310 if (!_headers[header]) { 5311 _headers[header] = value; 5312 } else { 5313 // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph) 5314 _headers[header] += ', ' + value; 5315 } 5316 return true; 5317 }, 3304 5318 3305 o1 = bits >> 16 & 0xff; 3306 o2 = bits >> 8 & 0xff; 3307 o3 = bits & 0xff; 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 }, 3308 5330 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); 5331 /** 5332 Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2. 3317 5333 3318 dec = tmp_arr.join(''); 5334 @method getAllResponseHeaders 5335 @return {String} reponse headers or empty string 5336 */ 5337 getAllResponseHeaders: function() { 5338 return _responseHeaders || ''; 5339 }, 3319 5340 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.js 5341 /** 5342 Returns the header field value from the response of which the field name matches header, 5343 unless the field name is Set-Cookie or Set-Cookie2. 3326 5344 3327 @method btoa 3328 @static 3329 @param {String} data String to encode 3330 @return {String} Base64 encoded string 3331 */ 3332 var btoa = function(data, utf8) { 3333 if (utf8) { 3334 data = utf8_encode(data); 3335 } 5345 @method getResponseHeader 5346 @param {String} header 5347 @return {String} value(s) for the specified header or null 5348 */ 5349 getResponseHeader: function(header) { 5350 header = header.toLowerCase(); 3336 5351 3337 if (typeof(window.btoa) === 'function') {3338 return window.btoa(data);3339 }5352 if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) { 5353 return null; 5354 } 3340 5355 3341 // http://kevin.vanzonneveld.net 3342 // + original by: Tyler Akins (http://rumkin.com) 3343 // + improved by: Bayron Guevara 3344 // + improved by: Thunder.m 3345 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 3346 // + bugfixed by: Pellentesque Malesuada 3347 // + 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 native 3352 // - 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 = []; 5356 if (_responseHeaders && _responseHeaders !== '') { 5357 // if we didn't parse response headers until now, do it and keep for later 5358 if (!_responseHeadersBag) { 5359 _responseHeadersBag = {}; 5360 Basic.each(_responseHeaders.split(/\r\n/), function(line) { 5361 var pair = line.split(/:\s+/); 5362 if (pair.length === 2) { // last line might be empty, omit 5363 pair[0] = Basic.trim(pair[0]); // just in case 5364 _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form 5365 header: pair[0], 5366 value: Basic.trim(pair[1]) 5367 }; 5368 } 5369 }); 5370 } 5371 if (_responseHeadersBag.hasOwnProperty(header)) { 5372 return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value; 5373 } 5374 } 5375 return null; 5376 }, 3358 5377 3359 if (!data) { 3360 return data; 3361 } 5378 /** 5379 Sets the Content-Type header for the response to mime. 5380 Throws an "InvalidStateError" exception if the state is LOADING or DONE. 5381 Throws a "SyntaxError" exception if mime is not a valid media type. 3362 5382 3363 do { // pack three octets into four hexets 3364 o1 = data.charCodeAt(i++); 3365 o2 = data.charCodeAt(i++); 3366 o3 = data.charCodeAt(i++); 5383 @method overrideMimeType 5384 @param String mime Mime type to set 5385 */ 5386 overrideMimeType: function(mime) { 5387 var matches, charset; 5388 5389 // 1 5390 if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { 5391 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5392 } 3367 5393 3368 bits = o1 << 16 | o2 << 8 | o3; 5394 // 2 5395 mime = Basic.trim(mime.toLowerCase()); 3369 5396 3370 h1 = bits >> 18 & 0x3f; 3371 h2 = bits >> 12 & 0x3f; 3372 h3 = bits >> 6 & 0x3f; 3373 h4 = bits & 0x3f; 5397 if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) { 5398 mime = matches[1]; 5399 if (matches[2]) { 5400 charset = matches[2]; 5401 } 5402 } 3374 5403 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);5404 if (!Mime.mimes[mime]) { 5405 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 5406 } 3378 5407 3379 enc = tmp_arr.join(''); 5408 // 3-4 5409 _finalMime = mime; 5410 _finalCharset = charset; 5411 }, 3380 5412 3381 var r = data.length % 3; 5413 /** 5414 Initiates the request. The optional argument provides the request entity body. 5415 The argument is ignored if request method is GET or HEAD. 3382 5416 3383 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); 3384 }; 5417 Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. 3385 5418 5419 @method send 5420 @param {Blob|Document|String|FormData} [data] Request entity body 5421 @param {Object} [options] Set of requirements and pre-requisities for runtime initialization 5422 */ 5423 send: function(data, options) { 5424 if (Basic.typeOf(options) === 'string') { 5425 _options = { ruid: options }; 5426 } else if (!options) { 5427 _options = {}; 5428 } else { 5429 _options = options; 5430 } 3386 5431 3387 return { 3388 utf8_encode: utf8_encode, 3389 utf8_decode: utf8_decode, 3390 atob: atob, 3391 btoa: btoa 3392 }; 3393 }); 5432 // 1-2 5433 if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) { 5434 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5435 } 3394 5436 3395 // Included from: src/javascript/file/Blob.js 5437 // 3 5438 // sending Blob 5439 if (data instanceof Blob) { 5440 _options.ruid = data.ruid; 5441 _mimeType = data.type || 'application/octet-stream'; 5442 } 3396 5443 3397 /** 3398 * Blob.js 3399 * 3400 * Copyright 2013, Moxiecode Systems AB 3401 * Released under GPL License. 3402 * 3403 * License: http://www.plupload.com/license 3404 * Contributing: http://www.plupload.com/contributing 3405 */ 5444 // FormData 5445 else if (data instanceof FormData) { 5446 if (data.hasBlob()) { 5447 var blob = data.getBlob(); 5448 _options.ruid = blob.ruid; 5449 _mimeType = blob.type || 'application/octet-stream'; 5450 } 5451 } 3406 5452 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 = {}; 5453 // DOMString 5454 else if (typeof data === 'string') { 5455 _encoding = 'UTF-8'; 5456 _mimeType = 'text/plain;charset=UTF-8'; 3414 5457 3415 /** 3416 @class Blob 3417 @constructor 3418 @param {String} ruid Unique id of the runtime, to which this blob belongs to 3419 @param {Object} blob Object "Native" blob object, as it is represented in the runtime 3420 */ 3421 function Blob(ruid, blob) { 5458 // data should be converted to Unicode and encoded as UTF-8 5459 data = Encode.utf8_encode(data); 5460 } 3422 5461 3423 function _sliceDetached(start, end, type) { 3424 var blob, data = blobpool[this.uid]; 5462 // if withCredentials not set, but requested, set it automatically 5463 if (!this.withCredentials) { 5464 this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag; 5465 } 3425 5466 3426 if (Basic.typeOf(data) !== 'string' || !data.length) { 3427 return null; // or throw exception 3428 } 5467 // 4 - storage mutex 5468 // 5 5469 _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP 5470 // 6 5471 _error_flag = false; 5472 // 7 5473 _upload_complete_flag = !data; 5474 // 8 - Asynchronous steps 5475 if (!_sync_flag) { 5476 // 8.1 5477 _send_flag = true; 5478 // 8.2 5479 // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr 5480 // 8.3 5481 //if (!_upload_complete_flag) { 5482 // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr 5483 //} 5484 } 5485 // 8.5 - Return the send() method call, but continue running the steps in this algorithm. 5486 _doXHR.call(this, data); 5487 }, 3429 5488 3430 blob = new Blob(null, { 3431 type: type, 3432 size: end - start 3433 }); 3434 blob.detach(data.substr(start, blob.size)); 5489 /** 5490 Cancels any network activity. 3435 5491 3436 return blob; 3437 } 5492 @method abort 5493 */ 5494 abort: function() { 5495 _error_flag = true; 5496 _sync_flag = false; 3438 5497 3439 RuntimeClient.call(this); 5498 if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) { 5499 _p('readyState', XMLHttpRequest.DONE); 5500 _send_flag = false; 3440 5501 3441 if (ruid) { 3442 this.connectRuntime(ruid); 3443 } 5502 if (_xhr) { 5503 _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag); 5504 } else { 5505 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5506 } 3444 5507 3445 if (!blob) {3446 blob = {};3447 } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string3448 blob = { data: blob };3449 }5508 _upload_complete_flag = true; 5509 } else { 5510 _p('readyState', XMLHttpRequest.UNSENT); 5511 } 5512 }, 3450 5513 3451 Basic.extend(this, { 3452 3453 /** 3454 Unique id of the component 5514 destroy: function() { 5515 if (_xhr) { 5516 if (Basic.typeOf(_xhr.destroy) === 'function') { 5517 _xhr.destroy(); 5518 } 5519 _xhr = null; 5520 } 3455 5521 3456 @property uid 3457 @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 initialized 3463 before this Blob can be used, modified or sent 5522 this.unbindAll(); 3464 5523 3465 @property ruid 3466 @type {String} 3467 */ 3468 ruid: ruid, 3469 3470 /** 3471 Size of blob 5524 if (this.upload) { 5525 this.upload.unbindAll(); 5526 this.upload = null; 5527 } 5528 } 5529 }); 3472 5530 3473 @property size 3474 @type {Number} 3475 @default 0 3476 */ 3477 size: blob.size || 0, 3478 3479 /** 3480 Mime type of blob 5531 this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons 5532 this.upload.handleEventProps(dispatches); 3481 5533 3482 @property type 3483 @type {String} 3484 @default '' 3485 */ 3486 type: blob.type || '', 3487 3488 /** 3489 @method slice 3490 @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 }, 5534 /* this is nice, but maybe too lengthy 3498 5535 3499 /** 3500 Returns "native" blob object (as it is represented in connected runtime) or null if not found 5536 // if supported by JS version, set getters/setters for specific properties 5537 o.defineProperty(this, 'readyState', { 5538 configurable: false, 3501 5539 3502 @method getSource 3503 @return {Blob} Returns "native" blob object or null if not found 3504 */ 3505 getSource: function() { 3506 if (!blobpool[this.uid]) { 3507 return null; 3508 } 3509 return blobpool[this.uid]; 3510 }, 5540 get: function() { 5541 return _p('readyState'); 5542 } 5543 }); 3511 5544 3512 /**3513 Detaches blob from any runtime that it depends on and initialize with standalone value5545 o.defineProperty(this, 'timeout', { 5546 configurable: false, 3514 5547 3515 @method detach 3516 @protected 3517 @param {DOMString} [data=''] Standalone value 3518 */ 3519 detach: function(data) { 3520 if (this.ruid) { 3521 this.getRuntime().exec.call(this, 'Blob', 'destroy'); 3522 this.disconnectRuntime(); 3523 this.ruid = null; 3524 } 5548 get: function() { 5549 return _p('timeout'); 5550 }, 3525 5551 3526 data = data || '';5552 set: function(value) { 3527 5553 3528 // if dataUrl, convert to binary string 3529 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)); 5554 if (_sync_flag) { 5555 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 3533 5556 } 3534 5557 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 isDetached 3544 @protected 3545 @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 using 5558 // timeout still should be measured relative to the start time of request 5559 _timeoutset_time = (new Date).getTime(); 3553 5560 3554 @method destroy 3555 */ 3556 destroy: function() { 3557 this.detach(); 3558 delete blobpool[this.uid]; 5561 _p('timeout', value); 3559 5562 } 3560 5563 }); 3561 5564 3562 3563 if (blob.data) { 3564 this.detach(blob.data); // auto-detach if payload has been passed 3565 } else { 3566 blobpool[this.uid] = blob; 3567 } 3568 } 3569 3570 return Blob; 3571 }); 3572 3573 // Included from: src/javascript/file/File.js 3574 3575 /** 3576 * File.js 3577 * 3578 * Copyright 2013, Moxiecode Systems AB 3579 * Released under GPL License. 3580 * 3581 * License: http://www.plupload.com/license 3582 * Contributing: http://www.plupload.com/contributing 3583 */ 5565 // the withCredentials attribute has no effect when fetching same-origin resources 5566 o.defineProperty(this, 'withCredentials', { 5567 configurable: false, 3584 5568 3585 define('moxie/file/File', [ 3586 'moxie/core/utils/Basic', 3587 'moxie/core/utils/Mime', 3588 'moxie/file/Blob' 3589 ], function(Basic, Mime, Blob) { 3590 /** 3591 @class File 3592 @extends Blob 3593 @constructor 3594 @param {String} ruid Unique id of the runtime, to which this blob belongs to 3595 @param {Object} file Object "Native" file object, as it is represented in the runtime 3596 */ 3597 function File(ruid, file) { 3598 if (!file) { // avoid extra errors in case we overlooked something 3599 file = {}; 3600 } 5569 get: function() { 5570 return _p('withCredentials'); 5571 }, 3601 5572 3602 Blob.apply(this, arguments); 5573 set: function(value) { 5574 // 1-2 5575 if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) { 5576 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5577 } 3603 5578 3604 if (!this.type) { 3605 this.type = Mime.getFileMime(file.name); 3606 } 5579 // 3-4 5580 if (_anonymous_flag || _sync_flag) { 5581 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 5582 } 3607 5583 3608 // sanitize file name or generate new one 3609 var name; 3610 if (file.name) { 3611 name = file.name.replace(/\\/g, '/'); 3612 name = name.substr(name.lastIndexOf('/') + 1); 3613 } else if (this.type) { 3614 var prefix = this.type.split('/')[0]; 3615 name = Basic.guid((prefix !== '' ? prefix : 'file') + '_'); 3616 3617 if (Mime.extensions[this.type]) { 3618 name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible 5584 // 5 5585 _p('withCredentials', value); 3619 5586 } 3620 } 3621 3622 3623 Basic.extend(this, { 3624 /** 3625 File name 3626 3627 @property name 3628 @type {String} 3629 @default UID 3630 */ 3631 name: name || Basic.guid('file_'), 3632 3633 /** 3634 Relative path to the file inside a directory 5587 }); 3635 5588 3636 @property relativePath 3637 @type {String} 3638 @default '' 3639 */ 3640 relativePath: '', 3641 3642 /** 3643 Date of last modification 5589 o.defineProperty(this, 'status', { 5590 configurable: false, 3644 5591 3645 @property lastModifiedDate 3646 @type {String} 3647 @default now 3648 */ 3649 lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) 5592 get: function() { 5593 return _p('status'); 5594 } 3650 5595 }); 3651 }3652 5596 3653 File.prototype = Blob.prototype; 3654 3655 return File; 3656 }); 5597 o.defineProperty(this, 'statusText', { 5598 configurable: false, 3657 5599 3658 // Included from: src/javascript/file/FileDrop.js 5600 get: function() { 5601 return _p('statusText'); 5602 } 5603 }); 3659 5604 3660 /** 3661 * FileDrop.js 3662 * 3663 * Copyright 2013, Moxiecode Systems AB 3664 * Released under GPL License. 3665 * 3666 * License: http://www.plupload.com/license 3667 * Contributing: http://www.plupload.com/contributing 3668 */ 5605 o.defineProperty(this, 'responseType', { 5606 configurable: false, 3669 5607 3670 define('moxie/file/FileDrop', [ 3671 'moxie/core/I18n', 3672 'moxie/core/utils/Dom', 3673 'moxie/core/Exceptions', 3674 'moxie/core/utils/Basic', 3675 'moxie/core/utils/Env', 3676 'moxie/file/File', 3677 'moxie/runtime/RuntimeClient', 3678 'moxie/core/EventTarget', 3679 'moxie/core/utils/Mime' 3680 ], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) { 3681 /** 3682 Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used 3683 in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through 3684 _XMLHttpRequest_. 5608 get: function() { 5609 return _p('responseType'); 5610 }, 3685 5611 3686 @example 3687 <div id="drop_zone"> 3688 Drop files here 3689 </div> 3690 <br /> 3691 <div id="filelist"></div> 5612 set: function(value) { 5613 // 1 5614 if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { 5615 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5616 } 3692 5617 3693 <script type="text/javascript"> 3694 var fileDrop = new mOxie.FileDrop('drop_zone'), fileList = mOxie.get('filelist'); 5618 // 2 5619 if (_sync_flag) { 5620 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 5621 } 3695 5622 3696 fileDrop.ondrop = function() { 3697 mOxie.each(this.files, function(file) { 3698 fileList.innerHTML += '<div>' + file.name + '</div>'; 3699 }); 3700 }; 5623 // 3 5624 _p('responseType', value.toLowerCase()); 5625 } 5626 }); 3701 5627 3702 fileDrop.init();3703 </script>5628 o.defineProperty(this, 'responseText', { 5629 configurable: false, 3704 5630 3705 @class FileDrop 3706 @constructor 3707 @extends EventTarget 3708 @uses RuntimeClient 3709 @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone 3710 @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone 3711 @param {Array} [options.accept] Array of mime types to accept. By default accepts all 3712 @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support 3713 */ 3714 var dispatches = [ 3715 /** 3716 Dispatched when runtime is connected and drop zone is ready to accept files. 5631 get: function() { 5632 // 1 5633 if (!~o.inArray(_p('responseType'), ['', 'text'])) { 5634 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5635 } 3717 5636 3718 @event ready3719 @param {Object} event3720 */3721 'ready',5637 // 2-3 5638 if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { 5639 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5640 } 3722 5641 3723 /** 3724 Dispatched when dragging cursor enters the drop zone. 5642 return _p('responseText'); 5643 } 5644 }); 3725 5645 3726 @event dragenter 3727 @param {Object} event 3728 */ 3729 'dragenter', 5646 o.defineProperty(this, 'responseXML', { 5647 configurable: false, 3730 5648 3731 /** 3732 Dispatched when dragging cursor leaves the drop zone. 5649 get: function() { 5650 // 1 5651 if (!~o.inArray(_p('responseType'), ['', 'document'])) { 5652 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5653 } 3733 5654 3734 @event dragleave3735 @param {Object} event3736 */3737 'dragleave',5655 // 2-3 5656 if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { 5657 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5658 } 3738 5659 3739 /** 3740 Dispatched when file is dropped onto the drop zone. 5660 return _p('responseXML'); 5661 } 5662 }); 3741 5663 3742 @event drop 3743 @param {Object} event 3744 */ 3745 'drop', 5664 o.defineProperty(this, 'response', { 5665 configurable: false, 3746 5666 3747 /** 3748 Dispatched if error occurs. 5667 get: function() { 5668 if (!!~o.inArray(_p('responseType'), ['', 'text'])) { 5669 if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { 5670 return ''; 5671 } 5672 } 5673 5674 if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { 5675 return null; 5676 } 5677 5678 return _p('response'); 5679 } 5680 }); 3749 5681 3750 @event error3751 @param {Object} event3752 5682 */ 3753 'error'3754 ];3755 5683 3756 function FileDrop(options) { 3757 if (MXI_DEBUG) { 3758 Env.log("Instantiating FileDrop..."); 5684 function _p(prop, value) { 5685 if (!props.hasOwnProperty(prop)) { 5686 return; 5687 } 5688 if (arguments.length === 1) { // get 5689 return Env.can('define_property') ? props[prop] : self[prop]; 5690 } else { // set 5691 if (Env.can('define_property')) { 5692 props[prop] = value; 5693 } else { 5694 self[prop] = value; 5695 } 5696 } 5697 } 5698 5699 /* 5700 function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) { 5701 // TODO: http://tools.ietf.org/html/rfc3490#section-4.1 5702 return str.toLowerCase(); 3759 5703 } 5704 */ 3760 5705 3761 var self = this, defaults;3762 5706 3763 // if flat argument passed it should be drop_zone id 3764 if (typeof(options) === 'string') { 3765 options = { drop_zone : options }; 3766 } 5707 function _doXHR(data) { 5708 var self = this; 3767 5709 3768 // figure out the options 3769 defaults = { 3770 accept: [{ 3771 title: I18n.translate('All Files'), 3772 extensions: '*' 3773 }], 3774 required_caps: { 3775 drag_and_drop: true 3776 } 3777 }; 3778 3779 options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults; 3780 3781 // this will help us to find proper default container 3782 options.container = Dom.get(options.drop_zone) || document.body; 3783 3784 // make container relative, if it is not 3785 if (Dom.getStyle(options.container, 'position') === 'static') { 3786 options.container.style.position = 'relative'; 3787 } 3788 3789 // normalize accept option (could be list of mime types or array of title/extensions pairs) 3790 if (typeof(options.accept) === 'string') { 3791 options.accept = Mime.mimes2extList(options.accept); 3792 } 5710 _start_time = new Date().getTime(); 3793 5711 3794 RuntimeClient.call(self);5712 _xhr = new RuntimeTarget(); 3795 5713 3796 Basic.extend(self, { 3797 uid: Basic.guid('uid_'), 5714 function loadEnd() { 5715 if (_xhr) { // it could have been destroyed by now 5716 _xhr.destroy(); 5717 _xhr = null; 5718 } 5719 self.dispatchEvent('loadend'); 5720 self = null; 5721 } 3798 5722 3799 ruid: null, 5723 function exec(runtime) { 5724 _xhr.bind('LoadStart', function(e) { 5725 _p('readyState', XMLHttpRequest.LOADING); 5726 self.dispatchEvent('readystatechange'); 3800 5727 3801 files: null,5728 self.dispatchEvent(e); 3802 5729 3803 init: function() { 3804 self.bind('RuntimeInit', function(e, runtime) { 3805 self.ruid = runtime.uid; 3806 runtime.exec.call(self, 'FileDrop', 'init', options); 3807 self.dispatchEvent('ready'); 3808 }); 3809 3810 // runtime needs: options.required_features, options.runtime_order and options.container 3811 self.connectRuntime(options); // throws RuntimeError 3812 }, 5730 if (_upload_events_flag) { 5731 self.upload.dispatchEvent(e); 5732 } 5733 }); 3813 5734 3814 destroy: function() { 3815 var runtime = this.getRuntime(); 3816 if (runtime) { 3817 runtime.exec.call(this, 'FileDrop', 'destroy'); 3818 this.disconnectRuntime(); 3819 } 3820 this.files = null; 3821 3822 this.unbindAll(); 3823 } 3824 }); 5735 _xhr.bind('Progress', function(e) { 5736 if (_p('readyState') !== XMLHttpRequest.LOADING) { 5737 _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example) 5738 self.dispatchEvent('readystatechange'); 5739 } 5740 self.dispatchEvent(e); 5741 }); 3825 5742 3826 this.handleEventProps(dispatches); 3827 } 5743 _xhr.bind('UploadProgress', function(e) { 5744 if (_upload_events_flag) { 5745 self.upload.dispatchEvent({ 5746 type: 'progress', 5747 lengthComputable: false, 5748 total: e.total, 5749 loaded: e.loaded 5750 }); 5751 } 5752 }); 3828 5753 3829 FileDrop.prototype = EventTarget.instance; 5754 _xhr.bind('Load', function(e) { 5755 _p('readyState', XMLHttpRequest.DONE); 5756 _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0)); 5757 _p('statusText', httpCode[_p('status')] || ""); 5758 5759 _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType'))); 5760 5761 if (!!~Basic.inArray(_p('responseType'), ['text', ''])) { 5762 _p('responseText', _p('response')); 5763 } else if (_p('responseType') === 'document') { 5764 _p('responseXML', _p('response')); 5765 } 3830 5766 3831 return FileDrop; 3832 }); 5767 _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders'); 3833 5768 3834 // Included from: src/javascript/file/FileReader.js 5769 self.dispatchEvent('readystatechange'); 3835 5770 3836 /** 3837 * FileReader.js 3838 * 3839 * Copyright 2013, Moxiecode Systems AB 3840 * Released under GPL License. 3841 * 3842 * License: http://www.plupload.com/license 3843 * Contributing: http://www.plupload.com/contributing 3844 */ 5771 if (_p('status') > 0) { // status 0 usually means that server is unreachable 5772 if (_upload_events_flag) { 5773 self.upload.dispatchEvent(e); 5774 } 5775 self.dispatchEvent(e); 5776 } else { 5777 _error_flag = true; 5778 self.dispatchEvent('error'); 5779 } 5780 loadEnd(); 5781 }); 3845 5782 3846 define('moxie/file/FileReader', [ 3847 'moxie/core/utils/Basic', 3848 'moxie/core/utils/Encode', 3849 'moxie/core/Exceptions', 3850 'moxie/core/EventTarget', 3851 'moxie/file/Blob', 3852 'moxie/runtime/RuntimeClient' 3853 ], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) { 3854 /** 3855 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 interface. Where possible uses native FileReader, where - not falls back to shims. 5783 _xhr.bind('Abort', function(e) { 5784 self.dispatchEvent(e); 5785 loadEnd(); 5786 }); 3857 5787 3858 @class FileReader 3859 @constructor FileReader 3860 @extends EventTarget 3861 @uses RuntimeClient 3862 */ 3863 var dispatches = [ 5788 _xhr.bind('Error', function(e) { 5789 _error_flag = true; 5790 _p('readyState', XMLHttpRequest.DONE); 5791 self.dispatchEvent('readystatechange'); 5792 _upload_complete_flag = true; 5793 self.dispatchEvent(e); 5794 loadEnd(); 5795 }); 3864 5796 3865 /** 3866 Dispatched when the read starts. 5797 runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', { 5798 url: _url, 5799 method: _method, 5800 async: _async, 5801 user: _user, 5802 password: _password, 5803 headers: _headers, 5804 mimeType: _mimeType, 5805 encoding: _encoding, 5806 responseType: self.responseType, 5807 withCredentials: self.withCredentials, 5808 options: _options 5809 }, data); 5810 } 5811 5812 // clarify our requirements 5813 if (typeof(_options.required_caps) === 'string') { 5814 _options.required_caps = Runtime.parseCaps(_options.required_caps); 5815 } 3867 5816 3868 @event loadstart 3869 @param {Object} event 3870 */ 3871 'loadstart', 5817 _options.required_caps = Basic.extend({}, _options.required_caps, { 5818 return_response_type: self.responseType 5819 }); 3872 5820 3873 /** 3874 Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total). 5821 if (data instanceof FormData) { 5822 _options.required_caps.send_multipart = true; 5823 } 3875 5824 3876 @event progress 3877 @param {Object} event 3878 */ 3879 'progress', 5825 if (!Basic.isEmptyObj(_headers)) { 5826 _options.required_caps.send_custom_headers = true; 5827 } 3880 5828 3881 /** 3882 Dispatched when the read has successfully completed. 5829 if (!_same_origin_flag) { 5830 _options.required_caps.do_cors = true; 5831 } 3883 5832 3884 @event load3885 @param {Object} event3886 */3887 'load',3888 5833 3889 /** 3890 Dispatched when the read has been aborted. For instance, by invoking the abort() method. 5834 if (_options.ruid) { // we do not need to wait if we can connect directly 5835 exec(_xhr.connectRuntime(_options)); 5836 } else { 5837 _xhr.bind('RuntimeInit', function(e, runtime) { 5838 exec(runtime); 5839 }); 5840 _xhr.bind('RuntimeError', function(e, err) { 5841 self.dispatchEvent('RuntimeError', err); 5842 }); 5843 _xhr.connectRuntime(_options); 5844 } 5845 } 3891 5846 3892 @event abort3893 @param {Object} event3894 */3895 'abort',3896 5847 3897 /** 3898 Dispatched when the read has failed. 5848 function _reset() { 5849 _p('responseText', ""); 5850 _p('responseXML', null); 5851 _p('response', null); 5852 _p('status', 0); 5853 _p('statusText', ""); 5854 _start_time = _timeoutset_time = null; 5855 } 5856 } 3899 5857 3900 @event error 3901 @param {Object} event 3902 */ 3903 'error', 5858 XMLHttpRequest.UNSENT = 0; 5859 XMLHttpRequest.OPENED = 1; 5860 XMLHttpRequest.HEADERS_RECEIVED = 2; 5861 XMLHttpRequest.LOADING = 3; 5862 XMLHttpRequest.DONE = 4; 3904 5863 3905 /** 3906 Dispatched when the request has completed (either in success or failure). 5864 XMLHttpRequest.prototype = EventTarget.instance; 3907 5865 3908 @event loadend 3909 @param {Object} event 3910 */ 3911 'loadend' 3912 ]; 3913 3914 function FileReader() { 5866 return XMLHttpRequest; 5867 }); 3915 5868 3916 RuntimeClient.call(this); 5869 // Included from: src/javascript/runtime/Transporter.js 3917 5870 3918 Basic.extend(this, { 3919 /** 3920 UID of the component instance. 5871 /** 5872 * Transporter.js 5873 * 5874 * Copyright 2013, Moxiecode Systems AB 5875 * Released under GPL License. 5876 * 5877 * License: http://www.plupload.com/license 5878 * Contributing: http://www.plupload.com/contributing 5879 */ 3921 5880 3922 @property uid 3923 @type {String} 3924 */ 3925 uid: Basic.guid('uid_'), 5881 define("moxie/runtime/Transporter", [ 5882 "moxie/core/utils/Basic", 5883 "moxie/core/utils/Encode", 5884 "moxie/runtime/RuntimeClient", 5885 "moxie/core/EventTarget" 5886 ], function(Basic, Encode, RuntimeClient, EventTarget) { 3926 5887 3927 5888 /** 3928 Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING 3929 and FileReader.DONE. 5889 @class moxie/runtime/Transporter 5890 @private 5891 @constructor 5892 */ 5893 function Transporter() { 5894 var mod, _runtime, _data, _size, _pos, _chunk_size; 3930 5895 3931 @property readyState 3932 @type {Number} 3933 @default FileReader.EMPTY 3934 */ 3935 readyState: FileReader.EMPTY, 3936 3937 /** 3938 Result of the successful read operation. 5896 RuntimeClient.call(this); 3939 5897 3940 @property result 3941 @type {String} 3942 */ 3943 result: null, 3944 3945 /** 3946 Stores the error of failed asynchronous read operation. 5898 Basic.extend(this, { 5899 uid: Basic.guid('uid_'), 3947 5900 3948 @property error 3949 @type {DOMError} 3950 */ 3951 error: null, 3952 3953 /** 3954 Initiates reading of File/Blob object contents to binary string. 5901 state: Transporter.IDLE, 3955 5902 3956 @method readAsBinaryString 3957 @param {Blob|File} blob Object to preload 3958 */ 3959 readAsBinaryString: function(blob) { 3960 _read.call(this, 'readAsBinaryString', blob); 3961 }, 3962 3963 /** 3964 Initiates reading of File/Blob object contents to dataURL string. 5903 result: null, 3965 5904 3966 @method readAsDataURL 3967 @param {Blob|File} blob Object to preload 3968 */ 3969 readAsDataURL: function(blob) { 3970 _read.call(this, 'readAsDataURL', blob); 3971 }, 3972 3973 /** 3974 Initiates reading of File/Blob object contents to string. 5905 transport: function(data, type, options) { 5906 var self = this; 3975 5907 3976 @method readAsText 3977 @param {Blob|File} blob Object to preload 3978 */ 3979 readAsText: function(blob) { 3980 _read.call(this, 'readAsText', blob); 3981 }, 3982 3983 /** 3984 Aborts preloading process. 5908 options = Basic.extend({ 5909 chunk_size: 204798 5910 }, options); 3985 5911 3986 @method abort 3987 */ 3988 abort: function() { 3989 this.result = null; 3990 3991 if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) { 3992 return; 3993 } else if (this.readyState === FileReader.LOADING) { 3994 this.readyState = FileReader.DONE; 3995 } 5912 // should divide by three, base64 requires this 5913 if ((mod = options.chunk_size % 3)) { 5914 options.chunk_size += 3 - mod; 5915 } 3996 5916 3997 this.exec('FileReader', 'abort'); 3998 3999 this.trigger('abort'); 4000 this.trigger('loadend'); 4001 }, 5917 _chunk_size = options.chunk_size; 4002 5918 4003 /** 4004 Destroy component and release resources. 5919 _reset.call(this); 5920 _data = data; 5921 _size = data.length; 4005 5922 4006 @method destroy 4007 */ 4008 destroy: function() { 4009 this.abort(); 4010 this.exec('FileReader', 'destroy'); 4011 this.disconnectRuntime(); 4012 this.unbindAll(); 4013 } 4014 }); 5923 if (Basic.typeOf(options) === 'string' || options.ruid) { 5924 _run.call(self, type, this.connectRuntime(options)); 5925 } else { 5926 // we require this to run only once 5927 var cb = function(e, runtime) { 5928 self.unbind("RuntimeInit", cb); 5929 _run.call(self, type, runtime); 5930 }; 5931 this.bind("RuntimeInit", cb); 5932 this.connectRuntime(options); 5933 } 5934 }, 4015 5935 4016 // uid must already be assigned 4017 this.handleEventProps(dispatches); 4018 4019 this.bind('Error', function(e, err) { 4020 this.readyState = FileReader.DONE; 4021 this.error = err; 4022 }, 999); 4023 4024 this.bind('Load', function(e) { 4025 this.readyState = FileReader.DONE; 4026 }, 999); 4027 4028 4029 function _read(op, blob) { 4030 var self = this; 4031 4032 this.trigger('loadstart'); 4033 4034 if (this.readyState === FileReader.LOADING) { 4035 this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR)); 4036 this.trigger('loadend'); 4037 return; 4038 } 4039 4040 // if source is not o.Blob/o.File 4041 if (!(blob instanceof Blob)) { 4042 this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR)); 4043 this.trigger('loadend'); 4044 return; 4045 } 4046 4047 this.result = null; 4048 this.readyState = FileReader.LOADING; 4049 4050 if (blob.isDetached()) { 4051 var src = blob.getSource(); 4052 switch (op) { 4053 case 'readAsText': 4054 case 'readAsBinaryString': 4055 this.result = src; 4056 break; 4057 case 'readAsDataURL': 4058 this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src); 4059 break; 4060 } 4061 this.readyState = FileReader.DONE; 4062 this.trigger('load'); 4063 this.trigger('loadend'); 4064 } else { 4065 this.connectRuntime(blob.ruid); 4066 this.exec('FileReader', 'read', op, blob); 4067 } 4068 } 4069 } 4070 4071 /** 4072 Initial FileReader state 5936 abort: function() { 5937 var self = this; 4073 5938 4074 @property EMPTY 4075 @type {Number} 4076 @final 4077 @static 4078 @default 0 4079 */ 4080 FileReader.EMPTY = 0; 5939 self.state = Transporter.IDLE; 5940 if (_runtime) { 5941 _runtime.exec.call(self, 'Transporter', 'clear'); 5942 self.trigger("TransportingAborted"); 5943 } 4081 5944 4082 /**4083 FileReader switches to this state when it is preloading the source5945 _reset.call(self); 5946 }, 4084 5947 4085 @property LOADING4086 @type {Number}4087 @final4088 @static4089 @default 14090 */4091 FileReader.LOADING = 1;4092 5948 4093 /** 4094 Preloading is complete, this is a final state 5949 destroy: function() { 5950 this.unbindAll(); 5951 _runtime = null; 5952 this.disconnectRuntime(); 5953 _reset.call(this); 5954 } 5955 }); 4095 5956 4096 @property DONE 4097 @type {Number} 4098 @final 4099 @static 4100 @default 2 4101 */ 4102 FileReader.DONE = 2; 5957 function _reset() { 5958 _size = _pos = 0; 5959 _data = this.result = null; 5960 } 4103 5961 4104 FileReader.prototype = EventTarget.instance; 5962 function _run(type, runtime) { 5963 var self = this; 4105 5964 4106 return FileReader; 4107 }); 5965 _runtime = runtime; 4108 5966 4109 // Included from: src/javascript/core/utils/Url.js 5967 //self.unbind("RuntimeInit"); 4110 5968 4111 /** 4112 * Url.js 4113 * 4114 * Copyright 2013, Moxiecode Systems AB 4115 * Released under GPL License. 4116 * 4117 * License: http://www.plupload.com/license 4118 * Contributing: http://www.plupload.com/contributing 4119 */ 5969 self.bind("TransportingProgress", function(e) { 5970 _pos = e.loaded; 5971 5972 if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) { 5973 _transport.call(self); 5974 } 5975 }, 999); 4120 5976 4121 define('moxie/core/utils/Url', [], function() { 4122 /** 4123 Parse url into separate components and fill in absent parts with parts from current url, 4124 based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js 5977 self.bind("TransportingComplete", function() { 5978 _pos = _size; 5979 self.state = Transporter.DONE; 5980 _data = null; // clean a bit 5981 self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || ''); 5982 }, 999); 4125 5983 4126 @method parseUrl 4127 @for Utils 4128 @static 4129 @param {String} url Url to parse (defaults to empty string if undefined) 4130 @return {Object} Hash containing extracted uri components 4131 */ 4132 var parseUrl = function(url, currentUrl) { 4133 var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'] 4134 , i = key.length 4135 , ports = { 4136 http: 80, 4137 https: 443 4138 } 4139 , uri = {} 4140 , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/ 4141 , m = regex.exec(url || '') 4142 ; 4143 4144 while (i--) { 4145 if (m[i]) { 4146 uri[key[i]] = m[i]; 4147 } 4148 } 5984 self.state = Transporter.BUSY; 5985 self.trigger("TransportingStarted"); 5986 _transport.call(self); 5987 } 4149 5988 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 } 4156 4157 uri.scheme = currentUrl.scheme; 4158 uri.host = currentUrl.host; 4159 uri.port = currentUrl.port; 4160 4161 var path = ''; 4162 // for urls without trailing slash we need to figure out the path 4163 if (/^[^\/]/.test(uri.path)) { 4164 path = currentUrl.path; 4165 // if path ends with a filename, strip it 4166 if (/\/[^\/]*\.[^\/]*$/.test(path)) { 4167 path = path.replace(/\/[^\/]+$/, '/'); 4168 } else { 4169 // avoid double slash at the end (see #127) 4170 path = path.replace(/\/?$/, '/'); 5989 function _transport() { 5990 var self = this, 5991 chunk, 5992 bytesLeft = _size - _pos; 5993 5994 if (_chunk_size > bytesLeft) { 5995 _chunk_size = bytesLeft; 5996 } 5997 5998 chunk = Encode.btoa(_data.substr(_pos, _chunk_size)); 5999 _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size); 4171 6000 } 4172 6001 } 4173 uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir4174 }4175 6002 4176 if (!uri.port) { 4177 uri.port = ports[uri.scheme] || 80; 4178 } 4179 4180 uri.port = parseInt(uri.port, 10); 6003 Transporter.IDLE = 0; 6004 Transporter.BUSY = 1; 6005 Transporter.DONE = 2; 4181 6006 4182 if (!uri.path) { 4183 uri.path = "/"; 4184 } 6007 Transporter.prototype = EventTarget.instance; 4185 6008 4186 delete uri.source; 6009 return Transporter; 6010 }); 4187 6011 4188 return uri; 4189 }; 6012 // Included from: src/javascript/image/Image.js 4190 6013 4191 /** 4192 Resolve url - among other things will turn relative url to absolute 6014 /** 6015 * Image.js 6016 * 6017 * Copyright 2013, Moxiecode Systems AB 6018 * Released under GPL License. 6019 * 6020 * License: http://www.plupload.com/license 6021 * Contributing: http://www.plupload.com/contributing 6022 */ 4193 6023 4194 @method resolveUrl 4195 @static 4196 @param {String|Object} url Either absolute or relative, or a result of parseUrl call 4197 @return {String} Resolved, absolute url 4198 */ 4199 var resolveUrl = function(url) { 4200 var ports = { // we ignore default ports 4201 http: 80, 4202 https: 443 4203 } 4204 , urlp = typeof(url) === 'object' ? url : parseUrl(url); 4205 ; 6024 define("moxie/image/Image", [ 6025 "moxie/core/utils/Basic", 6026 "moxie/core/utils/Dom", 6027 "moxie/core/Exceptions", 6028 "moxie/file/FileReaderSync", 6029 "moxie/xhr/XMLHttpRequest", 6030 "moxie/runtime/Runtime", 6031 "moxie/runtime/RuntimeClient", 6032 "moxie/runtime/Transporter", 6033 "moxie/core/utils/Env", 6034 "moxie/core/EventTarget", 6035 "moxie/file/Blob", 6036 "moxie/file/File", 6037 "moxie/core/utils/Encode" 6038 ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) { 6039 /** 6040 Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data. 4206 6041 4207 return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : ''); 4208 }; 6042 @class moxie/image/Image 6043 @constructor 6044 @extends EventTarget 6045 */ 6046 var dispatches = [ 6047 'progress', 4209 6048 4210 /**4211 Check if specified url has the same origin as the current document6049 /** 6050 Dispatched when loading is complete. 4212 6051 4213 @method hasSameOrigin 4214 @param {String|Object} url 4215 @return {Boolean} 4216 */ 4217 var hasSameOrigin = function(url) { 4218 function origin(url) { 4219 return [url.scheme, url.host, url.port].join('/'); 4220 } 4221 4222 if (typeof url === 'string') { 4223 url = parseUrl(url); 4224 } 4225 4226 return origin(parseUrl()) === origin(url); 4227 }; 6052 @event load 6053 @param {Object} event 6054 */ 6055 'load', 4228 6056 4229 return { 4230 parseUrl: parseUrl, 4231 resolveUrl: resolveUrl, 4232 hasSameOrigin: hasSameOrigin 4233 }; 4234 }); 6057 'error', 4235 6058 4236 // Included from: src/javascript/runtime/RuntimeTarget.js 6059 /** 6060 Dispatched when resize operation is complete. 4237 6061 4238 /** 4239 * RuntimeTarget.js 4240 * 4241 * Copyright 2013, Moxiecode Systems AB 4242 * Released under GPL License. 4243 * 4244 * License: http://www.plupload.com/license 4245 * Contributing: http://www.plupload.com/contributing 4246 */ 6062 @event resize 6063 @param {Object} event 6064 */ 6065 'resize', 4247 6066 4248 define('moxie/runtime/RuntimeTarget', [ 4249 'moxie/core/utils/Basic', 4250 'moxie/runtime/RuntimeClient', 4251 "moxie/core/EventTarget" 4252 ], function(Basic, RuntimeClient, EventTarget) { 4253 /** 4254 Instance of this class can be used as a target for the events dispatched by shims, 4255 when allowing them onto components is for either reason inappropriate 6067 /** 6068 Dispatched when visual representation of the image is successfully embedded 6069 into the corresponsing container. 4256 6070 4257 @class RuntimeTarget 4258 @constructor 4259 @protected 4260 @extends EventTarget 4261 */ 4262 function RuntimeTarget() { 4263 this.uid = Basic.guid('uid_'); 4264 4265 RuntimeClient.call(this); 4266 4267 this.destroy = function() { 4268 this.disconnectRuntime(); 4269 this.unbindAll(); 4270 }; 4271 } 6071 @event embedded 6072 @param {Object} event 6073 */ 6074 'embedded' 6075 ]; 4272 6076 4273 RuntimeTarget.prototype = EventTarget.instance;6077 function Image() { 4274 6078 4275 return RuntimeTarget; 4276 }); 6079 RuntimeClient.call(this); 4277 6080 4278 // Included from: src/javascript/file/FileReaderSync.js 6081 Basic.extend(this, { 6082 /** 6083 Unique id of the component 4279 6084 4280 /** 4281 * FileReaderSync.js 4282 * 4283 * Copyright 2013, Moxiecode Systems AB 4284 * Released under GPL License. 4285 * 4286 * License: http://www.plupload.com/license 4287 * Contributing: http://www.plupload.com/contributing 4288 */ 6085 @property uid 6086 @type {String} 6087 */ 6088 uid: Basic.guid('uid_'), 4289 6089 4290 define('moxie/file/FileReaderSync', [ 4291 'moxie/core/utils/Basic', 4292 'moxie/runtime/RuntimeClient', 4293 'moxie/core/utils/Encode' 4294 ], function(Basic, RuntimeClient, Encode) { 4295 /** 4296 Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here 4297 it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be, 4298 but probably < 1mb). Not meant to be used directly by user. 6090 /** 6091 Unique id of the connected runtime, if any. 4299 6092 4300 @class FileReaderSync 4301 @private 4302 @constructor 4303 */ 4304 return function() { 4305 RuntimeClient.call(this); 6093 @property ruid 6094 @type {String} 6095 */ 6096 ruid: null, 4306 6097 4307 Basic.extend(this, {4308 uid: Basic.guid('uid_'),6098 /** 6099 Name of the file, that was used to create an image, if available. If not equals to empty string. 4309 6100 4310 readAsBinaryString: function(blob) { 4311 return _read.call(this, 'readAsBinaryString', blob); 4312 }, 4313 4314 readAsDataURL: function(blob) { 4315 return _read.call(this, 'readAsDataURL', blob); 4316 }, 4317 4318 /*readAsArrayBuffer: function(blob) { 4319 return _read.call(this, 'readAsArrayBuffer', blob); 4320 },*/ 4321 4322 readAsText: function(blob) { 4323 return _read.call(this, 'readAsText', blob); 4324 } 4325 }); 6101 @property name 6102 @type {String} 6103 @default "" 6104 */ 6105 name: "", 4326 6106 4327 function _read(op, blob) { 4328 if (blob.isDetached()) { 4329 var src = blob.getSource(); 4330 switch (op) { 4331 case 'readAsBinaryString': 4332 return src; 4333 case 'readAsDataURL': 4334 return 'data:' + blob.type + ';base64,' + Encode.btoa(src); 4335 case 'readAsText': 4336 var txt = ''; 4337 for (var i = 0, length = src.length; i < length; i++) { 4338 txt += String.fromCharCode(src[i]); 4339 } 4340 return txt; 4341 } 4342 } else { 4343 var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob); 4344 this.disconnectRuntime(); 4345 return result; 4346 } 4347 } 4348 }; 4349 }); 6107 /** 6108 Size of the image in bytes. Actual value is set only after image is preloaded. 4350 6109 4351 // Included from: src/javascript/xhr/FormData.js 6110 @property size 6111 @type {Number} 6112 @default 0 6113 */ 6114 size: 0, 4352 6115 4353 /** 4354 * FormData.js 4355 * 4356 * Copyright 2013, Moxiecode Systems AB 4357 * Released under GPL License. 4358 * 4359 * License: http://www.plupload.com/license 4360 * Contributing: http://www.plupload.com/contributing 4361 */ 6116 /** 6117 Width of the image. Actual value is set only after image is preloaded. 4362 6118 4363 define("moxie/xhr/FormData", [ 4364 "moxie/core/Exceptions", 4365 "moxie/core/utils/Basic", 4366 "moxie/file/Blob" 4367 ], function(x, Basic, Blob) { 4368 /** 4369 FormData 6119 @property width 6120 @type {Number} 6121 @default 0 6122 */ 6123 width: 0, 4370 6124 4371 @class FormData 4372 @constructor 4373 */ 4374 function FormData() { 4375 var _blob, _fields = []; 6125 /** 6126 Height of the image. Actual value is set only after image is preloaded. 4376 6127 4377 Basic.extend(this, { 4378 /** 4379 Append another key-value pair to the FormData object 6128 @property height 6129 @type {Number} 6130 @default 0 6131 */ 6132 height: 0, 4380 6133 4381 @method append 4382 @param {String} name Name for the new field 4383 @param {String|Blob|Array|Object} value Value for the field 4384 */ 4385 append: function(name, value) { 4386 var self = this, valueType = Basic.typeOf(value); 4387 4388 // according to specs value might be either Blob or String 4389 if (value instanceof Blob) { 4390 _blob = { 4391 name: name, 4392 value: value // unfortunately we can only send single Blob in one FormData 4393 }; 4394 } else if ('array' === valueType) { 4395 name += '[]'; 6134 /** 6135 Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded. 4396 6136 4397 Basic.each(value, function(value) { 4398 self.append(name, value); 4399 }); 4400 } else if ('object' === valueType) { 4401 Basic.each(value, function(value, key) { 4402 self.append(name + '[' + key + ']', value); 4403 }); 4404 } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) { 4405 self.append(name, "false"); 4406 } else { 4407 _fields.push({ 4408 name: name, 4409 value: value.toString() 4410 }); 4411 } 4412 }, 6137 @property type 6138 @type {String} 6139 @default "" 6140 */ 6141 type: "", 4413 6142 4414 /**4415 Checks if FormData contains Blob.6143 /** 6144 Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded. 4416 6145 4417 @method hasBlob 4418 @return {Boolean} 4419 */ 4420 hasBlob: function() { 4421 return !!this.getBlob(); 4422 }, 6146 @property meta 6147 @type {Object} 6148 @default {} 6149 */ 6150 meta: {}, 4423 6151 4424 /**4425 Retrieves blob.6152 /** 6153 Alias for load method, that takes another moxie.image.Image object as a source (see load). 4426 6154 4427 @method getBlob 4428 @return {Object} Either Blob if found or null 4429 */ 4430 getBlob: function() { 4431 return _blob && _blob.value || null; 4432 }, 6155 @method clone 6156 @param {Image} src Source for the image 6157 @param {Boolean} [exact=false] Whether to activate in-depth clone mode 6158 */ 6159 clone: function() { 6160 this.load.apply(this, arguments); 6161 }, 6162 6163 /** 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. 4433 6168 4434 /** 4435 Retrieves blob field name. 6169 @example 6170 var img = new moxie.image.Image(); 6171 img.onload = function() { 6172 var blob = img.getAsBlob(); 4436 6173 4437 @method getBlobName 4438 @return {String} Either Blob field name or null 4439 */ 4440 getBlobName: function() { 4441 return _blob && _blob.name || null; 4442 }, 6174 var formData = new moxie.xhr.FormData(); 6175 formData.append('file', blob); 4443 6176 4444 /** 4445 Loop over the fields in FormData and invoke the callback for each of them. 6177 var xhr = new moxie.xhr.XMLHttpRequest(); 6178 xhr.onload = function() { 6179 // upload complete 6180 }; 6181 xhr.open('post', 'upload.php'); 6182 xhr.send(formData); 6183 }; 6184 img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg) 4446 6185 4447 @method each4448 @param {Function} cb Callback to call for each field4449 */4450 each: function(cb) {4451 Basic.each(_fields, function(field) {4452 cb(field.value, field.name);4453 });4454 6186 4455 if (_blob) { 4456 cb(_blob.value, _blob.name); 4457 } 4458 }, 6187 @method load 6188 @param {Image|Blob|File|String} src Source for the image 6189 @param {Boolean|Object} [mixed] 6190 */ 6191 load: function() { 6192 _load.apply(this, arguments); 6193 }, 6194 6195 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); 4459 6236 4460 destroy: function() { 4461 _blob = null; 4462 _fields = []; 4463 } 4464 }); 4465 } 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 } 4466 6241 4467 return FormData; 4468 }); 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 } 4469 6246 4470 // Included from: src/javascript/xhr/XMLHttpRequest.js 6247 // take into account orientation tag 6248 orientation = (self.meta && self.meta.tiff && self.meta.tiff.Orientation) || 1; 4471 6249 4472 /** 4473 * XMLHttpRequest.js 4474 * 4475 * Copyright 2013, Moxiecode Systems AB 4476 * Released under GPL License. 4477 * 4478 * License: http://www.plupload.com/license 4479 * Contributing: http://www.plupload.com/contributing 4480 */ 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 } 4481 6255 4482 define("moxie/xhr/XMLHttpRequest", [ 4483 "moxie/core/utils/Basic", 4484 "moxie/core/Exceptions", 4485 "moxie/core/EventTarget", 4486 "moxie/core/utils/Encode", 4487 "moxie/core/utils/Url", 4488 "moxie/runtime/Runtime", 4489 "moxie/runtime/RuntimeTarget", 4490 "moxie/file/Blob", 4491 "moxie/file/FileReaderSync", 4492 "moxie/xhr/FormData", 4493 "moxie/core/utils/Env", 4494 "moxie/core/utils/Mime" 4495 ], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) { 4496 4497 var httpCode = { 4498 100: 'Continue', 4499 101: 'Switching Protocols', 4500 102: 'Processing', 4501 4502 200: 'OK', 4503 201: 'Created', 4504 202: 'Accepted', 4505 203: 'Non-Authoritative Information', 4506 204: 'No Content', 4507 205: 'Reset Content', 4508 206: 'Partial Content', 4509 207: 'Multi-Status', 4510 226: 'IM Used', 4511 4512 300: 'Multiple Choices', 4513 301: 'Moved Permanently', 4514 302: 'Found', 4515 303: 'See Other', 4516 304: 'Not Modified', 4517 305: 'Use Proxy', 4518 306: 'Reserved', 4519 307: 'Temporary Redirect', 4520 4521 400: 'Bad Request', 4522 401: 'Unauthorized', 4523 402: 'Payment Required', 4524 403: 'Forbidden', 4525 404: 'Not Found', 4526 405: 'Method Not Allowed', 4527 406: 'Not Acceptable', 4528 407: 'Proxy Authentication Required', 4529 408: 'Request Timeout', 4530 409: 'Conflict', 4531 410: 'Gone', 4532 411: 'Length Required', 4533 412: 'Precondition Failed', 4534 413: 'Request Entity Too Large', 4535 414: 'Request-URI Too Long', 4536 415: 'Unsupported Media Type', 4537 416: 'Requested Range Not Satisfiable', 4538 417: 'Expectation Failed', 4539 422: 'Unprocessable Entity', 4540 423: 'Locked', 4541 424: 'Failed Dependency', 4542 426: 'Upgrade Required', 4543 4544 500: 'Internal Server Error', 4545 501: 'Not Implemented', 4546 502: 'Bad Gateway', 4547 503: 'Service Unavailable', 4548 504: 'Gateway Timeout', 4549 505: 'HTTP Version Not Supported', 4550 506: 'Variant Also Negotiates', 4551 507: 'Insufficient Storage', 4552 510: 'Not Extended' 4553 }; 6256 if (opts.crop) { 6257 scale = Math.max(opts.width/self.width, opts.height/self.height); 4554 6258 4555 function XMLHttpRequestUpload() { 4556 this.uid = Basic.guid('uid_'); 4557 } 4558 4559 XMLHttpRequestUpload.prototype = EventTarget.instance; 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); 4560 6263 4561 /** 4562 Implementation of XMLHttpRequest 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); 4563 6269 4564 @class XMLHttpRequest 4565 @constructor 4566 @uses RuntimeClient 4567 @extends EventTarget 4568 */ 4569 var dispatches = [ 4570 'loadstart', 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 } 4571 6337 4572 'progress', 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); 4573 6343 4574 'abort', 6344 // do not upscale if we were asked to not fit it 6345 if (scale > 1 && !opts.fit) { 6346 scale = 1; 6347 } 6348 } 4575 6349 4576 'error', 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 }, 4577 6356 4578 'load', 6357 /** 6358 Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions. 4579 6359 4580 'timeout', 6360 @method downsize 6361 @deprecated use resize() 6362 */ 6363 downsize: function(options) { 6364 var defaults = { 6365 width: this.width, 6366 height: this.height, 6367 type: this.type || 'image/jpeg', 6368 quality: 90, 6369 crop: false, 6370 fit: false, 6371 preserveHeaders: true, 6372 resample: 'default' 6373 }, opts; 4581 6374 4582 'loadend' 6375 if (typeof(options) === 'object') { 6376 opts = Basic.extend(defaults, options); 6377 } else { 6378 // for backward compatibility 6379 opts = Basic.extend(defaults, { 6380 width: arguments[0], 6381 height: arguments[1], 6382 crop: arguments[2], 6383 preserveHeaders: arguments[3] 6384 }); 6385 } 4583 6386 4584 // readystatechange (for historical reasons) 4585 ]; 4586 4587 var NATIVE = 1, RUNTIME = 2; 4588 4589 function XMLHttpRequest() { 4590 var self = this, 4591 // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible 4592 props = { 4593 /** 4594 The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout. 6387 this.resize(opts); 6388 }, 4595 6389 4596 @property timeout 4597 @type Number 4598 @default 0 4599 */ 4600 timeout: 0, 6390 /** 6391 Alias for downsize(width, height, true). (see downsize) 4601 6392 4602 /** 4603 Current state, can take following values: 4604 UNSENT (numeric value 0) 4605 The object has been constructed. 6393 @method crop 6394 @param {Number} width Resulting width 6395 @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) 6396 @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) 6397 */ 6398 crop: function(width, height, preserveHeaders) { 6399 this.downsize(width, height, true, preserveHeaders); 6400 }, 6401 6402 getAsCanvas: function() { 6403 if (!Env.can('create_canvas')) { 6404 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); 6405 } 6406 return this.exec('Image', 'getAsCanvas'); 6407 }, 4606 6408 4607 OPENED (numeric value 1) 4608 The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method. 6409 /** 6410 Retrieves image in it's current state as moxie.file.Blob object. Cannot be run on empty or image in progress (throws 6411 DOMException.INVALID_STATE_ERR). 6412 6413 @method getAsBlob 6414 @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png 6415 @param {Number} [quality=90] Applicable only together with mime type image/jpeg 6416 @return {Blob} Image as Blob 6417 */ 6418 getAsBlob: function(type, quality) { 6419 if (!this.size) { 6420 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 6421 } 6422 return this.exec('Image', 'getAsBlob', type || 'image/jpeg', quality || 90); 6423 }, 4609 6424 4610 HEADERS_RECEIVED (numeric value 2) 4611 All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available. 6425 /** 6426 Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws 6427 DOMException.INVALID_STATE_ERR). 4612 6428 4613 LOADING (numeric value 3) 4614 The response entity body is being received. 6429 @method getAsDataURL 6430 @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png 6431 @param {Number} [quality=90] Applicable only together with mime type image/jpeg 6432 @return {String} Image as dataURL string 6433 */ 6434 getAsDataURL: function(type, quality) { 6435 if (!this.size) { 6436 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 6437 } 6438 return this.exec('Image', 'getAsDataURL', type || 'image/jpeg', quality || 90); 6439 }, 4615 6440 4616 DONE (numeric value 4) 6441 /** 6442 Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws 6443 DOMException.INVALID_STATE_ERR). 4617 6444 4618 @property readyState 4619 @type Number 4620 @default 0 (UNSENT) 4621 */ 4622 readyState: XMLHttpRequest.UNSENT, 6445 @method getAsBinaryString 6446 @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png 6447 @param {Number} [quality=90] Applicable only together with mime type image/jpeg 6448 @return {String} Image as binary string 6449 */ 6450 getAsBinaryString: function(type, quality) { 6451 var dataUrl = this.getAsDataURL(type, quality); 6452 return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)); 6453 }, 6454 6455 /** 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, 6458 can be used in legacy browsers that do not have canvas or proper dataURI support). 4623 6459 4624 /** 4625 True when user credentials are to be included in a cross-origin request. False when they are to be excluded 4626 in a cross-origin request and when cookies are to be ignored in its response. Initially false. 6460 @method embed 6461 @param {DOMElement} el DOM element to insert the image object into 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 6469 */ 6470 embed: function(el, options) { 6471 var self = this 6472 , runtime // this has to be outside of all the closures to contain proper runtime 6473 ; 6474 6475 var opts = Basic.extend({ 6476 width: this.width, 6477 height: this.height, 6478 type: this.type || 'image/jpeg', 6479 quality: 90, 6480 fit: true, 6481 resample: 'nearest' 6482 }, options); 6483 6484 6485 function render(type, quality) { 6486 var img = this; 6487 6488 // if possible, embed a canvas element directly 6489 if (Env.can('create_canvas')) { 6490 var canvas = img.getAsCanvas(); 6491 if (canvas) { 6492 el.appendChild(canvas); 6493 canvas = null; 6494 img.destroy(); 6495 self.trigger('embedded'); 6496 return; 6497 } 6498 } 4627 6499 4628 @property withCredentials 4629 @type Boolean 4630 @default false 4631 */ 4632 withCredentials: false, 6500 var dataUrl = img.getAsDataURL(type, quality); 6501 if (!dataUrl) { 6502 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 6503 } 4633 6504 4634 /** 4635 Returns the HTTP status code. 6505 if (Env.can('use_data_uri_of', dataUrl.length)) { 6506 el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" alt="" />'; 6507 img.destroy(); 6508 self.trigger('embedded'); 6509 } else { 6510 var tr = new Transporter(); 4636 6511 4637 @property status 4638 @type Number 4639 @default 0 4640 */ 4641 status: 0, 6512 tr.bind("TransportingComplete", function() { 6513 runtime = self.connectRuntime(this.result.ruid); 4642 6514 4643 /** 4644 Returns the HTTP status text. 6515 self.bind("Embedded", function() { 6516 // position and size properly 6517 Basic.extend(runtime.getShimContainer().style, { 6518 //position: 'relative', 6519 top: '0px', 6520 left: '0px', 6521 width: img.width + 'px', 6522 height: img.height + 'px' 6523 }); 6524 6525 // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's 6526 // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and 6527 // sometimes 8 and they do not have this problem, we can comment this for now 6528 /*tr.bind("RuntimeInit", function(e, runtime) { 6529 tr.destroy(); 6530 runtime.destroy(); 6531 onResize.call(self); // re-feed our image data 6532 });*/ 4645 6533 4646 @property statusText 4647 @type String 4648 */ 4649 statusText: "", 6534 runtime = null; // release 6535 }, 999); 4650 6536 4651 /** 4652 Returns the response type. Can be set to change the response type. Values are: 4653 the empty string (default), "arraybuffer", "blob", "document", "json", and "text". 4654 4655 @property responseType 4656 @type String 4657 */ 4658 responseType: "", 6537 runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height); 6538 img.destroy(); 6539 }); 4659 6540 4660 /** 4661 Returns the document response entity body. 4662 4663 Throws an "InvalidStateError" exception if responseType is not the empty string or "document". 6541 tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, { 6542 required_caps: { 6543 display_media: true 6544 }, 6545 runtime_order: 'flash,silverlight', 6546 container: el 6547 }); 6548 } 6549 } 4664 6550 4665 @property responseXML4666 @type Document4667 */4668 responseXML: null,6551 try { 6552 if (!(el = Dom.get(el))) { 6553 throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR); 6554 } 4669 6555 4670 /** 4671 Returns the text response entity body. 4672 4673 Throws an "InvalidStateError" exception if responseType is not the empty string or "text". 6556 if (!this.size) { // only preloaded image objects can be used as source 6557 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 6558 } 4674 6559 4675 @property responseText4676 @type String4677 */4678 responseText: null,6560 // high-resolution images cannot be consistently handled across the runtimes 6561 if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { 6562 //throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); 6563 } 4679 6564 4680 /** 4681 Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body). 4682 Can become: ArrayBuffer, Blob, Document, JSON, Text 4683 4684 @property response 4685 @type Mixed 4686 */ 4687 response: null 4688 }, 6565 var imgCopy = new Image(); 4689 6566 4690 _async = true, 4691 _url, 4692 _method, 4693 _headers = {}, 4694 _user, 4695 _password, 4696 _encoding = null, 4697 _mimeType = null, 4698 4699 // flags 4700 _sync_flag = false, 4701 _send_flag = false, 4702 _upload_events_flag = false, 4703 _upload_complete_flag = false, 4704 _error_flag = false, 4705 _same_origin_flag = false, 4706 4707 // times 4708 _start_time, 4709 _timeoutset_time, 4710 4711 _finalMime = null, 4712 _finalCharset = null, 4713 4714 _options = {}, 4715 _xhr, 4716 _responseHeaders = '', 4717 _responseHeadersBag 4718 ; 6567 imgCopy.bind("Resize", function() { 6568 render.call(this, opts.type, opts.quality); 6569 }); 4719 6570 4720 4721 Basic.extend(this, props, { 4722 /** 4723 Unique id of the component 6571 imgCopy.bind("Load", function() { 6572 this.downsize(opts); 6573 }); 4724 6574 4725 @property uid 4726 @type String 4727 */ 4728 uid: Basic.guid('uid_'), 4729 4730 /** 4731 Target for Upload events 6575 // if embedded thumb data is available and dimensions are big enough, use it 6576 if (this.meta.thumb && this.meta.thumb.width >= opts.width && this.meta.thumb.height >= opts.height) { 6577 imgCopy.load(this.meta.thumb.data); 6578 } else { 6579 imgCopy.clone(this, false); 6580 } 4732 6581 4733 @property upload 4734 @type XMLHttpRequestUpload 4735 */ 4736 upload: new XMLHttpRequestUpload(), 4737 6582 return imgCopy; 6583 } catch(ex) { 6584 // for now simply trigger error event 6585 this.trigger('error', ex.code); 6586 } 6587 }, 4738 6588 4739 /** 4740 Sets the request method, request URL, synchronous flag, request username, and request password. 6589 /** 6590 Properly destroys the image and frees resources in use. If any. Recommended way to dispose 6591 moxie.image.Image object. 4741 6592 4742 Throws a "SyntaxError" exception if one of the following is true: 6593 @method destroy 6594 */ 6595 destroy: function() { 6596 if (this.ruid) { 6597 this.getRuntime().exec.call(this, 'Image', 'destroy'); 6598 this.disconnectRuntime(); 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 } 6604 this.unbindAll(); 6605 } 6606 }); 4743 6607 4744 method is not a valid HTTP method.4745 url cannot be resolved.4746 url contains the "user:password" format in the userinfo production.4747 Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK.4748 6608 4749 Throws an "InvalidAccessError" exception if one of the following is true: 6609 // this is here, because in order to bind properly, we need uid, which is created above 6610 this.handleEventProps(dispatches); 4750 6611 4751 Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin.4752 There is an associated XMLHttpRequest document and either the timeout attribute is not zero,4753 the withCredentials attribute is true, or the responseType attribute is not the empty string.6612 this.bind('Load Resize', function() { 6613 return _updateInfo.call(this); // if operation fails (e.g. image is neither PNG nor JPEG) cancel all pending events 6614 }, 999); 4754 6615 4755 6616 4756 @method open 4757 @param {String} method HTTP method to use on request 4758 @param {String} url URL to request 4759 @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default. 4760 @param {String} [user] Username to use in HTTP authentication process on server-side 4761 @param {String} [password] Password to use in HTTP authentication process on server-side 4762 */ 4763 open: function(method, url, async, user, password) { 4764 var urlp; 4765 4766 // first two arguments are required 4767 if (!method || !url) { 4768 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 4769 } 4770 4771 // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method 4772 if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) { 4773 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 4774 } 6617 function _updateInfo(info) { 6618 try { 6619 if (!info) { 6620 info = this.exec('Image', 'getInfo'); 6621 } 4775 6622 4776 // 34777 if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {4778 _method = method.toUpperCase();4779 }4780 4781 4782 // 4 - allowing these methods poses a security risk4783 if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {4784 throw new x.DOMException(x.DOMException.SECURITY_ERR);4785 }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; 6628 6629 // update file name, only if empty 6630 if (this.name === '') { 6631 this.name = info.name; 6632 } 4786 6633 4787 // 5 4788 url = Encode.utf8_encode(url); 4789 4790 // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError". 4791 urlp = Url.parseUrl(url); 4792 4793 _same_origin_flag = Url.hasSameOrigin(urlp); 4794 4795 // 7 - manually build up absolute url 4796 _url = Url.resolveUrl(url); 4797 4798 // 9-10, 12-13 4799 if ((user || password) && !_same_origin_flag) { 4800 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 6634 return true; 6635 } catch(ex) { 6636 this.trigger('error', ex.code); 6637 return false; 6638 } 4801 6639 } 4802 6640 4803 _user = user || urlp.user;4804 _password = password || urlp.pass;4805 4806 // 114807 _async = async || true;4808 4809 if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {4810 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);4811 }4812 4813 // 14 - terminate abort()4814 4815 // 15 - terminate send()4816 4817 // 184818 _sync_flag = !_async;4819 _send_flag = false;4820 _headers = {};4821 _reset.call(this);4822 4823 // 194824 _p('readyState', XMLHttpRequest.OPENED);4825 4826 // 204827 this.dispatchEvent('readystatechange');4828 },4829 4830 /**4831 Appends an header to the list of author request headers, or if header is already4832 in the list of author request headers, combines its value with value.4833 6641 4834 Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. 4835 Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value 4836 is not a valid HTTP header field value. 4837 4838 @method setRequestHeader 4839 @param {String} header 4840 @param {String|Number} value 4841 */ 4842 setRequestHeader: function(header, value) { 4843 var uaHeaders = [ // these headers are controlled by the user agent 4844 "accept-charset", 4845 "accept-encoding", 4846 "access-control-request-headers", 4847 "access-control-request-method", 4848 "connection", 4849 "content-length", 4850 "cookie", 4851 "cookie2", 4852 "content-transfer-encoding", 4853 "date", 4854 "expect", 4855 "host", 4856 "keep-alive", 4857 "origin", 4858 "referer", 4859 "te", 4860 "trailer", 4861 "transfer-encoding", 4862 "upgrade", 4863 "user-agent", 4864 "via" 4865 ]; 4866 4867 // 1-2 4868 if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) { 4869 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 4870 } 6642 function _load(src) { 6643 var srcType = Basic.typeOf(src); 4871 6644 4872 // 3 4873 if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) { 4874 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 6645 try { 6646 // if source is Image 6647 if (src instanceof Image) { 6648 if (!src.size) { // only preloaded image objects can be used as source 6649 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 6650 } 6651 _loadFromImage.apply(this, arguments); 6652 } 6653 // if source is o.Blob/o.File 6654 else if (src instanceof Blob) { 6655 if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) { 6656 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 6657 } 6658 _loadFromBlob.apply(this, arguments); 6659 } 6660 // if native blob/file 6661 else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) { 6662 _load.call(this, new File(null, src), arguments[1]); 6663 } 6664 // if String 6665 else if (srcType === 'string') { 6666 // if dataUrl String 6667 if (src.substr(0, 5) === 'data:') { 6668 _load.call(this, new Blob(null, { data: src }), arguments[1]); 6669 } 6670 // else assume Url, either relative or absolute 6671 else { 6672 _loadFromUrl.apply(this, arguments); 6673 } 6674 } 6675 // if source seems to be an img node 6676 else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') { 6677 _load.call(this, src.src, arguments[1]); 6678 } 6679 else { 6680 throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR); 6681 } 6682 } catch(ex) { 6683 // for now simply trigger error event 6684 this.trigger('error', ex.code); 6685 } 4875 6686 } 4876 6687 4877 // 44878 /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values4879 if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {4880 throw new x.DOMException(x.DOMException.SYNTAX_ERR);4881 }*/4882 6688 4883 header = Basic.trim(header).toLowerCase(); 4884 4885 // setting of proxy-* and sec-* headers is prohibited by spec 4886 if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) { 4887 return false; 6689 function _loadFromImage(img, exact) { 6690 var runtime = this.connectRuntime(img.ruid); 6691 this.ruid = runtime.uid; 6692 runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact)); 4888 6693 } 4889 6694 4890 // camelize4891 // browsers lowercase header names (at least for custom ones)4892 // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });4893 4894 if (!_headers[header]) {4895 _headers[header] = value;4896 } else {4897 // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph)4898 _headers[header] += ', ' + value;4899 }4900 return true;4901 },4902 6695 4903 /**4904 Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.6696 function _loadFromBlob(blob, options) { 6697 var self = this; 4905 6698 4906 @method getAllResponseHeaders 4907 @return {String} reponse headers or empty string 4908 */ 4909 getAllResponseHeaders: function() { 4910 return _responseHeaders || ''; 4911 }, 6699 self.name = blob.name || ''; 4912 6700 4913 /** 4914 Returns the header field value from the response of which the field name matches header, 4915 unless the field name is Set-Cookie or Set-Cookie2. 6701 function exec(runtime) { 6702 self.ruid = runtime.uid; 6703 runtime.exec.call(self, 'Image', 'loadFromBlob', blob); 6704 } 4916 6705 4917 @method getResponseHeader 4918 @param {String} header 4919 @return {String} value(s) for the specified header or null 4920 */ 4921 getResponseHeader: function(header) { 4922 header = header.toLowerCase(); 6706 if (blob.isDetached()) { 6707 this.bind('RuntimeInit', function(e, runtime) { 6708 exec(runtime); 6709 }); 4923 6710 4924 if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) { 4925 return null; 4926 } 6711 // convert to object representation 6712 if (options && typeof(options.required_caps) === 'string') { 6713 options.required_caps = Runtime.parseCaps(options.required_caps); 6714 } 4927 6715 4928 if (_responseHeaders && _responseHeaders !== '') { 4929 // if we didn't parse response headers until now, do it and keep for later 4930 if (!_responseHeadersBag) { 4931 _responseHeadersBag = {}; 4932 Basic.each(_responseHeaders.split(/\r\n/), function(line) { 4933 var pair = line.split(/:\s+/); 4934 if (pair.length === 2) { // last line might be empty, omit 4935 pair[0] = Basic.trim(pair[0]); // just in case 4936 _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form 4937 header: pair[0], 4938 value: Basic.trim(pair[1]) 4939 }; 6716 this.connectRuntime(Basic.extend({ 6717 required_caps: { 6718 access_image_binary: true, 6719 resize_image: true 4940 6720 } 4941 }); 4942 } 4943 if (_responseHeadersBag.hasOwnProperty(header)) { 4944 return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value; 6721 }, options)); 6722 } else { 6723 exec(this.connectRuntime(blob.ruid)); 4945 6724 } 4946 6725 } 4947 return null;4948 },4949 4950 /**4951 Sets the Content-Type header for the response to mime.4952 Throws an "InvalidStateError" exception if the state is LOADING or DONE.4953 Throws a "SyntaxError" exception if mime is not a valid media type.4954 6726 4955 @method overrideMimeType4956 @param String mime Mime type to set4957 */4958 overrideMimeType: function(mime) {4959 var matches, charset;4960 4961 // 14962 if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {4963 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);4964 }4965 6727 4966 // 24967 mime = Basic.trim(mime.toLowerCase());6728 function _loadFromUrl(url, options) { 6729 var self = this, xhr; 4968 6730 4969 if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) { 4970 mime = matches[1]; 4971 if (matches[2]) { 4972 charset = matches[2]; 4973 } 4974 } 6731 xhr = new XMLHttpRequest(); 4975 6732 4976 if (!Mime.mimes[mime]) { 4977 throw new x.DOMException(x.DOMException.SYNTAX_ERR); 4978 } 6733 xhr.open('get', url); 6734 xhr.responseType = 'blob'; 4979 6735 4980 // 3-4 4981 _finalMime = mime; 4982 _finalCharset = charset; 4983 }, 4984 4985 /** 4986 Initiates the request. The optional argument provides the request entity body. 4987 The argument is ignored if request method is GET or HEAD. 6736 xhr.onprogress = function(e) { 6737 self.trigger(e); 6738 }; 4988 6739 4989 Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. 6740 xhr.onload = function() { 6741 _loadFromBlob.call(self, xhr.response, true); 6742 }; 4990 6743 4991 @method send 4992 @param {Blob|Document|String|FormData} [data] Request entity body 4993 @param {Object} [options] Set of requirements and pre-requisities for runtime initialization 4994 */ 4995 send: function(data, options) { 4996 if (Basic.typeOf(options) === 'string') { 4997 _options = { ruid: options }; 4998 } else if (!options) { 4999 _options = {}; 5000 } else { 5001 _options = options; 5002 } 5003 5004 // 1-2 5005 if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) { 5006 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5007 } 5008 5009 // 3 5010 // sending Blob 5011 if (data instanceof Blob) { 5012 _options.ruid = data.ruid; 5013 _mimeType = data.type || 'application/octet-stream'; 5014 } 5015 5016 // FormData 5017 else if (data instanceof FormData) { 5018 if (data.hasBlob()) { 5019 var blob = data.getBlob(); 5020 _options.ruid = blob.ruid; 5021 _mimeType = blob.type || 'application/octet-stream'; 5022 } 5023 } 5024 5025 // DOMString 5026 else if (typeof data === 'string') { 5027 _encoding = 'UTF-8'; 5028 _mimeType = 'text/plain;charset=UTF-8'; 5029 5030 // data should be converted to Unicode and encoded as UTF-8 5031 data = Encode.utf8_encode(data); 5032 } 5033 5034 // if withCredentials not set, but requested, set it automatically 5035 if (!this.withCredentials) { 5036 this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag; 5037 } 6744 xhr.onerror = function(e) { 6745 self.trigger(e); 6746 }; 5038 6747 5039 // 4 - storage mutex 5040 // 5 5041 _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP 5042 // 6 5043 _error_flag = false; 5044 // 7 5045 _upload_complete_flag = !data; 5046 // 8 - Asynchronous steps 5047 if (!_sync_flag) { 5048 // 8.1 5049 _send_flag = true; 5050 // 8.2 5051 // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr 5052 // 8.3 5053 //if (!_upload_complete_flag) { 5054 // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr 5055 //} 6748 xhr.onloadend = function() { 6749 xhr.destroy(); 6750 }; 6751 6752 xhr.bind('RuntimeError', function(e, err) { 6753 self.trigger('RuntimeError', err); 6754 }); 6755 6756 xhr.send(null, options); 5056 6757 } 5057 // 8.5 - Return the send() method call, but continue running the steps in this algorithm. 5058 _doXHR.call(this, data); 5059 }, 5060 5061 /** 5062 Cancels any network activity. 5063 5064 @method abort 5065 */ 5066 abort: function() { 5067 _error_flag = true; 5068 _sync_flag = false; 5069 5070 if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) { 5071 _p('readyState', XMLHttpRequest.DONE); 5072 _send_flag = false; 6758 } 5073 6759 5074 if (_xhr) { 5075 _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag); 5076 } else { 5077 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5078 } 6760 // virtual world will crash on you if image has a resolution higher than this: 6761 Image.MAX_RESIZE_WIDTH = 8192; 6762 Image.MAX_RESIZE_HEIGHT = 8192; 6763 6764 Image.prototype = EventTarget.instance; 6765 6766 return Image; 6767 }); 6768 6769 // Included from: src/javascript/runtime/html5/Runtime.js 6770 6771 /** 6772 * Runtime.js 6773 * 6774 * Copyright 2013, Moxiecode Systems AB 6775 * Released under GPL License. 6776 * 6777 * License: http://www.plupload.com/license 6778 * Contributing: http://www.plupload.com/contributing 6779 */ 6780 6781 /*global File:true */ 6782 6783 /** 6784 Defines constructor for HTML5 runtime. 5079 6785 5080 _upload_complete_flag = true; 5081 } else { 5082 _p('readyState', XMLHttpRequest.UNSENT); 5083 } 5084 }, 6786 @class moxie/runtime/html5/Runtime 6787 @private 6788 */ 6789 define("moxie/runtime/html5/Runtime", [ 6790 "moxie/core/utils/Basic", 6791 "moxie/core/Exceptions", 6792 "moxie/runtime/Runtime", 6793 "moxie/core/utils/Env" 6794 ], function(Basic, x, Runtime, Env) { 6795 6796 var type = "html5", extensions = {}; 6797 6798 function Html5Runtime(options) { 6799 var I = this 6800 , Test = Runtime.capTest 6801 , True = Runtime.capTrue 6802 ; 5085 6803 5086 destroy: function() { 5087 if (_xhr) { 5088 if (Basic.typeOf(_xhr.destroy) === 'function') { 5089 _xhr.destroy(); 5090 } 5091 _xhr = null; 5092 } 6804 var caps = Basic.extend({ 6805 access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL), 6806 access_image_binary: function() { 6807 return I.can('access_binary') && !!extensions.Image; 6808 }, 6809 display_media: Test( 6810 (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && 6811 defined('moxie/image/Image') 6812 ), 6813 do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()), 6814 drag_and_drop: Test(function() { 6815 // this comes directly from Modernizr: http://www.modernizr.com/ 6816 var div = document.createElement('div'); 6817 // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop 6818 return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 6819 (Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>')); 6820 }()), 6821 filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest 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, 11, '<=')) || 6826 (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<')) || 6827 Env.os === 'iOS' || // as of iOS11, no extensions are supported in accept attribute 6828 Env.os === 'Android' 6829 ); 6830 }()), 6831 return_response_headers: True, 6832 return_response_type: function(responseType) { 6833 if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported 6834 return true; 6835 } 6836 return Env.can('return_response_type', responseType); 6837 }, 6838 return_status_code: True, 6839 report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload), 6840 resize_image: function() { 6841 return I.can('access_binary') && Env.can('create_canvas'); 6842 }, 6843 select_file: function() { 6844 return Env.can('use_fileinput') && window.File; 6845 }, 6846 select_folder: function() { 6847 return I.can('select_file') && ( 6848 Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=') || 6849 Env.browser === 'Firefox' && Env.verComp(Env.version, 42, '>=') // https://developer.mozilla.org/en-US/Firefox/Releases/42 6850 ); 6851 }, 6852 select_multiple: function() { 6853 // it is buggy on Safari Windows and iOS 6854 return I.can('select_file') && 6855 !(Env.browser === 'Safari' && Env.os === 'Windows') && 6856 !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.0", '>') && Env.verComp(Env.osVersion, "8.0.0", '<')); 6857 }, 6858 send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))), 6859 send_custom_headers: Test(window.XMLHttpRequest), 6860 send_multipart: function() { 6861 return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string'); 6862 }, 6863 slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)), 6864 stream_upload: function(){ 6865 return I.can('slice_blob') && I.can('send_multipart'); 6866 }, 6867 summon_file_dialog: function() { // yeah... some dirty sniffing here... 6868 return I.can('select_file') && !( 6869 (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) || 6870 (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) || 6871 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) 6872 ); 6873 }, 6874 upload_filesize: True, 6875 use_http_method: True 6876 }, 6877 arguments[2] 6878 ); 5093 6879 5094 this.unbindAll();6880 Runtime.call(this, options, (arguments[1] || type), caps); 5095 6881 5096 if (this.upload) {5097 this.upload.unbindAll();5098 this.upload = null;5099 }5100 }5101 });5102 6882 5103 this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons 5104 this.upload.handleEventProps(dispatches); 6883 Basic.extend(this, { 5105 6884 5106 /* this is nice, but maybe too lengthy 6885 init : function() { 6886 this.trigger("Init"); 6887 }, 5107 6888 5108 // if supported by JS version, set getters/setters for specific properties 5109 o.defineProperty(this, 'readyState', { 5110 configurable: false, 6889 destroy: (function(destroy) { // extend default destroy method 6890 return function() { 6891 destroy.call(I); 6892 destroy = I = null; 6893 }; 6894 }(this.destroy)) 6895 }); 5111 6896 5112 get: function() { 5113 return _p('readyState'); 6897 Basic.extend(this.getShim(), extensions); 5114 6898 } 6899 6900 Runtime.addConstructor(type, Html5Runtime); 6901 6902 return extensions; 5115 6903 }); 5116 6904 5117 o.defineProperty(this, 'timeout', { 5118 configurable: false, 6905 // Included from: src/javascript/runtime/html5/file/Blob.js 5119 6906 5120 get: function() { 5121 return _p('timeout'); 5122 }, 6907 /** 6908 * Blob.js 6909 * 6910 * Copyright 2013, Moxiecode Systems AB 6911 * Released under GPL License. 6912 * 6913 * License: http://www.plupload.com/license 6914 * Contributing: http://www.plupload.com/contributing 6915 */ 5123 6916 5124 set: function(value) { 6917 /** 6918 @class moxie/runtime/html5/file/Blob 6919 @private 6920 */ 6921 define("moxie/runtime/html5/file/Blob", [ 6922 "moxie/runtime/html5/Runtime", 6923 "moxie/file/Blob" 6924 ], function(extensions, Blob) { 6925 6926 function HTML5Blob() { 6927 function w3cBlobSlice(blob, start, end) { 6928 var blobSlice; 5125 6929 5126 if (_sync_flag) { 5127 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 6930 if (window.File.prototype.slice) { 6931 try { 6932 blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception 6933 return blob.slice(start, end); 6934 } catch (e) { 6935 // depricated slice method 6936 return blob.slice(start, end - start); 6937 } 6938 // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672 6939 } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) { 6940 return blobSlice.call(blob, start, end); 6941 } else { 6942 return null; // or throw some exception 6943 } 5128 6944 } 5129 6945 5130 // timeout still should be measured relative to the start time of request 5131 _timeoutset_time = (new Date).getTime(); 6946 this.slice = function() { 6947 return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments)); 6948 }; 5132 6949 5133 _p('timeout', value); 6950 this.destroy = function() { 6951 this.getRuntime().getShim().removeInstance(this.uid); 6952 }; 5134 6953 } 5135 });5136 6954 5137 // the withCredentials attribute has no effect when fetching same-origin resources 5138 o.defineProperty(this, 'withCredentials', { 5139 configurable: false, 6955 return (extensions.Blob = HTML5Blob); 6956 }); 5140 6957 5141 get: function() { 5142 return _p('withCredentials'); 5143 }, 6958 // Included from: src/javascript/core/utils/Events.js 5144 6959 5145 set: function(value) { 5146 // 1-2 5147 if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) { 5148 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5149 } 6960 /** 6961 * Events.js 6962 * 6963 * Copyright 2013, Moxiecode Systems AB 6964 * Released under GPL License. 6965 * 6966 * License: http://www.plupload.com/license 6967 * Contributing: http://www.plupload.com/contributing 6968 */ 5150 6969 5151 // 3-4 5152 if (_anonymous_flag || _sync_flag) { 5153 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); 5154 } 6970 /** 6971 @class moxie/core/utils/Events 6972 @public 6973 @static 6974 */ 5155 6975 5156 // 5 5157 _p('withCredentials', value); 6976 define('moxie/core/utils/Events', [ 6977 'moxie/core/utils/Basic' 6978 ], function(Basic) { 6979 var eventhash = {}, uid = 'moxie_' + Basic.guid(); 6980 6981 // IE W3C like event funcs 6982 function preventDefault() { 6983 this.returnValue = false; 5158 6984 } 5159 });5160 5161 o.defineProperty(this, 'status', {5162 configurable: false,5163 6985 5164 get: function() {5165 return _p('status');6986 function stopPropagation() { 6987 this.cancelBubble = true; 5166 6988 } 5167 });5168 6989 5169 o.defineProperty(this, 'statusText', { 5170 configurable: false, 6990 /** 6991 Adds an event handler to the specified object and store reference to the handler 6992 in objects internal Plupload registry (@see removeEvent). 5171 6993 5172 get: function() { 5173 return _p('statusText'); 5174 } 5175 }); 6994 @method addEvent 6995 @static 6996 @param {Object} obj DOM element like object to add handler to. 6997 @param {String} name Name to add event listener to. 6998 @param {Function} callback Function to call when event occurs. 6999 @param {String} [key] that might be used to add specifity to the event record. 7000 */ 7001 var addEvent = function(obj, name, callback, key) { 7002 var func, events; 7003 7004 name = name.toLowerCase(); 7005 7006 // Add event listener 7007 if (obj.addEventListener) { 7008 func = callback; 7009 7010 obj.addEventListener(name, func, false); 7011 } else if (obj.attachEvent) { 7012 func = function() { 7013 var evt = window.event; 5176 7014 5177 o.defineProperty(this, 'responseType', { 5178 configurable: false, 7015 if (!evt.target) { 7016 evt.target = evt.srcElement; 7017 } 5179 7018 5180 get: function() { 5181 return _p('responseType'); 5182 }, 7019 evt.preventDefault = preventDefault; 7020 evt.stopPropagation = stopPropagation; 5183 7021 5184 set: function(value) {5185 // 15186 if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { 5187 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);7022 callback(evt); 7023 }; 7024 7025 obj.attachEvent('on' + name, func); 5188 7026 } 5189 7027 5190 // 25191 if ( _sync_flag) {5192 throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);7028 // Log event handler to objects internal mOxie registry 7029 if (!obj[uid]) { 7030 obj[uid] = Basic.guid(); 5193 7031 } 5194 7032 5195 // 3 5196 _p('responseType', value.toLowerCase()); 5197 } 5198 }); 7033 if (!eventhash.hasOwnProperty(obj[uid])) { 7034 eventhash[obj[uid]] = {}; 7035 } 5199 7036 5200 o.defineProperty(this, 'responseText', { 5201 configurable: false, 7037 events = eventhash[obj[uid]]; 5202 7038 5203 get: function() { 5204 // 1 5205 if (!~o.inArray(_p('responseType'), ['', 'text'])) { 5206 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 7039 if (!events.hasOwnProperty(name)) { 7040 events[name] = []; 5207 7041 } 5208 7042 5209 // 2-3 5210 if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { 5211 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5212 } 7043 events[name].push({ 7044 func: func, 7045 orig: callback, // store original callback for IE 7046 key: key 7047 }); 7048 }; 5213 7049 5214 return _p('responseText');5215 }5216 });5217 7050 5218 o.defineProperty(this, 'responseXML', { 5219 configurable: false, 7051 /** 7052 Remove event handler from the specified object. If third argument (callback) 7053 is not specified remove all events with the specified name. 5220 7054 5221 get: function() { 5222 // 1 5223 if (!~o.inArray(_p('responseType'), ['', 'document'])) { 5224 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5225 } 7055 @method removeEvent 7056 @static 7057 @param {Object} obj DOM element to remove event listener(s) from. 7058 @param {String} name Name of event listener to remove. 7059 @param {Function|String} [callback] might be a callback or unique key to match. 7060 */ 7061 var removeEvent = function(obj, name, callback) { 7062 var type, undef; 5226 7063 5227 // 2-3 5228 if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { 5229 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 7064 name = name.toLowerCase(); 7065 7066 if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) { 7067 type = eventhash[obj[uid]][name]; 7068 } else { 7069 return; 5230 7070 } 5231 7071 5232 return _p('responseXML'); 5233 } 5234 }); 7072 for (var i = type.length - 1; i >= 0; i--) { 7073 // undefined or not, key should match 7074 if (type[i].orig === callback || type[i].key === callback) { 7075 if (obj.removeEventListener) { 7076 obj.removeEventListener(name, type[i].func, false); 7077 } else if (obj.detachEvent) { 7078 obj.detachEvent('on'+name, type[i].func); 7079 } 5235 7080 5236 o.defineProperty(this, 'response', { 5237 configurable: false, 7081 type[i].orig = null; 7082 type[i].func = null; 7083 type.splice(i, 1); 5238 7084 5239 get: function() {5240 if (!!~o.inArray(_p('responseType'), ['', 'text'])) {5241 if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {5242 return '';7085 // If callback was passed we are done here, otherwise proceed 7086 if (callback !== undef) { 7087 break; 7088 } 5243 7089 } 5244 7090 } 5245 7091 5246 if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { 5247 return null; 7092 // If event array got empty, remove it 7093 if (!type.length) { 7094 delete eventhash[obj[uid]][name]; 5248 7095 } 5249 7096 5250 return _p('response');5251 }5252 });7097 // If mOxie registry has become empty, remove it 7098 if (Basic.isEmptyObj(eventhash[obj[uid]])) { 7099 delete eventhash[obj[uid]]; 5253 7100 5254 */ 7101 // IE doesn't let you remove DOM object property with - delete 7102 try { 7103 delete obj[uid]; 7104 } catch(e) { 7105 obj[uid] = undef; 7106 } 7107 } 7108 }; 5255 7109 5256 function _p(prop, value) { 5257 if (!props.hasOwnProperty(prop)) { 5258 return; 5259 } 5260 if (arguments.length === 1) { // get 5261 return Env.can('define_property') ? props[prop] : self[prop]; 5262 } else { // set 5263 if (Env.can('define_property')) { 5264 props[prop] = value; 5265 } else { 5266 self[prop] = value; 7110 7111 /** 7112 Remove all kind of events from the specified object 7113 7114 @method removeAllEvents 7115 @static 7116 @param {Object} obj DOM element to remove event listeners from. 7117 @param {String} [key] unique key to match, when removing events. 7118 */ 7119 var removeAllEvents = function(obj, key) { 7120 if (!obj || !obj[uid]) { 7121 return; 5267 7122 } 5268 } 5269 } 5270 5271 /* 5272 function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) { 5273 // TODO: http://tools.ietf.org/html/rfc3490#section-4.1 5274 return str.toLowerCase(); 5275 } 5276 */ 5277 5278 5279 function _doXHR(data) { 5280 var self = this; 5281 5282 _start_time = new Date().getTime(); 5283 5284 _xhr = new RuntimeTarget(); 5285 5286 function loadEnd() { 5287 if (_xhr) { // it could have been destroyed by now 5288 _xhr.destroy(); 5289 _xhr = null; 5290 } 5291 self.dispatchEvent('loadend'); 5292 self = null; 5293 } 5294 5295 function exec(runtime) { 5296 _xhr.bind('LoadStart', function(e) { 5297 _p('readyState', XMLHttpRequest.LOADING); 5298 self.dispatchEvent('readystatechange'); 5299 5300 self.dispatchEvent(e); 5301 5302 if (_upload_events_flag) { 5303 self.upload.dispatchEvent(e); 5304 } 5305 }); 5306 5307 _xhr.bind('Progress', function(e) { 5308 if (_p('readyState') !== XMLHttpRequest.LOADING) { 5309 _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example) 5310 self.dispatchEvent('readystatechange'); 5311 } 5312 self.dispatchEvent(e); 7123 7124 Basic.each(eventhash[obj[uid]], function(events, name) { 7125 removeEvent(obj, name, key); 5313 7126 }); 5314 5315 _xhr.bind('UploadProgress', function(e) { 5316 if (_upload_events_flag) { 5317 self.upload.dispatchEvent({ 5318 type: 'progress', 5319 lengthComputable: false, 5320 total: e.total, 5321 loaded: e.loaded 7127 }; 7128 7129 return { 7130 addEvent: addEvent, 7131 removeEvent: removeEvent, 7132 removeAllEvents: removeAllEvents 7133 }; 7134 }); 7135 7136 // Included from: src/javascript/runtime/html5/file/FileInput.js 7137 7138 /** 7139 * FileInput.js 7140 * 7141 * Copyright 2013, Moxiecode Systems AB 7142 * Released under GPL License. 7143 * 7144 * License: http://www.plupload.com/license 7145 * Contributing: http://www.plupload.com/contributing 7146 */ 7147 7148 /** 7149 @class moxie/runtime/html5/file/FileInput 7150 @private 7151 */ 7152 define("moxie/runtime/html5/file/FileInput", [ 7153 "moxie/runtime/html5/Runtime", 7154 "moxie/file/File", 7155 "moxie/core/utils/Basic", 7156 "moxie/core/utils/Dom", 7157 "moxie/core/utils/Events", 7158 "moxie/core/utils/Mime", 7159 "moxie/core/utils/Env" 7160 ], function(extensions, File, Basic, Dom, Events, Mime, Env) { 7161 7162 function FileInput() { 7163 var _options, _browseBtnZIndex; // save original z-index 7164 7165 Basic.extend(this, { 7166 init: function(options) { 7167 var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top; 7168 7169 _options = options; 7170 7171 // figure out accept string 7172 mimes = Mime.extList2mimes(_options.accept, I.can('filter_by_extension')); 7173 7174 shimContainer = I.getShimContainer(); 7175 7176 shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' + 7177 (_options.multiple && I.can('select_multiple') ? 'multiple' : '') + 7178 (_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+ 7179 (mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />'; 7180 7181 input = Dom.get(I.uid); 7182 7183 // prepare file input to be placed underneath the browse_button element 7184 Basic.extend(input.style, { 7185 position: 'absolute', 7186 top: 0, 7187 left: 0, 7188 width: '100%', 7189 height: '100%' 5322 7190 }); 5323 } 5324 }); 5325 5326 _xhr.bind('Load', function(e) { 5327 _p('readyState', XMLHttpRequest.DONE); 5328 _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0)); 5329 _p('statusText', httpCode[_p('status')] || ""); 5330 5331 _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType'))); 5332 5333 if (!!~Basic.inArray(_p('responseType'), ['text', ''])) { 5334 _p('responseText', _p('response')); 5335 } else if (_p('responseType') === 'document') { 5336 _p('responseXML', _p('response')); 5337 } 5338 5339 _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders'); 5340 5341 self.dispatchEvent('readystatechange'); 5342 5343 if (_p('status') > 0) { // status 0 usually means that server is unreachable 5344 if (_upload_events_flag) { 5345 self.upload.dispatchEvent(e); 7191 7192 7193 browseButton = Dom.get(_options.browse_button); 7194 _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto'; 7195 7196 // Route click event to the input[type=file] element for browsers that support such behavior 7197 if (I.can('summon_file_dialog')) { 7198 if (Dom.getStyle(browseButton, 'position') === 'static') { 7199 browseButton.style.position = 'relative'; 7200 } 7201 7202 Events.addEvent(browseButton, 'click', function(e) { 7203 var input = Dom.get(I.uid); 7204 if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] 7205 input.click(); 7206 } 7207 e.preventDefault(); 7208 }, comp.uid); 7209 7210 comp.bind('Refresh', function() { 7211 zIndex = parseInt(_browseBtnZIndex, 10) || 1; 7212 7213 Dom.get(_options.browse_button).style.zIndex = zIndex; 7214 this.getRuntime().getShimContainer().style.zIndex = zIndex - 1; 7215 }); 5346 7216 } 5347 self.dispatchEvent(e);5348 } else {5349 _error_flag = true;5350 self.dispatchEvent('error');5351 }5352 loadEnd();5353 });5354 7217 5355 _xhr.bind('Abort', function(e) { 5356 self.dispatchEvent(e); 5357 loadEnd(); 5358 }); 5359 5360 _xhr.bind('Error', function(e) { 5361 _error_flag = true; 5362 _p('readyState', XMLHttpRequest.DONE); 5363 self.dispatchEvent('readystatechange'); 5364 _upload_complete_flag = true; 5365 self.dispatchEvent(e); 5366 loadEnd(); 5367 }); 7218 /* Since we have to place input[type=file] on top of the browse_button for some browsers, 7219 browse_button loses interactivity, so we restore it here */ 7220 top = I.can('summon_file_dialog') ? browseButton : shimContainer; 5368 7221 5369 runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', { 5370 url: _url, 5371 method: _method, 5372 async: _async, 5373 user: _user, 5374 password: _password, 5375 headers: _headers, 5376 mimeType: _mimeType, 5377 encoding: _encoding, 5378 responseType: self.responseType, 5379 withCredentials: self.withCredentials, 5380 options: _options 5381 }, data); 5382 } 5383 5384 // clarify our requirements 5385 if (typeof(_options.required_caps) === 'string') { 5386 _options.required_caps = Runtime.parseCaps(_options.required_caps); 5387 } 7222 Events.addEvent(top, 'mouseover', function() { 7223 comp.trigger('mouseenter'); 7224 }, comp.uid); 7225 7226 Events.addEvent(top, 'mouseout', function() { 7227 comp.trigger('mouseleave'); 7228 }, comp.uid); 7229 7230 Events.addEvent(top, 'mousedown', function() { 7231 comp.trigger('mousedown'); 7232 }, comp.uid); 7233 7234 Events.addEvent(Dom.get(_options.container), 'mouseup', function() { 7235 comp.trigger('mouseup'); 7236 }, comp.uid); 7237 7238 // it shouldn't be possible to tab into the hidden element 7239 (I.can('summon_file_dialog') ? input : browseButton).setAttribute('tabindex', -1); 7240 7241 input.onchange = function onChange() { // there should be only one handler for this 7242 comp.files = []; 7243 7244 Basic.each(this.files, function(file) { 7245 var relativePath = ''; 7246 7247 if (_options.directory) { 7248 // folders are represented by dots, filter them out (Chrome 11+) 7249 if (file.name == ".") { 7250 // if it looks like a folder... 7251 return true; 7252 } 7253 } 5388 7254 5389 _options.required_caps = Basic.extend({}, _options.required_caps,{5390 return_response_type: self.responseType5391 });7255 if (file.webkitRelativePath) { 7256 relativePath = '/' + file.webkitRelativePath.replace(/^\//, ''); 7257 } 5392 7258 5393 if (data instanceof FormData) { 5394 _options.required_caps.send_multipart = true; 5395 } 7259 file = new File(I.uid, file); 7260 file.relativePath = relativePath; 7261 7262 comp.files.push(file); 7263 }); 7264 7265 // clearing the value enables the user to select the same file again if they want to 7266 if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') { 7267 this.value = ''; 7268 } else { 7269 // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it 7270 var clone = this.cloneNode(true); 7271 this.parentNode.replaceChild(clone, this); 7272 clone.onchange = onChange; 7273 } 7274 7275 if (comp.files.length) { 7276 comp.trigger('change'); 7277 } 7278 }; 7279 7280 // ready event is perfectly asynchronous 7281 comp.trigger({ 7282 type: 'ready', 7283 async: true 7284 }); 7285 7286 shimContainer = null; 7287 }, 7288 7289 7290 setOption: function(name, value) { 7291 var I = this.getRuntime(); 7292 var input = Dom.get(I.uid); 7293 7294 switch (name) { 7295 case 'accept': 7296 if (value) { 7297 var mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension')); 7298 input.setAttribute('accept', mimes.join(',')); 7299 } else { 7300 input.removeAttribute('accept'); 7301 } 7302 break; 5396 7303 5397 if (!Basic.isEmptyObj(_headers)) { 5398 _options.required_caps.send_custom_headers = true; 5399 } 7304 case 'directory': 7305 if (value && I.can('select_folder')) { 7306 input.setAttribute('directory', ''); 7307 input.setAttribute('webkitdirectory', ''); 7308 } else { 7309 input.removeAttribute('directory'); 7310 input.removeAttribute('webkitdirectory'); 7311 } 7312 break; 5400 7313 5401 if (!_same_origin_flag) { 5402 _options.required_caps.do_cors = true; 5403 } 5404 7314 case 'multiple': 7315 if (value && I.can('select_multiple')) { 7316 input.setAttribute('multiple', ''); 7317 } else { 7318 input.removeAttribute('multiple'); 7319 } 5405 7320 5406 if (_options.ruid) { // we do not need to wait if we can connect directly 5407 exec(_xhr.connectRuntime(_options)); 5408 } else { 5409 _xhr.bind('RuntimeInit', function(e, runtime) { 5410 exec(runtime); 5411 }); 5412 _xhr.bind('RuntimeError', function(e, err) { 5413 self.dispatchEvent('RuntimeError', err); 5414 }); 5415 _xhr.connectRuntime(_options); 5416 } 5417 } 5418 5419 5420 function _reset() { 5421 _p('responseText', ""); 5422 _p('responseXML', null); 5423 _p('response', null); 5424 _p('status', 0); 5425 _p('statusText', ""); 5426 _start_time = _timeoutset_time = null; 5427 } 5428 } 7321 } 7322 }, 5429 7323 5430 XMLHttpRequest.UNSENT = 0;5431 XMLHttpRequest.OPENED = 1;5432 XMLHttpRequest.HEADERS_RECEIVED = 2;5433 XMLHttpRequest.LOADING = 3;5434 XMLHttpRequest.DONE = 4;5435 5436 XMLHttpRequest.prototype = EventTarget.instance;5437 7324 5438 return XMLHttpRequest;5439 });7325 disable: function(state) { 7326 var I = this.getRuntime(), input; 5440 7327 5441 // Included from: src/javascript/runtime/Transporter.js 7328 if ((input = Dom.get(I.uid))) { 7329 input.disabled = !!state; 7330 } 7331 }, 5442 7332 5443 /** 5444 * Transporter.js 5445 * 5446 * Copyright 2013, Moxiecode Systems AB 5447 * Released under GPL License. 5448 * 5449 * License: http://www.plupload.com/license 5450 * Contributing: http://www.plupload.com/contributing 5451 */ 7333 destroy: function() { 7334 var I = this.getRuntime() 7335 , shim = I.getShim() 7336 , shimContainer = I.getShimContainer() 7337 , container = _options && Dom.get(_options.container) 7338 , browseButton = _options && Dom.get(_options.browse_button) 7339 ; 5452 7340 5453 define("moxie/runtime/Transporter", [ 5454 "moxie/core/utils/Basic", 5455 "moxie/core/utils/Encode", 5456 "moxie/runtime/RuntimeClient", 5457 "moxie/core/EventTarget" 5458 ], function(Basic, Encode, RuntimeClient, EventTarget) { 5459 function Transporter() { 5460 var mod, _runtime, _data, _size, _pos, _chunk_size; 7341 if (container) { 7342 Events.removeAllEvents(container, this.uid); 7343 } 5461 7344 5462 RuntimeClient.call(this); 7345 if (browseButton) { 7346 Events.removeAllEvents(browseButton, this.uid); 7347 browseButton.style.zIndex = _browseBtnZIndex; // reset to original value 7348 } 5463 7349 5464 Basic.extend(this, { 5465 uid: Basic.guid('uid_'), 7350 if (shimContainer) { 7351 Events.removeAllEvents(shimContainer, this.uid); 7352 shimContainer.innerHTML = ''; 7353 } 5466 7354 5467 state: Transporter.IDLE,7355 shim.removeInstance(this.uid); 5468 7356 5469 result: null, 7357 _options = shimContainer = container = browseButton = shim = null; 7358 } 7359 }); 7360 } 5470 7361 5471 transport: function(data, type, options) {5472 var self = this;7362 return (extensions.FileInput = FileInput); 7363 }); 5473 7364 5474 options = Basic.extend({ 5475 chunk_size: 204798 5476 }, options); 7365 // Included from: src/javascript/runtime/html5/file/FileDrop.js 5477 7366 5478 // should divide by three, base64 requires this 5479 if ((mod = options.chunk_size % 3)) { 5480 options.chunk_size += 3 - mod; 5481 } 7367 /** 7368 * FileDrop.js 7369 * 7370 * Copyright 2013, Moxiecode Systems AB 7371 * Released under GPL License. 7372 * 7373 * License: http://www.plupload.com/license 7374 * Contributing: http://www.plupload.com/contributing 7375 */ 5482 7376 5483 _chunk_size = options.chunk_size; 7377 /** 7378 @class moxie/runtime/html5/file/FileDrop 7379 @private 7380 */ 7381 define("moxie/runtime/html5/file/FileDrop", [ 7382 "moxie/runtime/html5/Runtime", 7383 'moxie/file/File', 7384 "moxie/core/utils/Basic", 7385 "moxie/core/utils/Dom", 7386 "moxie/core/utils/Events", 7387 "moxie/core/utils/Mime" 7388 ], function(extensions, File, Basic, Dom, Events, Mime) { 7389 7390 function FileDrop() { 7391 var _files = [], _allowedExts = [], _options, _ruid; 7392 7393 Basic.extend(this, { 7394 init: function(options) { 7395 var comp = this, dropZone; 7396 7397 _options = options; 7398 _ruid = comp.ruid; // every dropped-in file should have a reference to the runtime 7399 _allowedExts = _extractExts(_options.accept); 7400 dropZone = _options.container; 5484 7401 5485 _reset.call(this); 5486 _data = data; 5487 _size = data.length; 7402 Events.addEvent(dropZone, 'dragover', function(e) { 7403 if (!_hasFiles(e)) { 7404 return; 7405 } 7406 e.preventDefault(); 7407 e.dataTransfer.dropEffect = 'copy'; 7408 }, comp.uid); 5488 7409 5489 if (Basic.typeOf(options) === 'string' || options.ruid) { 5490 _run.call(self, type, this.connectRuntime(options)); 5491 } else { 5492 // we require this to run only once 5493 var cb = function(e, runtime) { 5494 self.unbind("RuntimeInit", cb); 5495 _run.call(self, type, runtime); 5496 }; 5497 this.bind("RuntimeInit", cb); 5498 this.connectRuntime(options); 5499 } 5500 }, 7410 Events.addEvent(dropZone, 'drop', function(e) { 7411 if (!_hasFiles(e)) { 7412 return; 7413 } 7414 e.preventDefault(); 5501 7415 5502 abort: function() { 5503 var self = this; 7416 _files = []; 5504 7417 5505 self.state = Transporter.IDLE; 5506 if (_runtime) { 5507 _runtime.exec.call(self, 'Transporter', 'clear'); 5508 self.trigger("TransportingAborted"); 5509 } 7418 // Chrome 21+ accepts folders via Drag'n'Drop 7419 if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) { 7420 _readItems(e.dataTransfer.items, function() { 7421 comp.files = _files; 7422 comp.trigger("drop"); 7423 }); 7424 } else { 7425 Basic.each(e.dataTransfer.files, function(file) { 7426 _addFile(file); 7427 }); 7428 comp.files = _files; 7429 comp.trigger("drop"); 7430 } 7431 }, comp.uid); 5510 7432 5511 _reset.call(self); 5512 }, 7433 Events.addEvent(dropZone, 'dragenter', function(e) { 7434 comp.trigger("dragenter"); 7435 }, comp.uid); 7436 7437 Events.addEvent(dropZone, 'dragleave', function(e) { 7438 comp.trigger("dragleave"); 7439 }, comp.uid); 7440 }, 7441 7442 destroy: function() { 7443 Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); 7444 _ruid = _files = _allowedExts = _options = null; 7445 this.getRuntime().getShim().removeInstance(this.uid); 7446 } 7447 }); 5513 7448 5514 7449 5515 destroy: function() { 5516 this.unbindAll(); 5517 _runtime = null; 5518 this.disconnectRuntime(); 5519 _reset.call(this); 5520 } 5521 }); 7450 function _hasFiles(e) { 7451 if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover 7452 return false; 7453 } 5522 7454 5523 function _reset() { 5524 _size = _pos = 0; 5525 _data = this.result = null; 5526 } 7455 var types = Basic.toArray(e.dataTransfer.types || []); 5527 7456 5528 function _run(type, runtime) { 5529 var self = this; 7457 return Basic.inArray("Files", types) !== -1 || 7458 Basic.inArray("public.file-url", types) !== -1 || // Safari < 5 7459 Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6) 7460 ; 7461 } 5530 7462 5531 _runtime = runtime;5532 7463 5533 //self.unbind("RuntimeInit"); 7464 function _addFile(file, relativePath) { 7465 if (_isAcceptable(file)) { 7466 var fileObj = new File(_ruid, file); 7467 fileObj.relativePath = relativePath || ''; 7468 _files.push(fileObj); 7469 } 7470 } 5534 7471 5535 self.bind("TransportingProgress", function(e) {5536 _pos = e.loaded;5537 7472 5538 if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) { 5539 _transport.call(self); 7473 function _extractExts(accept) { 7474 var exts = []; 7475 for (var i = 0; i < accept.length; i++) { 7476 [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/)); 7477 } 7478 return Basic.inArray('*', exts) === -1 ? exts : []; 5540 7479 } 5541 }, 999);5542 7480 5543 self.bind("TransportingComplete", function() {5544 _pos = _size;5545 self.state = Transporter.DONE;5546 _data = null; // clean a bit5547 self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || '');5548 }, 999);5549 5550 self.state = Transporter.BUSY;5551 self.trigger("TransportingStarted");5552 _transport.call(self);5553 }5554 7481 5555 function _transport() { 5556 var self = this, 5557 chunk, 5558 bytesLeft = _size - _pos; 7482 function _isAcceptable(file) { 7483 if (!_allowedExts.length) { 7484 return true; 7485 } 7486 var ext = Mime.getFileExtension(file.name); 7487 return !ext || Basic.inArray(ext, _allowedExts) !== -1; 7488 } 5559 7489 5560 if (_chunk_size > bytesLeft) {5561 _chunk_size = bytesLeft;5562 }5563 7490 5564 chunk = Encode.btoa(_data.substr(_pos, _chunk_size)); 5565 _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size); 5566 } 5567 } 7491 function _readItems(items, cb) { 7492 var entries = []; 7493 Basic.each(items, function(item) { 7494 var entry = item.webkitGetAsEntry(); 7495 // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579) 7496 if (entry) { 7497 // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61 7498 if (entry.isFile) { 7499 _addFile(item.getAsFile(), entry.fullPath); 7500 } else { 7501 entries.push(entry); 7502 } 7503 } 7504 }); 5568 7505 5569 Transporter.IDLE = 0; 5570 Transporter.BUSY = 1; 5571 Transporter.DONE = 2; 7506 if (entries.length) { 7507 _readEntries(entries, cb); 7508 } else { 7509 cb(); 7510 } 7511 } 5572 7512 5573 Transporter.prototype = EventTarget.instance;5574 7513 5575 return Transporter; 5576 }); 7514 function _readEntries(entries, cb) { 7515 var queue = []; 7516 Basic.each(entries, function(entry) { 7517 queue.push(function(cbcb) { 7518 _readEntry(entry, cbcb); 7519 }); 7520 }); 7521 Basic.inSeries(queue, function() { 7522 cb(); 7523 }); 7524 } 5577 7525 5578 // Included from: src/javascript/image/Image.js5579 7526 5580 /** 5581 * Image.js 5582 * 5583 * Copyright 2013, Moxiecode Systems AB 5584 * Released under GPL License. 5585 * 5586 * License: http://www.plupload.com/license 5587 * Contributing: http://www.plupload.com/contributing 5588 */ 7527 function _readEntry(entry, cb) { 7528 if (entry.isFile) { 7529 entry.file(function(file) { 7530 _addFile(file, entry.fullPath); 7531 cb(); 7532 }, function() { 7533 // fire an error event maybe 7534 cb(); 7535 }); 7536 } else if (entry.isDirectory) { 7537 _readDirEntry(entry, cb); 7538 } else { 7539 cb(); // not file, not directory? what then?.. 7540 } 7541 } 5589 7542 5590 define("moxie/image/Image", [5591 "moxie/core/utils/Basic",5592 "moxie/core/utils/Dom",5593 "moxie/core/Exceptions",5594 "moxie/file/FileReaderSync",5595 "moxie/xhr/XMLHttpRequest",5596 "moxie/runtime/Runtime",5597 "moxie/runtime/RuntimeClient",5598 "moxie/runtime/Transporter",5599 "moxie/core/utils/Env",5600 "moxie/core/EventTarget",5601 "moxie/file/Blob",5602 "moxie/file/File",5603 "moxie/core/utils/Encode"5604 ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {5605 /**5606 Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.5607 7543 5608 @class Image 5609 @constructor 5610 @extends EventTarget 5611 */ 5612 var dispatches = [ 5613 'progress', 7544 function _readDirEntry(dirEntry, cb) { 7545 var entries = [], dirReader = dirEntry.createReader(); 5614 7546 5615 /** 5616 Dispatched when loading is complete. 7547 // keep quering recursively till no more entries 7548 function getEntries(cbcb) { 7549 dirReader.readEntries(function(moreEntries) { 7550 if (moreEntries.length) { 7551 [].push.apply(entries, moreEntries); 7552 getEntries(cbcb); 7553 } else { 7554 cbcb(); 7555 } 7556 }, cbcb); 7557 } 5617 7558 5618 @event load 5619 @param {Object} event 5620 */ 5621 'load', 7559 // ...and you thought FileReader was crazy... 7560 getEntries(function() { 7561 _readEntries(entries, cb); 7562 }); 7563 } 7564 } 5622 7565 5623 'error', 7566 return (extensions.FileDrop = FileDrop); 7567 }); 5624 7568 5625 /** 5626 Dispatched when resize operation is complete. 5627 5628 @event resize 5629 @param {Object} event 5630 */ 5631 'resize', 7569 // Included from: src/javascript/runtime/html5/file/FileReader.js 5632 7570 5633 7571 /** 5634 Dispatched when visual representation of the image is successfully embedded 5635 into the corresponsing container. 7572 * FileReader.js 7573 * 7574 * Copyright 2013, Moxiecode Systems AB 7575 * Released under GPL License. 7576 * 7577 * License: http://www.plupload.com/license 7578 * Contributing: http://www.plupload.com/contributing 7579 */ 5636 7580 5637 @event embedded 5638 @param {Object} event 5639 */ 5640 'embedded' 5641 ]; 7581 /** 7582 @class moxie/runtime/html5/file/FileReader 7583 @private 7584 */ 7585 define("moxie/runtime/html5/file/FileReader", [ 7586 "moxie/runtime/html5/Runtime", 7587 "moxie/core/utils/Encode", 7588 "moxie/core/utils/Basic" 7589 ], function(extensions, Encode, Basic) { 5642 7590 5643 function Image() { 7591 function FileReader() { 7592 var _fr, _convertToBinary = false; 5644 7593 5645 RuntimeClient.call(this);7594 Basic.extend(this, { 5646 7595 5647 Basic.extend(this, { 5648 /** 5649 Unique id of the component 7596 read: function(op, blob) { 7597 var comp = this; 5650 7598 5651 @property uid 5652 @type {String} 5653 */ 5654 uid: Basic.guid('uid_'), 7599 comp.result = ''; 5655 7600 5656 /** 5657 Unique id of the connected runtime, if any. 7601 _fr = new window.FileReader(); 5658 7602 5659 @property ruid 5660 @type {String} 5661 */ 5662 ruid: null, 7603 _fr.addEventListener('progress', function(e) { 7604 comp.trigger(e); 7605 }); 5663 7606 5664 /** 5665 Name of the file, that was used to create an image, if available. If not equals to empty string. 7607 _fr.addEventListener('load', function(e) { 7608 comp.result = _convertToBinary ? _toBinary(_fr.result) : _fr.result; 7609 comp.trigger(e); 7610 }); 5666 7611 5667 @property name 5668 @type {String} 5669 @default "" 5670 */ 5671 name: "", 7612 _fr.addEventListener('error', function(e) { 7613 comp.trigger(e, _fr.error); 7614 }); 5672 7615 5673 /** 5674 Size of the image in bytes. Actual value is set only after image is preloaded. 7616 _fr.addEventListener('loadend', function(e) { 7617 _fr = null; 7618 comp.trigger(e); 7619 }); 5675 7620 5676 @property size 5677 @type {Number} 5678 @default 0 5679 */ 5680 size: 0, 7621 if (Basic.typeOf(_fr[op]) === 'function') { 7622 _convertToBinary = false; 7623 _fr[op](blob.getSource()); 7624 } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+ 7625 _convertToBinary = true; 7626 _fr.readAsDataURL(blob.getSource()); 7627 } 7628 }, 5681 7629 5682 /** 5683 Width of the image. Actual value is set only after image is preloaded. 7630 abort: function() { 7631 if (_fr) { 7632 _fr.abort(); 7633 } 7634 }, 5684 7635 5685 @property width5686 @type {Number}5687 @default 05688 */5689 width: 0,7636 destroy: function() { 7637 _fr = null; 7638 this.getRuntime().getShim().removeInstance(this.uid); 7639 } 7640 }); 5690 7641 5691 /** 5692 Height of the image. Actual value is set only after image is preloaded. 7642 function _toBinary(str) { 7643 return Encode.atob(str.substring(str.indexOf('base64,') + 7)); 7644 } 7645 } 5693 7646 5694 @property height 5695 @type {Number} 5696 @default 0 5697 */ 5698 height: 0, 7647 return (extensions.FileReader = FileReader); 7648 }); 5699 7649 5700 /** 5701 Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded. 7650 // Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js 5702 7651 5703 @property type 5704 @type {String} 5705 @default "" 5706 */ 5707 type: "", 7652 /** 7653 * XMLHttpRequest.js 7654 * 7655 * Copyright 2013, Moxiecode Systems AB 7656 * Released under GPL License. 7657 * 7658 * License: http://www.plupload.com/license 7659 * Contributing: http://www.plupload.com/contributing 7660 */ 5708 7661 5709 /** 5710 Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded. 7662 /*global ActiveXObject:true */ 5711 7663 5712 @property meta 5713 @type {Object} 5714 @default {} 5715 */ 5716 meta: {}, 7664 /** 7665 @class moxie/runtime/html5/xhr/XMLHttpRequest 7666 @private 7667 */ 7668 define("moxie/runtime/html5/xhr/XMLHttpRequest", [ 7669 "moxie/runtime/html5/Runtime", 7670 "moxie/core/utils/Basic", 7671 "moxie/core/utils/Mime", 7672 "moxie/core/utils/Url", 7673 "moxie/file/File", 7674 "moxie/file/Blob", 7675 "moxie/xhr/FormData", 7676 "moxie/core/Exceptions", 7677 "moxie/core/utils/Env" 7678 ], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) { 5717 7679 5718 /** 5719 Alias for load method, that takes another mOxie.Image object as a source (see load). 7680 function XMLHttpRequest() { 7681 var self = this 7682 , _xhr 7683 , _filename 7684 ; 5720 7685 5721 @method clone 5722 @param {Image} src Source for the image 5723 @param {Boolean} [exact=false] Whether to activate in-depth clone mode 5724 */ 5725 clone: function() { 5726 this.load.apply(this, arguments); 5727 }, 7686 Basic.extend(this, { 7687 send: function(meta, data) { 7688 var target = this 7689 , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<')) 7690 , isAndroidBrowser = Env.browser === 'Android Browser' 7691 , mustSendAsBinary = false 7692 ; 7693 7694 // extract file name 7695 _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase(); 7696 7697 _xhr = _getNativeXHR(); 7698 _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password); 7699 7700 7701 // prepare data to be sent 7702 if (data instanceof Blob) { 7703 if (data.isDetached()) { 7704 mustSendAsBinary = true; 7705 } 7706 data = data.getSource(); 7707 } else if (data instanceof FormData) { 5728 7708 5729 /** 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. 7709 if (data.hasBlob()) { 7710 if (data.getBlob().isDetached()) { 7711 data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state 7712 mustSendAsBinary = true; 7713 } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) { 7714 // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150 7715 // Android browsers (default one and Dolphin) seem to have the same issue, see: #613 7716 _preloadAndSend.call(target, meta, data); 7717 return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D 7718 } 7719 } 5733 7720 5734 @example 5735 var img = new mOxie.Image(); 5736 img.onload = function() { 5737 var blob = img.getAsBlob(); 5738 5739 var formData = new mOxie.FormData(); 5740 formData.append('file', blob); 7721 // transfer fields to real FormData 7722 if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart() 7723 var fd = new window.FormData(); 7724 data.each(function(value, name) { 7725 if (value instanceof Blob) { 7726 fd.append(name, value.getSource()); 7727 } else { 7728 fd.append(name, value); 7729 } 7730 }); 7731 data = fd; 7732 } 7733 } 5741 7734 5742 var xhr = new mOxie.XMLHttpRequest();5743 xhr.onload = function() {5744 // upload complete5745 };5746 xhr.open('post', 'upload.php');5747 xhr.send(formData);5748 };5749 img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)5750 5751 7735 5752 @method load 5753 @param {Image|Blob|File|String} src Source for the image 5754 @param {Boolean|Object} [mixed] 5755 */ 5756 load: function() { 5757 _load.apply(this, arguments); 5758 }, 7736 // if XHR L2 7737 if (_xhr.upload) { 7738 if (meta.withCredentials) { 7739 _xhr.withCredentials = true; 7740 } 5759 7741 5760 /** 5761 Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions. 7742 _xhr.addEventListener('load', function(e) { 7743 target.trigger(e); 7744 }); 5762 7745 5763 @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 5770 */ 5771 downsize: function(opts) { 5772 var defaults = { 5773 width: this.width, 5774 height: this.height, 5775 type: this.type || 'image/jpeg', 5776 quality: 90, 5777 crop: false, 5778 preserveHeaders: true, 5779 resample: false 5780 }; 7746 _xhr.addEventListener('error', function(e) { 7747 target.trigger(e); 7748 }); 5781 7749 5782 if (typeof(opts) === 'object') { 5783 opts = Basic.extend(defaults, opts); 5784 } else { 5785 // for backward compatibility 5786 opts = Basic.extend(defaults, { 5787 width: arguments[0], 5788 height: arguments[1], 5789 crop: arguments[2], 5790 preserveHeaders: arguments[3] 5791 }); 5792 } 7750 // additionally listen to progress events 7751 _xhr.addEventListener('progress', function(e) { 7752 target.trigger(e); 7753 }); 5793 7754 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 } 7755 _xhr.upload.addEventListener('progress', function(e) { 7756 target.trigger({ 7757 type: 'UploadProgress', 7758 loaded: e.loaded, 7759 total: e.total 7760 }); 7761 }); 7762 // ... otherwise simulate XHR L2 7763 } else { 7764 _xhr.onreadystatechange = function onReadyStateChange() { 5798 7765 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 } 7766 // fake Level 2 events 7767 switch (_xhr.readyState) { 5803 7768 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 } 5809 }, 7769 case 1: // XMLHttpRequest.OPENED 7770 // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu 7771 break; 7772 7773 // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu 7774 case 2: // XMLHttpRequest.HEADERS_RECEIVED 7775 break; 7776 7777 case 3: // XMLHttpRequest.LOADING 7778 // try to fire progress event for not XHR L2 7779 var total, loaded; 7780 7781 try { 7782 if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers 7783 total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here 7784 } 7785 7786 if (_xhr.responseText) { // responseText was introduced in IE7 7787 loaded = _xhr.responseText.length; 7788 } 7789 } catch(ex) { 7790 total = loaded = 0; 7791 } 7792 7793 target.trigger({ 7794 type: 'progress', 7795 lengthComputable: !!total, 7796 total: parseInt(total, 10), 7797 loaded: loaded 7798 }); 7799 break; 7800 7801 case 4: // XMLHttpRequest.DONE 7802 // release readystatechange handler (mostly for IE) 7803 _xhr.onreadystatechange = function() {}; 7804 7805 // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout 7806 try { 7807 if (_xhr.status >= 200 && _xhr.status < 400) { 7808 target.trigger('load'); 7809 break; 7810 } 7811 } catch(ex) {} 5810 7812 5811 /** 5812 Alias for downsize(width, height, true). (see downsize) 5813 5814 @method crop 5815 @param {Number} width Resulting width 5816 @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) 5817 @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) 5818 */ 5819 crop: function(width, height, preserveHeaders) { 5820 this.downsize(width, height, true, preserveHeaders); 5821 }, 7813 target.trigger('error'); 7814 break; 7815 } 7816 }; 7817 } 5822 7818 5823 getAsCanvas: function() {5824 if (!Env.can('create_canvas')) {5825 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);5826 }5827 7819 5828 var runtime = this.connectRuntime(this.ruid); 5829 return runtime.exec.call(this, 'Image', 'getAsCanvas'); 5830 }, 7820 // set request headers 7821 if (!Basic.isEmptyObj(meta.headers)) { 7822 Basic.each(meta.headers, function(value, header) { 7823 _xhr.setRequestHeader(header, value); 7824 }); 7825 } 5831 7826 5832 /** 5833 Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws 5834 DOMException.INVALID_STATE_ERR). 7827 // request response type 7828 if ("" !== meta.responseType && 'responseType' in _xhr) { 7829 if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one 7830 _xhr.responseType = 'text'; 7831 } else { 7832 _xhr.responseType = meta.responseType; 7833 } 7834 } 5835 7835 5836 @method getAsBlob 5837 @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png 5838 @param {Number} [quality=90] Applicable only together with mime type image/jpeg 5839 @return {Blob} Image as Blob 5840 */ 5841 getAsBlob: function(type, quality) { 5842 if (!this.size) { 5843 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5844 } 5845 return this.exec('Image', 'getAsBlob', type || 'image/jpeg', quality || 90); 5846 }, 7836 // send ... 7837 if (!mustSendAsBinary) { 7838 _xhr.send(data); 7839 } else { 7840 if (_xhr.sendAsBinary) { // Gecko 7841 _xhr.sendAsBinary(data); 7842 } else { // other browsers having support for typed arrays 7843 (function() { 7844 // mimic Gecko's sendAsBinary 7845 var ui8a = new Uint8Array(data.length); 7846 for (var i = 0; i < data.length; i++) { 7847 ui8a[i] = (data.charCodeAt(i) & 0xff); 7848 } 7849 _xhr.send(ui8a.buffer); 7850 }()); 7851 } 7852 } 5847 7853 5848 /** 5849 Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws 5850 DOMException.INVALID_STATE_ERR). 7854 target.trigger('loadstart'); 7855 }, 5851 7856 5852 @method getAsDataURL 5853 @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png 5854 @param {Number} [quality=90] Applicable only together with mime type image/jpeg 5855 @return {String} Image as dataURL string 5856 */ 5857 getAsDataURL: function(type, quality) { 5858 if (!this.size) { 5859 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5860 } 5861 return this.exec('Image', 'getAsDataURL', type || 'image/jpeg', quality || 90); 5862 }, 7857 getStatus: function() { 7858 // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception 7859 try { 7860 if (_xhr) { 7861 return _xhr.status; 7862 } 7863 } catch(ex) {} 7864 return 0; 7865 }, 5863 7866 5864 /** 5865 Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws 5866 DOMException.INVALID_STATE_ERR). 7867 getResponse: function(responseType) { 7868 var I = this.getRuntime(); 5867 7869 5868 @method getAsBinaryString 5869 @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png 5870 @param {Number} [quality=90] Applicable only together with mime type image/jpeg 5871 @return {String} Image as binary string 5872 */ 5873 getAsBinaryString: function(type, quality) { 5874 var dataUrl = this.getAsDataURL(type, quality); 5875 return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)); 5876 }, 7870 try { 7871 switch (responseType) { 7872 case 'blob': 7873 var file = new File(I.uid, _xhr.response); 7874 7875 // try to extract file name from content-disposition if possible (might be - not, if CORS for example) 7876 var disposition = _xhr.getResponseHeader('Content-Disposition'); 7877 if (disposition) { 7878 // extract filename from response header if available 7879 var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/); 7880 if (match) { 7881 _filename = match[2]; 7882 } 7883 } 7884 file.name = _filename; 5877 7885 5878 /** 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, 5881 can be used in legacy browsers that do not have canvas or proper dataURI support). 7886 // pre-webkit Opera doesn't set type property on the blob response 7887 if (!file.type) { 7888 file.type = Mime.getFileMime(_filename); 7889 } 7890 return file; 5882 7891 5883 @method embed 5884 @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 5891 */ 5892 embed: function(el, opts) { 5893 var self = this 5894 , runtime // this has to be outside of all the closures to contain proper runtime 5895 ; 7892 case 'json': 7893 if (!Env.can('return_response_type', 'json')) { 7894 return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null; 7895 } 7896 return _xhr.response; 5896 7897 5897 opts = Basic.extend({ 5898 width: this.width, 5899 height: this.height, 5900 type: this.type || 'image/jpeg', 5901 quality: 90 5902 }, opts || {}); 5903 5904 5905 function render(type, quality) { 5906 var img = this; 5907 5908 // if possible, embed a canvas element directly 5909 if (Env.can('create_canvas')) { 5910 var canvas = img.getAsCanvas(); 5911 if (canvas) { 5912 el.appendChild(canvas); 5913 canvas = null; 5914 img.destroy(); 5915 self.trigger('embedded'); 5916 return; 5917 } 5918 } 7898 case 'document': 7899 return _getDocument(_xhr); 5919 7900 5920 var dataUrl = img.getAsDataURL(type, quality); 5921 if (!dataUrl) { 5922 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 5923 } 7901 default: 7902 return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes 7903 } 7904 } catch(ex) { 7905 return null; 7906 } 7907 }, 5924 7908 5925 if (Env.can('use_data_uri_of', dataUrl.length)) {5926 el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" />';5927 img.destroy();5928 self.trigger('embedded');5929 } else {5930 var tr = new Transporter();7909 getAllResponseHeaders: function() { 7910 try { 7911 return _xhr.getAllResponseHeaders(); 7912 } catch(ex) {} 7913 return ''; 7914 }, 5931 7915 5932 tr.bind("TransportingComplete", function() { 5933 runtime = self.connectRuntime(this.result.ruid); 7916 abort: function() { 7917 if (_xhr) { 7918 _xhr.abort(); 7919 } 7920 }, 5934 7921 5935 self.bind("Embedded", function() { 5936 // position and size properly 5937 Basic.extend(runtime.getShimContainer().style, { 5938 //position: 'relative', 5939 top: '0px', 5940 left: '0px', 5941 width: img.width + 'px', 5942 height: img.height + 'px' 5943 }); 7922 destroy: function() { 7923 self = _filename = null; 7924 this.getRuntime().getShim().removeInstance(this.uid); 7925 } 7926 }); 5944 7927 5945 // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's5946 // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and5947 // sometimes 8 and they do not have this problem, we can comment this for now5948 /*tr.bind("RuntimeInit", function(e, runtime) {5949 tr.destroy();5950 runtime.destroy();5951 onResize.call(self); // re-feed our image data5952 });*/5953 7928 5954 runtime = null; // release 5955 }, 999); 7929 // here we go... ugly fix for ugly bug 7930 function _preloadAndSend(meta, data) { 7931 var target = this, blob, fr; 7932 7933 // get original blob 7934 blob = data.getBlob().getSource(); 7935 7936 // preload blob in memory to be sent as binary string 7937 fr = new window.FileReader(); 7938 fr.onload = function() { 7939 // overwrite original blob 7940 data.append(data.getBlobName(), new Blob(null, { 7941 type: blob.type, 7942 data: fr.result 7943 })); 7944 // invoke send operation again 7945 self.send.call(target, meta, data); 7946 }; 7947 fr.readAsBinaryString(blob); 7948 } 5956 7949 5957 runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);5958 img.destroy();5959 });5960 7950 5961 tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, { 5962 required_caps: { 5963 display_media: true 5964 }, 5965 runtime_order: 'flash,silverlight', 5966 container: el 5967 }); 7951 function _getNativeXHR() { 7952 if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy 7953 return new window.XMLHttpRequest(); 7954 } else { 7955 return (function() { 7956 var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0 7957 for (var i = 0; i < progIDs.length; i++) { 7958 try { 7959 return new ActiveXObject(progIDs[i]); 7960 } catch (ex) {} 7961 } 7962 })(); 5968 7963 } 5969 7964 } 5970 7965 5971 try {5972 if (!(el = Dom.get(el))) {5973 throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);5974 }7966 // @credits Sergey Ilinsky (http://www.ilinsky.com/) 7967 function _getDocument(xhr) { 7968 var rXML = xhr.responseXML; 7969 var rText = xhr.responseText; 5975 7970 5976 if (!this.size) { // only preloaded image objects can be used as source 5977 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 5978 } 5979 5980 // high-resolution images cannot be consistently handled across the runtimes 5981 if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { 5982 //throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); 7971 // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type) 7972 if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) { 7973 rXML = new window.ActiveXObject("Microsoft.XMLDOM"); 7974 rXML.async = false; 7975 rXML.validateOnParse = false; 7976 rXML.loadXML(rText); 5983 7977 } 5984 7978 5985 var imgCopy = new Image(); 7979 // Check if there is no error in document 7980 if (rXML) { 7981 if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") { 7982 return null; 7983 } 7984 } 7985 return rXML; 7986 } 5986 7987 5987 imgCopy.bind("Resize", function() {5988 render.call(this, opts.type, opts.quality);5989 });5990 7988 5991 imgCopy.bind("Load", function() { 5992 imgCopy.downsize(opts); 5993 }); 7989 function _prepareMultipart(fd) { 7990 var boundary = '----moxieboundary' + new Date().getTime() 7991 , dashdash = '--' 7992 , crlf = '\r\n' 7993 , multipart = '' 7994 , I = this.getRuntime() 7995 ; 5994 7996 5995 // if embedded thumb data is available and dimensions are big enough, use it 5996 if (this.meta.thumb && this.meta.thumb.width >= opts.width && this.meta.thumb.height >= opts.height) { 5997 imgCopy.load(this.meta.thumb.data); 5998 } else { 5999 imgCopy.clone(this, false); 7997 if (!I.can('send_binary_string')) { 7998 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); 6000 7999 } 6001 8000 6002 return imgCopy; 6003 } catch(ex) { 6004 // for now simply trigger error event 6005 this.trigger('error', ex.code); 6006 } 6007 }, 8001 _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); 6008 8002 6009 /** 6010 Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object. 8003 // append multipart parameters 8004 fd.each(function(value, name) { 8005 // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), 8006 // so we try it here ourselves with: unescape(encodeURIComponent(value)) 8007 if (value instanceof Blob) { 8008 // Build RFC2388 blob 8009 multipart += dashdash + boundary + crlf + 8010 'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf + 8011 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf + 8012 value.getSource() + crlf; 8013 } else { 8014 multipart += dashdash + boundary + crlf + 8015 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf + 8016 unescape(encodeURIComponent(value)) + crlf; 8017 } 8018 }); 6011 8019 6012 @method destroy 6013 */ 6014 destroy: function() { 6015 if (this.ruid) { 6016 this.getRuntime().exec.call(this, 'Image', 'destroy'); 6017 this.disconnectRuntime(); 8020 multipart += dashdash + boundary + dashdash + crlf; 8021 8022 return multipart; 6018 8023 } 6019 this.unbindAll();6020 8024 } 8025 8026 return (extensions.XMLHttpRequest = XMLHttpRequest); 6021 8027 }); 6022 8028 8029 // Included from: src/javascript/runtime/html5/utils/BinaryReader.js 6023 8030 6024 // this is here, because in order to bind properly, we need uid, which is created above 6025 this.handleEventProps(dispatches); 8031 /** 8032 * BinaryReader.js 8033 * 8034 * Copyright 2013, Moxiecode Systems AB 8035 * Released under GPL License. 8036 * 8037 * License: http://www.plupload.com/license 8038 * Contributing: http://www.plupload.com/contributing 8039 */ 6026 8040 6027 this.bind('Load Resize', function() { 6028 _updateInfo.call(this); 6029 }, 999); 8041 /** 8042 @class moxie/runtime/html5/utils/BinaryReader 8043 @private 8044 */ 8045 define("moxie/runtime/html5/utils/BinaryReader", [ 8046 "moxie/core/utils/Basic" 8047 ], function(Basic) { 6030 8048 6031 8049 6032 function _updateInfo(info) { 6033 if (!info) { 6034 info = this.exec('Image', 'getInfo'); 8050 function BinaryReader(data) { 8051 if (data instanceof ArrayBuffer) { 8052 ArrayBufferReader.apply(this, arguments); 8053 } else { 8054 UTF16StringReader.apply(this, arguments); 8055 } 6035 8056 } 6036 8057 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; 8058 Basic.extend(BinaryReader.prototype, { 6042 8059 6043 // update file name, only if empty 6044 if (this.name === '') { 6045 this.name = info.name; 6046 } 6047 } 6048 8060 littleEndian: false, 6049 8061 6050 function _load(src) {6051 var srcType = Basic.typeOf(src);6052 8062 6053 try { 6054 // if source is Image 6055 if (src instanceof Image) { 6056 if (!src.size) { // only preloaded image objects can be used as source 6057 throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); 6058 } 6059 _loadFromImage.apply(this, arguments); 6060 } 6061 // if source is o.Blob/o.File 6062 else if (src instanceof Blob) { 6063 if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) { 6064 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 6065 } 6066 _loadFromBlob.apply(this, arguments); 6067 } 6068 // if native blob/file 6069 else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) { 6070 _load.call(this, new File(null, src), arguments[1]); 6071 } 6072 // if String 6073 else if (srcType === 'string') { 6074 // if dataUrl String 6075 if (src.substr(0, 5) === 'data:') { 6076 _load.call(this, new Blob(null, { data: src }), arguments[1]); 8063 read: function(idx, size) { 8064 var sum, mv, i; 8065 8066 if (idx + size > this.length()) { 8067 throw new Error("You are trying to read outside the source boundaries."); 6077 8068 } 6078 // else assume Url, either relative or absolute 6079 else { 6080 _loadFromUrl.apply(this, arguments); 8069 8070 mv = this.littleEndian 8071 ? 0 8072 : -8 * (size - 1) 8073 ; 8074 8075 for (i = 0, sum = 0; i < size; i++) { 8076 sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8)); 6081 8077 } 6082 } 6083 // if source seems to be an img node 6084 else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') { 6085 _load.call(this, src.src, arguments[1]); 6086 } 6087 else { 6088 throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR); 6089 } 6090 } catch(ex) { 6091 // for now simply trigger error event 6092 this.trigger('error', ex.code); 6093 } 6094 } 8078 return sum; 8079 }, 6095 8080 6096 8081 6097 function _loadFromImage(img, exact) { 6098 var runtime = this.connectRuntime(img.ruid); 6099 this.ruid = runtime.uid; 6100 runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact)); 6101 } 8082 write: function(idx, num, size) { 8083 var mv, i, str = ''; 6102 8084 8085 if (idx > this.length()) { 8086 throw new Error("You are trying to write outside the source boundaries."); 8087 } 6103 8088 6104 function _loadFromBlob(blob, options) { 6105 var self = this; 8089 mv = this.littleEndian 8090 ? 0 8091 : -8 * (size - 1) 8092 ; 6106 8093 6107 self.name = blob.name || ''; 8094 for (i = 0; i < size; i++) { 8095 this.writeByteAt(idx + i, (num >> Math.abs(mv + i*8)) & 255); 8096 } 8097 }, 6108 8098 6109 function exec(runtime) {6110 self.ruid = runtime.uid;6111 runtime.exec.call(self, 'Image', 'loadFromBlob', blob);6112 }6113 8099 6114 if (blob.isDetached()) { 6115 this.bind('RuntimeInit', function(e, runtime) { 6116 exec(runtime); 6117 }); 8100 BYTE: function(idx) { 8101 return this.read(idx, 1); 8102 }, 6118 8103 6119 // convert to object representation6120 if (options && typeof(options.required_caps) === 'string') {6121 options.required_caps = Runtime.parseCaps(options.required_caps);6122 }6123 8104 6124 this.connectRuntime(Basic.extend({ 6125 required_caps: { 6126 access_image_binary: true, 6127 resize_image: true 6128 } 6129 }, options)); 6130 } else { 6131 exec(this.connectRuntime(blob.ruid)); 6132 } 6133 } 8105 SHORT: function(idx) { 8106 return this.read(idx, 2); 8107 }, 6134 8108 6135 8109 6136 function _loadFromUrl(url, options) { 6137 var self = this, xhr; 8110 LONG: function(idx) { 8111 return this.read(idx, 4); 8112 }, 6138 8113 6139 xhr = new XMLHttpRequest();6140 8114 6141 xhr.open('get', url); 6142 xhr.responseType = 'blob'; 8115 SLONG: function(idx) { // 2's complement notation 8116 var num = this.read(idx, 4); 8117 return (num > 2147483647 ? num - 4294967296 : num); 8118 }, 6143 8119 6144 xhr.onprogress = function(e) {6145 self.trigger(e);6146 };6147 8120 6148 xhr.onload = function() {6149 _loadFromBlob.call(self, xhr.response, true);6150 };8121 CHAR: function(idx) { 8122 return String.fromCharCode(this.read(idx, 1)); 8123 }, 6151 8124 6152 xhr.onerror = function(e) {6153 self.trigger(e);6154 };6155 8125 6156 xhr.onloadend = function() {6157 xhr.destroy();6158 };8126 STRING: function(idx, count) { 8127 return this.asArray('CHAR', idx, count).join(''); 8128 }, 6159 8129 6160 xhr.bind('RuntimeError', function(e, err) {6161 self.trigger('RuntimeError', err);6162 });6163 8130 6164 xhr.send(null, options); 6165 } 6166 } 8131 asArray: function(type, idx, count) { 8132 var values = []; 6167 8133 6168 // virtual world will crash on you if image has a resolution higher than this: 6169 Image.MAX_RESIZE_WIDTH = 8192; 6170 Image.MAX_RESIZE_HEIGHT = 8192; 8134 for (var i = 0; i < count; i++) { 8135 values[i] = this[type](idx + i); 8136 } 8137 return values; 8138 } 8139 }); 6171 8140 6172 Image.prototype = EventTarget.instance;6173 8141 6174 return Image;6175 });8142 function ArrayBufferReader(data) { 8143 var _dv = new DataView(data); 6176 8144 6177 // Included from: src/javascript/runtime/html5/Runtime.js 8145 Basic.extend(this, { 6178 8146 6179 /** 6180 * Runtime.js 6181 * 6182 * Copyright 2013, Moxiecode Systems AB 6183 * Released under GPL License. 6184 * 6185 * License: http://www.plupload.com/license 6186 * Contributing: http://www.plupload.com/contributing 6187 */ 8147 readByteAt: function(idx) { 8148 return _dv.getUint8(idx); 8149 }, 6188 8150 6189 /*global File:true */6190 8151 6191 /** 6192 Defines constructor for HTML5 runtime. 8152 writeByteAt: function(idx, value) { 8153 _dv.setUint8(idx, value); 8154 }, 6193 8155 6194 @class moxie/runtime/html5/Runtime6195 @private6196 */6197 define("moxie/runtime/html5/Runtime", [6198 "moxie/core/utils/Basic",6199 "moxie/core/Exceptions",6200 "moxie/runtime/Runtime",6201 "moxie/core/utils/Env"6202 ], function(Basic, x, Runtime, Env) {6203 6204 var type = "html5", extensions = {};6205 6206 function Html5Runtime(options) {6207 var I = this6208 , Test = Runtime.capTest6209 , True = Runtime.capTrue6210 ;6211 6212 var caps = Basic.extend({6213 access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL),6214 access_image_binary: function() {6215 return I.can('access_binary') && !!extensions.Image;6216 },6217 display_media: Test(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')),6218 do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()),6219 drag_and_drop: Test(function() {6220 // this comes directly from Modernizr: http://www.modernizr.com/6221 var div = document.createElement('div');6222 // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop6223 return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) &&6224 (Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>'));6225 }()),6226 filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest6227 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, '>='));6230 }()),6231 return_response_headers: True,6232 return_response_type: function(responseType) {6233 if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported6234 return true;6235 }6236 return Env.can('return_response_type', responseType);6237 },6238 return_status_code: True,6239 report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload),6240 resize_image: function() {6241 return I.can('access_binary') && Env.can('create_canvas');6242 },6243 select_file: function() {6244 return Env.can('use_fileinput') && window.File;6245 },6246 select_folder: function() {6247 return I.can('select_file') && Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=');6248 },6249 select_multiple: function() {6250 // it is buggy on Safari Windows and iOS6251 return I.can('select_file') &&6252 !(Env.browser === 'Safari' && Env.os === 'Windows') &&6253 !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.0", '>') && Env.verComp(Env.osVersion, "8.0.0", '<'));6254 },6255 send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))),6256 send_custom_headers: Test(window.XMLHttpRequest),6257 send_multipart: function() {6258 return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string');6259 },6260 slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)),6261 stream_upload: function(){6262 return I.can('slice_blob') && I.can('send_multipart');6263 },6264 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'])6270 );6271 },6272 upload_filesize: True6273 },6274 arguments[2]6275 );6276 8156 6277 Runtime.call(this, options, (arguments[1] || type), caps); 8157 SEGMENT: function(idx, size, value) { 8158 switch (arguments.length) { 8159 case 2: 8160 return data.slice(idx, idx + size); 6278 8161 8162 case 1: 8163 return data.slice(idx); 6279 8164 6280 Basic.extend(this, { 8165 case 3: 8166 if (value === null) { 8167 value = new ArrayBuffer(); 8168 } 6281 8169 6282 init : function() { 6283 this.trigger("Init"); 6284 }, 8170 if (value instanceof ArrayBuffer) { 8171 var arr = new Uint8Array(this.length() - size + value.byteLength); 8172 if (idx > 0) { 8173 arr.set(new Uint8Array(data.slice(0, idx)), 0); 8174 } 8175 arr.set(new Uint8Array(value), idx); 8176 arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength); 6285 8177 6286 destroy: (function(destroy) { // extend default destroy method 6287 return function() { 6288 destroy.call(I); 6289 destroy = I = null; 6290 }; 6291 }(this.destroy)) 6292 }); 8178 this.clear(); 8179 data = arr.buffer; 8180 _dv = new DataView(data); 8181 break; 8182 } 6293 8183 6294 Basic.extend(this.getShim(), extensions); 6295 } 8184 default: return data; 8185 } 8186 }, 6296 8187 6297 Runtime.addConstructor(type, Html5Runtime);6298 8188 6299 return extensions; 6300 }); 8189 length: function() { 8190 return data ? data.byteLength : 0; 8191 }, 6301 8192 6302 // Included from: src/javascript/core/utils/Events.js6303 8193 6304 /** 6305 * Events.js 6306 * 6307 * Copyright 2013, Moxiecode Systems AB 6308 * Released under GPL License. 6309 * 6310 * License: http://www.plupload.com/license 6311 * Contributing: http://www.plupload.com/contributing 6312 */ 8194 clear: function() { 8195 _dv = data = null; 8196 } 8197 }); 8198 } 6313 8199 6314 define('moxie/core/utils/Events', [6315 'moxie/core/utils/Basic'6316 ], function(Basic) {6317 var eventhash = {}, uid = 'moxie_' + Basic.guid();6318 6319 // IE W3C like event funcs6320 function preventDefault() {6321 this.returnValue = false;6322 }6323 8200 6324 function stopPropagation() { 6325 this.cancelBubble = true; 6326 } 8201 function UTF16StringReader(data) { 8202 Basic.extend(this, { 6327 8203 6328 /** 6329 Adds an event handler to the specified object and store reference to the handler 6330 in objects internal Plupload registry (@see removeEvent). 6331 6332 @method addEvent 6333 @for Utils 6334 @static 6335 @param {Object} obj DOM element like object to add handler to. 6336 @param {String} name Name to add event listener to. 6337 @param {Function} callback Function to call when event occurs. 6338 @param {String} [key] that might be used to add specifity to the event record. 6339 */ 6340 var addEvent = function(obj, name, callback, key) { 6341 var func, events; 6342 6343 name = name.toLowerCase(); 8204 readByteAt: function(idx) { 8205 return data.charCodeAt(idx); 8206 }, 8207 8208 8209 writeByteAt: function(idx, value) { 8210 putstr(String.fromCharCode(value), idx, 1); 8211 }, 8212 8213 8214 SEGMENT: function(idx, length, segment) { 8215 switch (arguments.length) { 8216 case 1: 8217 return data.substr(idx); 8218 case 2: 8219 return data.substr(idx, length); 8220 case 3: 8221 putstr(segment !== null ? segment : '', idx, length); 8222 break; 8223 default: return data; 8224 } 8225 }, 6344 8226 6345 // Add event listener6346 if (obj.addEventListener) {6347 func = callback;6348 6349 obj.addEventListener(name, func, false);6350 } else if (obj.attachEvent) {6351 func = function() {6352 var evt = window.event;6353 8227 6354 if (!evt.target) {6355 evt.target = evt.srcElement;6356 }8228 length: function() { 8229 return data ? data.length : 0; 8230 }, 6357 8231 6358 evt.preventDefault = preventDefault; 6359 evt.stopPropagation = stopPropagation; 8232 clear: function() { 8233 data = null; 8234 } 8235 }); 6360 8236 6361 callback(evt);6362 };6363 8237 6364 obj.attachEvent('on' + name, func); 6365 } 6366 6367 // Log event handler to objects internal mOxie registry 6368 if (!obj[uid]) { 6369 obj[uid] = Basic.guid(); 6370 } 6371 6372 if (!eventhash.hasOwnProperty(obj[uid])) { 6373 eventhash[obj[uid]] = {}; 6374 } 6375 6376 events = eventhash[obj[uid]]; 6377 6378 if (!events.hasOwnProperty(name)) { 6379 events[name] = []; 6380 } 6381 6382 events[name].push({ 6383 func: func, 6384 orig: callback, // store original callback for IE 6385 key: key 6386 }); 6387 }; 6388 6389 6390 /** 6391 Remove event handler from the specified object. If third argument (callback) 6392 is not specified remove all events with the specified name. 6393 6394 @method removeEvent 6395 @static 6396 @param {Object} obj DOM element to remove event listener(s) from. 6397 @param {String} name Name of event listener to remove. 6398 @param {Function|String} [callback] might be a callback or unique key to match. 6399 */ 6400 var removeEvent = function(obj, name, callback) { 6401 var type, undef; 6402 6403 name = name.toLowerCase(); 6404 6405 if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) { 6406 type = eventhash[obj[uid]][name]; 6407 } else { 6408 return; 6409 } 6410 6411 for (var i = type.length - 1; i >= 0; i--) { 6412 // undefined or not, key should match 6413 if (type[i].orig === callback || type[i].key === callback) { 6414 if (obj.removeEventListener) { 6415 obj.removeEventListener(name, type[i].func, false); 6416 } else if (obj.detachEvent) { 6417 obj.detachEvent('on'+name, type[i].func); 6418 } 6419 6420 type[i].orig = null; 6421 type[i].func = null; 6422 type.splice(i, 1); 6423 6424 // If callback was passed we are done here, otherwise proceed 6425 if (callback !== undef) { 6426 break; 8238 function putstr(segment, idx, length) { 8239 length = arguments.length === 3 ? length : data.length - idx - 1; 8240 data = data.substr(0, idx) + segment + data.substr(length + idx); 6427 8241 } 6428 8242 } 6429 }6430 6431 // If event array got empty, remove it6432 if (!type.length) {6433 delete eventhash[obj[uid]][name];6434 }6435 6436 // If mOxie registry has become empty, remove it6437 if (Basic.isEmptyObj(eventhash[obj[uid]])) {6438 delete eventhash[obj[uid]];6439 6440 // IE doesn't let you remove DOM object property with - delete6441 try {6442 delete obj[uid];6443 } catch(e) {6444 obj[uid] = undef;6445 }6446 }6447 };6448 6449 6450 /**6451 Remove all kind of events from the specified object6452 6453 @method removeAllEvents6454 @static6455 @param {Object} obj DOM element to remove event listeners from.6456 @param {String} [key] unique key to match, when removing events.6457 */6458 var removeAllEvents = function(obj, key) {6459 if (!obj || !obj[uid]) {6460 return;6461 }6462 6463 Basic.each(eventhash[obj[uid]], function(events, name) {6464 removeEvent(obj, name, key);6465 });6466 };6467 8243 6468 return {6469 addEvent: addEvent,6470 removeEvent: removeEvent,6471 removeAllEvents: removeAllEvents6472 };6473 });6474 8244 6475 // Included from: src/javascript/runtime/html5/file/FileInput.js 8245 return BinaryReader; 8246 }); 8247 8248 // Included from: src/javascript/runtime/html5/image/JPEGHeaders.js 6476 8249 6477 /**6478 * FileInput.js6479 *6480 * Copyright 2013, Moxiecode Systems AB6481 * Released under GPL License.6482 *6483 * License: http://www.plupload.com/license6484 * Contributing: http://www.plupload.com/contributing6485 */8250 /** 8251 * JPEGHeaders.js 8252 * 8253 * Copyright 2013, Moxiecode Systems AB 8254 * Released under GPL License. 8255 * 8256 * License: http://www.plupload.com/license 8257 * Contributing: http://www.plupload.com/contributing 8258 */ 6486 8259 6487 /**6488 @class moxie/runtime/html5/ file/FileInput8260 /** 8261 @class moxie/runtime/html5/image/JPEGHeaders 6489 8262 @private 6490 */ 6491 define("moxie/runtime/html5/file/FileInput", [ 6492 "moxie/runtime/html5/Runtime", 6493 "moxie/file/File", 6494 "moxie/core/utils/Basic", 6495 "moxie/core/utils/Dom", 6496 "moxie/core/utils/Events", 6497 "moxie/core/utils/Mime", 6498 "moxie/core/utils/Env" 6499 ], function(extensions, File, Basic, Dom, Events, Mime, Env) { 6500 6501 function FileInput() { 6502 var _options; 6503 6504 Basic.extend(this, { 6505 init: function(options) { 6506 var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top; 6507 6508 _options = options; 6509 6510 // figure out accept string 6511 mimes = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension')); 6512 6513 shimContainer = I.getShimContainer(); 6514 6515 shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' + 6516 (_options.multiple && I.can('select_multiple') ? 'multiple' : '') + 6517 (_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+ 6518 (mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />'; 6519 6520 input = Dom.get(I.uid); 6521 6522 // prepare file input to be placed underneath the browse_button element 6523 Basic.extend(input.style, { 6524 position: 'absolute', 6525 top: 0, 6526 left: 0, 6527 width: '100%', 6528 height: '100%' 6529 }); 8263 */ 8264 define("moxie/runtime/html5/image/JPEGHeaders", [ 8265 "moxie/runtime/html5/utils/BinaryReader", 8266 "moxie/core/Exceptions" 8267 ], function(BinaryReader, x) { 8268 8269 return function JPEGHeaders(data) { 8270 var headers = [], _br, idx, marker, length = 0; 8271 8272 _br = new BinaryReader(data); 8273 8274 // Check if data is jpeg 8275 if (_br.SHORT(0) !== 0xFFD8) { 8276 _br.clear(); 8277 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 8278 } 6530 8279 8280 idx = 2; 6531 8281 6532 browseButton = Dom.get(_options.browse_button); 8282 while (idx <= _br.length()) { 8283 marker = _br.SHORT(idx); 6533 8284 6534 // Route click event to the input[type=file] element for browsers that support such behavior6535 if (I.can('summon_file_dialog')) {6536 if (Dom.getStyle(browseButton, 'position') === 'static') {6537 browseButton.style.position = 'relative';8285 // omit RST (restart) markers 8286 if (marker >= 0xFFD0 && marker <= 0xFFD7) { 8287 idx += 2; 8288 continue; 6538 8289 } 6539 8290 6540 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; 8291 // no headers allowed after SOS marker 8292 if (marker === 0xFFDA || marker === 0xFFD9) { 8293 break; 8294 } 6541 8295 6542 browseButton.style.zIndex = zIndex; 6543 shimContainer.style.zIndex = zIndex - 1; 8296 length = _br.SHORT(idx + 2) + 2; 6544 8297 6545 Events.addEvent(browseButton, 'click', function(e) { 6546 var input = Dom.get(I.uid); 6547 if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] 6548 input.click(); 6549 } 6550 e.preventDefault(); 6551 }, comp.uid); 6552 } 8298 // APPn marker detected 8299 if (marker >= 0xFFE1 && marker <= 0xFFEF) { 8300 headers.push({ 8301 hex: marker, 8302 name: 'APP' + (marker & 0x000F), 8303 start: idx, 8304 length: length, 8305 segment: _br.SEGMENT(idx, length) 8306 }); 8307 } 6553 8308 6554 /* Since we have to place input[type=file] on top of the browse_button for some browsers, 6555 browse_button loses interactivity, so we restore it here */ 6556 top = I.can('summon_file_dialog') ? browseButton : shimContainer; 8309 idx += length; 8310 } 6557 8311 6558 Events.addEvent(top, 'mouseover', function() { 6559 comp.trigger('mouseenter'); 6560 }, comp.uid); 8312 _br.clear(); 6561 8313 6562 Events.addEvent(top, 'mouseout', function() { 6563 comp.trigger('mouseleave'); 6564 }, comp.uid); 8314 return { 8315 headers: headers, 6565 8316 6566 Events.addEvent(top, 'mousedown', function() { 6567 comp.trigger('mousedown'); 6568 }, comp.uid); 8317 restore: function(data) { 8318 var max, i, br; 6569 8319 6570 Events.addEvent(Dom.get(_options.container), 'mouseup', function() { 6571 comp.trigger('mouseup'); 6572 }, comp.uid); 8320 br = new BinaryReader(data); 6573 8321 8322 idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2; 6574 8323 6575 input.onchange = function onChange(e) { // there should be only one handler for this 6576 comp.files = []; 8324 for (i = 0, max = headers.length; i < max; i++) { 8325 br.SEGMENT(idx, 0, headers[i].segment); 8326 idx += headers[i].length; 8327 } 6577 8328 6578 Basic.each(this.files, function(file) { 6579 var relativePath = ''; 8329 data = br.SEGMENT(); 8330 br.clear(); 8331 return data; 8332 }, 8333 8334 strip: function(data) { 8335 var br, headers, jpegHeaders, i; 8336 8337 jpegHeaders = new JPEGHeaders(data); 8338 headers = jpegHeaders.headers; 8339 jpegHeaders.purge(); 8340 8341 br = new BinaryReader(data); 8342 8343 i = headers.length; 8344 while (i--) { 8345 br.SEGMENT(headers[i].start, headers[i].length, ''); 8346 } 6580 8347 6581 if (_options.directory) { 6582 // folders are represented by dots, filter them out (Chrome 11+) 6583 if (file.name == ".") { 6584 // if it looks like a folder... 6585 return true; 8348 data = br.SEGMENT(); 8349 br.clear(); 8350 return data; 8351 }, 8352 8353 get: function(name) { 8354 var array = []; 8355 8356 for (var i = 0, max = headers.length; i < max; i++) { 8357 if (headers[i].name === name.toUpperCase()) { 8358 array.push(headers[i].segment); 6586 8359 } 6587 8360 } 8361 return array; 8362 }, 8363 8364 set: function(name, segment) { 8365 var array = [], i, ii, max; 6588 8366 6589 if (file.webkitRelativePath) { 6590 relativePath = '/' + file.webkitRelativePath.replace(/^\//, ''); 8367 if (typeof(segment) === 'string') { 8368 array.push(segment); 8369 } else { 8370 array = segment; 6591 8371 } 6592 6593 file = new File(I.uid, file);6594 file.relativePath = relativePath;6595 8372 6596 comp.files.push(file); 6597 }); 8373 for (i = ii = 0, max = headers.length; i < max; i++) { 8374 if (headers[i].name === name.toUpperCase()) { 8375 headers[i].segment = array[ii]; 8376 headers[i].length = array[ii].length; 8377 ii++; 8378 } 8379 if (ii >= array.length) { 8380 break; 8381 } 8382 } 8383 }, 6598 8384 6599 // clearing the value enables the user to select the same file again if they want to 6600 if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') { 6601 this.value = ''; 6602 } else { 6603 // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it 6604 var clone = this.cloneNode(true); 6605 this.parentNode.replaceChild(clone, this); 6606 clone.onchange = onChange; 8385 purge: function() { 8386 this.headers = headers = []; 6607 8387 } 8388 }; 8389 }; 8390 }); 6608 8391 6609 if (comp.files.length) { 6610 comp.trigger('change'); 8392 // Included from: src/javascript/runtime/html5/image/ExifParser.js 8393 8394 /** 8395 * ExifParser.js 8396 * 8397 * Copyright 2013, Moxiecode Systems AB 8398 * Released under GPL License. 8399 * 8400 * License: http://www.plupload.com/license 8401 * Contributing: http://www.plupload.com/contributing 8402 */ 8403 8404 /** 8405 @class moxie/runtime/html5/image/ExifParser 8406 @private 8407 */ 8408 define("moxie/runtime/html5/image/ExifParser", [ 8409 "moxie/core/utils/Basic", 8410 "moxie/runtime/html5/utils/BinaryReader", 8411 "moxie/core/Exceptions" 8412 ], function(Basic, BinaryReader, x) { 8413 8414 function ExifParser(data) { 8415 var __super__, tags, tagDescs, offsets, idx, Tiff; 8416 8417 BinaryReader.call(this, data); 8418 8419 tags = { 8420 tiff: { 8421 /* 8422 The image orientation viewed in terms of rows and columns. 8423 8424 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. 8425 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. 8426 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. 8427 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. 8428 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. 8429 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. 8430 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. 8431 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. 8432 */ 8433 0x0112: 'Orientation', 8434 0x010E: 'ImageDescription', 8435 0x010F: 'Make', 8436 0x0110: 'Model', 8437 0x0131: 'Software', 8438 0x8769: 'ExifIFDPointer', 8439 0x8825: 'GPSInfoIFDPointer' 8440 }, 8441 exif: { 8442 0x9000: 'ExifVersion', 8443 0xA001: 'ColorSpace', 8444 0xA002: 'PixelXDimension', 8445 0xA003: 'PixelYDimension', 8446 0x9003: 'DateTimeOriginal', 8447 0x829A: 'ExposureTime', 8448 0x829D: 'FNumber', 8449 0x8827: 'ISOSpeedRatings', 8450 0x9201: 'ShutterSpeedValue', 8451 0x9202: 'ApertureValue' , 8452 0x9207: 'MeteringMode', 8453 0x9208: 'LightSource', 8454 0x9209: 'Flash', 8455 0x920A: 'FocalLength', 8456 0xA402: 'ExposureMode', 8457 0xA403: 'WhiteBalance', 8458 0xA406: 'SceneCaptureType', 8459 0xA404: 'DigitalZoomRatio', 8460 0xA408: 'Contrast', 8461 0xA409: 'Saturation', 8462 0xA40A: 'Sharpness' 8463 }, 8464 gps: { 8465 0x0000: 'GPSVersionID', 8466 0x0001: 'GPSLatitudeRef', 8467 0x0002: 'GPSLatitude', 8468 0x0003: 'GPSLongitudeRef', 8469 0x0004: 'GPSLongitude' 8470 }, 8471 8472 thumb: { 8473 0x0201: 'JPEGInterchangeFormat', 8474 0x0202: 'JPEGInterchangeFormatLength' 6611 8475 } 6612 8476 }; 6613 8477 6614 // ready event is perfectly asynchronous 6615 comp.trigger({ 6616 type: 'ready', 6617 async: true 6618 }); 8478 tagDescs = { 8479 'ColorSpace': { 8480 1: 'sRGB', 8481 0: 'Uncalibrated' 8482 }, 8483 8484 'MeteringMode': { 8485 0: 'Unknown', 8486 1: 'Average', 8487 2: 'CenterWeightedAverage', 8488 3: 'Spot', 8489 4: 'MultiSpot', 8490 5: 'Pattern', 8491 6: 'Partial', 8492 255: 'Other' 8493 }, 8494 8495 'LightSource': { 8496 1: 'Daylight', 8497 2: 'Fliorescent', 8498 3: 'Tungsten', 8499 4: 'Flash', 8500 9: 'Fine weather', 8501 10: 'Cloudy weather', 8502 11: 'Shade', 8503 12: 'Daylight fluorescent (D 5700 - 7100K)', 8504 13: 'Day white fluorescent (N 4600 -5400K)', 8505 14: 'Cool white fluorescent (W 3900 - 4500K)', 8506 15: 'White fluorescent (WW 3200 - 3700K)', 8507 17: 'Standard light A', 8508 18: 'Standard light B', 8509 19: 'Standard light C', 8510 20: 'D55', 8511 21: 'D65', 8512 22: 'D75', 8513 23: 'D50', 8514 24: 'ISO studio tungsten', 8515 255: 'Other' 8516 }, 8517 8518 'Flash': { 8519 0x0000: 'Flash did not fire', 8520 0x0001: 'Flash fired', 8521 0x0005: 'Strobe return light not detected', 8522 0x0007: 'Strobe return light detected', 8523 0x0009: 'Flash fired, compulsory flash mode', 8524 0x000D: 'Flash fired, compulsory flash mode, return light not detected', 8525 0x000F: 'Flash fired, compulsory flash mode, return light detected', 8526 0x0010: 'Flash did not fire, compulsory flash mode', 8527 0x0018: 'Flash did not fire, auto mode', 8528 0x0019: 'Flash fired, auto mode', 8529 0x001D: 'Flash fired, auto mode, return light not detected', 8530 0x001F: 'Flash fired, auto mode, return light detected', 8531 0x0020: 'No flash function', 8532 0x0041: 'Flash fired, red-eye reduction mode', 8533 0x0045: 'Flash fired, red-eye reduction mode, return light not detected', 8534 0x0047: 'Flash fired, red-eye reduction mode, return light detected', 8535 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode', 8536 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', 8537 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', 8538 0x0059: 'Flash fired, auto mode, red-eye reduction mode', 8539 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', 8540 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode' 8541 }, 8542 8543 'ExposureMode': { 8544 0: 'Auto exposure', 8545 1: 'Manual exposure', 8546 2: 'Auto bracket' 8547 }, 8548 8549 'WhiteBalance': { 8550 0: 'Auto white balance', 8551 1: 'Manual white balance' 8552 }, 8553 8554 'SceneCaptureType': { 8555 0: 'Standard', 8556 1: 'Landscape', 8557 2: 'Portrait', 8558 3: 'Night scene' 8559 }, 8560 8561 'Contrast': { 8562 0: 'Normal', 8563 1: 'Soft', 8564 2: 'Hard' 8565 }, 8566 8567 'Saturation': { 8568 0: 'Normal', 8569 1: 'Low saturation', 8570 2: 'High saturation' 8571 }, 8572 8573 'Sharpness': { 8574 0: 'Normal', 8575 1: 'Soft', 8576 2: 'Hard' 8577 }, 8578 8579 // GPS related 8580 'GPSLatitudeRef': { 8581 N: 'North latitude', 8582 S: 'South latitude' 8583 }, 8584 8585 'GPSLongitudeRef': { 8586 E: 'East longitude', 8587 W: 'West longitude' 8588 } 8589 }; 6619 8590 6620 shimContainer = null; 6621 }, 8591 offsets = { 8592 tiffHeader: 10 8593 }; 6622 8594 8595 idx = offsets.tiffHeader; 6623 8596 6624 disable: function(state) { 6625 var I = this.getRuntime(), input; 8597 __super__ = { 8598 clear: this.clear 8599 }; 6626 8600 6627 if ((input = Dom.get(I.uid))) { 6628 input.disabled = !!state; 6629 } 6630 }, 8601 // Public functions 8602 Basic.extend(this, { 6631 8603 6632 destroy: function() { 6633 var I = this.getRuntime() 6634 , shim = I.getShim() 6635 , shimContainer = I.getShimContainer() 6636 ; 6637 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); 6641 6642 if (shimContainer) { 6643 shimContainer.innerHTML = ''; 6644 } 8604 read: function() { 8605 try { 8606 return ExifParser.prototype.read.apply(this, arguments); 8607 } catch (ex) { 8608 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8609 } 8610 }, 6645 8611 6646 shim.removeInstance(this.uid);6647 8612 6648 _options = shimContainer = shim = null; 6649 } 6650 }); 6651 } 8613 write: function() { 8614 try { 8615 return ExifParser.prototype.write.apply(this, arguments); 8616 } catch (ex) { 8617 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8618 } 8619 }, 6652 8620 6653 return (extensions.FileInput = FileInput);6654 });6655 8621 6656 // Included from: src/javascript/runtime/html5/file/Blob.js 8622 UNDEFINED: function() { 8623 return this.BYTE.apply(this, arguments); 8624 }, 6657 8625 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 8626 6668 /** 6669 @class moxie/runtime/html5/file/Blob 6670 @private 6671 */ 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; 8627 RATIONAL: function(idx) { 8628 return this.LONG(idx) / this.LONG(idx + 4) 8629 }, 6680 8630 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 8631 6697 this.slice = function() { 6698 return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments)); 6699 }; 6700 } 8632 SRATIONAL: function(idx) { 8633 return this.SLONG(idx) / this.SLONG(idx + 4) 8634 }, 6701 8635 6702 return (extensions.Blob = HTML5Blob); 6703 }); 8636 ASCII: function(idx) { 8637 return this.CHAR(idx); 8638 }, 6704 8639 6705 // Included from: src/javascript/runtime/html5/file/FileDrop.js 8640 TIFF: function() { 8641 return Tiff || null; 8642 }, 6706 8643 6707 /**6708 * FileDrop.js6709 *6710 * Copyright 2013, Moxiecode Systems AB6711 * Released under GPL License.6712 *6713 * License: http://www.plupload.com/license6714 * Contributing: http://www.plupload.com/contributing6715 */6716 8644 6717 /** 6718 @class moxie/runtime/html5/file/FileDrop 6719 @private 6720 */ 6721 define("moxie/runtime/html5/file/FileDrop", [ 6722 "moxie/runtime/html5/Runtime", 6723 'moxie/file/File', 6724 "moxie/core/utils/Basic", 6725 "moxie/core/utils/Dom", 6726 "moxie/core/utils/Events", 6727 "moxie/core/utils/Mime" 6728 ], function(extensions, File, Basic, Dom, Events, Mime) { 6729 6730 function FileDrop() { 6731 var _files = [], _allowedExts = [], _options, _ruid; 6732 6733 Basic.extend(this, { 6734 init: function(options) { 6735 var comp = this, dropZone; 6736 6737 _options = options; 6738 _ruid = comp.ruid; // every dropped-in file should have a reference to the runtime 6739 _allowedExts = _extractExts(_options.accept); 6740 dropZone = _options.container; 8645 EXIF: function() { 8646 var Exif = null; 6741 8647 6742 Events.addEvent(dropZone, 'dragover', function(e) { 6743 if (!_hasFiles(e)) { 6744 return; 6745 } 6746 e.preventDefault(); 6747 e.dataTransfer.dropEffect = 'copy'; 6748 }, comp.uid); 8648 if (offsets.exifIFD) { 8649 try { 8650 Exif = extractTags.call(this, offsets.exifIFD, tags.exif); 8651 } catch(ex) { 8652 return null; 8653 } 6749 8654 6750 Events.addEvent(dropZone, 'drop', function(e) { 6751 if (!_hasFiles(e)) { 6752 return; 6753 } 6754 e.preventDefault(); 8655 // Fix formatting of some tags 8656 if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') { 8657 for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) { 8658 exifVersion += String.fromCharCode(Exif.ExifVersion[i]); 8659 } 8660 Exif.ExifVersion = exifVersion; 8661 } 8662 } 6755 8663 6756 _files = []; 8664 return Exif; 8665 }, 6757 8666 6758 // Chrome 21+ accepts folders via Drag'n'Drop6759 if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) {6760 _readItems(e.dataTransfer.items, function() {6761 comp.files = _files;6762 comp.trigger("drop");6763 });6764 } else {6765 Basic.each(e.dataTransfer.files, function(file) {6766 _addFile(file);6767 });6768 comp.files = _files;6769 comp.trigger("drop");6770 }6771 }, comp.uid);6772 8667 6773 Events.addEvent(dropZone, 'dragenter', function(e) { 6774 comp.trigger("dragenter"); 6775 }, comp.uid); 8668 GPS: function() { 8669 var GPS = null; 6776 8670 6777 Events.addEvent(dropZone, 'dragleave', function(e) { 6778 comp.trigger("dragleave"); 6779 }, comp.uid); 6780 }, 8671 if (offsets.gpsIFD) { 8672 try { 8673 GPS = extractTags.call(this, offsets.gpsIFD, tags.gps); 8674 } catch (ex) { 8675 return null; 8676 } 6781 8677 6782 destroy: function() {6783 Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);6784 _ruid = _files = _allowedExts = _options = null;6785 }6786 });8678 // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..) 8679 if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') { 8680 GPS.GPSVersionID = GPS.GPSVersionID.join('.'); 8681 } 8682 } 6787 8683 8684 return GPS; 8685 }, 6788 8686 6789 function _hasFiles(e) {6790 if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover6791 return false;6792 }6793 8687 6794 var types = Basic.toArray(e.dataTransfer.types || []); 8688 thumb: function() { 8689 if (offsets.IFD1) { 8690 try { 8691 var IFD1Tags = extractTags.call(this, offsets.IFD1, tags.thumb); 6795 8692 6796 return Basic.inArray("Files", types) !== -1 || 6797 Basic.inArray("public.file-url", types) !== -1 || // Safari < 5 6798 Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6) 6799 ; 6800 } 8693 if ('JPEGInterchangeFormat' in IFD1Tags) { 8694 return this.SEGMENT(offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength); 8695 } 8696 } catch (ex) {} 8697 } 8698 return null; 8699 }, 6801 8700 6802 8701 6803 function _addFile(file, relativePath) { 6804 if (_isAcceptable(file)) { 6805 var fileObj = new File(_ruid, file); 6806 fileObj.relativePath = relativePath || ''; 6807 _files.push(fileObj); 6808 } 6809 } 8702 setExif: function(tag, value) { 8703 // Right now only setting of width/height is possible 8704 if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; } 6810 8705 6811 6812 function _extractExts(accept) { 6813 var exts = []; 6814 for (var i = 0; i < accept.length; i++) { 6815 [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/)); 6816 } 6817 return Basic.inArray('*', exts) === -1 ? exts : []; 6818 } 8706 return setTag.call(this, 'exif', tag, value); 8707 }, 6819 8708 6820 8709 6821 function _isAcceptable(file) { 6822 if (!_allowedExts.length) { 6823 return true; 6824 } 6825 var ext = Mime.getFileExtension(file.name); 6826 return !ext || Basic.inArray(ext, _allowedExts) !== -1; 6827 } 8710 clear: function() { 8711 __super__.clear(); 8712 data = tags = tagDescs = Tiff = offsets = __super__ = null; 8713 } 8714 }); 6828 8715 6829 8716 6830 function _readItems(items, cb) { 6831 var entries = []; 6832 Basic.each(items, function(item) { 6833 var entry = item.webkitGetAsEntry(); 6834 // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579) 6835 if (entry) { 6836 // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61 6837 if (entry.isFile) { 6838 _addFile(item.getAsFile(), entry.fullPath); 6839 } else { 6840 entries.push(entry); 6841 } 8717 // Check if that's APP1 and that it has EXIF 8718 if (this.SHORT(0) !== 0xFFE1 || this.STRING(4, 5).toUpperCase() !== "EXIF\0") { 8719 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 6842 8720 } 6843 });6844 8721 6845 if (entries.length) { 6846 _readEntries(entries, cb); 6847 } else { 6848 cb(); 6849 } 6850 } 8722 // Set read order of multi-byte data 8723 this.littleEndian = (this.SHORT(idx) == 0x4949); 6851 8724 8725 // Check if always present bytes are indeed present 8726 if (this.SHORT(idx+=2) !== 0x002A) { 8727 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8728 } 6852 8729 6853 function _readEntries(entries, cb) { 6854 var queue = []; 6855 Basic.each(entries, function(entry) { 6856 queue.push(function(cbcb) { 6857 _readEntry(entry, cbcb); 6858 }); 6859 }); 6860 Basic.inSeries(queue, function() { 6861 cb(); 6862 }); 6863 } 8730 offsets.IFD0 = offsets.tiffHeader + this.LONG(idx += 2); 8731 Tiff = extractTags.call(this, offsets.IFD0, tags.tiff); 6864 8732 8733 if ('ExifIFDPointer' in Tiff) { 8734 offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer; 8735 delete Tiff.ExifIFDPointer; 8736 } 6865 8737 6866 function _readEntry(entry, cb) { 6867 if (entry.isFile) { 6868 entry.file(function(file) { 6869 _addFile(file, entry.fullPath); 6870 cb(); 6871 }, function() { 6872 // fire an error event maybe 6873 cb(); 6874 }); 6875 } else if (entry.isDirectory) { 6876 _readDirEntry(entry, cb); 6877 } else { 6878 cb(); // not file, not directory? what then?.. 6879 } 6880 } 8738 if ('GPSInfoIFDPointer' in Tiff) { 8739 offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer; 8740 delete Tiff.GPSInfoIFDPointer; 8741 } 6881 8742 8743 if (Basic.isEmptyObj(Tiff)) { 8744 Tiff = null; 8745 } 6882 8746 6883 function _readDirEntry(dirEntry, cb) { 6884 var entries = [], dirReader = dirEntry.createReader(); 8747 // check if we have a thumb as well 8748 var IFD1Offset = this.LONG(offsets.IFD0 + this.SHORT(offsets.IFD0) * 12 + 2); 8749 if (IFD1Offset) { 8750 offsets.IFD1 = offsets.tiffHeader + IFD1Offset; 8751 } 6885 8752 6886 // keep quering recursively till no more entries6887 function getEntries(cbcb) {6888 dirReader.readEntries(function(moreEntries) {6889 if (moreEntries.length) {6890 [].push.apply(entries, moreEntries);6891 getEntries(cbcb);6892 } else {6893 cbcb();6894 }6895 }, cbcb);6896 }6897 8753 6898 // ...and you thought FileReader was crazy... 6899 getEntries(function() { 6900 _readEntries(entries, cb); 6901 }); 6902 } 6903 } 8754 function extractTags(IFD_offset, tags2extract) { 8755 var data = this; 8756 var length, i, tag, type, count, size, offset, value, values = [], hash = {}; 6904 8757 6905 return (extensions.FileDrop = FileDrop); 6906 }); 8758 var types = { 8759 1 : 'BYTE', 8760 7 : 'UNDEFINED', 8761 2 : 'ASCII', 8762 3 : 'SHORT', 8763 4 : 'LONG', 8764 5 : 'RATIONAL', 8765 9 : 'SLONG', 8766 10: 'SRATIONAL' 8767 }; 6907 8768 6908 // Included from: src/javascript/runtime/html5/file/FileReader.js 8769 var sizes = { 8770 'BYTE' : 1, 8771 'UNDEFINED' : 1, 8772 'ASCII' : 1, 8773 'SHORT' : 2, 8774 'LONG' : 4, 8775 'RATIONAL' : 8, 8776 'SLONG' : 4, 8777 'SRATIONAL' : 8 8778 }; 6909 8779 6910 /** 6911 * FileReader.js 6912 * 6913 * Copyright 2013, Moxiecode Systems AB 6914 * Released under GPL License. 6915 * 6916 * License: http://www.plupload.com/license 6917 * Contributing: http://www.plupload.com/contributing 6918 */ 8780 length = data.SHORT(IFD_offset); 6919 8781 6920 /** 6921 @class moxie/runtime/html5/file/FileReader 6922 @private 6923 */ 6924 define("moxie/runtime/html5/file/FileReader", [ 6925 "moxie/runtime/html5/Runtime", 6926 "moxie/core/utils/Encode", 6927 "moxie/core/utils/Basic" 6928 ], function(extensions, Encode, Basic) { 6929 6930 function FileReader() { 6931 var _fr, _convertToBinary = false; 6932 6933 Basic.extend(this, { 6934 6935 read: function(op, blob) { 6936 var comp = this; 8782 // The size of APP1 including all these elements shall not exceed the 64 Kbytes specified in the JPEG standard. 6937 8783 6938 comp.result = ''; 8784 for (i = 0; i < length; i++) { 8785 values = []; 6939 8786 6940 _fr = new window.FileReader(); 8787 // Set binary reader pointer to beginning of the next tag 8788 offset = IFD_offset + 2 + i*12; 6941 8789 6942 _fr.addEventListener('progress', function(e) { 6943 comp.trigger(e); 6944 }); 8790 tag = tags2extract[data.SHORT(offset)]; 6945 8791 6946 _fr.addEventListener('load', function(e) { 6947 comp.result = _convertToBinary ? _toBinary(_fr.result) : _fr.result; 6948 comp.trigger(e); 6949 }); 8792 if (tag === undefined) { 8793 continue; // Not the tag we requested 8794 } 6950 8795 6951 _fr.addEventListener('error', function(e) {6952 comp.trigger(e, _fr.error);6953 });8796 type = types[data.SHORT(offset+=2)]; 8797 count = data.LONG(offset+=2); 8798 size = sizes[type]; 6954 8799 6955 _fr.addEventListener('loadend', function(e) { 6956 _fr = null; 6957 comp.trigger(e); 6958 }); 8800 if (!size) { 8801 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8802 } 6959 8803 6960 if (Basic.typeOf(_fr[op]) === 'function') { 6961 _convertToBinary = false; 6962 _fr[op](blob.getSource()); 6963 } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+ 6964 _convertToBinary = true; 6965 _fr.readAsDataURL(blob.getSource()); 6966 } 6967 }, 8804 offset += 4; 8805 8806 // tag can only fit 4 bytes of data, if data is larger we should look outside 8807 if (size * count > 4) { 8808 // instead of data tag contains an offset of the data 8809 offset = data.LONG(offset) + offsets.tiffHeader; 8810 } 8811 8812 // in case we left the boundaries of data throw an early exception 8813 if (offset + size * count >= this.length()) { 8814 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8815 } 8816 8817 // special care for the string 8818 if (type === 'ASCII') { 8819 hash[tag] = Basic.trim(data.STRING(offset, count).replace(/\0$/, '')); // strip trailing NULL 8820 continue; 8821 } else { 8822 values = data.asArray(type, offset, count); 8823 value = (count == 1 ? values[0] : values); 6968 8824 6969 abort: function() { 6970 if (_fr) { 6971 _fr.abort(); 8825 if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') { 8826 hash[tag] = tagDescs[tag][value]; 8827 } else { 8828 hash[tag] = value; 8829 } 8830 } 8831 } 8832 8833 return hash; 6972 8834 } 6973 },6974 8835 6975 destroy: function() { 6976 _fr = null; 6977 } 6978 }); 8836 // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported 8837 function setTag(ifd, tag, value) { 8838 var offset, length, tagOffset, valueOffset = 0; 8839 8840 // If tag name passed translate into hex key 8841 if (typeof(tag) === 'string') { 8842 var tmpTags = tags[ifd.toLowerCase()]; 8843 for (var hex in tmpTags) { 8844 if (tmpTags[hex] === tag) { 8845 tag = hex; 8846 break; 8847 } 8848 } 8849 } 8850 offset = offsets[ifd.toLowerCase() + 'IFD']; 8851 length = this.SHORT(offset); 6979 8852 6980 function _toBinary(str) { 6981 return Encode.atob(str.substring(str.indexOf('base64,') + 7)); 6982 } 6983 } 8853 for (var i = 0; i < length; i++) { 8854 tagOffset = offset + 12 * i + 2; 8855 8856 if (this.SHORT(tagOffset) == tag) { 8857 valueOffset = tagOffset + 8; 8858 break; 8859 } 8860 } 6984 8861 6985 return (extensions.FileReader = FileReader); 6986 }); 8862 if (!valueOffset) { 8863 return false; 8864 } 6987 8865 6988 // Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js 8866 try { 8867 this.write(valueOffset, value, 4); 8868 } catch(ex) { 8869 return false; 8870 } 6989 8871 6990 /** 6991 * XMLHttpRequest.js 6992 * 6993 * Copyright 2013, Moxiecode Systems AB 6994 * Released under GPL License. 6995 * 6996 * License: http://www.plupload.com/license 6997 * Contributing: http://www.plupload.com/contributing 6998 */ 8872 return true; 8873 } 8874 } 6999 8875 7000 /*global ActiveXObject:true */ 8876 ExifParser.prototype = BinaryReader.prototype; 7001 8877 7002 /** 7003 @class moxie/runtime/html5/xhr/XMLHttpRequest 7004 @private 7005 */ 7006 define("moxie/runtime/html5/xhr/XMLHttpRequest", [ 7007 "moxie/runtime/html5/Runtime", 7008 "moxie/core/utils/Basic", 7009 "moxie/core/utils/Mime", 7010 "moxie/core/utils/Url", 7011 "moxie/file/File", 7012 "moxie/file/Blob", 7013 "moxie/xhr/FormData", 7014 "moxie/core/Exceptions", 7015 "moxie/core/utils/Env" 7016 ], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) { 7017 7018 function XMLHttpRequest() { 7019 var self = this 7020 , _xhr 7021 , _filename 7022 ; 7023 7024 Basic.extend(this, { 7025 send: function(meta, data) { 7026 var target = this 7027 , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<')) 7028 , isAndroidBrowser = Env.browser === 'Android Browser' 7029 , mustSendAsBinary = false 7030 ; 8878 return ExifParser; 8879 }); 8880 8881 // Included from: src/javascript/runtime/html5/image/JPEG.js 8882 8883 /** 8884 * JPEG.js 8885 * 8886 * Copyright 2013, Moxiecode Systems AB 8887 * Released under GPL License. 8888 * 8889 * License: http://www.plupload.com/license 8890 * Contributing: http://www.plupload.com/contributing 8891 */ 7031 8892 7032 // extract file name 7033 _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase(); 8893 /** 8894 @class moxie/runtime/html5/image/JPEG 8895 @private 8896 */ 8897 define("moxie/runtime/html5/image/JPEG", [ 8898 "moxie/core/utils/Basic", 8899 "moxie/core/Exceptions", 8900 "moxie/runtime/html5/image/JPEGHeaders", 8901 "moxie/runtime/html5/utils/BinaryReader", 8902 "moxie/runtime/html5/image/ExifParser" 8903 ], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) { 7034 8904 7035 _xhr = _getNativeXHR();7036 _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);8905 function JPEG(data) { 8906 var _br, _hm, _ep, _info; 7037 8907 8908 _br = new BinaryReader(data); 7038 8909 7039 // prepare data to be sent 7040 if (data instanceof Blob) { 7041 if (data.isDetached()) { 7042 mustSendAsBinary = true; 7043 } 7044 data = data.getSource(); 7045 } else if (data instanceof FormData) { 7046 7047 if (data.hasBlob()) { 7048 if (data.getBlob().isDetached()) { 7049 data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state 7050 mustSendAsBinary = true; 7051 } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) { 7052 // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150 7053 // Android browsers (default one and Dolphin) seem to have the same issue, see: #613 7054 _preloadAndSend.call(target, meta, data); 7055 return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D 7056 } 7057 } 7058 7059 // transfer fields to real FormData 7060 if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart() 7061 var fd = new window.FormData(); 7062 data.each(function(value, name) { 7063 if (value instanceof Blob) { 7064 fd.append(name, value.getSource()); 7065 } else { 7066 fd.append(name, value); 7067 } 7068 }); 7069 data = fd; 7070 } 8910 // check if it is jpeg 8911 if (_br.SHORT(0) !== 0xFFD8) { 8912 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 7071 8913 } 7072 8914 8915 // backup headers 8916 _hm = new JPEGHeaders(data); 7073 8917 7074 // if XHR L2 7075 if (_xhr.upload) { 7076 if (meta.withCredentials) { 7077 _xhr.withCredentials = true; 7078 } 8918 // extract exif info 8919 try { 8920 _ep = new ExifParser(_hm.get('app1')[0]); 8921 } catch(ex) {} 7079 8922 7080 _xhr.addEventListener('load', function(e) { 7081 target.trigger(e); 7082 }); 8923 // get dimensions 8924 _info = _getDimensions.call(this); 7083 8925 7084 _xhr.addEventListener('error', function(e) { 7085 target.trigger(e); 7086 }); 8926 Basic.extend(this, { 8927 type: 'image/jpeg', 7087 8928 7088 // additionally listen to progress events 7089 _xhr.addEventListener('progress', function(e) { 7090 target.trigger(e); 7091 }); 8929 size: _br.length(), 7092 8930 7093 _xhr.upload.addEventListener('progress', function(e) { 7094 target.trigger({ 7095 type: 'UploadProgress', 7096 loaded: e.loaded, 7097 total: e.total 7098 }); 7099 }); 7100 // ... otherwise simulate XHR L2 7101 } else { 7102 _xhr.onreadystatechange = function onReadyStateChange() { 7103 7104 // fake Level 2 events 7105 switch (_xhr.readyState) { 7106 7107 case 1: // XMLHttpRequest.OPENED 7108 // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu 7109 break; 7110 7111 // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu 7112 case 2: // XMLHttpRequest.HEADERS_RECEIVED 7113 break; 7114 7115 case 3: // XMLHttpRequest.LOADING 7116 // try to fire progress event for not XHR L2 7117 var total, loaded; 7118 7119 try { 7120 if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers 7121 total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here 7122 } 8931 width: _info && _info.width || 0, 7123 8932 7124 if (_xhr.responseText) { // responseText was introduced in IE7 7125 loaded = _xhr.responseText.length; 7126 } 7127 } catch(ex) { 7128 total = loaded = 0; 7129 } 8933 height: _info && _info.height || 0, 7130 8934 7131 target.trigger({ 7132 type: 'progress', 7133 lengthComputable: !!total, 7134 total: parseInt(total, 10), 7135 loaded: loaded 7136 }); 7137 break; 7138 7139 case 4: // XMLHttpRequest.DONE 7140 // release readystatechange handler (mostly for IE) 7141 _xhr.onreadystatechange = function() {}; 7142 7143 // 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 } 7149 break; 8935 setExif: function(tag, value) { 8936 if (!_ep) { 8937 return false; // or throw an exception 7150 8938 } 7151 };7152 }7153 7154 7155 // set request headers7156 if (!Basic.isEmptyObj(meta.headers)) {7157 Basic.each(meta.headers, function(value, header) {7158 _xhr.setRequestHeader(header, value);7159 });7160 }7161 8939 7162 // request response type 7163 if ("" !== meta.responseType && 'responseType' in _xhr) { 7164 if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one 7165 _xhr.responseType = 'text'; 7166 } else { 7167 _xhr.responseType = meta.responseType; 7168 } 7169 } 8940 if (Basic.typeOf(tag) === 'object') { 8941 Basic.each(tag, function(value, tag) { 8942 _ep.setExif(tag, value); 8943 }); 8944 } else { 8945 _ep.setExif(tag, value); 8946 } 7170 8947 7171 // send ... 7172 if (!mustSendAsBinary) { 7173 _xhr.send(data); 7174 } else { 7175 if (_xhr.sendAsBinary) { // Gecko 7176 _xhr.sendAsBinary(data); 7177 } else { // other browsers having support for typed arrays 7178 (function() { 7179 // mimic Gecko's sendAsBinary 7180 var ui8a = new Uint8Array(data.length); 7181 for (var i = 0; i < data.length; i++) { 7182 ui8a[i] = (data.charCodeAt(i) & 0xff); 7183 } 7184 _xhr.send(ui8a.buffer); 7185 }()); 7186 } 7187 } 8948 // update internal headers 8949 _hm.set('app1', _ep.SEGMENT()); 8950 }, 8951 8952 writeHeaders: function() { 8953 if (!arguments.length) { 8954 // if no arguments passed, update headers internally 8955 return _hm.restore(data); 8956 } 8957 return _hm.restore(arguments[0]); 8958 }, 7188 8959 7189 target.trigger('loadstart'); 7190 }, 8960 stripHeaders: function(data) { 8961 return _hm.strip(data); 8962 }, 7191 8963 7192 getStatus: function() { 7193 // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception 7194 try { 7195 if (_xhr) { 7196 return _xhr.status; 8964 purge: function() { 8965 _purge.call(this); 7197 8966 } 7198 } catch(ex) {} 7199 return 0; 7200 }, 8967 }); 7201 8968 7202 getResponse: function(responseType) { 7203 var I = this.getRuntime(); 8969 if (_ep) { 8970 this.meta = { 8971 tiff: _ep.TIFF(), 8972 exif: _ep.EXIF(), 8973 gps: _ep.GPS(), 8974 thumb: _getThumb() 8975 }; 8976 } 7204 8977 7205 try {7206 switch (responseType) {7207 case 'blob':7208 var file = new File(I.uid, _xhr.response);7209 7210 // try to extract file name from content-disposition if possible (might be - not, if CORS for example)7211 var disposition = _xhr.getResponseHeader('Content-Disposition');7212 if (disposition) {7213 // extract filename from response header if available7214 var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);7215 if (match) {7216 _filename = match[2];7217 }7218 }7219 file.name = _filename;7220 7221 // pre-webkit Opera doesn't set type property on the blob response7222 if (!file.type) {7223 file.type = Mime.getFileMime(_filename);7224 }7225 return file;7226 7227 case 'json':7228 if (!Env.can('return_response_type', 'json')) {7229 return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;7230 }7231 return _xhr.response;7232 8978 7233 case 'document': 7234 return _getDocument(_xhr); 8979 function _getDimensions(br) { 8980 var idx = 0 8981 , marker 8982 , length 8983 ; 7235 8984 7236 default:7237 return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes8985 if (!br) { 8986 br = _br; 7238 8987 } 7239 } catch(ex) {7240 return null;7241 }7242 },7243 8988 7244 getAllResponseHeaders: function() { 7245 try { 7246 return _xhr.getAllResponseHeaders(); 7247 } catch(ex) {} 7248 return ''; 7249 }, 7250 7251 abort: function() { 7252 if (_xhr) { 7253 _xhr.abort(); 8989 // examine all through the end, since some images might have very large APP segments 8990 while (idx <= br.length()) { 8991 marker = br.SHORT(idx += 2); 8992 8993 if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn 8994 idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte) 8995 return { 8996 height: br.SHORT(idx), 8997 width: br.SHORT(idx += 2) 8998 }; 8999 } 9000 length = br.SHORT(idx += 2); 9001 idx += length - 2; 9002 } 9003 return null; 7254 9004 } 7255 },7256 7257 destroy: function() {7258 self = _filename = null;7259 }7260 });7261 9005 7262 9006 7263 // here we go... ugly fix for ugly bug 7264 function _preloadAndSend(meta, data) { 7265 var target = this, blob, fr; 7266 7267 // get original blob 7268 blob = data.getBlob().getSource(); 7269 7270 // preload blob in memory to be sent as binary string 7271 fr = new window.FileReader(); 7272 fr.onload = function() { 7273 // overwrite original blob 7274 data.append(data.getBlobName(), new Blob(null, { 7275 type: blob.type, 7276 data: fr.result 7277 })); 7278 // invoke send operation again 7279 self.send.call(target, meta, data); 7280 }; 7281 fr.readAsBinaryString(blob); 7282 } 9007 function _getThumb() { 9008 var data = _ep.thumb() 9009 , br 9010 , info 9011 ; 7283 9012 7284 7285 function _getNativeXHR() { 7286 if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy 7287 return new window.XMLHttpRequest(); 7288 } else { 7289 return (function() { 7290 var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0 7291 for (var i = 0; i < progIDs.length; i++) { 7292 try { 7293 return new ActiveXObject(progIDs[i]); 7294 } catch (ex) {} 9013 if (data) { 9014 br = new BinaryReader(data); 9015 info = _getDimensions(br); 9016 br.clear(); 9017 9018 if (info) { 9019 info.data = data; 9020 return info; 9021 } 7295 9022 } 7296 })();7297 }7298 }7299 7300 // @credits Sergey Ilinsky (http://www.ilinsky.com/)7301 function _getDocument(xhr) {7302 var rXML = xhr.responseXML;7303 var rText = xhr.responseText;7304 7305 // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)7306 if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {7307 rXML = new window.ActiveXObject("Microsoft.XMLDOM");7308 rXML.async = false;7309 rXML.validateOnParse = false;7310 rXML.loadXML(rText);7311 }7312 7313 // Check if there is no error in document7314 if (rXML) {7315 if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {7316 9023 return null; 7317 9024 } 7318 }7319 return rXML;7320 }7321 9025 7322 9026 7323 function _prepareMultipart(fd) { 7324 var boundary = '----moxieboundary' + new Date().getTime() 7325 , dashdash = '--' 7326 , crlf = '\r\n' 7327 , multipart = '' 7328 , I = this.getRuntime() 7329 ; 7330 7331 if (!I.can('send_binary_string')) { 7332 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); 7333 } 7334 7335 _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); 7336 7337 // append multipart parameters 7338 fd.each(function(value, name) { 7339 // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), 7340 // so we try it here ourselves with: unescape(encodeURIComponent(value)) 7341 if (value instanceof Blob) { 7342 // Build RFC2388 blob 7343 multipart += dashdash + boundary + crlf + 7344 'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf + 7345 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf + 7346 value.getSource() + crlf; 7347 } else { 7348 multipart += dashdash + boundary + crlf + 7349 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf + 7350 unescape(encodeURIComponent(value)) + crlf; 9027 function _purge() { 9028 if (!_ep || !_hm || !_br) { 9029 return; // ignore any repeating purge requests 9030 } 9031 _ep.clear(); 9032 _hm.purge(); 9033 _br.clear(); 9034 _info = _hm = _ep = _br = null; 7351 9035 } 7352 }); 7353 7354 multipart += dashdash + boundary + dashdash + crlf; 7355 7356 return multipart; 7357 } 7358 } 9036 } 7359 9037 7360 return (extensions.XMLHttpRequest = XMLHttpRequest);7361 });9038 return JPEG; 9039 }); 7362 9040 7363 // Included from: src/javascript/runtime/html5/ utils/BinaryReader.js9041 // Included from: src/javascript/runtime/html5/image/PNG.js 7364 9042 7365 /**7366 * BinaryReader.js7367 *7368 * Copyright 2013, Moxiecode Systems AB7369 * Released under GPL License.7370 *7371 * License: http://www.plupload.com/license7372 * Contributing: http://www.plupload.com/contributing7373 */9043 /** 9044 * PNG.js 9045 * 9046 * Copyright 2013, Moxiecode Systems AB 9047 * Released under GPL License. 9048 * 9049 * License: http://www.plupload.com/license 9050 * Contributing: http://www.plupload.com/contributing 9051 */ 7374 9052 7375 /**7376 @class moxie/runtime/html5/ utils/BinaryReader9053 /** 9054 @class moxie/runtime/html5/image/PNG 7377 9055 @private 7378 */ 7379 define("moxie/runtime/html5/utils/BinaryReader", [ 7380 "moxie/core/utils/Basic" 7381 ], function(Basic) { 7382 7383 7384 function BinaryReader(data) { 7385 if (data instanceof ArrayBuffer) { 7386 ArrayBufferReader.apply(this, arguments); 7387 } else { 7388 UTF16StringReader.apply(this, arguments); 7389 } 7390 } 7391 9056 */ 9057 define("moxie/runtime/html5/image/PNG", [ 9058 "moxie/core/Exceptions", 9059 "moxie/core/utils/Basic", 9060 "moxie/runtime/html5/utils/BinaryReader" 9061 ], function(x, Basic, BinaryReader) { 7392 9062 7393 Basic.extend(BinaryReader.prototype, { 7394 7395 littleEndian: false, 9063 function PNG(data) { 9064 var _br, _hm, _ep, _info; 7396 9065 9066 _br = new BinaryReader(data); 7397 9067 7398 read: function(idx, size) { 7399 var sum, mv, i; 9068 // check if it's png 9069 (function() { 9070 var idx = 0, i = 0 9071 , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A] 9072 ; 7400 9073 7401 if (idx + size > this.length()) { 7402 throw new Error("You are trying to read outside the source boundaries."); 7403 } 7404 7405 mv = this.littleEndian 7406 ? 0 7407 : -8 * (size - 1) 7408 ; 9074 for (i = 0; i < signature.length; i++, idx += 2) { 9075 if (signature[i] != _br.SHORT(idx)) { 9076 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 9077 } 9078 } 9079 }()); 7409 9080 7410 for (i = 0, sum = 0; i < size; i++) { 7411 sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8)); 7412 } 7413 return sum; 7414 }, 9081 function _getDimensions() { 9082 var chunk, idx; 7415 9083 9084 chunk = _getChunkAt.call(this, 8); 7416 9085 7417 write: function(idx, num, size) { 7418 var mv, i, str = ''; 9086 if (chunk.type == 'IHDR') { 9087 idx = chunk.start; 9088 return { 9089 width: _br.LONG(idx), 9090 height: _br.LONG(idx += 4) 9091 }; 9092 } 9093 return null; 9094 } 7419 9095 7420 if (idx > this.length()) { 7421 throw new Error("You are trying to write outside the source boundaries."); 7422 } 9096 function _purge() { 9097 if (!_br) { 9098 return; // ignore any repeating purge requests 9099 } 9100 _br.clear(); 9101 data = _info = _hm = _ep = _br = null; 9102 } 7423 9103 7424 mv = this.littleEndian 7425 ? 0 7426 : -8 * (size - 1) 7427 ; 9104 _info = _getDimensions.call(this); 7428 9105 7429 for (i = 0; i < size; i++) { 7430 this.writeByteAt(idx + i, (num >> Math.abs(mv + i*8)) & 255); 7431 } 7432 }, 9106 Basic.extend(this, { 9107 type: 'image/png', 7433 9108 9109 size: _br.length(), 7434 9110 7435 BYTE: function(idx) { 7436 return this.read(idx, 1); 7437 }, 9111 width: _info.width, 7438 9112 9113 height: _info.height, 7439 9114 7440 SHORT: function(idx) { 7441 return this.read(idx, 2); 7442 }, 9115 purge: function() { 9116 _purge.call(this); 9117 } 9118 }); 7443 9119 9120 // for PNG we can safely trigger purge automatically, as we do not keep any data for later 9121 _purge.call(this); 7444 9122 7445 LONG: function(idx) { 7446 return this.read(idx, 4); 7447 }, 9123 function _getChunkAt(idx) { 9124 var length, type, start, CRC; 7448 9125 9126 length = _br.LONG(idx); 9127 type = _br.STRING(idx += 4, 4); 9128 start = idx += 4; 9129 CRC = _br.LONG(idx + length); 7449 9130 7450 SLONG: function(idx) { // 2's complement notation 7451 var num = this.read(idx, 4); 7452 return (num > 2147483647 ? num - 4294967296 : num); 7453 }, 9131 return { 9132 length: length, 9133 type: type, 9134 start: start, 9135 CRC: CRC 9136 }; 9137 } 9138 } 7454 9139 9140 return PNG; 9141 }); 7455 9142 7456 CHAR: function(idx) { 7457 return String.fromCharCode(this.read(idx, 1)); 7458 }, 9143 // Included from: src/javascript/runtime/html5/image/ImageInfo.js 7459 9144 9145 /** 9146 * ImageInfo.js 9147 * 9148 * Copyright 2013, Moxiecode Systems AB 9149 * Released under GPL License. 9150 * 9151 * License: http://www.plupload.com/license 9152 * Contributing: http://www.plupload.com/contributing 9153 */ 7460 9154 7461 STRING: function(idx, count) { 7462 return this.asArray('CHAR', idx, count).join(''); 7463 }, 9155 /** 9156 Optional image investigation tool for HTML5 runtime. Provides the following features: 9157 - ability to distinguish image type (JPEG or PNG) by signature 9158 - ability to extract image width/height directly from it's internals, without preloading in memory (fast) 9159 - ability to extract APP headers from JPEGs (Exif, GPS, etc) 9160 - ability to replace width/height tags in extracted JPEG headers 9161 - ability to restore APP headers, that were for example stripped during image manipulation 7464 9162 9163 @class moxie/runtime/html5/image/ImageInfo 9164 @private 9165 @param {String} data Image source as binary string 9166 */ 9167 define("moxie/runtime/html5/image/ImageInfo", [ 9168 "moxie/core/utils/Basic", 9169 "moxie/core/Exceptions", 9170 "moxie/runtime/html5/image/JPEG", 9171 "moxie/runtime/html5/image/PNG" 9172 ], function(Basic, x, JPEG, PNG) { 9173 9174 return function(data) { 9175 var _cs = [JPEG, PNG], _img; 9176 9177 // figure out the format, throw: ImageError.WRONG_FORMAT if not supported 9178 _img = (function() { 9179 for (var i = 0; i < _cs.length; i++) { 9180 try { 9181 return new _cs[i](data); 9182 } catch (ex) { 9183 // console.info(ex); 9184 } 9185 } 9186 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 9187 }()); 7465 9188 7466 asArray: function(type, idx, count) { 7467 var values = []; 9189 Basic.extend(this, { 9190 /** 9191 Image Mime Type extracted from it's depths 7468 9192 7469 for (var i = 0; i < count; i++) { 7470 values[i] = this[type](idx + i); 7471 } 7472 return values; 7473 } 7474 }); 9193 @property type 9194 @type {String} 9195 @default '' 9196 */ 9197 type: '', 7475 9198 9199 /** 9200 Image size in bytes 7476 9201 7477 function ArrayBufferReader(data) { 7478 var _dv = new DataView(data); 9202 @property size 9203 @type {Number} 9204 @default 0 9205 */ 9206 size: 0, 7479 9207 7480 Basic.extend(this, { 7481 7482 readByteAt: function(idx) { 7483 return _dv.getUint8(idx); 7484 }, 9208 /** 9209 Image width extracted from image source 7485 9210 9211 @property width 9212 @type {Number} 9213 @default 0 9214 */ 9215 width: 0, 7486 9216 7487 writeByteAt: function(idx, value) { 7488 _dv.setUint8(idx, value); 7489 }, 7490 9217 /** 9218 Image height extracted from image source 7491 9219 7492 SEGMENT: function(idx, size, value) { 7493 switch (arguments.length) { 7494 case 2: 7495 return data.slice(idx, idx + size); 9220 @property height 9221 @type {Number} 9222 @default 0 9223 */ 9224 height: 0, 7496 9225 7497 case 1:7498 return data.slice(idx);9226 /** 9227 Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs. 7499 9228 7500 case 3: 7501 if (value === null) { 7502 value = new ArrayBuffer(); 7503 } 9229 @method setExif 9230 @param {String} tag Tag to set 9231 @param {Mixed} value Value to assign to the tag 9232 */ 9233 setExif: function() {}, 7504 9234 7505 if (value instanceof ArrayBuffer) { 7506 var arr = new Uint8Array(this.length() - size + value.byteLength); 7507 if (idx > 0) { 7508 arr.set(new Uint8Array(data.slice(0, idx)), 0); 7509 } 7510 arr.set(new Uint8Array(value), idx); 7511 arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength); 9235 /** 9236 Restores headers to the source. 7512 9237 7513 this.clear(); 7514 data = arr.buffer; 7515 _dv = new DataView(data); 7516 break; 7517 } 9238 @method writeHeaders 9239 @param {String} data Image source as binary string 9240 @return {String} Updated binary string 9241 */ 9242 writeHeaders: function(data) { 9243 return data; 9244 }, 7518 9245 7519 default: return data; 7520 } 7521 }, 9246 /** 9247 Strip all headers from the source. 9248 9249 @method stripHeaders 9250 @param {String} data Image source as binary string 9251 @return {String} Updated binary string 9252 */ 9253 stripHeaders: function(data) { 9254 return data; 9255 }, 7522 9256 9257 /** 9258 Dispose resources. 7523 9259 7524 length: function() { 7525 return data ? data.byteLength : 0; 7526 }, 9260 @method purge 9261 */ 9262 purge: function() { 9263 data = null; 9264 } 9265 }); 7527 9266 9267 Basic.extend(this, _img); 7528 9268 7529 clear: function() { 7530 _dv = data = null; 7531 } 9269 this.purge = function() { 9270 _img.purge(); 9271 _img = null; 9272 }; 9273 }; 7532 9274 }); 7533 }7534 9275 9276 // Included from: src/javascript/runtime/html5/image/ResizerCanvas.js 7535 9277 7536 function UTF16StringReader(data) { 7537 Basic.extend(this, { 7538 7539 readByteAt: function(idx) { 7540 return data.charCodeAt(idx); 7541 }, 9278 /** 9279 * ResizerCanvas.js 9280 * 9281 * Copyright 2013, Moxiecode Systems AB 9282 * Released under GPL License. 9283 * 9284 * License: http://www.plupload.com/license 9285 * Contributing: http://www.plupload.com/contributing 9286 */ 9287 9288 /** 9289 * Resizes image/canvas using canvas 9290 */ 9291 define("moxie/runtime/html5/image/ResizerCanvas", [], function() { 7542 9292 9293 function scale(image, ratio, resample) { 9294 var sD = image.width > image.height ? 'width' : 'height'; // take the largest side 9295 var dD = Math.round(image[sD] * ratio); 9296 var scaleCapped = false; 7543 9297 7544 writeByteAt: function(idx, value) { 7545 putstr(String.fromCharCode(value), idx, 1); 7546 }, 9298 if (resample !== 'nearest' && (ratio < 0.5 || ratio > 2)) { 9299 ratio = ratio < 0.5 ? 0.5 : 2; 9300 scaleCapped = true; 9301 } 7547 9302 9303 var tCanvas = _scale(image, ratio); 7548 9304 7549 SEGMENT: function(idx, length, segment) { 7550 switch (arguments.length) { 7551 case 1: 7552 return data.substr(idx); 7553 case 2: 7554 return data.substr(idx, length); 7555 case 3: 7556 putstr(segment !== null ? segment : '', idx, length); 7557 break; 7558 default: return data; 9305 if (scaleCapped) { 9306 return scale(tCanvas, dD / tCanvas[sD], resample); 9307 } else { 9308 return tCanvas; 7559 9309 } 7560 } ,9310 } 7561 9311 7562 9312 7563 length: function() { 7564 return data ? data.length : 0; 7565 }, 9313 function _scale(image, ratio) { 9314 var sW = image.width; 9315 var sH = image.height; 9316 var dW = Math.round(sW * ratio); 9317 var dH = Math.round(sH * ratio); 7566 9318 7567 clear: function() {7568 data = null;7569 }7570 });9319 var canvas = document.createElement('canvas'); 9320 canvas.width = dW; 9321 canvas.height = dH; 9322 canvas.getContext("2d").drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH); 7571 9323 9324 image = null; // just in case 9325 return canvas; 9326 } 7572 9327 7573 function putstr(segment, idx, length) { 7574 length = arguments.length === 3 ? length : data.length - idx - 1; 7575 data = data.substr(0, idx) + segment + data.substr(length + idx); 7576 } 7577 } 9328 return { 9329 scale: scale 9330 }; 7578 9331 9332 }); 7579 9333 7580 return BinaryReader; 7581 }); 9334 // Included from: src/javascript/runtime/html5/image/Image.js 7582 9335 7583 // Included from: src/javascript/runtime/html5/image/JPEGHeaders.js 9336 /** 9337 * Image.js 9338 * 9339 * Copyright 2013, Moxiecode Systems AB 9340 * Released under GPL License. 9341 * 9342 * License: http://www.plupload.com/license 9343 * Contributing: http://www.plupload.com/contributing 9344 */ 7584 9345 7585 /** 7586 * JPEGHeaders.js 7587 * 7588 * Copyright 2013, Moxiecode Systems AB 7589 * Released under GPL License. 7590 * 7591 * License: http://www.plupload.com/license 7592 * Contributing: http://www.plupload.com/contributing 7593 */ 7594 7595 /** 7596 @class moxie/runtime/html5/image/JPEGHeaders 9346 /** 9347 @class moxie/runtime/html5/image/Image 7597 9348 @private 7598 */ 7599 define("moxie/runtime/html5/image/JPEGHeaders", [ 7600 "moxie/runtime/html5/utils/BinaryReader", 7601 "moxie/core/Exceptions" 7602 ], function(BinaryReader, x) { 7603 7604 return function JPEGHeaders(data) { 7605 var headers = [], _br, idx, marker, length = 0; 7606 7607 _br = new BinaryReader(data); 7608 7609 // Check if data is jpeg 7610 if (_br.SHORT(0) !== 0xFFD8) { 7611 _br.clear(); 7612 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 7613 } 9349 */ 9350 define("moxie/runtime/html5/image/Image", [ 9351 "moxie/runtime/html5/Runtime", 9352 "moxie/core/utils/Basic", 9353 "moxie/core/Exceptions", 9354 "moxie/core/utils/Encode", 9355 "moxie/file/Blob", 9356 "moxie/file/File", 9357 "moxie/runtime/html5/image/ImageInfo", 9358 "moxie/runtime/html5/image/ResizerCanvas", 9359 "moxie/core/utils/Mime", 9360 "moxie/core/utils/Env" 9361 ], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, ResizerCanvas, Mime, Env) { 9362 9363 function HTML5Image() { 9364 var me = this 9365 , _img, _imgInfo, _canvas, _binStr, _blob 9366 , _modified = false // is set true whenever image is modified 9367 , _preserveHeaders = true 9368 ; 7614 9369 7615 idx = 2; 9370 Basic.extend(this, { 9371 loadFromBlob: function(blob) { 9372 var I = this.getRuntime() 9373 , asBinary = arguments.length > 1 ? arguments[1] : true 9374 ; 7616 9375 7617 while (idx <= _br.length()) { 7618 marker = _br.SHORT(idx); 9376 if (!I.can('access_binary')) { 9377 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); 9378 } 7619 9379 7620 // omit RST (restart) markers 7621 if (marker >= 0xFFD0 && marker <= 0xFFD7) { 7622 idx += 2; 7623 continue; 7624 } 9380 _blob = blob; 7625 9381 7626 // no headers allowed after SOS marker 7627 if (marker === 0xFFDA || marker === 0xFFD9) { 7628 break; 7629 } 9382 if (blob.isDetached()) { 9383 _binStr = blob.getSource(); 9384 _preload.call(this, _binStr); 9385 return; 9386 } else { 9387 _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) { 9388 if (asBinary) { 9389 _binStr = _toBinary(dataUrl); 9390 } 9391 _preload.call(this, dataUrl); 9392 }); 9393 } 9394 }, 7630 9395 7631 length = _br.SHORT(idx + 2) + 2; 9396 loadFromImage: function(img, exact) { 9397 this.meta = img.meta; 7632 9398 7633 // APPn marker detected 7634 if (marker >= 0xFFE1 && marker <= 0xFFEF) { 7635 headers.push({ 7636 hex: marker, 7637 name: 'APP' + (marker & 0x000F), 7638 start: idx, 7639 length: length, 7640 segment: _br.SEGMENT(idx, length) 7641 }); 7642 } 9399 _blob = new File(null, { 9400 name: img.name, 9401 size: img.size, 9402 type: img.type 9403 }); 7643 9404 7644 idx += length;7645 }9405 _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL()); 9406 }, 7646 9407 7647 _br.clear(); 9408 getInfo: function() { 9409 var I = this.getRuntime(), info; 7648 9410 7649 return { 7650 headers: headers, 9411 if (!_imgInfo && _binStr && I.can('access_image_binary')) { 9412 _imgInfo = new ImageInfo(_binStr); 9413 } 7651 9414 7652 restore: function(data) { 7653 var max, i, br; 9415 // this stuff below is definitely having fun with itself 9416 info = { 9417 width: _getImg().width || 0, 9418 height: _getImg().height || 0, 9419 type: _blob.type || Mime.getFileMime(_blob.name), 9420 size: _binStr && _binStr.length || _blob.size || 0, 9421 name: _blob.name || '', 9422 meta: null 9423 }; 7654 9424 7655 br = new BinaryReader(data); 9425 if (_preserveHeaders) { 9426 info.meta = _imgInfo && _imgInfo.meta || this.meta || {}; 7656 9427 7657 idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2; 9428 // if data was taken from ImageInfo it will be a binary string, so we convert it to blob 9429 if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) { 9430 info.meta.thumb.data = new Blob(null, { 9431 type: 'image/jpeg', 9432 data: info.meta.thumb.data 9433 }); 9434 } 9435 } 7658 9436 7659 for (i = 0, max = headers.length; i < max; i++) { 7660 br.SEGMENT(idx, 0, headers[i].segment); 7661 idx += headers[i].length; 7662 } 9437 return info; 9438 }, 7663 9439 7664 data = br.SEGMENT();7665 br.clear();7666 return data;7667 },7668 9440 7669 strip: function(data) { 7670 var br, headers, jpegHeaders, i; 9441 resize: function(rect, ratio, options) { 9442 var canvas = document.createElement('canvas'); 9443 canvas.width = rect.width; 9444 canvas.height = rect.height; 7671 9445 7672 jpegHeaders = new JPEGHeaders(data); 7673 headers = jpegHeaders.headers; 7674 jpegHeaders.purge(); 9446 canvas.getContext("2d").drawImage(_getImg(), rect.x, rect.y, rect.width, rect.height, 0, 0, canvas.width, canvas.height); 7675 9447 7676 br = new BinaryReader(data);9448 _canvas = ResizerCanvas.scale(canvas, ratio); 7677 9449 7678 i = headers.length; 7679 while (i--) { 7680 br.SEGMENT(headers[i].start, headers[i].length, ''); 7681 } 7682 7683 data = br.SEGMENT(); 7684 br.clear(); 7685 return data; 7686 }, 9450 _preserveHeaders = options.preserveHeaders; 7687 9451 7688 get: function(name) { 7689 var array = []; 9452 // rotate if required, according to orientation tag 9453 if (!_preserveHeaders) { 9454 var orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1; 9455 _canvas = _rotateToOrientaion(_canvas, orientation); 9456 } 7690 9457 7691 for (var i = 0, max = headers.length; i < max; i++) { 7692 if (headers[i].name === name.toUpperCase()) { 7693 array.push(headers[i].segment); 7694 } 7695 } 7696 return array; 7697 }, 9458 this.width = _canvas.width; 9459 this.height = _canvas.height; 7698 9460 7699 set: function(name, segment) { 7700 var array = [], i, ii, max; 9461 _modified = true; 7701 9462 7702 if (typeof(segment) === 'string') { 7703 array.push(segment); 7704 } else { 7705 array = segment; 7706 } 9463 this.trigger('Resize'); 9464 }, 7707 9465 7708 for (i = ii = 0, max = headers.length; i < max; i++) { 7709 if (headers[i].name === name.toUpperCase()) { 7710 headers[i].segment = array[ii]; 7711 headers[i].length = array[ii].length; 7712 ii++; 7713 } 7714 if (ii >= array.length) { 7715 break; 7716 } 7717 } 7718 }, 9466 getAsCanvas: function() { 9467 if (!_canvas) { 9468 _canvas = _getCanvas(); 9469 } 9470 _canvas.id = this.uid + '_canvas'; 9471 return _canvas; 9472 }, 9473 9474 getAsBlob: function(type, quality) { 9475 if (type !== this.type) { 9476 _modified = true; // reconsider the state 9477 return new File(null, { 9478 name: _blob.name || '', 9479 type: type, 9480 data: me.getAsDataURL(type, quality) 9481 }); 9482 } 9483 return new File(null, { 9484 name: _blob.name || '', 9485 type: type, 9486 data: me.getAsBinaryString(type, quality) 9487 }); 9488 }, 7719 9489 7720 purge: function() { 7721 this.headers = headers = []; 7722 } 7723 }; 7724 }; 7725 }); 9490 getAsDataURL: function(type) { 9491 var quality = arguments[1] || 90; 7726 9492 7727 // Included from: src/javascript/runtime/html5/image/ExifParser.js 9493 // if image has not been modified, return the source right away 9494 if (!_modified) { 9495 return _img.src; 9496 } 7728 9497 7729 /** 7730 * ExifParser.js 7731 * 7732 * Copyright 2013, Moxiecode Systems AB 7733 * Released under GPL License. 7734 * 7735 * License: http://www.plupload.com/license 7736 * Contributing: http://www.plupload.com/contributing 7737 */ 9498 // make sure we have a canvas to work with 9499 _getCanvas(); 7738 9500 7739 /** 7740 @class moxie/runtime/html5/image/ExifParser 7741 @private 7742 */ 7743 define("moxie/runtime/html5/image/ExifParser", [ 7744 "moxie/core/utils/Basic", 7745 "moxie/runtime/html5/utils/BinaryReader", 7746 "moxie/core/Exceptions" 7747 ], function(Basic, BinaryReader, x) { 7748 7749 function ExifParser(data) { 7750 var __super__, tags, tagDescs, offsets, idx, Tiff; 7751 7752 BinaryReader.call(this, data); 9501 if ('image/jpeg' !== type) { 9502 return _canvas.toDataURL('image/png'); 9503 } else { 9504 try { 9505 // older Geckos used to result in an exception on quality argument 9506 return _canvas.toDataURL('image/jpeg', quality/100); 9507 } catch (ex) { 9508 return _canvas.toDataURL('image/jpeg'); 9509 } 9510 } 9511 }, 7753 9512 7754 tags = { 7755 tiff: { 7756 /* 7757 The image orientation viewed in terms of rows and columns. 9513 getAsBinaryString: function(type, quality) { 9514 // if image has not been modified, return the source right away 9515 if (!_modified) { 9516 // if image was not loaded from binary string 9517 if (!_binStr) { 9518 _binStr = _toBinary(me.getAsDataURL(type, quality)); 9519 } 9520 return _binStr; 9521 } 7758 9522 7759 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. 7760 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. 7761 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. 7762 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. 7763 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. 7764 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. 7765 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. 7766 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. 7767 */ 7768 0x0112: 'Orientation', 7769 0x010E: 'ImageDescription', 7770 0x010F: 'Make', 7771 0x0110: 'Model', 7772 0x0131: 'Software', 7773 0x8769: 'ExifIFDPointer', 7774 0x8825: 'GPSInfoIFDPointer' 7775 }, 7776 exif: { 7777 0x9000: 'ExifVersion', 7778 0xA001: 'ColorSpace', 7779 0xA002: 'PixelXDimension', 7780 0xA003: 'PixelYDimension', 7781 0x9003: 'DateTimeOriginal', 7782 0x829A: 'ExposureTime', 7783 0x829D: 'FNumber', 7784 0x8827: 'ISOSpeedRatings', 7785 0x9201: 'ShutterSpeedValue', 7786 0x9202: 'ApertureValue' , 7787 0x9207: 'MeteringMode', 7788 0x9208: 'LightSource', 7789 0x9209: 'Flash', 7790 0x920A: 'FocalLength', 7791 0xA402: 'ExposureMode', 7792 0xA403: 'WhiteBalance', 7793 0xA406: 'SceneCaptureType', 7794 0xA404: 'DigitalZoomRatio', 7795 0xA408: 'Contrast', 7796 0xA409: 'Saturation', 7797 0xA40A: 'Sharpness' 7798 }, 7799 gps: { 7800 0x0000: 'GPSVersionID', 7801 0x0001: 'GPSLatitudeRef', 7802 0x0002: 'GPSLatitude', 7803 0x0003: 'GPSLongitudeRef', 7804 0x0004: 'GPSLongitude' 7805 }, 9523 if ('image/jpeg' !== type) { 9524 _binStr = _toBinary(me.getAsDataURL(type, quality)); 9525 } else { 9526 var dataUrl; 7806 9527 7807 thumb: { 7808 0x0201: 'JPEGInterchangeFormat', 7809 0x0202: 'JPEGInterchangeFormatLength' 7810 } 7811 }; 7812 7813 tagDescs = { 7814 'ColorSpace': { 7815 1: 'sRGB', 7816 0: 'Uncalibrated' 7817 }, 9528 // if jpeg 9529 if (!quality) { 9530 quality = 90; 9531 } 7818 9532 7819 'MeteringMode': { 7820 0: 'Unknown', 7821 1: 'Average', 7822 2: 'CenterWeightedAverage', 7823 3: 'Spot', 7824 4: 'MultiSpot', 7825 5: 'Pattern', 7826 6: 'Partial', 7827 255: 'Other' 7828 }, 9533 // make sure we have a canvas to work with 9534 _getCanvas(); 7829 9535 7830 'LightSource': { 7831 1: 'Daylight', 7832 2: 'Fliorescent', 7833 3: 'Tungsten', 7834 4: 'Flash', 7835 9: 'Fine weather', 7836 10: 'Cloudy weather', 7837 11: 'Shade', 7838 12: 'Daylight fluorescent (D 5700 - 7100K)', 7839 13: 'Day white fluorescent (N 4600 -5400K)', 7840 14: 'Cool white fluorescent (W 3900 - 4500K)', 7841 15: 'White fluorescent (WW 3200 - 3700K)', 7842 17: 'Standard light A', 7843 18: 'Standard light B', 7844 19: 'Standard light C', 7845 20: 'D55', 7846 21: 'D65', 7847 22: 'D75', 7848 23: 'D50', 7849 24: 'ISO studio tungsten', 7850 255: 'Other' 7851 }, 9536 try { 9537 // older Geckos used to result in an exception on quality argument 9538 dataUrl = _canvas.toDataURL('image/jpeg', quality/100); 9539 } catch (ex) { 9540 dataUrl = _canvas.toDataURL('image/jpeg'); 9541 } 7852 9542 7853 'Flash': { 7854 0x0000: 'Flash did not fire', 7855 0x0001: 'Flash fired', 7856 0x0005: 'Strobe return light not detected', 7857 0x0007: 'Strobe return light detected', 7858 0x0009: 'Flash fired, compulsory flash mode', 7859 0x000D: 'Flash fired, compulsory flash mode, return light not detected', 7860 0x000F: 'Flash fired, compulsory flash mode, return light detected', 7861 0x0010: 'Flash did not fire, compulsory flash mode', 7862 0x0018: 'Flash did not fire, auto mode', 7863 0x0019: 'Flash fired, auto mode', 7864 0x001D: 'Flash fired, auto mode, return light not detected', 7865 0x001F: 'Flash fired, auto mode, return light detected', 7866 0x0020: 'No flash function', 7867 0x0041: 'Flash fired, red-eye reduction mode', 7868 0x0045: 'Flash fired, red-eye reduction mode, return light not detected', 7869 0x0047: 'Flash fired, red-eye reduction mode, return light detected', 7870 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode', 7871 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', 7872 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', 7873 0x0059: 'Flash fired, auto mode, red-eye reduction mode', 7874 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', 7875 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode' 7876 }, 9543 _binStr = _toBinary(dataUrl); 7877 9544 7878 'ExposureMode': { 7879 0: 'Auto exposure', 7880 1: 'Manual exposure', 7881 2: 'Auto bracket' 7882 }, 9545 if (_imgInfo) { 9546 _binStr = _imgInfo.stripHeaders(_binStr); 7883 9547 7884 'WhiteBalance': { 7885 0: 'Auto white balance', 7886 1: 'Manual white balance' 7887 }, 9548 if (_preserveHeaders) { 9549 // update dimensions info in exif 9550 if (_imgInfo.meta && _imgInfo.meta.exif) { 9551 _imgInfo.setExif({ 9552 PixelXDimension: this.width, 9553 PixelYDimension: this.height 9554 }); 9555 } 7888 9556 7889 'SceneCaptureType': { 7890 0: 'Standard', 7891 1: 'Landscape', 7892 2: 'Portrait', 7893 3: 'Night scene' 7894 }, 9557 // re-inject the headers 9558 _binStr = _imgInfo.writeHeaders(_binStr); 9559 } 7895 9560 7896 'Contrast': {7897 0: 'Normal',7898 1: 'Soft',7899 2: 'Hard'7900 },9561 // will be re-created from fresh on next getInfo call 9562 _imgInfo.purge(); 9563 _imgInfo = null; 9564 } 9565 } 7901 9566 7902 'Saturation': { 7903 0: 'Normal', 7904 1: 'Low saturation', 7905 2: 'High saturation' 7906 }, 9567 _modified = false; 7907 9568 7908 'Sharpness': { 7909 0: 'Normal', 7910 1: 'Soft', 7911 2: 'Hard' 7912 }, 9569 return _binStr; 9570 }, 7913 9571 7914 // GPS related 7915 'GPSLatitudeRef': { 7916 N: 'North latitude', 7917 S: 'South latitude' 7918 }, 9572 destroy: function() { 9573 me = null; 9574 _purge.call(this); 9575 this.getRuntime().getShim().removeInstance(this.uid); 9576 } 9577 }); 7919 9578 7920 'GPSLongitudeRef': { 7921 E: 'East longitude', 7922 W: 'West longitude' 7923 } 7924 }; 7925 7926 offsets = { 7927 tiffHeader: 10 7928 }; 7929 7930 idx = offsets.tiffHeader; 7931 7932 __super__ = { 7933 clear: this.clear 7934 }; 7935 7936 // Public functions 7937 Basic.extend(this, { 7938 7939 read: function() { 7940 try { 7941 return ExifParser.prototype.read.apply(this, arguments); 7942 } catch (ex) { 7943 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 9579 9580 function _getImg() { 9581 if (!_canvas && !_img) { 9582 throw new x.ImageError(x.DOMException.INVALID_STATE_ERR); 9583 } 9584 return _canvas || _img; 7944 9585 } 7945 },7946 9586 7947 9587 7948 write: function() { 7949 try { 7950 return ExifParser.prototype.write.apply(this, arguments); 7951 } catch (ex) { 7952 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 9588 function _getCanvas() { 9589 var canvas = _getImg(); 9590 if (canvas.nodeName.toLowerCase() == 'canvas') { 9591 return canvas; 9592 } 9593 _canvas = document.createElement('canvas'); 9594 _canvas.width = canvas.width; 9595 _canvas.height = canvas.height; 9596 _canvas.getContext("2d").drawImage(canvas, 0, 0); 9597 return _canvas; 7953 9598 } 7954 },7955 9599 7956 9600 7957 UNDEFINED: function() { 7958 return this.BYTE.apply(this, arguments); 7959 }, 7960 9601 function _toBinary(str) { 9602 return Encode.atob(str.substring(str.indexOf('base64,') + 7)); 9603 } 7961 9604 7962 RATIONAL: function(idx) {7963 return this.LONG(idx) / this.LONG(idx + 4)7964 },7965 9605 9606 function _toDataUrl(str, type) { 9607 return 'data:' + (type || '') + ';base64,' + Encode.btoa(str); 9608 } 7966 9609 7967 SRATIONAL: function(idx) {7968 return this.SLONG(idx) / this.SLONG(idx + 4)7969 },7970 9610 7971 ASCII: function(idx) { 7972 return this.CHAR(idx); 7973 }, 9611 function _preload(str) { 9612 var comp = this; 7974 9613 7975 TIFF: function() { 7976 return Tiff || null; 7977 }, 9614 _img = new Image(); 9615 _img.onerror = function() { 9616 _purge.call(this); 9617 comp.trigger('error', x.ImageError.WRONG_FORMAT); 9618 }; 9619 _img.onload = function() { 9620 comp.trigger('load'); 9621 }; 7978 9622 9623 _img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type); 9624 } 7979 9625 7980 EXIF: function() {7981 var Exif = null;7982 9626 7983 if (offsets.exifIFD) { 7984 try { 7985 Exif = extractTags.call(this, offsets.exifIFD, tags.exif); 7986 } catch(ex) { 7987 return null; 7988 } 9627 function _readAsDataUrl(file, callback) { 9628 var comp = this, fr; 7989 9629 7990 // Fix formatting of some tags 7991 if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') { 7992 for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) { 7993 exifVersion += String.fromCharCode(Exif.ExifVersion[i]); 7994 } 7995 Exif.ExifVersion = exifVersion; 9630 // use FileReader if it's available 9631 if (window.FileReader) { 9632 fr = new FileReader(); 9633 fr.onload = function() { 9634 callback.call(comp, this.result); 9635 }; 9636 fr.onerror = function() { 9637 comp.trigger('error', x.ImageError.WRONG_FORMAT); 9638 }; 9639 fr.readAsDataURL(file); 9640 } else { 9641 return callback.call(this, file.getAsDataURL()); 7996 9642 } 7997 9643 } 7998 9644 7999 return Exif; 8000 }, 8001 8002 8003 GPS: function() { 8004 var GPS = null; 8005 8006 if (offsets.gpsIFD) { 8007 try { 8008 GPS = extractTags.call(this, offsets.gpsIFD, tags.gps); 8009 } catch (ex) { 8010 return null; 9645 /** 9646 * Transform canvas coordination according to specified frame size and orientation 9647 * Orientation value is from EXIF tag 9648 * @author Shinichi Tomita <shinichi.tomita@gmail.com> 9649 */ 9650 function _rotateToOrientaion(img, orientation) { 9651 var RADIANS = Math.PI/180; 9652 var canvas = document.createElement('canvas'); 9653 var ctx = canvas.getContext('2d'); 9654 var width = img.width; 9655 var height = img.height; 9656 9657 if (Basic.inArray(orientation, [5,6,7,8]) > -1) { 9658 canvas.width = height; 9659 canvas.height = width; 9660 } else { 9661 canvas.width = width; 9662 canvas.height = height; 8011 9663 } 8012 9664 8013 // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..) 8014 if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') { 8015 GPS.GPSVersionID = GPS.GPSVersionID.join('.'); 9665 /** 9666 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. 9667 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. 9668 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. 9669 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. 9670 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. 9671 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. 9672 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. 9673 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. 9674 */ 9675 switch (orientation) { 9676 case 2: 9677 // horizontal flip 9678 ctx.translate(width, 0); 9679 ctx.scale(-1, 1); 9680 break; 9681 case 3: 9682 // 180 rotate left 9683 ctx.translate(width, height); 9684 ctx.rotate(180 * RADIANS); 9685 break; 9686 case 4: 9687 // vertical flip 9688 ctx.translate(0, height); 9689 ctx.scale(1, -1); 9690 break; 9691 case 5: 9692 // vertical flip + 90 rotate right 9693 ctx.rotate(90 * RADIANS); 9694 ctx.scale(1, -1); 9695 break; 9696 case 6: 9697 // 90 rotate right 9698 ctx.rotate(90 * RADIANS); 9699 ctx.translate(0, -height); 9700 break; 9701 case 7: 9702 // horizontal flip + 90 rotate right 9703 ctx.rotate(90 * RADIANS); 9704 ctx.translate(width, -height); 9705 ctx.scale(-1, 1); 9706 break; 9707 case 8: 9708 // 90 rotate left 9709 ctx.rotate(-90 * RADIANS); 9710 ctx.translate(-width, 0); 9711 break; 8016 9712 } 8017 }8018 8019 return GPS;8020 },8021 8022 9713 8023 thumb: function() { 8024 if (offsets.IFD1) { 8025 try { 8026 var IFD1Tags = extractTags.call(this, offsets.IFD1, tags.thumb); 8027 8028 if ('JPEGInterchangeFormat' in IFD1Tags) { 8029 return this.SEGMENT(offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength); 8030 } 8031 } catch (ex) {} 9714 ctx.drawImage(img, 0, 0, width, height); 9715 return canvas; 8032 9716 } 8033 return null;8034 },8035 8036 8037 setExif: function(tag, value) {8038 // Right now only setting of width/height is possible8039 if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; }8040 9717 8041 return setTag.call(this, 'exif', tag, value);8042 },8043 9718 9719 function _purge() { 9720 if (_imgInfo) { 9721 _imgInfo.purge(); 9722 _imgInfo = null; 9723 } 8044 9724 8045 clear: function() {8046 __super__.clear();8047 data = tags = tagDescs = Tiff = offsets = __super__ = null;9725 _binStr = _img = _canvas = _blob = null; 9726 _modified = false; 9727 } 8048 9728 } 9729 9730 return (extensions.Image = HTML5Image); 8049 9731 }); 8050 9732 9733 // Included from: src/javascript/runtime/flash/Runtime.js 8051 9734 8052 // Check if that's APP1 and that it has EXIF 8053 if (this.SHORT(0) !== 0xFFE1 || this.STRING(4, 5).toUpperCase() !== "EXIF\0") { 8054 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8055 } 9735 /** 9736 * Runtime.js 9737 * 9738 * Copyright 2013, Moxiecode Systems AB 9739 * Released under GPL License. 9740 * 9741 * License: http://www.plupload.com/license 9742 * Contributing: http://www.plupload.com/contributing 9743 */ 8056 9744 8057 // Set read order of multi-byte data 8058 this.littleEndian = (this.SHORT(idx) == 0x4949); 9745 /*global ActiveXObject:true */ 8059 9746 8060 // Check if always present bytes are indeed present 8061 if (this.SHORT(idx+=2) !== 0x002A) { 8062 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8063 } 9747 /** 9748 Defines constructor for Flash runtime. 8064 9749 8065 offsets.IFD0 = offsets.tiffHeader + this.LONG(idx += 2); 8066 Tiff = extractTags.call(this, offsets.IFD0, tags.tiff); 9750 @class moxie/runtime/flash/Runtime 9751 @private 9752 */ 9753 define("moxie/runtime/flash/Runtime", [ 9754 "moxie/core/utils/Basic", 9755 "moxie/core/utils/Env", 9756 "moxie/core/utils/Dom", 9757 "moxie/core/Exceptions", 9758 "moxie/runtime/Runtime" 9759 ], function(Basic, Env, Dom, x, Runtime) { 8067 9760 8068 if ('ExifIFDPointer' in Tiff) { 8069 offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer; 8070 delete Tiff.ExifIFDPointer; 8071 } 9761 var type = 'flash', extensions = {}; 8072 9762 8073 if ('GPSInfoIFDPointer' in Tiff) { 8074 offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer; 8075 delete Tiff.GPSInfoIFDPointer; 8076 } 9763 /** 9764 Get the version of the Flash Player 8077 9765 8078 if (Basic.isEmptyObj(Tiff)) { 8079 Tiff = null; 8080 } 9766 @method getShimVersion 9767 @private 9768 @return {Number} Flash Player version 9769 */ 9770 function getShimVersion() { 9771 var version; 8081 9772 8082 // check if we have a thumb as well 8083 var IFD1Offset = this.LONG(offsets.IFD0 + this.SHORT(offsets.IFD0) * 12 + 2); 8084 if (IFD1Offset) { 8085 offsets.IFD1 = offsets.tiffHeader + IFD1Offset; 8086 } 9773 try { 9774 version = navigator.plugins['Shockwave Flash']; 9775 version = version.description; 9776 } catch (e1) { 9777 try { 9778 version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); 9779 } catch (e2) { 9780 version = '0.0'; 9781 } 9782 } 9783 version = version.match(/\d+/g); 9784 return parseFloat(version[0] + '.' + version[1]); 9785 } 8087 9786 8088 9787 8089 function extractTags(IFD_offset, tags2extract) { 8090 var data = this; 8091 var length, i, tag, type, count, size, offset, value, values = [], hash = {}; 8092 8093 var types = { 8094 1 : 'BYTE', 8095 7 : 'UNDEFINED', 8096 2 : 'ASCII', 8097 3 : 'SHORT', 8098 4 : 'LONG', 8099 5 : 'RATIONAL', 8100 9 : 'SLONG', 8101 10: 'SRATIONAL' 8102 }; 9788 /** 9789 Cross-browser SWF removal 9790 - Especially needed to safely and completely remove a SWF in Internet Explorer 8103 9791 8104 var sizes = { 8105 'BYTE' : 1, 8106 'UNDEFINED' : 1, 8107 'ASCII' : 1, 8108 'SHORT' : 2, 8109 'LONG' : 4, 8110 'RATIONAL' : 8, 8111 'SLONG' : 4, 8112 'SRATIONAL' : 8 8113 }; 9792 Originated from SWFObject v2.2 <http://code.google.com/p/swfobject/> 9793 */ 9794 function removeSWF(id) { 9795 var obj = Dom.get(id); 9796 if (obj && obj.nodeName == "OBJECT") { 9797 if (Env.browser === 'IE') { 9798 obj.style.display = "none"; 9799 (function onInit(){ 9800 // http://msdn.microsoft.com/en-us/library/ie/ms534360(v=vs.85).aspx 9801 if (obj.readyState == 4) { 9802 removeObjectInIE(id); 9803 } 9804 else { 9805 setTimeout(onInit, 10); 9806 } 9807 })(); 9808 } 9809 else { 9810 obj.parentNode.removeChild(obj); 9811 } 9812 } 9813 } 8114 9814 8115 length = data.SHORT(IFD_offset);8116 9815 8117 // The size of APP1 including all these elements shall not exceed the 64 Kbytes specified in the JPEG standard. 9816 function removeObjectInIE(id) { 9817 var obj = Dom.get(id); 9818 if (obj) { 9819 for (var i in obj) { 9820 if (typeof obj[i] == "function") { 9821 obj[i] = null; 9822 } 9823 } 9824 obj.parentNode.removeChild(obj); 9825 } 9826 } 8118 9827 8119 for (i = 0; i < length; i++) { 8120 values = []; 9828 /** 9829 Constructor for the Flash Runtime 9830 */ 9831 function FlashRuntime(options) { 9832 var I = this, initTimer; 9833 9834 options = Basic.extend({ swf_url: Env.swf_url }, options); 9835 9836 Runtime.call(this, options, type, { 9837 access_binary: function(value) { 9838 return value && I.mode === 'browser'; 9839 }, 9840 access_image_binary: function(value) { 9841 return value && I.mode === 'browser'; 9842 }, 9843 display_media: Runtime.capTest(defined('moxie/image/Image')), 9844 do_cors: Runtime.capTrue, 9845 drag_and_drop: false, 9846 report_upload_progress: function() { 9847 return I.mode === 'client'; 9848 }, 9849 resize_image: Runtime.capTrue, 9850 return_response_headers: false, 9851 return_response_type: function(responseType) { 9852 if (responseType === 'json' && !!window.JSON) { 9853 return true; 9854 } 9855 return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser'; 9856 }, 9857 return_status_code: function(code) { 9858 return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]); 9859 }, 9860 select_file: Runtime.capTrue, 9861 select_multiple: Runtime.capTrue, 9862 send_binary_string: function(value) { 9863 return value && I.mode === 'browser'; 9864 }, 9865 send_browser_cookies: function(value) { 9866 return value && I.mode === 'browser'; 9867 }, 9868 send_custom_headers: function(value) { 9869 return value && I.mode === 'browser'; 9870 }, 9871 send_multipart: Runtime.capTrue, 9872 slice_blob: function(value) { 9873 return value && I.mode === 'browser'; 9874 }, 9875 stream_upload: function(value) { 9876 return value && I.mode === 'browser'; 9877 }, 9878 summon_file_dialog: false, 9879 upload_filesize: function(size) { 9880 return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client'; 9881 }, 9882 use_http_method: function(methods) { 9883 return !Basic.arrayDiff(methods, ['GET', 'POST']); 9884 } 9885 }, { 9886 // capabilities that require specific mode 9887 access_binary: function(value) { 9888 return value ? 'browser' : 'client'; 9889 }, 9890 access_image_binary: function(value) { 9891 return value ? 'browser' : 'client'; 9892 }, 9893 report_upload_progress: function(value) { 9894 return value ? 'browser' : 'client'; 9895 }, 9896 return_response_type: function(responseType) { 9897 return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser']; 9898 }, 9899 return_status_code: function(code) { 9900 return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser']; 9901 }, 9902 send_binary_string: function(value) { 9903 return value ? 'browser' : 'client'; 9904 }, 9905 send_browser_cookies: function(value) { 9906 return value ? 'browser' : 'client'; 9907 }, 9908 send_custom_headers: function(value) { 9909 return value ? 'browser' : 'client'; 9910 }, 9911 slice_blob: function(value) { 9912 return value ? 'browser' : 'client'; 9913 }, 9914 stream_upload: function(value) { 9915 return value ? 'client' : 'browser'; 9916 }, 9917 upload_filesize: function(size) { 9918 return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser'; 9919 } 9920 }, 'client'); 8121 9921 8122 // Set binary reader pointer to beginning of the next tag8123 offset = IFD_offset + 2 + i*12;8124 9922 8125 tag = tags2extract[data.SHORT(offset)]; 9923 // minimal requirement for Flash Player version 9924 if (getShimVersion() < 11.3) { 9925 if (MXI_DEBUG && Env.debug.runtime) { 9926 Env.log("\tFlash didn't meet minimal version requirement (11.3)."); 9927 } 8126 9928 8127 if (tag === undefined) { 8128 continue; // Not the tag we requested 9929 this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before 8129 9930 } 8130 9931 8131 type = types[data.SHORT(offset+=2)];8132 count = data.LONG(offset+=2);8133 size = sizes[type];8134 9932 8135 if (!size) { 8136 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8137 } 9933 Basic.extend(this, { 8138 9934 8139 offset += 4; 9935 getShim: function() { 9936 return Dom.get(this.uid); 9937 }, 8140 9938 8141 // tag can only fit 4 bytes of data, if data is larger we should look outside 8142 if (size * count > 4) { 8143 // instead of data tag contains an offset of the data 8144 offset = data.LONG(offset) + offsets.tiffHeader; 8145 } 9939 shimExec: function(component, action) { 9940 var args = [].slice.call(arguments, 2); 9941 return I.getShim().exec(this.uid, component, action, args); 9942 }, 8146 9943 8147 // in case we left the boundaries of data throw an early exception 8148 if (offset + size * count >= this.length()) { 8149 throw new x.ImageError(x.ImageError.INVALID_META_ERR); 8150 } 9944 init: function() { 9945 var html, el, container; 8151 9946 8152 // special care for the string 8153 if (type === 'ASCII') { 8154 hash[tag] = Basic.trim(data.STRING(offset, count).replace(/\0$/, '')); // strip trailing NULL 8155 continue; 8156 } else { 8157 values = data.asArray(type, offset, count); 8158 value = (count == 1 ? values[0] : values); 9947 container = this.getShimContainer(); 8159 9948 8160 if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') { 8161 hash[tag] = tagDescs[tag][value]; 8162 } else { 8163 hash[tag] = value; 8164 } 8165 } 8166 } 9949 // 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) 9950 Basic.extend(container.style, { 9951 position: 'absolute', 9952 top: '-8px', 9953 left: '-8px', 9954 width: '9px', 9955 height: '9px', 9956 overflow: 'hidden' 9957 }); 8167 9958 8168 return hash;8169 }9959 // insert flash object 9960 html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' + options.swf_url + '" '; 8170 9961 8171 // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported 8172 function setTag(ifd, tag, value) { 8173 var offset, length, tagOffset, valueOffset = 0; 8174 8175 // If tag name passed translate into hex key 8176 if (typeof(tag) === 'string') { 8177 var tmpTags = tags[ifd.toLowerCase()]; 8178 for (var hex in tmpTags) { 8179 if (tmpTags[hex] === tag) { 8180 tag = hex; 8181 break; 8182 } 8183 } 8184 } 8185 offset = offsets[ifd.toLowerCase() + 'IFD']; 8186 length = this.SHORT(offset); 9962 if (Env.browser === 'IE') { 9963 html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '; 9964 } 8187 9965 8188 for (var i = 0; i < length; i++) { 8189 tagOffset = offset + 12 * i + 2; 9966 html += 'width="100%" height="100%" style="outline:0">' + 9967 '<param name="movie" value="' + options.swf_url + '" />' + 9968 '<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Runtime.getGlobalEventTarget() + '" />' + 9969 '<param name="wmode" value="transparent" />' + 9970 '<param name="allowscriptaccess" value="always" />' + 9971 '</object>'; 9972 9973 if (Env.browser === 'IE') { 9974 el = document.createElement('div'); 9975 container.appendChild(el); 9976 el.outerHTML = html; 9977 el = container = null; // just in case 9978 } else { 9979 container.innerHTML = html; 9980 } 8190 9981 8191 if (this.SHORT(tagOffset) == tag) { 8192 valueOffset = tagOffset + 8; 8193 break; 8194 } 8195 } 9982 // Init is dispatched by the shim 9983 initTimer = setTimeout(function() { 9984 if (I && !I.initialized) { // runtime might be already destroyed by this moment 9985 I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); 8196 9986 8197 if (!valueOffset) { 8198 return false; 8199 } 9987 if (MXI_DEBUG && Env.debug.runtime) { 9988 Env.log("\tFlash failed to initialize within a specified period of time (typically 5s)."); 9989 } 9990 } 9991 }, 5000); 9992 }, 8200 9993 8201 try { 8202 this.write(valueOffset, value, 4); 8203 } catch(ex) { 8204 return false; 8205 } 9994 destroy: (function(destroy) { // extend default destroy method 9995 return function() { 9996 removeSWF(I.uid); // SWF removal requires special care in IE 8206 9997 8207 return true; 8208 } 8209 } 9998 destroy.call(I); 9999 clearTimeout(initTimer); // initialization check might be still onwait 10000 options = initTimer = destroy = I = null; 10001 }; 10002 }(this.destroy)) 8210 10003 8211 ExifParser.prototype = BinaryReader.prototype; 10004 }, extensions); 10005 } 8212 10006 8213 return ExifParser; 8214 }); 10007 Runtime.addConstructor(type, FlashRuntime); 8215 10008 8216 // Included from: src/javascript/runtime/html5/image/JPEG.js 10009 return extensions; 10010 }); 8217 10011 8218 /** 8219 * JPEG.js 8220 * 8221 * Copyright 2013, Moxiecode Systems AB 8222 * Released under GPL License. 8223 * 8224 * License: http://www.plupload.com/license 8225 * Contributing: http://www.plupload.com/contributing 8226 */ 10012 // Included from: src/javascript/runtime/flash/file/Blob.js 8227 10013 8228 /** 8229 @class moxie/runtime/html5/image/JPEG 10014 /** 10015 * Blob.js 10016 * 10017 * Copyright 2013, Moxiecode Systems AB 10018 * Released under GPL License. 10019 * 10020 * License: http://www.plupload.com/license 10021 * Contributing: http://www.plupload.com/contributing 10022 */ 10023 10024 /** 10025 @class moxie/runtime/flash/file/Blob 8230 10026 @private 8231 */ 8232 define("moxie/runtime/html5/image/JPEG", [ 8233 "moxie/core/utils/Basic", 8234 "moxie/core/Exceptions", 8235 "moxie/runtime/html5/image/JPEGHeaders", 8236 "moxie/runtime/html5/utils/BinaryReader", 8237 "moxie/runtime/html5/image/ExifParser" 8238 ], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) { 8239 8240 function JPEG(data) { 8241 var _br, _hm, _ep, _info; 8242 8243 _br = new BinaryReader(data); 8244 8245 // check if it is jpeg 8246 if (_br.SHORT(0) !== 0xFFD8) { 8247 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 8248 } 10027 */ 10028 define("moxie/runtime/flash/file/Blob", [ 10029 "moxie/runtime/flash/Runtime", 10030 "moxie/file/Blob" 10031 ], function(extensions, Blob) { 8249 10032 8250 // backup headers 8251 _hm = new JPEGHeaders(data); 10033 var FlashBlob = { 10034 slice: function(blob, start, end, type) { 10035 var self = this.getRuntime(); 8252 10036 8253 // extract exif info 8254 try { 8255 _ep = new ExifParser(_hm.get('app1')[0]); 8256 } catch(ex) {} 10037 if (start < 0) { 10038 start = Math.max(blob.size + start, 0); 10039 } else if (start > 0) { 10040 start = Math.min(start, blob.size); 10041 } 8257 10042 8258 // get dimensions 8259 _info = _getDimensions.call(this); 10043 if (end < 0) { 10044 end = Math.max(blob.size + end, 0); 10045 } else if (end > 0) { 10046 end = Math.min(end, blob.size); 10047 } 8260 10048 8261 Basic.extend(this, { 8262 type: 'image/jpeg', 10049 blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || ''); 8263 10050 8264 size: _br.length(), 10051 if (blob) { 10052 blob = new Blob(self.uid, blob); 10053 } 10054 return blob; 10055 } 10056 }; 8265 10057 8266 width: _info && _info.width || 0, 10058 return (extensions.Blob = FlashBlob); 10059 }); 8267 10060 8268 height: _info && _info.height || 0, 10061 // Included from: src/javascript/runtime/flash/file/FileInput.js 8269 10062 8270 setExif: function(tag, value) { 8271 if (!_ep) { 8272 return false; // or throw an exception 8273 } 10063 /** 10064 * FileInput.js 10065 * 10066 * Copyright 2013, Moxiecode Systems AB 10067 * Released under GPL License. 10068 * 10069 * License: http://www.plupload.com/license 10070 * Contributing: http://www.plupload.com/contributing 10071 */ 8274 10072 8275 if (Basic.typeOf(tag) === 'object') { 8276 Basic.each(tag, function(value, tag) { 8277 _ep.setExif(tag, value); 8278 }); 8279 } else { 8280 _ep.setExif(tag, value); 8281 } 10073 /** 10074 @class moxie/runtime/flash/file/FileInput 10075 @private 10076 */ 10077 define("moxie/runtime/flash/file/FileInput", [ 10078 "moxie/runtime/flash/Runtime", 10079 "moxie/file/File", 10080 "moxie/core/utils/Dom", 10081 "moxie/core/utils/Basic" 10082 ], function(extensions, File, Dom, Basic) { 10083 10084 var FileInput = { 10085 init: function(options) { 10086 var comp = this, I = this.getRuntime(); 10087 var browseButton = Dom.get(options.browse_button); 10088 10089 if (browseButton) { 10090 browseButton.setAttribute('tabindex', -1); 10091 browseButton = null; 10092 } 10093 10094 this.bind("Change", function() { 10095 var files = I.shimExec.call(comp, 'FileInput', 'getFiles'); 10096 comp.files = []; 10097 Basic.each(files, function(file) { 10098 comp.files.push(new File(I.uid, file)); 10099 }); 10100 }, 999); 8282 10101 8283 // update internal headers 8284 _hm.set('app1', _ep.SEGMENT()); 8285 }, 10102 this.getRuntime().shimExec.call(this, 'FileInput', 'init', { 10103 accept: options.accept, 10104 multiple: options.multiple 10105 }); 8286 10106 8287 writeHeaders: function() { 8288 if (!arguments.length) { 8289 // if no arguments passed, update headers internally 8290 return _hm.restore(data); 10107 this.trigger('ready'); 8291 10108 } 8292 return _hm.restore(arguments[0]); 8293 }, 8294 8295 stripHeaders: function(data) { 8296 return _hm.strip(data); 8297 }, 10109 }; 8298 10110 8299 purge: function() { 8300 _purge.call(this); 8301 } 10111 return (extensions.FileInput = FileInput); 8302 10112 }); 8303 10113 8304 if (_ep) { 8305 this.meta = { 8306 tiff: _ep.TIFF(), 8307 exif: _ep.EXIF(), 8308 gps: _ep.GPS(), 8309 thumb: _getThumb() 8310 }; 8311 } 10114 // Included from: src/javascript/runtime/flash/file/FileReader.js 8312 10115 10116 /** 10117 * FileReader.js 10118 * 10119 * Copyright 2013, Moxiecode Systems AB 10120 * Released under GPL License. 10121 * 10122 * License: http://www.plupload.com/license 10123 * Contributing: http://www.plupload.com/contributing 10124 */ 8313 10125 8314 function _getDimensions(br) { 8315 var idx = 0 8316 , marker 8317 , length 8318 ; 8319 8320 if (!br) { 8321 br = _br; 8322 } 8323 8324 // examine all through the end, since some images might have very large APP segments 8325 while (idx <= br.length()) { 8326 marker = br.SHORT(idx += 2); 10126 /** 10127 @class moxie/runtime/flash/file/FileReader 10128 @private 10129 */ 10130 define("moxie/runtime/flash/file/FileReader", [ 10131 "moxie/runtime/flash/Runtime", 10132 "moxie/core/utils/Encode" 10133 ], function(extensions, Encode) { 8327 10134 8328 if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn 8329 idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte) 8330 return { 8331 height: br.SHORT(idx), 8332 width: br.SHORT(idx += 2) 8333 }; 10135 function _formatData(data, op) { 10136 switch (op) { 10137 case 'readAsText': 10138 return Encode.atob(data, 'utf8'); 10139 case 'readAsBinaryString': 10140 return Encode.atob(data); 10141 case 'readAsDataURL': 10142 return data; 8334 10143 } 8335 length = br.SHORT(idx += 2); 8336 idx += length - 2; 10144 return null; 8337 10145 } 8338 return null;8339 }8340 10146 10147 var FileReader = { 10148 read: function(op, blob) { 10149 var comp = this; 8341 10150 8342 function _getThumb() { 8343 var data = _ep.thumb() 8344 , br 8345 , info 8346 ; 8347 8348 if (data) { 8349 br = new BinaryReader(data); 8350 info = _getDimensions(br); 8351 br.clear(); 10151 comp.result = ''; 8352 10152 8353 if (info) { 8354 info.data = data; 8355 return info; 8356 } 8357 } 8358 return null; 8359 } 10153 // special prefix for DataURL read mode 10154 if (op === 'readAsDataURL') { 10155 comp.result = 'data:' + (blob.type || '') + ';base64,'; 10156 } 8360 10157 10158 comp.bind('Progress', function(e, data) { 10159 if (data) { 10160 comp.result += _formatData(data, op); 10161 } 10162 }, 999); 8361 10163 8362 function _purge() { 8363 if (!_ep || !_hm || !_br) { 8364 return; // ignore any repeating purge requests 8365 } 8366 _ep.clear(); 8367 _hm.purge(); 8368 _br.clear(); 8369 _info = _hm = _ep = _br = null; 8370 } 8371 } 10164 return comp.getRuntime().shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid); 10165 } 10166 }; 8372 10167 8373 return JPEG;8374 });10168 return (extensions.FileReader = FileReader); 10169 }); 8375 10170 8376 // Included from: src/javascript/runtime/ html5/image/PNG.js10171 // Included from: src/javascript/runtime/flash/file/FileReaderSync.js 8377 10172 8378 /**8379 * PNG.js8380 *8381 * Copyright 2013, Moxiecode Systems AB8382 * Released under GPL License.8383 *8384 * License: http://www.plupload.com/license8385 * Contributing: http://www.plupload.com/contributing8386 */10173 /** 10174 * FileReaderSync.js 10175 * 10176 * Copyright 2013, Moxiecode Systems AB 10177 * Released under GPL License. 10178 * 10179 * License: http://www.plupload.com/license 10180 * Contributing: http://www.plupload.com/contributing 10181 */ 8387 10182 8388 /**8389 @class moxie/runtime/ html5/image/PNG10183 /** 10184 @class moxie/runtime/flash/file/FileReaderSync 8390 10185 @private 8391 */ 8392 define("moxie/runtime/html5/image/PNG", [ 8393 "moxie/core/Exceptions", 8394 "moxie/core/utils/Basic", 8395 "moxie/runtime/html5/utils/BinaryReader" 8396 ], function(x, Basic, BinaryReader) { 8397 8398 function PNG(data) { 8399 var _br, _hm, _ep, _info; 8400 8401 _br = new BinaryReader(data); 8402 8403 // check if it's png 8404 (function() { 8405 var idx = 0, i = 0 8406 , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A] 8407 ; 10186 */ 10187 define("moxie/runtime/flash/file/FileReaderSync", [ 10188 "moxie/runtime/flash/Runtime", 10189 "moxie/core/utils/Encode" 10190 ], function(extensions, Encode) { 8408 10191 8409 for (i = 0; i < signature.length; i++, idx += 2) { 8410 if (signature[i] != _br.SHORT(idx)) { 8411 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 10192 function _formatData(data, op) { 10193 switch (op) { 10194 case 'readAsText': 10195 return Encode.atob(data, 'utf8'); 10196 case 'readAsBinaryString': 10197 return Encode.atob(data); 10198 case 'readAsDataURL': 10199 return data; 8412 10200 } 10201 return null; 8413 10202 } 8414 }());8415 8416 function _getDimensions() {8417 var chunk, idx;8418 8419 chunk = _getChunkAt.call(this, 8);8420 8421 if (chunk.type == 'IHDR') {8422 idx = chunk.start;8423 return {8424 width: _br.LONG(idx),8425 height: _br.LONG(idx += 4)8426 };8427 }8428 return null;8429 }8430 8431 function _purge() {8432 if (!_br) {8433 return; // ignore any repeating purge requests8434 }8435 _br.clear();8436 data = _info = _hm = _ep = _br = null;8437 }8438 8439 _info = _getDimensions.call(this);8440 10203 8441 Basic.extend(this, { 8442 type: 'image/png', 10204 var FileReaderSync = { 10205 read: function(op, blob) { 10206 var result, self = this.getRuntime(); 8443 10207 8444 size: _br.length(), 10208 result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid); 10209 if (!result) { 10210 return null; // or throw ex 10211 } 8445 10212 8446 width: _info.width, 10213 // special prefix for DataURL read mode 10214 if (op === 'readAsDataURL') { 10215 result = 'data:' + (blob.type || '') + ';base64,' + result; 10216 } 8447 10217 8448 height: _info.height, 10218 return _formatData(result, op, blob.type); 10219 } 10220 }; 8449 10221 8450 purge: function() { 8451 _purge.call(this); 8452 } 10222 return (extensions.FileReaderSync = FileReaderSync); 8453 10223 }); 8454 10224 8455 // for PNG we can safely trigger purge automatically, as we do not keep any data for later 8456 _purge.call(this); 10225 // Included from: src/javascript/runtime/flash/runtime/Transporter.js 8457 10226 8458 function _getChunkAt(idx) { 8459 var length, type, start, CRC; 8460 8461 length = _br.LONG(idx); 8462 type = _br.STRING(idx += 4, 4); 8463 start = idx += 4; 8464 CRC = _br.LONG(idx + length); 10227 /** 10228 * Transporter.js 10229 * 10230 * Copyright 2013, Moxiecode Systems AB 10231 * Released under GPL License. 10232 * 10233 * License: http://www.plupload.com/license 10234 * Contributing: http://www.plupload.com/contributing 10235 */ 8465 10236 8466 return { 8467 length: length, 8468 type: type, 8469 start: start, 8470 CRC: CRC 10237 /** 10238 @class moxie/runtime/flash/runtime/Transporter 10239 @private 10240 */ 10241 define("moxie/runtime/flash/runtime/Transporter", [ 10242 "moxie/runtime/flash/Runtime", 10243 "moxie/file/Blob" 10244 ], function(extensions, Blob) { 10245 10246 var Transporter = { 10247 getAsBlob: function(type) { 10248 var self = this.getRuntime() 10249 , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type) 10250 ; 10251 if (blob) { 10252 return new Blob(self.uid, blob); 10253 } 10254 return null; 10255 } 8471 10256 }; 8472 }8473 }8474 10257 8475 return PNG;8476 });10258 return (extensions.Transporter = Transporter); 10259 }); 8477 10260 8478 // Included from: src/javascript/runtime/ html5/image/ImageInfo.js10261 // Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js 8479 10262 8480 /**8481 * ImageInfo.js8482 *8483 * Copyright 2013, Moxiecode Systems AB8484 * Released under GPL License.8485 *8486 * License: http://www.plupload.com/license8487 * Contributing: http://www.plupload.com/contributing8488 */10263 /** 10264 * XMLHttpRequest.js 10265 * 10266 * Copyright 2013, Moxiecode Systems AB 10267 * Released under GPL License. 10268 * 10269 * License: http://www.plupload.com/license 10270 * Contributing: http://www.plupload.com/contributing 10271 */ 8489 10272 8490 /**8491 @class moxie/runtime/ html5/image/ImageInfo10273 /** 10274 @class moxie/runtime/flash/xhr/XMLHttpRequest 8492 10275 @private 8493 */ 8494 define("moxie/runtime/html5/image/ImageInfo", [ 8495 "moxie/core/utils/Basic", 8496 "moxie/core/Exceptions", 8497 "moxie/runtime/html5/image/JPEG", 8498 "moxie/runtime/html5/image/PNG" 8499 ], 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 signature 8503 - 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 headers 8506 - ability to restore APP headers, that were for example stripped during image manipulation 10276 */ 10277 define("moxie/runtime/flash/xhr/XMLHttpRequest", [ 10278 "moxie/runtime/flash/Runtime", 10279 "moxie/core/utils/Basic", 10280 "moxie/file/Blob", 10281 "moxie/file/File", 10282 "moxie/file/FileReaderSync", 10283 "moxie/runtime/flash/file/FileReaderSync", 10284 "moxie/xhr/FormData", 10285 "moxie/runtime/Transporter", 10286 "moxie/runtime/flash/runtime/Transporter" 10287 ], function(extensions, Basic, Blob, File, FileReaderSync, FileReaderSyncFlash, FormData, Transporter, TransporterFlash) { 8507 10288 8508 @class ImageInfo 8509 @constructor 8510 @param {String} data Image source as binary string 8511 */ 8512 return function(data) { 8513 var _cs = [JPEG, PNG], _img; 8514 8515 // figure out the format, throw: ImageError.WRONG_FORMAT if not supported 8516 _img = (function() { 8517 for (var i = 0; i < _cs.length; i++) { 8518 try { 8519 return new _cs[i](data); 8520 } catch (ex) { 8521 // console.info(ex); 8522 } 8523 } 8524 throw new x.ImageError(x.ImageError.WRONG_FORMAT); 8525 }()); 10289 var XMLHttpRequest = { 8526 10290 8527 Basic.extend(this, { 8528 /** 8529 Image Mime Type extracted from it's depths 10291 send: function(meta, data) { 10292 var target = this, self = target.getRuntime(); 8530 10293 8531 @property type 8532 @type {String} 8533 @default '' 8534 */ 8535 type: '', 10294 function send() { 10295 meta.transport = self.mode; 10296 self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data); 10297 } 8536 10298 8537 /**8538 Image size in bytes8539 10299 8540 @property size8541 @type {Number}8542 @default 08543 */8544 size: 0,10300 function appendBlob(name, blob) { 10301 self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid); 10302 data = null; 10303 send(); 10304 } 8545 10305 8546 /**8547 Image width extracted from image source8548 10306 8549 @property width 8550 @type {Number} 8551 @default 0 8552 */ 8553 width: 0, 10307 function attachBlob(blob, cb) { 10308 var tr = new Transporter(); 8554 10309 8555 /** 8556 Image height extracted from image source 10310 tr.bind("TransportingComplete", function() { 10311 cb(this.result); 10312 }); 8557 10313 8558 @property height 8559 @type {Number} 8560 @default 0 8561 */ 8562 height: 0, 10314 tr.transport(blob.getSource(), blob.type, { 10315 ruid: self.uid 10316 }); 10317 } 8563 10318 8564 /** 8565 Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs. 10319 // copy over the headers if any 10320 if (!Basic.isEmptyObj(meta.headers)) { 10321 Basic.each(meta.headers, function(value, header) { 10322 self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object 10323 }); 10324 } 8566 10325 8567 @method setExif 8568 @param {String} tag Tag to set 8569 @param {Mixed} value Value to assign to the tag 8570 */ 8571 setExif: function() {}, 10326 // transfer over multipart params and blob itself 10327 if (data instanceof FormData) { 10328 var blobField; 10329 data.each(function(value, name) { 10330 if (value instanceof Blob) { 10331 blobField = name; 10332 } else { 10333 self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value); 10334 } 10335 }); 8572 10336 8573 /** 8574 Restores headers to the source. 10337 if (!data.hasBlob()) { 10338 data = null; 10339 send(); 10340 } else { 10341 var blob = data.getBlob(); 10342 if (blob.isDetached()) { 10343 attachBlob(blob, function(attachedBlob) { 10344 blob.destroy(); 10345 appendBlob(blobField, attachedBlob); 10346 }); 10347 } else { 10348 appendBlob(blobField, blob); 10349 } 10350 } 10351 } else if (data instanceof Blob) { 10352 if (data.isDetached()) { 10353 attachBlob(data, function(attachedBlob) { 10354 data.destroy(); 10355 data = attachedBlob.uid; 10356 send(); 10357 }); 10358 } else { 10359 data = data.uid; 10360 send(); 10361 } 10362 } else { 10363 send(); 10364 } 10365 }, 8575 10366 8576 @method writeHeaders 8577 @param {String} data Image source as binary string 8578 @return {String} Updated binary string 8579 */ 8580 writeHeaders: function(data) { 8581 return data; 8582 }, 10367 getResponse: function(responseType) { 10368 var frs, blob, self = this.getRuntime(); 8583 10369 8584 /** 8585 Strip all headers from the source. 10370 blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob'); 8586 10371 8587 @method stripHeaders 8588 @param {String} data Image source as binary string 8589 @return {String} Updated binary string 8590 */ 8591 stripHeaders: function(data) { 8592 return data; 8593 }, 10372 if (blob) { 10373 blob = new File(self.uid, blob); 8594 10374 8595 /** 8596 Dispose resources. 10375 if ('blob' === responseType) { 10376 return blob; 10377 } 8597 10378 8598 @method purge 8599 */ 8600 purge: function() { 8601 data = null; 8602 } 8603 }); 10379 try { 10380 frs = new FileReaderSync(); 10381 10382 if (!!~Basic.inArray(responseType, ["", "text"])) { 10383 return frs.readAsText(blob); 10384 } else if ('json' === responseType && !!window.JSON) { 10385 return JSON.parse(frs.readAsText(blob)); 10386 } 10387 } finally { 10388 blob.destroy(); 10389 } 10390 } 10391 return null; 10392 }, 8604 10393 8605 Basic.extend(this, _img); 10394 abort: function(upload_complete_flag) { 10395 var self = this.getRuntime(); 8606 10396 8607 this.purge = function() { 8608 _img.purge(); 8609 _img = null; 8610 }; 8611 }; 8612 }); 10397 self.shimExec.call(this, 'XMLHttpRequest', 'abort'); 8613 10398 8614 // Included from: src/javascript/runtime/html5/image/MegaPixel.js 10399 this.dispatchEvent('readystatechange'); 10400 // this.dispatchEvent('progress'); 10401 this.dispatchEvent('abort'); 8615 10402 8616 /** 8617 (The MIT License) 10403 //if (!upload_complete_flag) { 10404 // this.dispatchEvent('uploadprogress'); 10405 //} 10406 } 10407 }; 8618 10408 8619 Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>; 10409 return (extensions.XMLHttpRequest = XMLHttpRequest); 10410 }); 8620 10411 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: 8628 8629 The above copyright notice and this permission notice shall be 8630 included in all copies or substantial portions of the Software. 8631 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 */ 10412 // Included from: src/javascript/runtime/flash/image/Image.js 8640 10413 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 */ 10414 /** 10415 * Image.js 10416 * 10417 * Copyright 2013, Moxiecode Systems AB 10418 * Released under GPL License. 10419 * 10420 * License: http://www.plupload.com/license 10421 * Contributing: http://www.plupload.com/contributing 10422 */ 8651 10423 8652 /**8653 @class moxie/runtime/ html5/image/MegaPixel10424 /** 10425 @class moxie/runtime/flash/image/Image 8654 10426 @private 8655 */ 8656 define("moxie/runtime/html5/image/MegaPixel", [], function() { 10427 */ 10428 define("moxie/runtime/flash/image/Image", [ 10429 "moxie/runtime/flash/Runtime", 10430 "moxie/core/utils/Basic", 10431 "moxie/runtime/Transporter", 10432 "moxie/file/Blob", 10433 "moxie/file/FileReaderSync" 10434 ], function(extensions, Basic, Transporter, Blob, FileReaderSync) { 10435 10436 var Image = { 10437 loadFromBlob: function(blob) { 10438 var comp = this, self = comp.getRuntime(); 10439 10440 function exec(srcBlob) { 10441 self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid); 10442 comp = self = null; 10443 } 8657 10444 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 } 10445 if (blob.isDetached()) { // binary string 10446 var tr = new Transporter(); 10447 tr.bind("TransportingComplete", function() { 10448 exec(tr.result.getSource()); 10449 }); 10450 tr.transport(blob.getSource(), blob.type, { ruid: self.uid }); 10451 } else { 10452 exec(blob.getSource()); 10453 } 10454 }, 8694 10455 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 } 10456 loadFromImage: function(img) { 10457 var self = this.getRuntime(); 10458 return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid); 10459 }, 8714 10460 10461 getInfo: function() { 10462 var self = this.getRuntime() 10463 , info = self.shimExec.call(this, 'Image', 'getInfo') 10464 ; 8715 10465 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 } 10466 if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) { 10467 info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data); 10468 } 10469 return info; 10470 }, 8744 10471 8745 return { 8746 isSubsampled: detectSubsampling, 8747 renderTo: renderImageToCanvas 8748 }; 8749 }); 10472 getAsBlob: function(type, quality) { 10473 var self = this.getRuntime() 10474 , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality) 10475 ; 10476 if (blob) { 10477 return new Blob(self.uid, blob); 10478 } 10479 return null; 10480 }, 8750 10481 8751 // Included from: src/javascript/runtime/html5/image/Image.js 10482 getAsDataURL: function() { 10483 var self = this.getRuntime() 10484 , blob = self.Image.getAsBlob.apply(this, arguments) 10485 , frs 10486 ; 10487 if (!blob) { 10488 return null; 10489 } 10490 frs = new FileReaderSync(); 10491 return frs.readAsDataURL(blob); 10492 } 10493 }; 8752 10494 8753 /** 8754 * Image.js 8755 * 8756 * Copyright 2013, Moxiecode Systems AB 8757 * Released under GPL License. 8758 * 8759 * License: http://www.plupload.com/license 8760 * Contributing: http://www.plupload.com/contributing 8761 */ 10495 return (extensions.Image = Image); 10496 }); 10497 10498 // Included from: src/javascript/runtime/silverlight/Runtime.js 10499 10500 /** 10501 * RunTime.js 10502 * 10503 * Copyright 2013, Moxiecode Systems AB 10504 * Released under GPL License. 10505 * 10506 * License: http://www.plupload.com/license 10507 * Contributing: http://www.plupload.com/contributing 10508 */ 8762 10509 8763 /** 8764 @class moxie/runtime/html5/image/Image 8765 @private 8766 */ 8767 define("moxie/runtime/html5/image/Image", [ 8768 "moxie/runtime/html5/Runtime", 8769 "moxie/core/utils/Basic", 8770 "moxie/core/Exceptions", 8771 "moxie/core/utils/Encode", 8772 "moxie/file/Blob", 8773 "moxie/file/File", 8774 "moxie/runtime/html5/image/ImageInfo", 8775 "moxie/runtime/html5/image/MegaPixel", 8776 "moxie/core/utils/Mime", 8777 "moxie/core/utils/Env" 8778 ], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, MegaPixel, Mime, Env) { 8779 8780 function HTML5Image() { 8781 var me = this 8782 , _img, _imgInfo, _canvas, _binStr, _blob 8783 , _modified = false // is set true whenever image is modified 8784 , _preserveHeaders = true 8785 ; 8786 8787 Basic.extend(this, { 8788 loadFromBlob: function(blob) { 8789 var comp = this, I = comp.getRuntime() 8790 , asBinary = arguments.length > 1 ? arguments[1] : true 8791 ; 10510 /*global ActiveXObject:true */ 8792 10511 8793 if (!I.can('access_binary')) { 8794 throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); 8795 } 10512 /** 10513 Defines constructor for Silverlight runtime. 8796 10514 8797 _blob = blob; 10515 @class moxie/runtime/silverlight/Runtime 10516 @private 10517 */ 10518 define("moxie/runtime/silverlight/Runtime", [ 10519 "moxie/core/utils/Basic", 10520 "moxie/core/utils/Env", 10521 "moxie/core/utils/Dom", 10522 "moxie/core/Exceptions", 10523 "moxie/runtime/Runtime" 10524 ], function(Basic, Env, Dom, x, Runtime) { 10525 10526 var type = "silverlight", extensions = {}; 10527 10528 function isInstalled(version) { 10529 var isVersionSupported = false, control = null, actualVer, 10530 actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0; 8798 10531 8799 if (blob.isDetached()) { 8800 _binStr = blob.getSource(); 8801 _preload.call(this, _binStr); 8802 return; 8803 } else { 8804 _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) { 8805 if (asBinary) { 8806 _binStr = _toBinary(dataUrl); 10532 try { 10533 try { 10534 control = new ActiveXObject('AgControl.AgControl'); 10535 10536 if (control.IsVersionSupported(version)) { 10537 isVersionSupported = true; 8807 10538 } 8808 _preload.call(comp, dataUrl);8809 });8810 }8811 },8812 10539 8813 loadFromImage: function(img, exact) { 8814 this.meta = img.meta; 10540 control = null; 10541 } catch (e) { 10542 var plugin = navigator.plugins["Silverlight Plug-In"]; 8815 10543 8816 _blob = new File(null, { 8817 name: img.name, 8818 size: img.size, 8819 type: img.type 8820 }); 10544 if (plugin) { 10545 actualVer = plugin.description; 8821 10546 8822 _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL()); 8823 }, 10547 if (actualVer === "1.0.30226.2") { 10548 actualVer = "2.0.30226.2"; 10549 } 8824 10550 8825 getInfo: function() { 8826 var I = this.getRuntime(), info; 10551 actualVerArray = actualVer.split("."); 8827 10552 8828 if (!_imgInfo && _binStr && I.can('access_image_binary')) {8829 _imgInfo = new ImageInfo(_binStr);8830 }10553 while (actualVerArray.length > 3) { 10554 actualVerArray.pop(); 10555 } 8831 10556 8832 info = { 8833 width: _getImg().width || 0, 8834 height: _getImg().height || 0, 8835 type: _blob.type || Mime.getFileMime(_blob.name), 8836 size: _binStr && _binStr.length || _blob.size || 0, 8837 name: _blob.name || '', 8838 meta: _imgInfo && _imgInfo.meta || this.meta || {} 8839 }; 10557 while ( actualVerArray.length < 4) { 10558 actualVerArray.push(0); 10559 } 8840 10560 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 }); 8847 } 10561 reqVerArray = version.split("."); 8848 10562 8849 return info; 8850 }, 10563 while (reqVerArray.length > 4) { 10564 reqVerArray.pop(); 10565 } 8851 10566 8852 downsize: function() { 8853 _downsize.apply(this, arguments); 8854 }, 10567 do { 10568 requiredVersionPart = parseInt(reqVerArray[index], 10); 10569 actualVersionPart = parseInt(actualVerArray[index], 10); 10570 index++; 10571 } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart); 8855 10572 8856 getAsCanvas: function() { 8857 if (_canvas) { 8858 _canvas.id = this.uid + '_canvas'; 10573 if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) { 10574 isVersionSupported = true; 10575 } 10576 } 10577 } 10578 } catch (e2) { 10579 isVersionSupported = false; 8859 10580 } 8860 return _canvas;8861 },8862 10581 8863 getAsBlob: function(type, quality) { 8864 if (type !== this.type) { 8865 // if different mime type requested prepare image for conversion 8866 _downsize.call(this, this.width, this.height, false); 8867 } 8868 return new File(null, { 8869 name: _blob.name || '', 8870 type: type, 8871 data: me.getAsBinaryString.call(this, type, quality) 8872 }); 8873 }, 10582 return isVersionSupported; 10583 } 8874 10584 8875 getAsDataURL: function(type) { 8876 var quality = arguments[1] || 90; 10585 /** 10586 Constructor for the Silverlight Runtime 10587 */ 10588 function SilverlightRuntime(options) { 10589 var I = this, initTimer; 10590 10591 options = Basic.extend({ xap_url: Env.xap_url }, options); 10592 10593 Runtime.call(this, options, type, { 10594 access_binary: Runtime.capTrue, 10595 access_image_binary: Runtime.capTrue, 10596 display_media: Runtime.capTest(defined('moxie/image/Image')), 10597 do_cors: Runtime.capTrue, 10598 drag_and_drop: false, 10599 report_upload_progress: Runtime.capTrue, 10600 resize_image: Runtime.capTrue, 10601 return_response_headers: function(value) { 10602 return value && I.mode === 'client'; 10603 }, 10604 return_response_type: function(responseType) { 10605 if (responseType !== 'json') { 10606 return true; 10607 } else { 10608 return !!window.JSON; 10609 } 10610 }, 10611 return_status_code: function(code) { 10612 return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]); 10613 }, 10614 select_file: Runtime.capTrue, 10615 select_multiple: Runtime.capTrue, 10616 send_binary_string: Runtime.capTrue, 10617 send_browser_cookies: function(value) { 10618 return value && I.mode === 'browser'; 10619 }, 10620 send_custom_headers: function(value) { 10621 return value && I.mode === 'client'; 10622 }, 10623 send_multipart: Runtime.capTrue, 10624 slice_blob: Runtime.capTrue, 10625 stream_upload: true, 10626 summon_file_dialog: false, 10627 upload_filesize: Runtime.capTrue, 10628 use_http_method: function(methods) { 10629 return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']); 10630 } 10631 }, { 10632 // capabilities that require specific mode 10633 return_response_headers: function(value) { 10634 return value ? 'client' : 'browser'; 10635 }, 10636 return_status_code: function(code) { 10637 return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser']; 10638 }, 10639 send_browser_cookies: function(value) { 10640 return value ? 'browser' : 'client'; 10641 }, 10642 send_custom_headers: function(value) { 10643 return value ? 'client' : 'browser'; 10644 }, 10645 use_http_method: function(methods) { 10646 return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser']; 10647 } 10648 }); 8877 10649 8878 // if image has not been modified, return the source right away8879 if (!_modified) {8880 return _img.src;8881 }8882 10650 8883 if ('image/jpeg' !== type) { 8884 return _canvas.toDataURL('image/png'); 8885 } else { 8886 try { 8887 // older Geckos used to result in an exception on quality argument 8888 return _canvas.toDataURL('image/jpeg', quality/100); 8889 } catch (ex) { 8890 return _canvas.toDataURL('image/jpeg'); 10651 // minimal requirement 10652 if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') { 10653 if (MXI_DEBUG && Env.debug.runtime) { 10654 Env.log("\tSilverlight is not installed or minimal version (2.0.31005.0) requirement not met (not likely)."); 8891 10655 } 8892 }8893 },8894 10656 8895 getAsBinaryString: function(type, quality) { 8896 // if image has not been modified, return the source right away 8897 if (!_modified) { 8898 // if image was not loaded from binary string 8899 if (!_binStr) { 8900 _binStr = _toBinary(me.getAsDataURL(type, quality)); 8901 } 8902 return _binStr; 10657 this.mode = false; 8903 10658 } 8904 10659 8905 if ('image/jpeg' !== type) {8906 _binStr = _toBinary(me.getAsDataURL(type, quality));8907 } else {8908 var dataUrl;8909 10660 8910 // if jpeg8911 if (!quality) {8912 quality = 90;8913 } 10661 Basic.extend(this, { 10662 getShim: function() { 10663 return Dom.get(this.uid).content.Moxie; 10664 }, 8914 10665 8915 try { 8916 // older Geckos used to result in an exception on quality argument 8917 dataUrl = _canvas.toDataURL('image/jpeg', quality/100); 8918 } catch (ex) { 8919 dataUrl = _canvas.toDataURL('image/jpeg'); 8920 } 10666 shimExec: function(component, action) { 10667 var args = [].slice.call(arguments, 2); 10668 return I.getShim().exec(this.uid, component, action, args); 10669 }, 8921 10670 8922 _binStr = _toBinary(dataUrl); 10671 init : function() { 10672 var container; 8923 10673 8924 if (_imgInfo) { 8925 _binStr = _imgInfo.stripHeaders(_binStr); 10674 container = this.getShimContainer(); 8926 10675 8927 if (_preserveHeaders) { 8928 // update dimensions info in exif 8929 if (_imgInfo.meta && _imgInfo.meta.exif) { 8930 _imgInfo.setExif({ 8931 PixelXDimension: this.width, 8932 PixelYDimension: this.height 8933 }); 10676 container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' + 10677 '<param name="source" value="' + options.xap_url + '"/>' + 10678 '<param name="background" value="Transparent"/>' + 10679 '<param name="windowless" value="true"/>' + 10680 '<param name="enablehtmlaccess" value="true"/>' + 10681 '<param name="initParams" value="uid=' + this.uid + ',target=' + Runtime.getGlobalEventTarget() + '"/>' + 10682 '</object>'; 10683 10684 // Init is dispatched by the shim 10685 initTimer = setTimeout(function() { 10686 if (I && !I.initialized) { // runtime might be already destroyed by this moment 10687 I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); 10688 10689 if (MXI_DEBUG && Env.debug.runtime) { 10690 Env.log("\Silverlight failed to initialize within a specified period of time (5-10s)."); 10691 } 8934 10692 } 10693 }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac) 10694 }, 8935 10695 8936 // re-inject the headers 8937 _binStr = _imgInfo.writeHeaders(_binStr); 8938 } 10696 destroy: (function(destroy) { // extend default destroy method 10697 return function() { 10698 destroy.call(I); 10699 clearTimeout(initTimer); // initialization check might be still onwait 10700 options = initTimer = destroy = I = null; 10701 }; 10702 }(this.destroy)) 8939 10703 8940 // will be re-created from fresh on next getInfo call 8941 _imgInfo.purge(); 8942 _imgInfo = null; 8943 } 8944 } 10704 }, extensions); 10705 } 8945 10706 8946 _modified = false;10707 Runtime.addConstructor(type, SilverlightRuntime); 8947 10708 8948 return _binStr;8949 },10709 return extensions; 10710 }); 8950 10711 8951 destroy: function() { 8952 me = null; 8953 _purge.call(this); 8954 this.getRuntime().getShim().removeInstance(this.uid); 8955 } 10712 // Included from: src/javascript/runtime/silverlight/file/Blob.js 10713 10714 /** 10715 * Blob.js 10716 * 10717 * Copyright 2013, Moxiecode Systems AB 10718 * Released under GPL License. 10719 * 10720 * License: http://www.plupload.com/license 10721 * Contributing: http://www.plupload.com/contributing 10722 */ 10723 10724 /** 10725 @class moxie/runtime/silverlight/file/Blob 10726 @private 10727 */ 10728 define("moxie/runtime/silverlight/file/Blob", [ 10729 "moxie/runtime/silverlight/Runtime", 10730 "moxie/core/utils/Basic", 10731 "moxie/runtime/flash/file/Blob" 10732 ], function(extensions, Basic, Blob) { 10733 return (extensions.Blob = Basic.extend({}, Blob)); 8956 10734 }); 8957 10735 10736 // Included from: src/javascript/runtime/silverlight/file/FileInput.js 8958 10737 8959 function _getImg() { 8960 if (!_canvas && !_img) { 8961 throw new x.ImageError(x.DOMException.INVALID_STATE_ERR); 8962 } 8963 return _canvas || _img; 8964 } 10738 /** 10739 * FileInput.js 10740 * 10741 * Copyright 2013, Moxiecode Systems AB 10742 * Released under GPL License. 10743 * 10744 * License: http://www.plupload.com/license 10745 * Contributing: http://www.plupload.com/contributing 10746 */ 8965 10747 10748 /** 10749 @class moxie/runtime/silverlight/file/FileInput 10750 @private 10751 */ 10752 define("moxie/runtime/silverlight/file/FileInput", [ 10753 "moxie/runtime/silverlight/Runtime", 10754 "moxie/file/File", 10755 "moxie/core/utils/Dom", 10756 "moxie/core/utils/Basic" 10757 ], function(extensions, File, Dom, Basic) { 8966 10758 8967 function _toBinary(str) { 8968 return Encode.atob(str.substring(str.indexOf('base64,') + 7)); 8969 } 10759 function toFilters(accept) { 10760 var filter = ''; 10761 for (var i = 0; i < accept.length; i++) { 10762 filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.'); 10763 } 10764 return filter; 10765 } 8970 10766 8971 10767 8972 function _toDataUrl(str, type) { 8973 return 'data:' + (type || '') + ';base64,' + Encode.btoa(str); 8974 } 10768 var FileInput = { 10769 init: function(options) { 10770 var comp = this, I = this.getRuntime(); 10771 var browseButton = Dom.get(options.browse_button); 8975 10772 10773 if (browseButton) { 10774 browseButton.setAttribute('tabindex', -1); 10775 browseButton = null; 10776 } 8976 10777 8977 function _preload(str) { 8978 var comp = this; 10778 this.bind("Change", function() { 10779 var files = I.shimExec.call(comp, 'FileInput', 'getFiles'); 10780 comp.files = []; 10781 Basic.each(files, function(file) { 10782 comp.files.push(new File(I.uid, file)); 10783 }); 10784 }, 999); 8979 10785 8980 _img = new Image(); 8981 _img.onerror = function() { 8982 _purge.call(this); 8983 comp.trigger('error', x.ImageError.WRONG_FORMAT); 8984 }; 8985 _img.onload = function() { 8986 comp.trigger('load'); 10786 I.shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.multiple); 10787 this.trigger('ready'); 10788 }, 10789 10790 setOption: function(name, value) { 10791 if (name == 'accept') { 10792 value = toFilters(value); 10793 } 10794 this.getRuntime().shimExec.call(this, 'FileInput', 'setOption', name, value); 10795 } 8987 10796 }; 8988 10797 8989 _img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);8990 } 10798 return (extensions.FileInput = FileInput); 10799 }); 8991 10800 10801 // Included from: src/javascript/runtime/silverlight/file/FileDrop.js 8992 10802 8993 function _readAsDataUrl(file, callback) { 8994 var comp = this, fr; 10803 /** 10804 * FileDrop.js 10805 * 10806 * Copyright 2013, Moxiecode Systems AB 10807 * Released under GPL License. 10808 * 10809 * License: http://www.plupload.com/license 10810 * Contributing: http://www.plupload.com/contributing 10811 */ 8995 10812 8996 // use FileReader if it's available8997 if (window.FileReader) { 8998 fr = new FileReader(); 8999 fr.onload = function() {9000 callback(this.result);9001 };9002 fr.onerror = function() {9003 comp.trigger('error', x.ImageError.WRONG_FORMAT);9004 };9005 fr.readAsDataURL(file); 9006 } else {9007 return callback(file.getAsDataURL());9008 }9009 }10813 /** 10814 @class moxie/runtime/silverlight/file/FileDrop 10815 @private 10816 */ 10817 define("moxie/runtime/silverlight/file/FileDrop", [ 10818 "moxie/runtime/silverlight/Runtime", 10819 "moxie/core/utils/Dom", 10820 "moxie/core/utils/Events" 10821 ], function(extensions, Dom, Events) { 10822 10823 // not exactly useful, since works only in safari (...crickets...) 10824 var FileDrop = { 10825 init: function() { 10826 var comp = this, self = comp.getRuntime(), dropZone; 9010 10827 9011 function _downsize(width, height, crop, preserveHeaders) { 9012 var self = this 9013 , scale 9014 , mathFn 9015 , x = 0 9016 , y = 0 9017 , img 9018 , destWidth 9019 , destHeight 9020 , orientation 9021 ; 10828 dropZone = self.getShimContainer(); 9022 10829 9023 _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString()) 10830 Events.addEvent(dropZone, 'dragover', function(e) { 10831 e.preventDefault(); 10832 e.stopPropagation(); 10833 e.dataTransfer.dropEffect = 'copy'; 10834 }, comp.uid); 9024 10835 9025 // take into account orientation tag 9026 orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1; 10836 Events.addEvent(dropZone, 'dragenter', function(e) { 10837 e.preventDefault(); 10838 var flag = Dom.get(self.uid).dragEnter(e); 10839 // If handled, then stop propagation of event in DOM 10840 if (flag) { 10841 e.stopPropagation(); 10842 } 10843 }, comp.uid); 9027 10844 9028 if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation 9029 // swap dimensions 9030 var tmp = width; 9031 width = height; 9032 height = tmp; 9033 } 10845 Events.addEvent(dropZone, 'drop', function(e) { 10846 e.preventDefault(); 10847 var flag = Dom.get(self.uid).dragDrop(e); 10848 // If handled, then stop propagation of event in DOM 10849 if (flag) { 10850 e.stopPropagation(); 10851 } 10852 }, comp.uid); 9034 10853 9035 img = _getImg(); 10854 return self.shimExec.call(this, 'FileDrop', 'init'); 10855 } 10856 }; 9036 10857 9037 // unify dimensions 9038 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 value 9042 width = Math.min(width, img.width); 9043 height = Math.min(height, img.height); 10858 return (extensions.FileDrop = FileDrop); 10859 }); 9044 10860 9045 scale = Math.max(width/img.width, height/img.height); 9046 } 9047 9048 // we only downsize here 9049 if (scale > 1 && !crop && preserveHeaders) { 9050 this.trigger('Resize'); 9051 return; 9052 } 10861 // Included from: src/javascript/runtime/silverlight/file/FileReader.js 9053 10862 9054 // prepare canvas if necessary 9055 if (!_canvas) { 9056 _canvas = document.createElement("canvas"); 9057 } 10863 /** 10864 * FileReader.js 10865 * 10866 * Copyright 2013, Moxiecode Systems AB 10867 * Released under GPL License. 10868 * 10869 * License: http://www.plupload.com/license 10870 * Contributing: http://www.plupload.com/contributing 10871 */ 9058 10872 9059 // calculate dimensions of proportionally resized image 9060 destWidth = Math.round(img.width * scale); 9061 destHeight = Math.round(img.height * scale); 10873 /** 10874 @class moxie/runtime/silverlight/file/FileReader 10875 @private 10876 */ 10877 define("moxie/runtime/silverlight/file/FileReader", [ 10878 "moxie/runtime/silverlight/Runtime", 10879 "moxie/core/utils/Basic", 10880 "moxie/runtime/flash/file/FileReader" 10881 ], function(extensions, Basic, FileReader) { 10882 return (extensions.FileReader = Basic.extend({}, FileReader)); 10883 }); 9062 10884 9063 // scale image and canvas 9064 if (crop) { 9065 _canvas.width = width; 9066 _canvas.height = height; 10885 // Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js 9067 10886 9068 // if dimensions of the resulting image still larger than canvas, center it 9069 if (destWidth > width) { 9070 x = Math.round((destWidth - width) / 2); 9071 } 10887 /** 10888 * FileReaderSync.js 10889 * 10890 * Copyright 2013, Moxiecode Systems AB 10891 * Released under GPL License. 10892 * 10893 * License: http://www.plupload.com/license 10894 * Contributing: http://www.plupload.com/contributing 10895 */ 9072 10896 9073 if (destHeight > height) { 9074 y = Math.round((destHeight - height) / 2); 9075 } 9076 } else { 9077 _canvas.width = destWidth; 9078 _canvas.height = destHeight; 9079 } 10897 /** 10898 @class moxie/runtime/silverlight/file/FileReaderSync 10899 @private 10900 */ 10901 define("moxie/runtime/silverlight/file/FileReaderSync", [ 10902 "moxie/runtime/silverlight/Runtime", 10903 "moxie/core/utils/Basic", 10904 "moxie/runtime/flash/file/FileReaderSync" 10905 ], function(extensions, Basic, FileReaderSync) { 10906 return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync)); 10907 }); 9080 10908 9081 // rotate if required, according to orientation tag 9082 if (!_preserveHeaders) { 9083 _rotateToOrientaion(_canvas.width, _canvas.height, orientation); 9084 } 10909 // Included from: src/javascript/runtime/silverlight/runtime/Transporter.js 9085 10910 9086 _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight); 10911 /** 10912 * Transporter.js 10913 * 10914 * Copyright 2013, Moxiecode Systems AB 10915 * Released under GPL License. 10916 * 10917 * License: http://www.plupload.com/license 10918 * Contributing: http://www.plupload.com/contributing 10919 */ 9087 10920 9088 this.width = _canvas.width; 9089 this.height = _canvas.height; 10921 /** 10922 @class moxie/runtime/silverlight/runtime/Transporter 10923 @private 10924 */ 10925 define("moxie/runtime/silverlight/runtime/Transporter", [ 10926 "moxie/runtime/silverlight/Runtime", 10927 "moxie/core/utils/Basic", 10928 "moxie/runtime/flash/runtime/Transporter" 10929 ], function(extensions, Basic, Transporter) { 10930 return (extensions.Transporter = Basic.extend({}, Transporter)); 10931 }); 9090 10932 9091 _modified = true; 9092 self.trigger('Resize'); 9093 } 10933 // Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js 9094 10934 10935 /** 10936 * XMLHttpRequest.js 10937 * 10938 * Copyright 2013, Moxiecode Systems AB 10939 * Released under GPL License. 10940 * 10941 * License: http://www.plupload.com/license 10942 * Contributing: http://www.plupload.com/contributing 10943 */ 9095 10944 9096 function _drawToCanvas(img, canvas, x, y, w, h) { 9097 if (Env.OS === 'iOS') { 9098 // avoid squish bug in iOS6 9099 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 } 10945 /** 10946 @class moxie/runtime/silverlight/xhr/XMLHttpRequest 10947 @private 10948 */ 10949 define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [ 10950 "moxie/runtime/silverlight/Runtime", 10951 "moxie/core/utils/Basic", 10952 "moxie/runtime/flash/xhr/XMLHttpRequest", 10953 "moxie/runtime/silverlight/file/FileReaderSync", 10954 "moxie/runtime/silverlight/runtime/Transporter" 10955 ], function(extensions, Basic, XMLHttpRequest, FileReaderSyncSilverlight, TransporterSilverlight) { 10956 return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest)); 10957 }); 9105 10958 10959 // Included from: src/javascript/runtime/silverlight/image/Image.js 9106 10960 9107 10961 /** 9108 * Transform canvas coordination according to specified frame size and orientation 9109 * Orientation value is from EXIF tag 9110 * @author Shinichi Tomita <shinichi.tomita@gmail.com> 9111 */ 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; 9124 } 9125 9126 /** 9127 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. 9128 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. 9129 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. 9130 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. 9131 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. 9132 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. 9133 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. 9134 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. 9135 */ 10962 * Image.js 10963 * 10964 * Copyright 2013, Moxiecode Systems AB 10965 * Released under GPL License. 10966 * 10967 * License: http://www.plupload.com/license 10968 * Contributing: http://www.plupload.com/contributing 10969 */ 9136 10970 9137 var ctx = _canvas.getContext('2d'); 9138 switch (orientation) { 9139 case 2: 9140 // horizontal flip 9141 ctx.translate(width, 0); 9142 ctx.scale(-1, 1); 9143 break; 9144 case 3: 9145 // 180 rotate left 9146 ctx.translate(width, height); 9147 ctx.rotate(Math.PI); 9148 break; 9149 case 4: 9150 // vertical flip 9151 ctx.translate(0, height); 9152 ctx.scale(1, -1); 9153 break; 9154 case 5: 9155 // vertical flip + 90 rotate right 9156 ctx.rotate(0.5 * Math.PI); 9157 ctx.scale(1, -1); 9158 break; 9159 case 6: 9160 // 90 rotate right 9161 ctx.rotate(0.5 * Math.PI); 9162 ctx.translate(0, -height); 9163 break; 9164 case 7: 9165 // horizontal flip + 90 rotate right 9166 ctx.rotate(0.5 * Math.PI); 9167 ctx.translate(width, -height); 9168 ctx.scale(-1, 1); 9169 break; 9170 case 8: 9171 // 90 rotate left 9172 ctx.rotate(-0.5 * Math.PI); 9173 ctx.translate(-width, 0); 9174 break; 9175 } 9176 } 10971 /** 10972 @class moxie/runtime/silverlight/image/Image 10973 @private 10974 */ 10975 define("moxie/runtime/silverlight/image/Image", [ 10976 "moxie/runtime/silverlight/Runtime", 10977 "moxie/core/utils/Basic", 10978 "moxie/file/Blob", 10979 "moxie/runtime/flash/image/Image" 10980 ], function(extensions, Basic, Blob, Image) { 10981 return (extensions.Image = Basic.extend({}, Image, { 10982 10983 getInfo: function() { 10984 var self = this.getRuntime() 10985 , grps = ['tiff', 'exif', 'gps', 'thumb'] 10986 , info = { meta: {} } 10987 , rawInfo = self.shimExec.call(this, 'Image', 'getInfo') 10988 ; 9177 10989 10990 if (rawInfo.meta) { 10991 Basic.each(grps, function(grp) { 10992 var meta = rawInfo.meta[grp] 10993 , tag 10994 , i 10995 , length 10996 , value 10997 ; 10998 if (meta && meta.keys) { 10999 info.meta[grp] = {}; 11000 for (i = 0, length = meta.keys.length; i < length; i++) { 11001 tag = meta.keys[i]; 11002 value = meta[tag]; 11003 if (value) { 11004 // convert numbers 11005 if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero) 11006 value = parseInt(value, 10); 11007 } else if (/^\d*\.\d+$/.test(value)) { // double 11008 value = parseFloat(value); 11009 } 11010 info.meta[grp][tag] = value; 11011 } 11012 } 11013 } 11014 }); 9178 11015 9179 function _purge() { 9180 if (_imgInfo) { 9181 _imgInfo.purge(); 9182 _imgInfo = null; 9183 } 9184 _binStr = _img = _canvas = _blob = null; 9185 _modified = false; 9186 } 9187 } 11016 // save thumb data as blob 11017 if (info.meta && info.meta.thumb && info.meta.thumb.data && !(self.meta.thumb.data instanceof Blob)) { 11018 info.meta.thumb.data = new Blob(self.uid, info.meta.thumb.data); 11019 } 11020 } 9188 11021 9189 return (extensions.Image = HTML5Image); 9190 }); 11022 info.width = parseInt(rawInfo.width, 10); 11023 info.height = parseInt(rawInfo.height, 10); 11024 info.size = parseInt(rawInfo.size, 10); 11025 info.type = rawInfo.type; 11026 info.name = rawInfo.name; 9191 11027 9192 /** 9193 * Stub for moxie/runtime/flash/Runtime 9194 * @private 9195 */ 9196 define("moxie/runtime/flash/Runtime", [ 9197 ], function() { 9198 return {}; 9199 }); 11028 return info; 11029 }, 9200 11030 9201 /** 9202 * Stub for moxie/runtime/silverlight/Runtime 9203 * @private 9204 */ 9205 define("moxie/runtime/silverlight/Runtime", [ 9206 ], function() { 9207 return {}; 9208 }); 11031 resize: function(rect, ratio, opts) { 11032 this.getRuntime().shimExec.call(this, 'Image', 'resize', rect.x, rect.y, rect.width, rect.height, ratio, opts.preserveHeaders, opts.resample); 11033 } 11034 })); 11035 }); 9209 11036 9210 11037 // Included from: src/javascript/runtime/html4/Runtime.js 9211 11038 9212 /**9213 * Runtime.js9214 *9215 * Copyright 2013, Moxiecode Systems AB9216 * Released under GPL License.9217 *9218 * License: http://www.plupload.com/license9219 * Contributing: http://www.plupload.com/contributing9220 */11039 /** 11040 * Runtime.js 11041 * 11042 * Copyright 2013, Moxiecode Systems AB 11043 * Released under GPL License. 11044 * 11045 * License: http://www.plupload.com/license 11046 * Contributing: http://www.plupload.com/contributing 11047 */ 9221 11048 9222 /*global File:true */11049 /*global File:true */ 9223 11050 9224 /**11051 /** 9225 11052 Defines constructor for HTML4 runtime. 9226 11053 9227 11054 @class moxie/runtime/html4/Runtime 9228 11055 @private 9229 */ 9230 define("moxie/runtime/html4/Runtime", [ 9231 "moxie/core/utils/Basic", 9232 "moxie/core/Exceptions", 9233 "moxie/runtime/Runtime", 9234 "moxie/core/utils/Env" 9235 ], function(Basic, x, Runtime, Env) { 9236 9237 var type = 'html4', extensions = {}; 9238 9239 function Html4Runtime(options) { 9240 var I = this 9241 , Test = Runtime.capTest 9242 , True = Runtime.capTrue 9243 ; 9244 9245 Runtime.call(this, options, type, { 9246 access_binary: Test(window.FileReader || window.File && File.getAsDataURL), 9247 access_image_binary: false, 9248 display_media: Test(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))), 9249 do_cors: false, 9250 drag_and_drop: false, 9251 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, '>=')); 9255 }()), 9256 resize_image: function() { 9257 return extensions.Image && I.can('access_binary') && Env.can('create_canvas'); 9258 }, 9259 report_upload_progress: false, 9260 return_response_headers: false, 9261 return_response_type: function(responseType) { 9262 if (responseType === 'json' && !!window.JSON) { 9263 return true; 9264 } 9265 return !!~Basic.inArray(responseType, ['text', 'document', '']); 9266 }, 9267 return_status_code: function(code) { 9268 return !Basic.arrayDiff(code, [200, 404]); 9269 }, 9270 select_file: function() { 9271 return Env.can('use_fileinput'); 9272 }, 9273 select_multiple: false, 9274 send_binary_string: false, 9275 send_custom_headers: false, 9276 send_multipart: true, 9277 slice_blob: false, 9278 stream_upload: function() { 9279 return I.can('select_file'); 9280 }, 9281 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']) 9287 ); 9288 }, 9289 upload_filesize: True, 9290 use_http_method: function(methods) { 9291 return !Basic.arrayDiff(methods, ['GET', 'POST']); 11056 */ 11057 define("moxie/runtime/html4/Runtime", [ 11058 "moxie/core/utils/Basic", 11059 "moxie/core/Exceptions", 11060 "moxie/runtime/Runtime", 11061 "moxie/core/utils/Env" 11062 ], function(Basic, x, Runtime, Env) { 11063 11064 var type = 'html4', extensions = {}; 11065 11066 function Html4Runtime(options) { 11067 var I = this 11068 , Test = Runtime.capTest 11069 , True = Runtime.capTrue 11070 ; 11071 11072 Runtime.call(this, options, type, { 11073 access_binary: Test(window.FileReader || window.File && File.getAsDataURL), 11074 access_image_binary: false, 11075 display_media: Test( 11076 (Env.can('create_canvas') || Env.can('use_data_uri_over32kb')) && 11077 defined('moxie/image/Image') 11078 ), 11079 do_cors: false, 11080 drag_and_drop: false, 11081 filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest 11082 return !( 11083 (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '<')) || 11084 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) || 11085 (Env.browser === 'Safari' && Env.verComp(Env.version, 11, '<=')) || 11086 (Env.browser === 'Firefox' && Env.verComp(Env.version, 37, '<')) || 11087 Env.os === 'iOS' || // as of iOS11, no extensions are supported in accept attribute 11088 Env.os === 'Android' 11089 ); 11090 }()), 11091 resize_image: function() { 11092 return extensions.Image && I.can('access_binary') && Env.can('create_canvas'); 11093 }, 11094 report_upload_progress: false, 11095 return_response_headers: false, 11096 return_response_type: function(responseType) { 11097 if (responseType === 'json' && !!window.JSON) { 11098 return true; 11099 } 11100 return !!~Basic.inArray(responseType, ['text', 'document', '']); 11101 }, 11102 return_status_code: function(code) { 11103 return !Basic.arrayDiff(code, [200, 404]); 11104 }, 11105 select_file: function() { 11106 return Env.can('use_fileinput'); 11107 }, 11108 select_multiple: false, 11109 send_binary_string: false, 11110 send_custom_headers: false, 11111 send_multipart: true, 11112 slice_blob: false, 11113 stream_upload: function() { 11114 return I.can('select_file'); 11115 }, 11116 summon_file_dialog: function() { // yeah... some dirty sniffing here... 11117 return I.can('select_file') && !( 11118 (Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '<')) || 11119 (Env.browser === 'Opera' && Env.verComp(Env.version, 12, '<')) || 11120 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) 11121 ); 11122 }, 11123 upload_filesize: True, 11124 use_http_method: function(methods) { 11125 return !Basic.arrayDiff(methods, ['GET', 'POST']); 11126 } 11127 }); 11128 11129 11130 Basic.extend(this, { 11131 init : function() { 11132 this.trigger("Init"); 11133 }, 11134 11135 destroy: (function(destroy) { // extend default destroy method 11136 return function() { 11137 destroy.call(I); 11138 destroy = I = null; 11139 }; 11140 }(this.destroy)) 11141 }); 11142 11143 Basic.extend(this.getShim(), extensions); 9292 11144 } 11145 11146 Runtime.addConstructor(type, Html4Runtime); 11147 11148 return extensions; 9293 11149 }); 9294 11150 11151 // Included from: src/javascript/runtime/html4/file/FileInput.js 11152 11153 /** 11154 * FileInput.js 11155 * 11156 * Copyright 2013, Moxiecode Systems AB 11157 * Released under GPL License. 11158 * 11159 * License: http://www.plupload.com/license 11160 * Contributing: http://www.plupload.com/contributing 11161 */ 11162 11163 /** 11164 @class moxie/runtime/html4/file/FileInput 11165 @private 11166 */ 11167 define("moxie/runtime/html4/file/FileInput", [ 11168 "moxie/runtime/html4/Runtime", 11169 "moxie/file/File", 11170 "moxie/core/utils/Basic", 11171 "moxie/core/utils/Dom", 11172 "moxie/core/utils/Events", 11173 "moxie/core/utils/Mime", 11174 "moxie/core/utils/Env" 11175 ], function(extensions, File, Basic, Dom, Events, Mime, Env) { 11176 11177 function FileInput() { 11178 var _uid, _mimes = [], _options, _browseBtnZIndex; // save original z-index; 9295 11179 9296 Basic.extend(this, { 9297 init : function() { 9298 this.trigger("Init"); 9299 }, 11180 function addInput() { 11181 var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid; 9300 11182 9301 destroy: (function(destroy) { // extend default destroy method 9302 return function() { 9303 destroy.call(I); 9304 destroy = I = null; 9305 }; 9306 }(this.destroy)) 9307 }); 11183 uid = Basic.guid('uid_'); 9308 11184 9309 Basic.extend(this.getShim(), extensions); 9310 } 11185 shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE 9311 11186 9312 Runtime.addConstructor(type, Html4Runtime); 11187 if (_uid) { // move previous form out of the view 11188 currForm = Dom.get(_uid + '_form'); 11189 if (currForm) { 11190 Basic.extend(currForm.style, { top: '100%' }); 11191 // it shouldn't be possible to tab into the hidden element 11192 currForm.firstChild.setAttribute('tabindex', -1); 11193 } 11194 } 9313 11195 9314 return extensions; 9315 }); 11196 // build form in DOM, since innerHTML version not able to submit file for some reason 11197 form = document.createElement('form'); 11198 form.setAttribute('id', uid + '_form'); 11199 form.setAttribute('method', 'post'); 11200 form.setAttribute('enctype', 'multipart/form-data'); 11201 form.setAttribute('encoding', 'multipart/form-data'); 9316 11202 9317 // Included from: src/javascript/runtime/html4/file/FileInput.js 11203 Basic.extend(form.style, { 11204 overflow: 'hidden', 11205 position: 'absolute', 11206 top: 0, 11207 left: 0, 11208 width: '100%', 11209 height: '100%' 11210 }); 9318 11211 9319 /** 9320 * FileInput.js 9321 * 9322 * Copyright 2013, Moxiecode Systems AB 9323 * Released under GPL License. 9324 * 9325 * License: http://www.plupload.com/license 9326 * Contributing: http://www.plupload.com/contributing 9327 */ 11212 input = document.createElement('input'); 11213 input.setAttribute('id', uid); 11214 input.setAttribute('type', 'file'); 11215 input.setAttribute('accept', _mimes.join(',')); 9328 11216 9329 /** 9330 @class moxie/runtime/html4/file/FileInput 9331 @private 9332 */ 9333 define("moxie/runtime/html4/file/FileInput", [ 9334 "moxie/runtime/html4/Runtime", 9335 "moxie/file/File", 9336 "moxie/core/utils/Basic", 9337 "moxie/core/utils/Dom", 9338 "moxie/core/utils/Events", 9339 "moxie/core/utils/Mime", 9340 "moxie/core/utils/Env" 9341 ], function(extensions, File, Basic, Dom, Events, Mime, Env) { 9342 9343 function FileInput() { 9344 var _uid, _mimes = [], _options; 9345 9346 function addInput() { 9347 var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid; 9348 9349 uid = Basic.guid('uid_'); 9350 9351 shimContainer = I.getShimContainer(); // we get new ref everytime to avoid memory leaks in IE 9352 9353 if (_uid) { // move previous form out of the view 9354 currForm = Dom.get(_uid + '_form'); 9355 if (currForm) { 9356 Basic.extend(currForm.style, { top: '100%' }); 9357 } 9358 } 11217 if (I.can('summon_file_dialog')) { 11218 input.setAttribute('tabindex', -1); 11219 } 9359 11220 9360 // build form in DOM, since innerHTML version not able to submit file for some reason 9361 form = document.createElement('form'); 9362 form.setAttribute('id', uid + '_form'); 9363 form.setAttribute('method', 'post'); 9364 form.setAttribute('enctype', 'multipart/form-data'); 9365 form.setAttribute('encoding', 'multipart/form-data'); 9366 9367 Basic.extend(form.style, { 9368 overflow: 'hidden', 9369 position: 'absolute', 9370 top: 0, 9371 left: 0, 9372 width: '100%', 9373 height: '100%' 9374 }); 11221 Basic.extend(input.style, { 11222 fontSize: '999px', 11223 opacity: 0 11224 }); 9375 11225 9376 input = document.createElement('input'); 9377 input.setAttribute('id', uid); 9378 input.setAttribute('type', 'file'); 9379 input.setAttribute('name', _options.name || 'Filedata'); 9380 input.setAttribute('accept', _mimes.join(',')); 9381 9382 Basic.extend(input.style, { 9383 fontSize: '999px', 9384 opacity: 0 9385 }); 11226 form.appendChild(input); 11227 shimContainer.appendChild(form); 9386 11228 9387 form.appendChild(input); 9388 shimContainer.appendChild(form); 11229 // prepare file input to be placed underneath the browse_button element 11230 Basic.extend(input.style, { 11231 position: 'absolute', 11232 top: 0, 11233 left: 0, 11234 width: '100%', 11235 height: '100%' 11236 }); 9389 11237 9390 // prepare file input to be placed underneath the browse_button element 9391 Basic.extend(input.style, { 9392 position: 'absolute', 9393 top: 0, 9394 left: 0, 9395 width: '100%', 9396 height: '100%' 9397 }); 11238 if (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) { 11239 Basic.extend(input.style, { 11240 filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)" 11241 }); 11242 } 9398 11243 9399 if (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) { 9400 Basic.extend(input.style, { 9401 filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)" 9402 }); 9403 } 11244 input.onchange = function() { // there should be only one handler for this 11245 var file; 9404 11246 9405 input.onchange = function() { // there should be only one handler for this 9406 var file; 11247 if (!this.value) { 11248 return; 11249 } 9407 11250 9408 if (!this.value) { 9409 return; 9410 } 11251 if (this.files) { // check if browser is fresh enough 11252 file = this.files[0]; 11253 } else { 11254 file = { 11255 name: this.value 11256 }; 11257 } 9411 11258 9412 if (this.files) { // check if browser is fresh enough 9413 file = this.files[0]; 11259 file = new File(I.uid, file); 9414 11260 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 } else { 9421 file = { 9422 name: this.value 11261 // clear event handler 11262 this.onchange = function() {}; 11263 addInput.call(comp); 11264 11265 comp.files = [file]; 11266 11267 // substitute all ids with file uids (consider file.uid read-only - we cannot do it the other way around) 11268 input.setAttribute('id', file.uid); 11269 form.setAttribute('id', file.uid + '_form'); 11270 11271 comp.trigger('change'); 11272 11273 input = form = null; 9423 11274 }; 9424 }9425 11275 9426 file = new File(I.uid, file);9427 11276 9428 // clear event handler 9429 this.onchange = function() {}; 9430 addInput.call(comp); 11277 // route click event to the input 11278 if (I.can('summon_file_dialog')) { 11279 browseButton = Dom.get(_options.browse_button); 11280 Events.removeEvent(browseButton, 'click', comp.uid); 11281 Events.addEvent(browseButton, 'click', function(e) { 11282 if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] 11283 input.click(); 11284 } 11285 e.preventDefault(); 11286 }, comp.uid); 11287 } 11288 11289 _uid = uid; 9431 11290 9432 comp.files = [file]; 11291 shimContainer = currForm = browseButton = null; 11292 } 9433 11293 9434 // substitute all ids with file uids (consider file.uid read-only - we cannot do it the other way around) 9435 input.setAttribute('id', file.uid); 9436 form.setAttribute('id', file.uid + '_form'); 9437 9438 comp.trigger('change'); 11294 Basic.extend(this, { 11295 init: function(options) { 11296 var comp = this, I = comp.getRuntime(), shimContainer; 9439 11297 9440 input = form = null; 9441 }; 11298 // figure out accept string 11299 _options = options; 11300 _mimes = Mime.extList2mimes(options.accept, I.can('filter_by_extension')); 9442 11301 11302 shimContainer = I.getShimContainer(); 9443 11303 9444 // route click event to the input 9445 if (I.can('summon_file_dialog')) { 9446 browseButton = Dom.get(_options.browse_button); 9447 Events.removeEvent(browseButton, 'click', comp.uid); 9448 Events.addEvent(browseButton, 'click', function(e) { 9449 if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] 9450 input.click(); 9451 } 9452 e.preventDefault(); 9453 }, comp.uid); 9454 } 11304 (function() { 11305 var browseButton, zIndex, top; 9455 11306 9456 _uid = uid; 11307 browseButton = Dom.get(options.browse_button); 11308 _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto'; 9457 11309 9458 shimContainer = currForm = browseButton = null; 9459 } 11310 // Route click event to the input[type=file] element for browsers that support such behavior 11311 if (I.can('summon_file_dialog')) { 11312 if (Dom.getStyle(browseButton, 'position') === 'static') { 11313 browseButton.style.position = 'relative'; 11314 } 9460 11315 9461 Basic.extend(this, { 9462 init: function(options) { 9463 var comp = this, I = comp.getRuntime(), shimContainer; 9464 9465 // figure out accept string 9466 _options = options; 9467 _mimes = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension')); 11316 comp.bind('Refresh', function() { 11317 zIndex = parseInt(_browseBtnZIndex, 10) || 1; 9468 11318 9469 shimContainer = I.getShimContainer(); 11319 Dom.get(_options.browse_button).style.zIndex = zIndex; 11320 this.getRuntime().getShimContainer().style.zIndex = zIndex - 1; 11321 }); 11322 } else { 11323 // it shouldn't be possible to tab into the hidden element 11324 browseButton.setAttribute('tabindex', -1); 11325 } 9470 11326 9471 (function() { 9472 var browseButton, zIndex, top; 11327 /* Since we have to place input[type=file] on top of the browse_button for some browsers, 11328 browse_button loses interactivity, so we restore it here */ 11329 top = I.can('summon_file_dialog') ? browseButton : shimContainer; 9473 11330 9474 browseButton = Dom.get(options.browse_button); 11331 Events.addEvent(top, 'mouseover', function() { 11332 comp.trigger('mouseenter'); 11333 }, comp.uid); 9475 11334 9476 // Route click event to the input[type=file] element for browsers that support such behavior 9477 if (I.can('summon_file_dialog')) { 9478 if (Dom.getStyle(browseButton, 'position') === 'static') { 9479 browseButton.style.position = 'relative'; 9480 } 11335 Events.addEvent(top, 'mouseout', function() { 11336 comp.trigger('mouseleave'); 11337 }, comp.uid); 9481 11338 9482 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; 11339 Events.addEvent(top, 'mousedown', function() { 11340 comp.trigger('mousedown'); 11341 }, comp.uid); 9483 11342 9484 browseButton.style.zIndex = zIndex;9485 shimContainer.style.zIndex = zIndex - 1;9486 }11343 Events.addEvent(Dom.get(options.container), 'mouseup', function() { 11344 comp.trigger('mouseup'); 11345 }, comp.uid); 9487 11346 9488 /* Since we have to place input[type=file] on top of the browse_button for some browsers, 9489 browse_button loses interactivity, so we restore it here */ 9490 top = I.can('summon_file_dialog') ? browseButton : shimContainer; 11347 browseButton = null; 11348 }()); 9491 11349 9492 Events.addEvent(top, 'mouseover', function() { 9493 comp.trigger('mouseenter'); 9494 }, comp.uid); 11350 addInput.call(this); 9495 11351 9496 Events.addEvent(top, 'mouseout', function() { 9497 comp.trigger('mouseleave'); 9498 }, comp.uid); 11352 shimContainer = null; 9499 11353 9500 Events.addEvent(top, 'mousedown', function() { 9501 comp.trigger('mousedown'); 9502 }, comp.uid); 11354 // trigger ready event asynchronously 11355 comp.trigger({ 11356 type: 'ready', 11357 async: true 11358 }); 11359 }, 9503 11360 9504 Events.addEvent(Dom.get(options.container), 'mouseup', function() {9505 comp.trigger('mouseup');9506 }, comp.uid);11361 setOption: function(name, value) { 11362 var I = this.getRuntime(); 11363 var input; 9507 11364 9508 browseButton = null; 9509 }()); 11365 if (name == 'accept') { 11366 _mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension')); 11367 } 9510 11368 9511 addInput.call(this); 11369 // update current input 11370 input = Dom.get(_uid) 11371 if (input) { 11372 input.setAttribute('accept', _mimes.join(',')); 11373 } 11374 }, 9512 11375 9513 shimContainer = null;9514 11376 9515 // trigger ready event asynchronously 9516 comp.trigger({ 9517 type: 'ready', 9518 async: true 9519 }); 9520 }, 11377 disable: function(state) { 11378 var input; 11379 11380 if ((input = Dom.get(_uid))) { 11381 input.disabled = !!state; 11382 } 11383 }, 9521 11384 11385 destroy: function() { 11386 var I = this.getRuntime() 11387 , shim = I.getShim() 11388 , shimContainer = I.getShimContainer() 11389 , container = _options && Dom.get(_options.container) 11390 , browseButton = _options && Dom.get(_options.browse_button) 11391 ; 9522 11392 9523 disable: function(state) { 9524 var input; 11393 if (container) { 11394 Events.removeAllEvents(container, this.uid); 11395 } 9525 11396 9526 if ((input = Dom.get(_uid))) {9527 input.disabled = !!state;9528 }9529 },11397 if (browseButton) { 11398 Events.removeAllEvents(browseButton, this.uid); 11399 browseButton.style.zIndex = _browseBtnZIndex; // reset to original value 11400 } 9530 11401 9531 destroy: function() { 9532 var I = this.getRuntime() 9533 , shim = I.getShim() 9534 , shimContainer = I.getShimContainer() 9535 ; 9536 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); 9540 9541 if (shimContainer) { 9542 shimContainer.innerHTML = ''; 9543 } 11402 if (shimContainer) { 11403 Events.removeAllEvents(shimContainer, this.uid); 11404 shimContainer.innerHTML = ''; 11405 } 9544 11406 9545 shim.removeInstance(this.uid);11407 shim.removeInstance(this.uid); 9546 11408 9547 _uid = _mimes = _options = shimContainer = shim = null; 11409 _uid = _mimes = _options = shimContainer = container = browseButton = shim = null; 11410 } 11411 }); 9548 11412 } 9549 });9550 }9551 11413 9552 return (extensions.FileInput = FileInput);9553 });11414 return (extensions.FileInput = FileInput); 11415 }); 9554 11416 9555 11417 // Included from: src/javascript/runtime/html4/file/FileReader.js 9556 11418 9557 /**9558 * FileReader.js9559 *9560 * Copyright 2013, Moxiecode Systems AB9561 * Released under GPL License.9562 *9563 * License: http://www.plupload.com/license9564 * Contributing: http://www.plupload.com/contributing9565 */11419 /** 11420 * FileReader.js 11421 * 11422 * Copyright 2013, Moxiecode Systems AB 11423 * Released under GPL License. 11424 * 11425 * License: http://www.plupload.com/license 11426 * Contributing: http://www.plupload.com/contributing 11427 */ 9566 11428 9567 /**11429 /** 9568 11430 @class moxie/runtime/html4/file/FileReader 9569 11431 @private 9570 */9571 define("moxie/runtime/html4/file/FileReader", [9572 "moxie/runtime/html4/Runtime",9573 "moxie/runtime/html5/file/FileReader"9574 ], function(extensions, FileReader) {9575 return (extensions.FileReader = FileReader);9576 });11432 */ 11433 define("moxie/runtime/html4/file/FileReader", [ 11434 "moxie/runtime/html4/Runtime", 11435 "moxie/runtime/html5/file/FileReader" 11436 ], function(extensions, FileReader) { 11437 return (extensions.FileReader = FileReader); 11438 }); 9577 11439 9578 11440 // Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js 9579 11441 9580 /**9581 * XMLHttpRequest.js9582 *9583 * Copyright 2013, Moxiecode Systems AB9584 * Released under GPL License.9585 *9586 * License: http://www.plupload.com/license9587 * Contributing: http://www.plupload.com/contributing9588 */11442 /** 11443 * XMLHttpRequest.js 11444 * 11445 * Copyright 2013, Moxiecode Systems AB 11446 * Released under GPL License. 11447 * 11448 * License: http://www.plupload.com/license 11449 * Contributing: http://www.plupload.com/contributing 11450 */ 9589 11451 9590 /**11452 /** 9591 11453 @class moxie/runtime/html4/xhr/XMLHttpRequest 9592 11454 @private 9593 */ 9594 define("moxie/runtime/html4/xhr/XMLHttpRequest", [ 9595 "moxie/runtime/html4/Runtime", 9596 "moxie/core/utils/Basic", 9597 "moxie/core/utils/Dom", 9598 "moxie/core/utils/Url", 9599 "moxie/core/Exceptions", 9600 "moxie/core/utils/Events", 9601 "moxie/file/Blob", 9602 "moxie/xhr/FormData" 9603 ], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) { 9604 9605 function XMLHttpRequest() { 9606 var _status, _response, _iframe; 9607 9608 function cleanup(cb) { 9609 var target = this, uid, form, inputs, i, hasFile = false; 9610 9611 if (!_iframe) { 9612 return; 9613 } 9614 9615 uid = _iframe.id.replace(/_iframe$/, ''); 9616 9617 form = Dom.get(uid + '_form'); 9618 if (form) { 9619 inputs = form.getElementsByTagName('input'); 9620 i = inputs.length; 11455 */ 11456 define("moxie/runtime/html4/xhr/XMLHttpRequest", [ 11457 "moxie/runtime/html4/Runtime", 11458 "moxie/core/utils/Basic", 11459 "moxie/core/utils/Dom", 11460 "moxie/core/utils/Url", 11461 "moxie/core/Exceptions", 11462 "moxie/core/utils/Events", 11463 "moxie/file/Blob", 11464 "moxie/xhr/FormData" 11465 ], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) { 9621 11466 9622 while (i--) {9623 switch (inputs[i].getAttribute('type')) {9624 case 'hidden': 9625 inputs[i].parentNode.removeChild(inputs[i]);9626 break;9627 case 'file': 9628 hasFile = true; // flag the case for later9629 break;11467 function XMLHttpRequest() { 11468 var _status, _response, _iframe; 11469 11470 function cleanup(cb) { 11471 var target = this, uid, form, inputs, i, hasFile = false; 11472 11473 if (!_iframe) { 11474 return; 9630 11475 } 9631 }9632 inputs = [];9633 11476 9634 if (!hasFile) { // we need to keep the form for sake of possible retries 9635 form.parentNode.removeChild(form); 9636 } 9637 form = null; 9638 } 11477 uid = _iframe.id.replace(/_iframe$/, ''); 9639 11478 9640 // without timeout, request is marked as canceled (in console) 9641 setTimeout(function() { 9642 Events.removeEvent(_iframe, 'load', target.uid); 9643 if (_iframe.parentNode) { // #382 9644 _iframe.parentNode.removeChild(_iframe); 9645 } 11479 form = Dom.get(uid + '_form'); 11480 if (form) { 11481 inputs = form.getElementsByTagName('input'); 11482 i = inputs.length; 11483 11484 while (i--) { 11485 switch (inputs[i].getAttribute('type')) { 11486 case 'hidden': 11487 inputs[i].parentNode.removeChild(inputs[i]); 11488 break; 11489 case 'file': 11490 hasFile = true; // flag the case for later 11491 break; 11492 } 11493 } 11494 inputs = []; 9646 11495 9647 // check if shim container has any other children, if - not, remove it as well9648 var shimContainer = target.getRuntime().getShimContainer();9649 if (!shimContainer.children.length) {9650 shimContainer.parentNode.removeChild(shimContainer);9651 }11496 if (!hasFile) { // we need to keep the form for sake of possible retries 11497 form.parentNode.removeChild(form); 11498 } 11499 form = null; 11500 } 9652 11501 9653 shimContainer = _iframe = null; 9654 cb(); 9655 }, 1); 9656 } 11502 // without timeout, request is marked as canceled (in console) 11503 setTimeout(function() { 11504 Events.removeEvent(_iframe, 'load', target.uid); 11505 if (_iframe.parentNode) { // #382 11506 _iframe.parentNode.removeChild(_iframe); 11507 } 9657 11508 9658 Basic.extend(this, {9659 send: function(meta, data) {9660 var target = this, I = target.getRuntime(), uid, form, input, blob;9661 9662 _status = _response = null;9663 9664 function createIframe() {9665 var container = I.getShimContainer() || document.body9666 , temp = document.createElement('div')9667 ;11509 // check if shim container has any other children, if - not, remove it as well 11510 var shimContainer = target.getRuntime().getShimContainer(); 11511 if (!shimContainer.children.length) { 11512 shimContainer.parentNode.removeChild(shimContainer); 11513 } 11514 11515 shimContainer = _iframe = null; 11516 cb(); 11517 }, 1); 11518 } 9668 11519 9669 // IE 6 won't be able to set the name using setAttribute or iframe.name 9670 temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:""" style="display:none"></iframe>'; 9671 _iframe = temp.firstChild; 9672 container.appendChild(_iframe); 11520 Basic.extend(this, { 11521 send: function(meta, data) { 11522 var target = this, I = target.getRuntime(), uid, form, input, blob; 11523 11524 _status = _response = null; 11525 11526 function createIframe() { 11527 var container = I.getShimContainer() || document.body 11528 , temp = document.createElement('div') 11529 ; 11530 11531 // IE 6 won't be able to set the name using setAttribute or iframe.name 11532 temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:""" style="display:none"></iframe>'; 11533 _iframe = temp.firstChild; 11534 container.appendChild(_iframe); 9673 11535 9674 /* _iframe.onreadystatechange = function() {11536 /* _iframe.onreadystatechange = function() { 9675 11537 console.info(_iframe.readyState); 9676 11538 };*/ 9677 11539 9678 Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8 9679 var el; 9680 9681 try { 9682 el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document; 9683 9684 // try to detect some standard error pages 9685 if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error 9686 _status = el.title.replace(/^(\d+).*$/, '$1'); 9687 } else { 9688 _status = 200; 9689 // get result 9690 _response = Basic.trim(el.body.innerHTML); 11540 Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8 11541 var el; 9691 11542 9692 // we need to fire these at least once 9693 target.trigger({ 9694 type: 'progress', 9695 loaded: _response.length, 9696 total: _response.length 9697 }); 11543 try { 11544 el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document; 9698 11545 9699 if (blob) { // if we were uploading a file 9700 target.trigger({ 9701 type: 'uploadprogress', 9702 loaded: blob.size || 1025, 9703 total: blob.size || 1025 9704 }); 11546 // try to detect some standard error pages 11547 if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error 11548 _status = el.title.replace(/^(\d+).*$/, '$1'); 11549 } else { 11550 _status = 200; 11551 // get result 11552 _response = Basic.trim(el.body.innerHTML); 11553 11554 // we need to fire these at least once 11555 target.trigger({ 11556 type: 'progress', 11557 loaded: _response.length, 11558 total: _response.length 11559 }); 11560 11561 if (blob) { // if we were uploading a file 11562 target.trigger({ 11563 type: 'uploadprogress', 11564 loaded: blob.size || 1025, 11565 total: blob.size || 1025 11566 }); 11567 } 11568 } 11569 } catch (ex) { 11570 if (Url.hasSameOrigin(meta.url)) { 11571 // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm 11572 // which obviously results to cross domain error (wtf?) 11573 _status = 404; 11574 } else { 11575 cleanup.call(target, function() { 11576 target.trigger('error'); 11577 }); 11578 return; 11579 } 9705 11580 } 9706 } 9707 } catch (ex) { 9708 if (Url.hasSameOrigin(meta.url)) { 9709 // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm 9710 // which obviously results to cross domain error (wtf?) 9711 _status = 404; 9712 } else { 11581 9713 11582 cleanup.call(target, function() { 9714 target.trigger(' error');11583 target.trigger('load'); 9715 11584 }); 9716 return; 11585 }, target.uid); 11586 } // end createIframe 11587 11588 // prepare data to be sent and convert if required 11589 if (data instanceof FormData && data.hasBlob()) { 11590 blob = data.getBlob(); 11591 uid = blob.uid; 11592 input = Dom.get(uid); 11593 form = Dom.get(uid + '_form'); 11594 if (!form) { 11595 throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); 9717 11596 } 9718 } 9719 9720 cleanup.call(target, function() { 9721 target.trigger('load'); 9722 }); 9723 }, target.uid); 9724 } // end createIframe 9725 9726 // prepare data to be sent and convert if required 9727 if (data instanceof FormData && data.hasBlob()) { 9728 blob = data.getBlob(); 9729 uid = blob.uid; 9730 input = Dom.get(uid); 9731 form = Dom.get(uid + '_form'); 9732 if (!form) { 9733 throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); 9734 } 9735 } else { 9736 uid = Basic.guid('uid_'); 11597 } else { 11598 uid = Basic.guid('uid_'); 9737 11599 9738 form = document.createElement('form');9739 form.setAttribute('id', uid + '_form');9740 form.setAttribute('method', meta.method);9741 form.setAttribute('enctype', 'multipart/form-data');9742 form.setAttribute('encoding', 'multipart/form-data');11600 form = document.createElement('form'); 11601 form.setAttribute('id', uid + '_form'); 11602 form.setAttribute('method', meta.method); 11603 form.setAttribute('enctype', 'multipart/form-data'); 11604 form.setAttribute('encoding', 'multipart/form-data'); 9743 11605 9744 I.getShimContainer().appendChild(form);9745 }11606 I.getShimContainer().appendChild(form); 11607 } 9746 11608 9747 // set upload target9748 form.setAttribute('target', uid + '_iframe');11609 // set upload target 11610 form.setAttribute('target', uid + '_iframe'); 9749 11611 9750 if (data instanceof FormData) {9751 data.each(function(value, name) {9752 if (value instanceof Blob) {9753 if (input) {9754 input.setAttribute('name', name);9755 }9756 } else {9757 var hidden = document.createElement('input');11612 if (data instanceof FormData) { 11613 data.each(function(value, name) { 11614 if (value instanceof Blob) { 11615 if (input) { 11616 input.setAttribute('name', name); 11617 } 11618 } else { 11619 var hidden = document.createElement('input'); 9758 11620 9759 Basic.extend(hidden, {9760 type : 'hidden',9761 name : name,9762 value : value9763 });11621 Basic.extend(hidden, { 11622 type : 'hidden', 11623 name : name, 11624 value : value 11625 }); 9764 11626 9765 // make sure that input[type="file"], if it's there, comes last 9766 if (input) { 9767 form.insertBefore(hidden, input); 9768 } else { 9769 form.appendChild(hidden); 9770 } 11627 // make sure that input[type="file"], if it's there, comes last 11628 if (input) { 11629 form.insertBefore(hidden, input); 11630 } else { 11631 form.appendChild(hidden); 11632 } 11633 } 11634 }); 9771 11635 } 9772 });9773 }9774 11636 9775 // set destination url9776 form.setAttribute("action", meta.url);11637 // set destination url 11638 form.setAttribute("action", meta.url); 9777 11639 9778 createIframe(); 9779 form.submit(); 9780 target.trigger('loadstart'); 9781 }, 9782 9783 getStatus: function() { 9784 return _status; 9785 }, 11640 createIframe(); 11641 form.submit(); 11642 target.trigger('loadstart'); 11643 }, 11644 11645 getStatus: function() { 11646 return _status; 11647 }, 11648 11649 getResponse: function(responseType) { 11650 if ('json' === responseType) { 11651 // strip off <pre>..</pre> tags that might be enclosing the response 11652 if (Basic.typeOf(_response) === 'string' && !!window.JSON) { 11653 try { 11654 return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, '')); 11655 } catch (ex) { 11656 return null; 11657 } 11658 } 11659 } else if ('document' === responseType) { 9786 11660 9787 getResponse: function(responseType) {9788 if ('json' === responseType) {9789 // strip off <pre>..</pre> tags that might be enclosing the response9790 if (Basic.typeOf(_response) === 'string' && !!window.JSON) {9791 try {9792 return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));9793 } catch (ex) {9794 return null;9795 11661 } 9796 }9797 } else if ('document' === responseType) {11662 return _response; 11663 }, 9798 11664 9799 } 9800 return _response; 9801 }, 11665 abort: function() { 11666 var target = this; 9802 11667 9803 abort: function() { 9804 var target = this; 11668 if (_iframe && _iframe.contentWindow) { 11669 if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome 11670 _iframe.contentWindow.stop(); 11671 } else if (_iframe.contentWindow.document.execCommand) { // IE 11672 _iframe.contentWindow.document.execCommand('Stop'); 11673 } else { 11674 _iframe.src = "about:blank"; 11675 } 11676 } 9805 11677 9806 if (_iframe && _iframe.contentWindow) { 9807 if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome 9808 _iframe.contentWindow.stop(); 9809 } else if (_iframe.contentWindow.document.execCommand) { // IE 9810 _iframe.contentWindow.document.execCommand('Stop'); 9811 } else { 9812 _iframe.src = "about:blank"; 9813 } 9814 } 11678 cleanup.call(this, function() { 11679 // target.dispatchEvent('readystatechange'); 11680 target.dispatchEvent('abort'); 11681 }); 11682 }, 9815 11683 9816 cleanup.call(this,function() {9817 // target.dispatchEvent('readystatechange');9818 target.dispatchEvent('abort');11684 destroy: function() { 11685 this.getRuntime().getShim().removeInstance(this.uid); 11686 } 9819 11687 }); 9820 11688 } 9821 });9822 }9823 11689 9824 return (extensions.XMLHttpRequest = XMLHttpRequest);9825 });11690 return (extensions.XMLHttpRequest = XMLHttpRequest); 11691 }); 9826 11692 9827 11693 // Included from: src/javascript/runtime/html4/image/Image.js 9828 11694 9829 /**9830 * Image.js9831 *9832 * Copyright 2013, Moxiecode Systems AB9833 * Released under GPL License.9834 *9835 * License: http://www.plupload.com/license9836 * Contributing: http://www.plupload.com/contributing9837 */11695 /** 11696 * Image.js 11697 * 11698 * Copyright 2013, Moxiecode Systems AB 11699 * Released under GPL License. 11700 * 11701 * License: http://www.plupload.com/license 11702 * Contributing: http://www.plupload.com/contributing 11703 */ 9838 11704 9839 /**11705 /** 9840 11706 @class moxie/runtime/html4/image/Image 9841 11707 @private 9842 */ 9843 define("moxie/runtime/html4/image/Image", [ 9844 "moxie/runtime/html4/Runtime", 9845 "moxie/runtime/html5/image/Image" 9846 ], function(extensions, Image) { 9847 return (extensions.Image = Image); 9848 }); 9849 9850 expose(["moxie/core/utils/Basic","moxie/core/utils/Env","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"]); 9851 })(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); 11708 */ 11709 define("moxie/runtime/html4/image/Image", [ 11710 "moxie/runtime/html4/Runtime", 11711 "moxie/runtime/html5/image/Image" 11712 ], function(extensions, Image) { 11713 return (extensions.Image = Image); 11714 }); 9889 11715 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); 11716 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"]); 11717 })(this); 11718 })); -
src/js/_enqueues/vendor/plupload/plupload.js
1 1 /** 2 2 * Plupload - multi-runtime File Uploader 3 * v 2.1.93 * v3.1.2 4 4 * 5 * Copyright 201 3, Moxiecode Systems AB6 * Released under GPLLicense.5 * Copyright 2018, Ephox 6 * Released under AGPLv3 License. 7 7 * 8 8 * License: http://www.plupload.com/license 9 9 * Contributing: http://www.plupload.com/contributing 10 10 * 11 * Date: 2016-05-15 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 11 * Date: 2018-02-20 21 12 */ 13 ;(function (global, factory) { 14 var extract = function() { 15 var ctx = {}; 16 factory.apply(ctx, arguments); 17 return ctx.plupload; 18 }; 22 19 23 /** 24 * Modified for WordPress, Silverlight and Flash runtimes support was removed. 25 * See https://core.trac.wordpress.org/ticket/41755. 26 */ 20 if (typeof define === "function" && define.amd) { 21 define("plupload", ['./moxie'], extract); 22 } else if (typeof module === "object" && module.exports) { 23 module.exports = extract(require('./moxie')); 24 } else { 25 global.plupload = extract(global.moxie); 26 } 27 }(this || window, function(moxie) { 28 /** 29 * Compiled inline version. (Library mode) 30 */ 27 31 28 /*global mOxie:true */ 32 /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ 33 /*globals $code */ 29 34 30 ;(function(window, o, undef) { 35 (function(exports, undefined) { 36 "use strict"; 31 37 32 var delay = window.setTimeout 33 , fileFilters = {} 34 ; 35 36 // convert plupload features to caps acceptable by mOxie 37 function normalizeCaps(settings) { 38 var features = settings.required_features, caps = {}; 39 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 }; 55 56 if (map[feature]) { 57 caps[map[feature]] = value; 58 } else if (!strict) { 59 caps[feature] = value; 60 } 61 }