Make WordPress Core

Ticket #48277: 48277.2.diff

File 48277.2.diff, 788.0 KB (added by desrosj, 6 years ago)
  • src/js/_enqueues/vendor/plupload/license.txt

     
    1                     GNU GENERAL PUBLIC LICENSE
    2                        Version 2, June 1991
     1                    GNU AFFERO GENERAL PUBLIC LICENSE
     2                       Version 3, 19 November 2007
    33
    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/>
    65 Everyone is permitted to copy and distribute verbatim copies
    76 of this license document, but changing it is not allowed.
    87
    9                             Preamble
     8                            Preamble
    109
    11   The licenses for most software are designed to take away your
    12 freedom to share and change it.  By contrast, the GNU General Public
    13 License is intended to guarantee your freedom to share and change free
    14 software--to make sure the software is free for all its users.  This
    15 General Public License applies to most of the Free Software
    16 Foundation's software and to any other program whose authors commit to
    17 using it.  (Some other Free Software Foundation software is covered by
    18 the GNU Lesser General Public License instead.)  You can apply it to
    19 your programs, too.
     10  The GNU Affero General Public License is a free, copyleft license for
     11software and other kinds of works, specifically designed to ensure
     12cooperation with the community in the case of network server software.
     13
     14  The licenses for most software and other practical works are designed
     15to take away your freedom to share and change the works.  By contrast,
     16our General Public Licenses are intended to guarantee your freedom to
     17share and change all versions of a program--to make sure it remains free
     18software for all its users.
    2019
    2120  When we speak of free software, we are referring to freedom, not
    2221price.  Our General Public Licenses are designed to make sure that you
    2322have 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.
     23them if you wish), that you receive source code or can get it if you
     24want it, that you can change the software or use pieces of it in new
     25free programs, and that you know you can do these things.
     26
     27  Developers that use our General Public Licenses protect your rights
     28with two steps: (1) assert copyright on the software, and (2) offer
     29you this License which gives you legal permission to copy, distribute
     30and/or modify the software.
     31
     32  A secondary benefit of defending all users' freedom is that
     33improvements made in alternate versions of the program, if they
     34receive widespread use, become available for other developers to
     35incorporate.  Many developers of free software are heartened and
     36encouraged by the resulting cooperation.  However, in the case of
     37software used on network servers, this result may fail to come about.
     38The GNU General Public License permits making a modified version and
     39letting the public access it on a server without ever releasing its
     40source code to the public.
     41
     42  The GNU Affero General Public License is designed specifically to
     43ensure that, in such cases, the modified source code becomes available
     44to the community.  It requires the operator of a network server to
     45provide the source code of the modified version running there to the
     46users of that server.  Therefore, public use of a modified version, on
     47a publicly accessible server, gives the public access to the source
     48code of the modified version.
     49
     50  An older license, called the Affero General Public License and
     51published by Affero, was designed to accomplish similar goals.  This is
     52a different license, not a version of the Affero GPL, but Affero has
     53released a new version of the Affero GPL which permits relicensing under
     54this license.
    5555
    5656  The precise terms and conditions for copying, distribution and
    5757modification follow.
    5858
    59                     GNU GENERAL PUBLIC LICENSE
    60    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
     59                       TERMS AND CONDITIONS
    6160
    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
     66works, such as semiconductor masks.
     67
     68  "The Program" refers to any copyrightable work licensed under this
     69License.  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
     73in a fashion requiring copyright permission, other than the making of an
     74exact copy.  The resulting work is called a "modified version" of the
     75earlier work or a work "based on" the earlier work.
     76
     77  A "covered work" means either the unmodified Program or a work based
     78on the Program.
     79
     80  To "propagate" a work means to do anything with it that, without
     81permission, would make you directly or secondarily liable for
     82infringement under applicable copyright law, except executing it on a
     83computer or modifying a private copy.  Propagation includes copying,
     84distribution (with or without modification), making available to the
     85public, and in some countries other activities as well.
     86
     87  To "convey" a work means any kind of propagation that enables other
     88parties to make or receive copies.  Mere interaction with a user through
     89a computer network, with no transfer of a copy, is not conveying.
     90
     91  An interactive user interface displays "Appropriate Legal Notices"
     92to the extent that it includes a convenient and prominently visible
     93feature that (1) displays an appropriate copyright notice, and (2)
     94tells the user that there is no warranty for the work (except to the
     95extent that warranties are provided), that licensees may convey the
     96work under this License, and how to view a copy of this License.  If
     97the interface presents a list of user commands or options, such as a
     98menu, 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
     103for making modifications to it.  "Object code" means any non-source
     104form of a work.
     105
     106  A "Standard Interface" means an interface that either is an official
     107standard defined by a recognized standards body, or, in the case of
     108interfaces specified for a particular programming language, one that
     109is widely used among developers working in that language.
     110
     111  The "System Libraries" of an executable work include anything, other
     112than the work as a whole, that (a) is included in the normal form of
     113packaging a Major Component, but which is not part of that Major
     114Component, and (b) serves only to enable use of the work with that
     115Major Component, or to implement a Standard Interface for which an
     116implementation 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
     120produce 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
     123the source code needed to generate, install, and (for an executable
     124work) run the object code and to modify the work, including scripts to
     125control those activities.  However, it does not include the work's
     126System Libraries, or general-purpose tools or generally available free
     127programs which are used unmodified in performing those activities but
     128which are not part of the work.  For example, Corresponding Source
     129includes interface definition files associated with source files for
     130the work, and the source code for shared libraries and dynamically
     131linked subprograms that the work is specifically designed to require,
     132such as by intimate data communication or control flow between those
     133subprograms and other parts of the work.
     134
     135  The Corresponding Source need not include anything that users
     136can regenerate automatically from other parts of the Corresponding
     137Source.
     138
     139  The Corresponding Source for a work in source code form is that
     140same work.
     141
     142  2. Basic Permissions.
     143
     144  All rights granted under this License are granted for the term of
     145copyright on the Program, and are irrevocable provided the stated
     146conditions are met.  This License explicitly affirms your unlimited
     147permission to run the unmodified Program.  The output from running a
     148covered work is covered by this License only if the output, given its
     149content, constitutes a covered work.  This License acknowledges your
     150rights 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
     153convey, without conditions so long as your license otherwise remains
     154in force.  You may convey covered works to others for the sole purpose
     155of having them make modifications exclusively for you, or provide you
     156with facilities for running those works, provided that you comply with
     157the terms of this License in conveying all material for which you do
     158not control copyright.  Those thus making or running the covered works
     159for you must do so exclusively on your behalf, under your direction
     160and control, on terms that prohibit them from making any copies of
     161your copyrighted material outside their relationship with you.
     162
     163  Conveying under any other circumstances is permitted solely under
     164the conditions stated below.  Sublicensing is not allowed; section 10
     165makes 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
     170measure under any applicable law fulfilling obligations under article
     17111 of the WIPO copyright treaty adopted on 20 December 1996, or
     172similar laws prohibiting or restricting circumvention of such
     173measures.
     174
     175  When you convey a covered work, you waive any legal power to forbid
     176circumvention of technological measures to the extent such circumvention
     177is effected by exercising rights under this License with respect to
     178the covered work, and you disclaim any intention to limit operation or
     179modification of the work as a means of enforcing, against the work's
     180users, your or third parties' legal rights to forbid circumvention of
     181technological measures.
     182
     183  4. Conveying Verbatim Copies.
     184
     185  You may convey verbatim copies of the Program's source code as you
     186receive it, in any medium, provided that you conspicuously and
     187appropriately publish on each copy an appropriate copyright notice;
     188keep intact all notices stating that this License and any
     189non-permissive terms added in accord with section 7 apply to the code;
     190keep intact all notices of the absence of any warranty; and give all
     191recipients 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,
     194and 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
     199produce it from the Program, in the form of source code under the
     200terms 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
     224works, which are not by their nature extensions of the covered work,
     225and which are not combined with it such as to form a larger program,
     226in or on a volume of a storage or distribution medium, is called an
     227"aggregate" if the compilation and its resulting copyright are not
     228used to limit the access or legal rights of the compilation's users
     229beyond what the individual works permit.  Inclusion of a covered work
     230in an aggregate does not cause this License to apply to the other
     231parts 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
     236of sections 4 and 5, provided that you also convey the
     237machine-readable Corresponding Source under the terms of this License,
     238in 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
     282from the Corresponding Source as a System Library, need not be
     283included in conveying the object code work.
     284
     285  A "User Product" is either (1) a "consumer product", which means any
     286tangible personal property which is normally used for personal, family,
     287or household purposes, or (2) anything designed or sold for incorporation
     288into a dwelling.  In determining whether a product is a consumer product,
     289doubtful cases shall be resolved in favor of coverage.  For a particular
     290product received by a particular user, "normally used" refers to a
     291typical or common use of that class of product, regardless of the status
     292of the particular user or of the way in which the particular user
     293actually uses, or expects or is expected to use, the product.  A product
     294is a consumer product regardless of whether the product has substantial
     295commercial, industrial or non-consumer uses, unless such uses represent
     296the only significant mode of use of the product.
     297
     298  "Installation Information" for a User Product means any methods,
     299procedures, authorization keys, or other information required to install
     300and execute modified versions of a covered work in that User Product from
     301a modified version of its Corresponding Source.  The information must
     302suffice to ensure that the continued functioning of the modified object
     303code is in no case prevented or interfered with solely because
     304modification has been made.
     305
     306  If you convey an object code work under this section in, or with, or
     307specifically for use in, a User Product, and the conveying occurs as
     308part of a transaction in which the right of possession and use of the
     309User Product is transferred to the recipient in perpetuity or for a
     310fixed term (regardless of how the transaction is characterized), the
     311Corresponding Source conveyed under this section must be accompanied
     312by the Installation Information.  But this requirement does not apply
     313if neither you nor any third party retains the ability to install
     314modified object code on the User Product (for example, the work has
     315been installed in ROM).
     316
     317  The requirement to provide Installation Information does not include a
     318requirement to continue to provide support service, warranty, or updates
     319for a work that has been modified or installed by the recipient, or for
     320the User Product in which it has been modified or installed.  Access to a
     321network may be denied when the modification itself materially and
     322adversely affects the operation of the network or violates the rules and
     323protocols for communication across the network.
     324
     325  Corresponding Source conveyed, and Installation Information provided,
     326in accord with this section must be in a format that is publicly
     327documented (and with an implementation available to the public in
     328source code form), and must require no special password or key for
     329unpacking, reading or copying.
     330
     331  7. Additional Terms.
     332
     333  "Additional permissions" are terms that supplement the terms of this
     334License by making exceptions from one or more of its conditions.
     335Additional permissions that are applicable to the entire Program shall
     336be treated as though they were included in this License, to the extent
     337that they are valid under applicable law.  If additional permissions
     338apply only to part of the Program, that part may be used separately
     339under those permissions, but the entire Program remains governed by
     340this License without regard to the additional permissions.
     341
     342  When you convey a copy of a covered work, you may at your option
     343remove any additional permissions from that copy, or from any part of
     344it.  (Additional permissions may be written to require their own
     345removal in certain cases when you modify the work.)  You may place
     346additional permissions on material, added by you to a covered work,
     347for which you have or can give appropriate copyright permission.
     348
     349  Notwithstanding any other provision of this License, for material you
     350add to a covered work, you may (if authorized by the copyright holders of
     351that 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
     377restrictions" within the meaning of section 10.  If the Program as you
     378received it, or any part of it, contains a notice stating that it is
     379governed by this License along with a term that is a further
     380restriction, you may remove that term.  If a license document contains
     381a further restriction but permits relicensing or conveying under this
     382License, you may add to a covered work material governed by the terms
     383of that license document, provided that the further restriction does
     384not survive such relicensing or conveying.
     385
     386  If you add terms to a covered work in accord with this section, you
     387must place, in the relevant source files, a statement of the
     388additional terms that apply to those files, or a notice indicating
     389where to find the applicable terms.
     390
     391  Additional terms, permissive or non-permissive, may be stated in the
     392form of a separately written license, or stated as exceptions;
     393the above requirements apply either way.
     394
     395  8. Termination.
     396
     397  You may not propagate or modify a covered work except as expressly
     398provided under this License.  Any attempt otherwise to propagate or
     399modify it is void, and will automatically terminate your rights under
     400this License (including any patent licenses granted under the third
     401paragraph of section 11).
     402
     403  However, if you cease all violation of this License, then your
     404license from a particular copyright holder is reinstated (a)
     405provisionally, unless and until the copyright holder explicitly and
     406finally terminates your license, and (b) permanently, if the copyright
     407holder fails to notify you of the violation by some reasonable means
     408prior to 60 days after the cessation.
     409
     410  Moreover, your license from a particular copyright holder is
     411reinstated permanently if the copyright holder notifies you of the
     412violation by some reasonable means, this is the first time you have
     413received notice of violation of this License (for any work) from that
     414copyright holder, and you cure the violation prior to 30 days after
     415your receipt of the notice.
     416
     417  Termination of your rights under this section does not terminate the
     418licenses of parties who have received copies or rights from you under
     419this License.  If your rights have been terminated and not permanently
     420reinstated, you do not qualify to receive new licenses for the same
     421material 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
     426run a copy of the Program.  Ancillary propagation of a covered work
     427occurring solely as a consequence of using peer-to-peer transmission
     428to receive a copy likewise does not require acceptance.  However,
     429nothing other than this License grants you permission to propagate or
     430modify any covered work.  These actions infringe copyright if you do
     431not accept this License.  Therefore, by modifying or propagating a
     432covered 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
     437receives a license from the original licensors, to run, modify and
     438propagate that work, subject to this License.  You are not responsible
     439for enforcing compliance by third parties with this License.
     440
     441  An "entity transaction" is a transaction transferring control of an
     442organization, or substantially all assets of one, or subdividing an
     443organization, or merging organizations.  If propagation of a covered
     444work results from an entity transaction, each party to that
     445transaction who receives a copy of the work also receives whatever
     446licenses to the work the party's predecessor in interest had or could
     447give under the previous paragraph, plus a right to possession of the
     448Corresponding Source of the work from the predecessor in interest, if
     449the predecessor has it or can get it with reasonable efforts.
     450
     451  You may not impose any further restrictions on the exercise of the
     452rights granted or affirmed under this License.  For example, you may
     453not impose a license fee, royalty, or other charge for exercise of
     454rights granted under this License, and you may not initiate litigation
     455(including a cross-claim or counterclaim in a lawsuit) alleging that
     456any patent claim is infringed by making, using, selling, offering for
     457sale, 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
     462License of the Program or a work on which the Program is based.  The
     463work thus licensed is called the contributor's "contributor version".
     464
     465  A contributor's "essential patent claims" are all patent claims
     466owned or controlled by the contributor, whether already acquired or
     467hereafter acquired, that would be infringed by some manner, permitted
     468by this License, of making, using, or selling its contributor version,
     469but do not include claims that would be infringed only as a
     470consequence of further modification of the contributor version.  For
     471purposes of this definition, "control" includes the right to grant
     472patent sublicenses in a manner consistent with the requirements of
    195473this License.
    196474
    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
     476patent license under the contributor's essential patent claims, to
     477make, use, sell, offer for sale, import and otherwise run, modify and
     478propagate the contents of its contributor version.
     479
     480  In the following three paragraphs, a "patent license" is any express
     481agreement or commitment, however denominated, not to enforce a patent
     482(such as an express permission to practice a patent or covenant not to
     483sue for patent infringement).  To "grant" such a patent license to a
     484party means to make such an agreement or commitment not to enforce a
     485patent against the party.
     486
     487  If you convey a covered work, knowingly relying on a patent license,
     488and the Corresponding Source of the work is not available for anyone
     489to copy, free of charge and under the terms of this License, through a
     490publicly available network server or other readily accessible means,
     491then you must either (1) cause the Corresponding Source to be so
     492available, or (2) arrange to deprive yourself of the benefit of the
     493patent license for this particular work, or (3) arrange, in a manner
     494consistent with the requirements of this License, to extend the patent
     495license to downstream recipients.  "Knowingly relying" means you have
     496actual knowledge that, but for the patent license, your conveying the
     497covered work in a country, or your recipient's use of the covered work
     498in a country, would infringe one or more identifiable patents in that
     499country that you have reason to believe are valid.
     500
     501  If, pursuant to or in connection with a single transaction or
     502arrangement, you convey, or propagate by procuring conveyance of, a
     503covered work, and grant a patent license to some of the parties
     504receiving the covered work authorizing them to use, propagate, modify
     505or convey a specific copy of the covered work, then the patent license
     506you grant is automatically extended to all recipients of the covered
     507work and works based on it.
     508
     509  A patent license is "discriminatory" if it does not include within
     510the scope of its coverage, prohibits the exercise of, or is
     511conditioned on the non-exercise of one or more of the rights that are
     512specifically granted under this License.  You may not convey a covered
     513work if you are a party to an arrangement with a third party that is
     514in the business of distributing software, under which you make payment
     515to the third party based on the extent of your activity of conveying
     516the work, and under which the third party grants, to any of the
     517parties who would receive the covered work from you, a discriminatory
     518patent license (a) in connection with copies of the covered work
     519conveyed by you (or copies made from those copies), or (b) primarily
     520for and in connection with specific products or compilations that
     521contain the covered work, unless you entered into that arrangement,
     522or that patent license was granted, prior to 28 March 2007.
     523
     524  Nothing in this License shall be construed as excluding or limiting
     525any implied license or other defenses to infringement that may
     526otherwise 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
    200531otherwise) 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
     532excuse you from the conditions of this License.  If you cannot convey a
     533covered work so as to satisfy simultaneously your obligations under this
     534License and any other pertinent obligations, then as a consequence you may
     535not convey it at all.  For example, if you agree to terms that obligate you
     536to collect a royalty for further conveying from those to whom you convey
     537the Program, the only way you could satisfy both those terms and this
     538License 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
     543Program, your modified version must prominently offer all users
     544interacting with it remotely through a computer network (if your version
     545supports such interaction) an opportunity to receive the Corresponding
     546Source of your version by providing access to the Corresponding Source
     547from a network server at no charge, through some standard or customary
     548means of facilitating copying of software.  This Corresponding Source
     549shall include the Corresponding Source for any work covered by version 3
     550of the GNU General Public License that is incorporated pursuant to the
     551following paragraph.
     552
     553  Notwithstanding any other provision of this License, you have
     554permission to link or combine any covered work with a work licensed
     555under version 3 of the GNU General Public License into a single
     556combined work, and to convey the resulting work.  The terms of this
     557License will continue to apply to the part which is the covered work,
     558but the work with which it is combined will remain governed by version
     5593 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
     564the GNU Affero General Public License from time to time.  Such new versions
     565will be similar in spirit to the present version, but may differ in detail to
    240566address new problems or concerns.
    241567
    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
     569Program specifies that a certain numbered version of the GNU Affero General
     570Public License "or any later version" applies to it, you have the
     571option of following the terms and conditions either of that numbered
     572version or of any later version published by the Free Software
     573Foundation.  If the Program does not specify a version number of the
     574GNU Affero General Public License, you may choose any version ever published
     575by the Free Software Foundation.
     576
     577  If the Program specifies that a proxy can decide which future
     578versions of the GNU Affero General Public License can be used, that proxy's
     579public statement of acceptance of a version permanently authorizes you
     580to choose that version for the Program.
     581
     582  Later license versions may give you additional or different
     583permissions.  However, no additional obligations are imposed on any
     584author or copyright holder as a result of your choosing to follow a
     585later version.
     586
     587  15. Disclaimer of Warranty.
     588
     589  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
     590APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
     591HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
     592OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
     593THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     594PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
     595IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
     596ALL 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
     601WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
     602THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
     603GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
     604USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
     605DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
     606PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
     607EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
     608SUCH DAMAGES.
     609
     610  17. Interpretation of Sections 15 and 16.
     611
     612  If the disclaimer of warranty and limitation of liability provided
     613above cannot be given local legal effect according to their terms,
     614reviewing courts shall apply local law that most closely approximates
     615an absolute waiver of all civil liability in connection with the
     616Program, unless a warranty or assumption of liability accompanies a
     617copy of the Program in return for a fee.
    279618
    280                      END OF TERMS AND CONDITIONS
     619                     END OF TERMS AND CONDITIONS
    281620
    282             How to Apply These Terms to Your New Programs
     621            How to Apply These Terms to Your New Programs
    283622
    284623  If you develop a new program, and you want it to be of the greatest
    285624possible use to the public, the best way to achieve this is to make it
     
    287626
    288627  To do so, attach the following notices to the program.  It is safest
    289628to attach them to the start of each source file to most effectively
    290 convey the exclusion of warranty; and each file should have at least
     629state the exclusion of warranty; and each file should have at least
    291630the "copyright" line and a pointer to where the full notice is found.
    292631
    293632    <one line to give the program's name and a brief idea of what it does.>
    294633    Copyright (C) <year>  <name of author>
    295634
    296     This program is free software; you can redistribute it and/or modify
    297     it under the terms of the GNU General Public License as published by
    298     the Free Software Foundation; either version 2 of the License, or
     635    This program is free software: you can redistribute it and/or modify
     636    it under the terms of the GNU Affero General Public License as published by
     637    the Free Software Foundation, either version 3 of the License, or
    299638    (at your option) any later version.
    300639
    301640    This program is distributed in the hope that it will be useful,
    302641    but WITHOUT ANY WARRANTY; without even the implied warranty of
    303642    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.
    305644
    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/>.
    309647
    310648Also add information on how to contact you by electronic and paper mail.
    311649
    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
     651network, you should also make sure that it provides a way for users to
     652get its source.  For example, if your program is a web application, its
     653interface could display a "Source" link that leads users to an archive
     654of the code.  There are many ways you could offer source, and different
     655solutions will be better for different programs; see section 13 for the
     656specific requirements.
     657
     658  You should also get your employer (if you work as a programmer) or school,
     659if any, to sign a "copyright disclaimer" for the program, if necessary.
     660For 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

     
    11;var MXI_DEBUG = false;
    22/**
    33 * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
    4  * v1.3.5
     4 * v1.5.8
    55 *
    66 * Copyright 2013, Moxiecode Systems AB
    77 * Released under GPL License.
     
    99 * License: http://www.plupload.com/license
    1010 * Contributing: http://www.plupload.com/contributing
    1111 *
    12  * Date: 2016-05-15
    13  */
    14 /**
    15  * Compiled inline version. (Library mode)
     12 * Date: 2018-02-19
    1613 */
     14;(function (global, factory) {
     15        var extract = function() {
     16                var ctx = {};
     17                factory.apply(ctx, arguments);
     18                return ctx.moxie;
     19        };
    1720
    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         */
    2232
    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 */
    2535
    26 (function(exports, undefined) {
    27         "use strict";
     36        (function(exports, undefined) {
     37                "use strict";
    2838
    29         var modules = {};
     39                var modules = {};
    3040
    31         function require(ids, callback) {
    32                 var module, defs = [];
     41                function require(ids, callback) {
     42                        var module, defs = [];
    3343
    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);
    3851                        }
    3952
    40                         defs.push(module);
     53                        callback.apply(null, defs);
    4154                }
    4255
    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                        }
    4560
    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                        }
    5064
    51                 if (dependencies === undefined) {
    52                         throw 'invalid module definition, dependencies must be specified';
    53                 }
     65                        if (definition === undefined) {
     66                                throw 'invalid module definition, definition function must be specified';
     67                        }
    5468
    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                        });
    5772                }
    5873
    59                 require(dependencies, function() {
    60                         modules[id] = definition.apply(null, arguments);
    61                 });
    62         }
     74                function defined(id) {
     75                        return !!modules[id];
     76                }
    6377
    64         function defined(id) {
    65                 return !!modules[id];
    66         }
     78                function resolve(id) {
     79                        var target = exports;
     80                        var fragments = id.split(/[.\/]/);
    6781
    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                                }
    7186
    72                 for (var fi = 0; fi < fragments.length; ++fi) {
    73                         if (!target[fragments[fi]]) {
    74                                 return;
     87                                target = target[fragments[fi]];
    7588                        }
    7689
    77                         target = target[fragments[fi]];
     90                        return target;
    7891                }
    7992
    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(/[.\/]/);
    8298
    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                                        }
    88103
    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]];
    92105                                }
    93106
    94                                 target = target[fragments[fi]];
     107                                target[fragments[fragments.length - 1]] = modules[id];
    95108                        }
    96 
    97                         target[fragments[fragments.length - 1]] = modules[id];
    98109                }
    99         }
    100110
    101111// Included from: src/javascript/core/utils/Basic.js
    102112
    103 /**
    104  * Basic.js
    105  *
    106  * Copyright 2013, Moxiecode Systems AB
    107  * Released under GPL License.
    108  *
    109  * License: http://www.plupload.com/license
    110  * Contributing: http://www.plupload.com/contributing
    111  */
     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                */
    112122
    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                        /**
    115131        Gets the true type of the built-in object (better version of typeof).
    116132        @author Angus Croll (http://javascriptweblog.wordpress.com/)
    117133
    118134        @method typeOf
    119         @for Utils
    120135        @static
    121136        @param {Object} o Object to check.
    122137        @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;
    134141
    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).
    141156
    142157        @method extend
    143158        @static
    144159        @param {Object} target Object to extend.
    145160        @param {Object} [obj]* Multiple objects to extend with.
    146161        @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                                                });
    160241                                        }
    161242                                });
     243
     244                                return target;
    162245                        }
    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                        /**
    168289        Executes the callback function for each item in array/object. If you return false in the
    169290        callback it will break the loop.
    170291
     
    172293        @static
    173294        @param {Object} obj Object to iterate.
    174295        @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;
    185305                                        }
    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                                                        }
    193322                                                }
    194323                                        }
    195324                                }
    196325                        }
    197                 }
    198         };
    199326
    200         /**
     327                        /**
    201328        Checks if object is empty.
    202        
     329
    203330        @method isEmptyObj
    204331        @static
    205332        @param {Object} o Object to check.
    206333        @return {Boolean}
    207         */
    208         var isEmptyObj = function(obj) {
    209                 var prop;
     334                         */
     335                        function isEmptyObj(obj) {
     336                                var prop;
    210337
    211                 if (!obj || typeOf(obj) !== 'object') {
    212                         return true;
    213                 }
     338                                if (!obj || typeOf(obj) !== 'object') {
     339                                        return true;
     340                                }
    214341
    215                 for (prop in obj) {
    216                         return false;
    217                 }
     342                                for (prop in obj) {
     343                                        return false;
     344                                }
    218345
    219                 return true;
    220         };
     346                                return true;
     347                        }
    221348
    222         /**
     349                        /**
    223350        Recieve an array of functions (usually async) to call in sequence, each  function
    224351        receives a callback as first argument that it should call, when it completes. Finally,
    225352        after everything is complete, main callback is called. Passing truthy value to the
     
    230357        @static
    231358        @param {Array} queue Array of functions to call in sequence
    232359        @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;
    236363
    237                 if (typeOf(cb) !== 'function') {
    238                         cb = function() {};
    239                 }
     364                                if (typeOf(cb) !== 'function') {
     365                                        cb = function() {};
     366                                }
    240367
    241                 if (!queue || !queue.length) {
    242                         cb();
    243                 }
     368                                if (!queue || !queue.length) {
     369                                        cb();
     370                                }
    244371
    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);
    251381                        }
    252                 }
    253                 callNext(i);
    254         };
    255382
    256383
    257         /**
     384                        /**
    258385        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
    260387        everything is complete, main callback is called. Passing truthy value to the
    261388        callback as a first argument will interrupt the process and invoke main callback
    262389        immediately.
     
    264391        @method inParallel
    265392        @static
    266393        @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 error
    268         */
    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 not
    280 
    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                        /**
    294421        Find an element in array and return it's index if present, otherwise return -1.
    295        
     422
    296423        @method inArray
    297424        @static
    298425        @param {Mixed} needle Element to find
    299426        @param {Array} array
    300427        @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                                        }
    311440                                }
     441                                return -1;
    312442                        }
    313                 }
    314                 return -1;
    315         };
    316443
    317444
    318         /**
     445                        /**
    319446        Returns elements of first array if they are not present in second. And false - otherwise.
    320447
    321448        @private
     
    323450        @param {Array} needles
    324451        @param {Array} array
    325452        @return {Array|Boolean}
    326         */
    327         var arrayDiff = function(needles, array) {
    328                 var diff = [];
     453                         */
     454                        function arrayDiff(needles, array) {
     455                                var diff = [];
    329456
    330                 if (typeOf(needles) !== 'array') {
    331                         needles = [needles];
    332                 }
     457                                if (typeOf(needles) !== 'array') {
     458                                        needles = [needles];
     459                                }
    333460
    334                 if (typeOf(array) !== 'array') {
    335                         array = [array];
    336                 }
     461                                if (typeOf(array) !== 'array') {
     462                                        array = [array];
     463                                }
    337464
    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                        }
    345472
    346473
    347         /**
     474                        /**
    348475        Find intersection of two arrays.
    349476
    350477        @private
     
    352479        @param {Array} array1
    353480        @param {Array} array2
    354481        @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;
    361491                        }
    362                 });
    363                 return result.length ? result : null;
    364         };
    365        
    366        
    367         /**
     492
     493
     494                        /**
    368495        Forces anything into an array.
    369        
     496
    370497        @method toArray
    371498        @static
    372499        @param {Object} obj Object with length field.
    373500        @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 = [];
    377504
    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                                }
    381508
    382                 return arr;
    383         };
    384        
    385                        
    386         /**
     509                                return arr;
     510                        }
     511
     512
     513                        /**
    387514        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
    390517        to be hit with an asteroid.
    391        
     518
    392519        @method guid
    393520        @static
    394521        @param {String} prefix to prepend (by default 'o' will be prepended).
    395522        @method guid
    396523        @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;
    412527
    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                        /**
    414541        Trims white spaces around the string
    415        
     542
    416543        @method trim
    417544        @static
    418545        @param {String} str
    419546        @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                        }
    427554
    428555
    429         /**
     556                        /**
    430557        Parses the specified size string into a byte value. For example 10kb becomes 10240.
    431        
     558
    432559        @method parseSizeStr
    433560        @static
    434561        @param {String/Number} size String to parse or number to just pass through.
    435562        @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                                }
    449568
     569                                var muls = {
     570                                                t: 1099511627776,
     571                                                g: 1073741824,
     572                                                m: 1048576,
     573                                                k: 1024
     574                                        },
     575                                        mul;
    450576
    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];
    460580
     581                                if (muls.hasOwnProperty(mul)) {
     582                                        size *= muls[mul];
     583                                }
     584                                return Math.floor(size);
     585                        }
    461586
    462         /**
    463          * Pseudo sprintf implementation - simple way to replace tokens with specified values.
    464          *
    465          * @param {String} str String with tokens
    466          * @return {String} String with replaced tokens
    467          */
    468         var sprintf = function(str) {
    469                 var args = [].slice.call(arguments, 1);
    470587
    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);
    477596
    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();
    495599
    496 // Included from: src/javascript/core/utils/Env.js
     600                                        switch ($1) {
     601                                                case 's':
     602                                                        return value + '';
    497603
    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);
    507606
    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);
    521609
    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 '';
    1045612
     613                                                default:
     614                                                        return value;
     615                                        }
     616                                });
     617                        }
    1046618
    1047         var can = (function() {
    1048                 var caps = {
    1049                                 define_property: (function() {
    1050                                         /* // currently too much extra code required, not exactly worth it
    1051                                         try { // as of IE8, getters/setters are supported only on DOM elements
    1052                                                 var obj = {};
    1053                                                 if (Object.defineProperty) {
    1054                                                         Object.defineProperty(obj, 'prop', {
    1055                                                                 enumerable: true,
    1056                                                                 configurable: true
    1057                                                         });
    1058                                                         return true;
    1059                                                 }
    1060                                         } catch(ex) {}
    1061619
    1062                                         if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
    1063                                                 return true;
    1064                                         }*/
    1065                                         return false;
    1066                                 }()),
    1067620
    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                        }
    1075627
    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 exception
    1083                                                         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                                 },
    1095628
    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                });
    1099652
    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
    1109654
    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                 */
    1113664
    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                 */
    1117670
    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() {
    1122672
    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));
    1127683                        };
    1128684
    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
    1135687
     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                        };
    1136696
    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
    1138700
     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);
    1139760
    1140         var Env = {
    1141                 can: can,
     761                                dec = tmp_arr.join('');
    1142762
    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                        };
    1149765
    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
    1151769
    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);
    1154821
    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('');
    1188823
    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;
    1197825
    1198         return Env;
    1199 });
     826                                return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
     827                        };
    1200828
    1201 // Included from: src/javascript/core/I18n.js
    1202829
    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                });
    1212837
    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
    1217839
    1218         return {
    1219840                /**
    1220                  * Extends the language pack object with new items.
     841                 * Env.js
    1221842                 *
    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.
    1231845                 *
    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
    1234848                 */
    1235                 translate: function(str) {
    1236                         return i18n[str] || str;
    1237                 },
    1238849
    1239850                /**
    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
    1244854                 */
    1245                 _: function(str) {
    1246                         return this.translate(str);
    1247                 },
    1248855
    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                                };
    1257905
    1258                         return str.replace(/%[a-z]/g, function() {
    1259                                 var value = args.shift();
    1260                                 return Basic.typeOf(value) !== 'undefined' ? value : '';
    1261                         });
    1262                 }
    1263         };
    1264 });
    1265906
    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                                                        }
    1267934
    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                                                        }
    1277971
    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                                        },
    1402976
    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;
    1411989                                                        }
    1412                                                 });
    1413                                         } else if (self.extensions[mime]) {
    1414                                                 [].push.apply(exts, self.extensions[mime]);
     990                                                }
     991                                                return str;
    1415992                                        }
    1416                                 }
    1417                         });
    1418                         return exts;
    1419                 },
     993                                };
    1420994
    1421995
    1422                 mimes2extList: function(mimes) {
    1423                         var accept = [], exts = [];
     996                                ///////////////
     997                                // String map
     998                                //////////////
    1424999
    1425                         if (Basic.typeOf(mimes) === 'string') {
    1426                                 mimes = Basic.trim(mimes).split(/\s*,\s*/);
    1427                         }
    14281000
    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                                        },
    14381022
    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                                        },
    14411034
     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                                };
    14421052
    1443                 getFileExtension: function(fileName) {
    1444                         var matches = fileName && fileName.match(/\.([^.]+)$/);
    1445                         if (matches) {
    1446                                 return matches[1].toLowerCase();
    1447                         }
    1448                         return '';
    1449                 },
    14501053
    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                                };
    14551239
    1456         Mime.addMimeType(mimeData);
    14571240
    1458         return Mime;
    1459 });
     1241                                /////////////////
     1242                                // Constructor
     1243                                ////////////////
    14601244
    1461 // Included from: src/javascript/core/utils/Dom.js
    14621245
    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) {
    14721247
    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);
    14741249
    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                                };
    14771276
    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                        })();
    14891279
    1490         /**
    1491         Checks if specified DOM element has specified class.
    14921280
    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                                        };
    15021342
    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                                }
    15061363
    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                        }
    15091393
    1510         @method addClass
    1511         @static
    1512         @param {Object} obj DOM element like object to add handler to.
    1513         @param {String} name Class name
    1514         */
    1515         var addClass = function(obj, name) {
    1516                 if (!hasClass(obj, name)) {
    1517                         obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
    1518                 }
    1519         };
    15201394
    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) {}
    15231413
    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                                        }()),
    15371419
    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                                        },
    15401429
    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                                        },
    15531449
     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                                                };
    15541467
    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                                        }()),
    15571473
    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                                        },
    15801481
    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                                                }
    15861486
    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) {}
    15911499
    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                                                }
    15971503
    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                                };
    16041510
    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                        }());
    16111517
    1612                 return {
    1613                         x : x,
    1614                         y : y
    1615                 };
    1616         };
    16171518
    1618         /**
    1619         Returns the size of the specified node in pixels.
     1519                        var uaResult = new UAParser().getResult();
    16201520
    1621         @method getSize
    1622         @static
    1623         @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.clientHeight
    1630                 };
    1631         };
    16321521
    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,
    16431524
    1644 // Included from: src/javascript/core/Exceptions.js
     1525                                uaParser: UAParser,
    16451526
    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,
    16551531
    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,
    16681533
    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                        };
    18021538
    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                                };
    18041548
    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() {
    18141550
    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                                                }
    18221567
    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                                                }
    18341575
    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                        }
    18421580
    1843                         @method init
    1844                         */
    1845                         init: function() {
    1846                                 if (!this.uid) {
    1847                                         this.uid = Basic.guid('uid_');
    1848                                 }
    1849                         },
     1581                        return Env;
     1582                });
    18501583
    1851                         /**
    1852                         Register a handler to a specific event dispatched by the object
     1584// Included from: src/javascript/core/Exceptions.js
    18531585
    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                 */
    18921595
    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) {
    19041599
    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;
    19341605                                        }
    19351606                                }
    1936                         },
    1937                        
    1938                         /**
    1939                         Remove all event handlers from the object
     1607                                return null;
     1608                        }
    19401609
    1941                         @method removeAllEventListeners
    1942                         */
    1943                         removeAllEventListeners: function() {
    1944                                 if (eventpool[this.uid]) {
    1945                                         delete eventpool[this.uid];
    1946                                 }
    1947                         },
    1948                        
    19491610                        /**
    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                                        };
    19511621
    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);
    19741626                                        }
    1975                                 }
    1976                                
    1977                                 // check if event is meant to be dispatched on an object having specific uid
    1978                                 if (type.indexOf('::') !== -1) {
    1979                                         (function(arr) {
    1980                                                 uid = arr[0];
    1981                                                 type = arr[1];
    1982                                         }(type.split('::')));
    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 prority
    1993                                         list.sort(function(a, b) { return b.priority - a.priority; });
    1994                                        
    1995                                         args = [].slice.call(arguments);
    1996                                        
    1997                                         // first argument will be pseudo-event object
    1998                                         args.shift();
    1999                                         evt.type = type;
    2000                                         args.unshift(evt);
    20011627
    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';
    20041638                                        }
    20051639
    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
    20231642                                        });
    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 addEventListener
    20351643
    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;
    20451645
    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                                }()),
    20551648
    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                                        };
    20651655
    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                                        }
    20731661
    2074                         /**
    2075                         Handle properties of on[event] type.
     1662                                        Basic.extend(ImageError, namecodes);
     1663                                        ImageError.prototype = Error.prototype;
    20761664
    2077                         @method handleEventProps
    2078                         @private
    2079                         */
    2080                         handleEventProps: function(dispatches) {
    2081                                 var self = this;
     1665                                        return ImageError;
     1666                                }()),
    20821667
    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                                        };
    20891679
    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;
    20951684                                        }
    2096                                 });
    2097                         }
    2098                        
    2099                 });
    2100         }
    21011685
    2102         EventTarget.instance = new EventTarget();
     1686                                        Basic.extend(FileException, namecodes);
     1687                                        FileException.prototype = Error.prototype;
     1688                                        return FileException;
     1689                                }()),
    21031690
    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                                        };
    21061719
    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                                        }
    21081725
    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                                }()),
    21181730
    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                                        }
    21261736
    2127         /**
    2128         Common set of methods and properties for every runtime instance
     1737                                        Basic.extend(EventException, {
     1738                                                UNSPECIFIED_EVENT_TYPE_ERR: 0
     1739                                        });
    21291740
    2130         @class Runtime
     1741                                        EventException.prototype = Error.prototype;
    21311742
    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                });
    21421747
    2143                 @event Init
    2144                 */
     1748// Included from: src/javascript/core/utils/Dom.js
    21451749
    21461750                /**
    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                 */
    21631759
    21641760                /**
    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                 */
    22291765
    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) {
    22511767
    2252                                 removeInstance: function(uid) {
    2253                                         delete objpool[uid];
    2254                                 },
     1768                        /**
     1769        Get DOM Element by it's id.
    22551770
    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;
    22641778                                }
     1779                                return document.getElementById(id);
    22651780                        };
    2266                 }());
    22671781
    2268 
    2269                 // public methods
    2270                 Basic.extend(this, {
    22711782                        /**
    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.
    22791784
    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                                }
    22821794
    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                        };
    22871798
    22881799                        /**
    2289                         Runtime type (e.g. flash, html5, etc)
     1800        Adds specified className to specified DOM element.
    22901801
    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                        };
    22951812
    22961813                        /**
    2297                         Runtime (not native one) may operate in browser or client mode.
     1814        Removes specified className from specified DOM element.
    22981815
    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                        };
    23041829
    23051830                        /**
    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.
    23121832
    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                        };
    23151845
    2316                         @property clients
    2317                         @type {Number}
    2318                         */
    2319                         clients: 0,
    23201846
    23211847                        /**
    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.
    23281849
    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                                        }
    23311872
    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                                        };
    23441877                                }
    23451878
    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                                        };
    23531888                                }
    23541889
    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;
    23601902                                }
    2361                         },
     1903
     1904                                return {
     1905                                        x : x,
     1906                                        y : y
     1907                                };
     1908                        };
    23621909
    23631910                        /**
    2364                         Returns container for the runtime as DOM element
     1911        Returns the size of the specified node in pixels.
    23651912
    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                        };
    23801924
    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                });
    23891935
    2390                                         container.appendChild(shimContainer);
    2391                                         container = null;
    2392                                 }
     1936// Included from: src/javascript/core/EventTarget.js
    23931937
    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                 */
    23961947
    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) {
    23991953
    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 = {};
    24061956
    24071957                        /**
    2408                         Invokes a method within the runtime itself (might differ across the runtimes)
     1958        Parent object for all event dispatching components and objects
    24091959
    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
    24191966
    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                        }
    24231972
    2424                         @method exec
    2425                         @param {Mixed} []*
    2426                         @protected
    2427                         @return {Mixed} Depends on the action and component
    2428                         */
    2429                         exec: function(component, action) { // this is called in the context of component, not runtime
    2430                                 var args = [].slice.call(arguments, 2);
    24311973
    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, {
    24371975
    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
    24401978
    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                                },
    24471986
    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
    24521989
    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                                        }
    24562013
    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;
    24632016
    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});
    24692019
     2020                                        if (!eventpool[this.uid]) {
     2021                                                eventpool[this.uid] = {};
     2022                                        }
     2023                                        eventpool[this.uid][type] = list;
     2024                                },
    24702025
    2471         /**
    2472         Default order to try different runtime types
     2026                                /**
     2027                Check if any handlers were registered to the specified event
    24732028
    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                                },
    24792043
     2044                                /**
     2045                Unregister the handler from the event, or if former was not specified - unregister all handlers
    24802046
    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                                        }
    24832063
    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];
    24932065
     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                                                }
    24942077
    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                                },
    24972089
    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
    25072092
     2093                @method removeAllEventListeners
     2094                                 */
     2095                                removeAllEventListeners: function() {
     2096                                        if (eventpool[this.uid]) {
     2097                                                delete eventpool[this.uid];
     2098                                        }
     2099                                },
    25082100
    2509         /**
    2510         Get the constructor for the specified type.
     2101                                /**
     2102                Dispatch the event
    25112103
    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                                        }
    25202128
     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                                        }
    25212138
    2522         /**
    2523         Get info about the runtime (uid, type, capabilities)
     2139                                        type = type.toLowerCase();
    25242140
    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];
    25322142
    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; });
    25452146
     2147                                                args = [].slice.call(arguments);
    25462148
    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);
    25492153
    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                                                }
    25572157
    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                                },
    25612184
    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
    25652187
    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                                },
    25682202
    2569         /**
    2570         Test the specified runtime for specific capabilities.
     2203                                /**
     2204                Alias for addEventListener
    25712205
    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
    25932215
     2216                @method unbind
     2217                @protected
     2218                                 */
     2219                                unbind: function() {
     2220                                        this.removeEventListener.apply(this, arguments);
     2221                                },
    25942222
    2595         /**
    2596         Figure out a runtime that supports specified capabilities.
     2223                                /**
     2224                Alias for removeAllEventListeners
    25972225
    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                                },
    26132232
     2233                                /**
     2234                Alias for dispatchEvent
    26142235
    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                                },
    26172242
    2618         @method getMode
    2619         @static
    2620         @param {Object} modeCaps Set of capabilities that depend on particular runtime mode
    2621         @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
    2622         @param {String|Boolean} [defaultMode='browser'] Default mode to use
    2623         @return {String|Boolean} Compatible operational mode
    2624         */
    2625         Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
    2626                 var mode = null;
    26272243
    2628                 if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
    2629                         defaultMode = 'browser';
    2630                 }
     2244                                /**
     2245                Handle properties of on[event] type.
    26312246
    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;
    26472252
    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);
    26502257                                                }
     2258                                        });
    26512259
    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                                        });
    26542267                                }
    26552268
    2656                                 if (MXI_DEBUG && Env.debug.runtime) {
    2657                                         Env.log("\t\t%c: %v (compatible modes: %s)", cap, value, mode);
    2658                                 }
    26592269                        });
    26602270
    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         };
    26692271
     2272                        EventTarget.instance = new EventTarget();
    26702273
    2671         /**
    2672         Capability check that always returns true
     2274                        return EventTarget;
     2275                });
    26732276
    2674         @private
    2675         @static
    2676         @return {True}
    2677         */
    2678         Runtime.capTrue = function() {
    2679                 return true;
    2680         };
     2277// Included from: src/javascript/runtime/Runtime.js
    26812278
    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                 */
    26842288
    2685         @private
    2686         @static
    2687         @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 = {};
    26922296
    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
    26952299
    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
    27062301
    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;
    27094477
    2710 // Included from: src/javascript/runtime/RuntimeClient.js
     4478                        /**
     4479        FileReader switches to this state when it is preloading the source
    27114480
    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;
    27214488
    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                });
    27304504
    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                 */
    27354522
    2736                 Basic.extend(this, {
     4523                define('moxie/core/utils/Url', [
     4524                        'moxie/core/utils/Basic'
     4525                ], function(Basic) {
    27374526                        /**
    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
    27404529
    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                                ;
    27574548
    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;
    27644553
    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];
    27684562                                        }
     4563                                }
    27694564
    2770                                         // try initializing the runtime
    2771                                         runtime = new constructor(options);
     4565                                isRelative = !isSchemeLess && !uri.scheme;
    27724566
    2773                                         runtime.bind('Init', function() {
    2774                                                 // mark runtime as initialized
    2775                                                 runtime.initialized = true;
     4567                                if (isSchemeLess || isRelative) {
     4568                                        uri.scheme = currentUrl.scheme;
     4569                                }
    27764570
    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(/\/?$/, '/');
    27794586                                                }
     4587                                        }
     4588                                        uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
     4589                                }
    27804590
    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                                }
    27884594
    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);
    27934596
    2794                                                 runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here
    2795                                                 initialize(items);
    2796                                         });
     4597                                if (!uri.path) {
     4598                                        uri.path = "/";
     4599                                }
    27974600
    2798                                         /*runtime.bind('Exception', function() { });*/
     4601                                delete uri.source;
    27994602
    2800                                         if (MXI_DEBUG && Env.debug.runtime) {
    2801                                                 Env.log("\tselected mode: %s", runtime.mode);   
    2802                                         }
     4603                                return uri;
     4604                        };
    28034605
    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
    28094608
    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
    28114618                                }
     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
    28124627
    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('/');
    28184636                                }
    28194637
    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);
    28294640                                }
    28304641
    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
    28344653
     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                 */
    28354663
     4664                define('moxie/runtime/RuntimeTarget', [
     4665                        'moxie/core/utils/Basic',
     4666                        'moxie/runtime/RuntimeClient',
     4667                        "moxie/core/EventTarget"
     4668                ], function(Basic, RuntimeClient, EventTarget) {
    28364669                        /**
    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
    28384672
    2839                         @private
    2840                         @method disconnectRuntime
    2841                         */
    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_');
    28464680
    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
    28504695
     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                 */
    28514705
     4706                define('moxie/file/FileReaderSync', [
     4707                        'moxie/core/utils/Basic',
     4708                        'moxie/runtime/RuntimeClient',
     4709                        'moxie/core/utils/Encode'
     4710                ], function(Basic, RuntimeClient, Encode) {
    28524711                        /**
    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.
    28544715
    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                                        }
    28614763                                }
    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
    28644768
     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                 */
    28654778
     4779                define("moxie/xhr/FormData", [
     4780                        "moxie/core/Exceptions",
     4781                        "moxie/core/utils/Basic",
     4782                        "moxie/file/Blob"
     4783                ], function(x, Basic, Blob) {
    28664784                        /**
    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                                });
    28784881                        }
    28794882
     4883                        return FormData;
    28804884                });
    2881         };
    28824885
     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                 */
    28834897
    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                        };
    28854970
    2886 // Included from: src/javascript/file/FileInput.js
     4971                        function XMLHttpRequestUpload() {
     4972                                this.uid = Basic.guid('uid_');
     4973                        }
    28874974
    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;
    28974976
    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
    29134979
    2914         @class FileInput
     4980        @class moxie/xhr/XMLHttpRequest
    29154981        @constructor
    2916         @extends EventTarget
    29174982        @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',
    29274995
    2928         @example
    2929                 <div id="container">
    2930                         <a id="file-picker" href="javascript:;">Browse...</a>
    2931                 </div>
     4996                                'timeout',
    29324997
    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'
    29424999
    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                        ];
    29475002
    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;
    29545004
    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.
    29595011
    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,
    29635017
    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.
    29675022
    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.
    29705025
    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.
    29755028
    2976                 'cancel', // TODO: might be useful
     5029                                LOADING (numeric value 3)
     5030                                The response entity body is being received.
    29775031
    2978                 /**
    2979                 Dispatched when mouse cursor enters file-picker area. Can be used to style element
    2980                 accordingly.
     5032                                DONE (numeric value 4)
    29815033
    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,
    29865039
    2987                 /**
    2988                 Dispatched when mouse cursor leaves file-picker area. Can be used to style element
    2989                 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.
    29905043
    2991                 @event mouseleave
    2992                 @param {Object} event
    2993                 */
    2994                 'mouseleave',
     5044                                @property withCredentials
     5045                                @type Boolean
     5046                                @default false
     5047                                                 */
     5048                                                withCredentials: false,
    29955049
    2996                 /**
    2997                 Dispatched when functional mouse button is pressed on top of file-picker area.
     5050                                                /**
     5051                                Returns the HTTP status code.
    29985052
    2999                 @event mousedown
    3000                 @param {Object} event
    3001                 */
    3002                 'mousedown',
     5053                                @property status
     5054                                @type Number
     5055                                @default 0
     5056                                                 */
     5057                                                status: 0,
    30035058
    3004                 /**
    3005                 Dispatched when functional mouse button is released on top of file-picker area.
     5059                                                /**
     5060                                Returns the HTTP status text.
    30065061
    3007                 @event mouseup
    3008                 @param {Object} event
    3009                 */
    3010                 'mouseup'
    3011         ];
     5062                                @property statusText
     5063                                @type String
     5064                                                 */
     5065                                                statusText: "",
    30125066
    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".
    30175070
    3018                 var self = this,
    3019                         container, browseButton, defaults;
     5071                                @property responseType
     5072                                @type String
     5073                                                 */
     5074                                                responseType: "",
    30205075
    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.
    30255078
    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".
    30325080
    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,
    30565085
    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.
    30625088
    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".
    30675090
    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                                        /**
    30745139                        Unique id of the component
    30755140
    30765141                        @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_'),
    30865145
    3087                         @property ruid
    3088                         @protected
    3089                         @type {String}
    3090                         */
    3091                         ruid: null,
     5146                                        /**
     5147                        Target for Upload events
    30925148
    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(),
    30955153
    3096                         @property shimid
    3097                         @protected
    3098                         @type {String}
    3099                         */
    3100                         shimid: null,
    3101                        
    3102                         /**
    3103                         Array of selected mOxie.File objects
    31045154
    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.
    31105157
    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:
    31135159
    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.
    31205164
    3121                                         self.bind("Ready", function() {
    3122                                                 self.trigger("Refresh");
    3123                                         }, 999);
     5165                        Throws an "InvalidAccessError" exception if one of the following is true:
    31245166
    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.
    31315170
    3132                                                 if (browseButton) {
    3133                                                         pos = Dom.getPos(browseButton, Dom.get(options.container));
    3134                                                         size = Dom.getSize(browseButton);
    31355171
    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);
    31445185                                                }
    3145                                                 shimContainer = browseButton = null;
    3146                                         });
    3147                                        
    3148                                         runtime.exec.call(self, 'FileInput', 'init', options);
    3149                                 });
    31505186
    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                                                }
    31585191
    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                                                }
    31615196
    3162                         @method disable
    3163                         @param {Boolean} [state=true] Disable component if - true, enable if - false
    3164                         */
    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                         },
    31715197
     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                                                }
    31725202
    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);
    31755205
    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);
    31815208
     5209                                                _same_origin_flag = Url.hasSameOrigin(urlp);
    31825210
    3183                         /**
    3184                         Destroy component.
     5211                                                // 7 - manually build up absolute url
     5212                                                _url = Url.resolveUrl(url);
    31855213
    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                                                }
    31945218
    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;
    32025221
    3203                                 this.unbindAll();
    3204                         }
    3205                 });
     5222                                                // 11
     5223                                                _async = async || true;
    32065224
    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                                                }
    32095228
    3210         FileInput.prototype = EventTarget.instance;
     5229                                                // 14 - terminate abort()
    32115230
    3212         return FileInput;
    3213 });
     5231                                                // 15 - terminate send()
    32145232
    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);
    32165238
    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);
    32265241
    3227 define('moxie/core/utils/Encode', [], function() {
     5242                                                // 20
     5243                                                this.dispatchEvent('readystatechange');
     5244                                        },
    32285245
    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.
    32315249
    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.
    32445253
    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                                                }
    32575287
    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                                                }
    32675292
    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                                }*/
    32905298
    3291                 if (!data) {
    3292                         return data;
    3293                 }
     5299                                                header = Basic.trim(header).toLowerCase();
    32945300
    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                                                }
    32965305
    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(); });
    33025309
    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                                        },
    33045318
    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                                        },
    33085330
    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.
    33175333
    3318                 dec = tmp_arr.join('');
     5334                        @method getAllResponseHeaders
     5335                        @return {String} reponse headers or empty string
     5336                                         */
     5337                                        getAllResponseHeaders: function() {
     5338                                                return _responseHeaders || '';
     5339                                        },
    33195340
    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.
    33265344
    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();
    33365351
    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                                                }
    33405355
    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                                        },
    33585377
    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.
    33625382
    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                                                }
    33675393
    3368                         bits = o1 << 16 | o2 << 8 | o3;
     5394                                                // 2
     5395                                                mime = Basic.trim(mime.toLowerCase());
    33695396
    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                                                }
    33745403
    3375                         // use hexets to index into b64, and append result to encoded string
    3376                         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                                                }
    33785407
    3379                 enc = tmp_arr.join('');
     5408                                                // 3-4
     5409                                                _finalMime = mime;
     5410                                                _finalCharset = charset;
     5411                                        },
    33805412
    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.
    33825416
    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.
    33855418
     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                                                }
    33865431
    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                                                }
    33945436
    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                                                }
    33965443
    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                                                }
    34065452
    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';
    34145457
    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                                                }
    34225461
    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                                                }
    34255466
    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                                        },
    34295488
    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.
    34355491
    3436                         return blob;
    3437                 }
     5492                        @method abort
     5493                                         */
     5494                                        abort: function() {
     5495                                                _error_flag = true;
     5496                                                _sync_flag = false;
    34385497
    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;
    34405501
    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                                                        }
    34445507
    3445                 if (!blob) {
    3446                         blob = {};
    3447                 } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string
    3448                         blob = { data: blob };
    3449                 }
     5508                                                        _upload_complete_flag = true;
     5509                                                } else {
     5510                                                        _p('readyState', XMLHttpRequest.UNSENT);
     5511                                                }
     5512                                        },
    34505513
    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                                                }
    34555521
    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();
    34645523
    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                                });
    34725530
    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);
    34815533
    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
    34985535
    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,
    35015539
    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                });
    35115544
    3512                         /**
    3513                         Detaches blob from any runtime that it depends on and initialize with standalone value
     5545                o.defineProperty(this, 'timeout', {
     5546                        configurable: false,
    35145547
    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                        },
    35255551
    3526                                 data = data || '';
     5552                        set: function(value) {
    35275553
    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);
    35335556                                }
    35345557
    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();
    35535560
    3554                         @method destroy
    3555                         */
    3556                         destroy: function() {
    3557                                 this.detach();
    3558                                 delete blobpool[this.uid];
     5561                                _p('timeout', value);
    35595562                        }
    35605563                });
    35615564
    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,
    35845568
    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                        },
    36015572
    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                                }
    36035578
    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                                }
    36075583
    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);
    36195586                        }
    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                });
    36355588
    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,
    36445591
    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                        }
    36505595                });
    3651         }
    36525596
    3653         File.prototype = Blob.prototype;
    3654 
    3655         return File;
    3656 });
     5597                o.defineProperty(this, 'statusText', {
     5598                        configurable: false,
    36575599
    3658 // Included from: src/javascript/file/FileDrop.js
     5600                        get: function() {
     5601                                return _p('statusText');
     5602                        }
     5603                });
    36595604
    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,
    36695607
    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                        },
    36855611
    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                                }
    36925617
    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                                }
    36955622
    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                });
    37015627
    3702                         fileDrop.init();
    3703                 </script>
     5628                o.defineProperty(this, 'responseText', {
     5629                        configurable: false,
    37045630
    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                                }
    37175636
    3718                 @event ready
    3719                 @param {Object} event
    3720                 */
    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                                }
    37225641
    3723                 /**
    3724                 Dispatched when dragging cursor enters the drop zone.
     5642                                return _p('responseText');
     5643                        }
     5644                });
    37255645
    3726                 @event dragenter
    3727                 @param {Object} event
    3728                 */
    3729                 'dragenter',
     5646                o.defineProperty(this, 'responseXML', {
     5647                        configurable: false,
    37305648
    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                                }
    37335654
    3734                 @event dragleave
    3735                 @param {Object} event
    3736                 */
    3737                 'dragleave',
     5655                                // 2-3
     5656                                if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
     5657                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     5658                                }
    37385659
    3739                 /**
    3740                 Dispatched when file is dropped onto the drop zone.
     5660                                return _p('responseXML');
     5661                        }
     5662                });
    37415663
    3742                 @event drop
    3743                 @param {Object} event
    3744                 */
    3745                 'drop',
     5664                o.defineProperty(this, 'response', {
     5665                        configurable: false,
    37465666
    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                });
    37495681
    3750                 @event error
    3751                 @param {Object} event
    37525682                */
    3753                 'error'
    3754         ];
    37555683
    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();
    37595703                }
     5704                */
    37605705
    3761                 var self = this, defaults;
    37625706
    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;
    37675709
    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();
    37935711
    3794                 RuntimeClient.call(self);
     5712                                        _xhr = new RuntimeTarget();
    37955713
    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                                        }
    37985722
    3799                         ruid: null,
     5723                                        function exec(runtime) {
     5724                                                _xhr.bind('LoadStart', function(e) {
     5725                                                        _p('readyState', XMLHttpRequest.LOADING);
     5726                                                        self.dispatchEvent('readystatechange');
    38005727
    3801                         files: null,
     5728                                                        self.dispatchEvent(e);
    38025729
    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                                                });
    38135734
    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                                                });
    38255742
    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                                                });
    38285753
    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                                                        }
    38305766
    3831         return FileDrop;
    3832 });
     5767                                                        _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders');
    38335768
    3834 // Included from: src/javascript/file/FileReader.js
     5769                                                        self.dispatchEvent('readystatechange');
    38355770
    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                                                });
    38455782
    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                                                });
    38575787
    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                                                });
    38645796
    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                                        }
    38675816
    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                                        });
    38725820
    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                                        }
    38755824
    3876                 @event progress
    3877                 @param {Object} event
    3878                 */
    3879                 'progress',
     5825                                        if (!Basic.isEmptyObj(_headers)) {
     5826                                                _options.required_caps.send_custom_headers = true;
     5827                                        }
    38805828
    3881                 /**
    3882                 Dispatched when the read has successfully completed.
     5829                                        if (!_same_origin_flag) {
     5830                                                _options.required_caps.do_cors = true;
     5831                                        }
    38835832
    3884                 @event load
    3885                 @param {Object} event
    3886                 */
    3887                 'load',
    38885833
    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                                }
    38915846
    3892                 @event abort
    3893                 @param {Object} event
    3894                 */
    3895                 'abort',
    38965847
    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                        }
    38995857
    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;
    39045863
    3905                 /**
    3906                 Dispatched when the request has completed (either in success or failure).
     5864                        XMLHttpRequest.prototype = EventTarget.instance;
    39075865
    3908                 @event loadend
    3909                 @param {Object} event
    3910                 */
    3911                 'loadend'
    3912         ];
    3913        
    3914         function FileReader() {
     5866                        return XMLHttpRequest;
     5867                });
    39155868
    3916                 RuntimeClient.call(this);
     5869// Included from: src/javascript/runtime/Transporter.js
    39175870
    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                 */
    39215880
    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) {
    39265887
    39275888                        /**
    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;
    39305895
    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);
    39395897
    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_'),
    39475900
    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,
    39555902
    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,
    39655904
    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;
    39755907
    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);
    39855911
    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                                                }
    39965916
    3997                                 this.exec('FileReader', 'abort');
    3998                                
    3999                                 this.trigger('abort');
    4000                                 this.trigger('loadend');
    4001                         },
     5917                                                _chunk_size = options.chunk_size;
    40025918
    4003                         /**
    4004                         Destroy component and release resources.
     5919                                                _reset.call(this);
     5920                                                _data = data;
     5921                                                _size = data.length;
    40055922
    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                                        },
    40155935
    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;
    40735938
    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                                                }
    40815944
    4082         /**
    4083         FileReader switches to this state when it is preloading the source
     5945                                                _reset.call(self);
     5946                                        },
    40845947
    4085         @property LOADING
    4086         @type {Number}
    4087         @final
    4088         @static
    4089         @default 1
    4090         */
    4091         FileReader.LOADING = 1;
    40925948
    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                                });
    40955956
    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                                }
    41035961
    4104         FileReader.prototype = EventTarget.instance;
     5962                                function _run(type, runtime) {
     5963                                        var self = this;
    41055964
    4106         return FileReader;
    4107 });
     5965                                        _runtime = runtime;
    41085966
    4109 // Included from: src/javascript/core/utils/Url.js
     5967                                        //self.unbind("RuntimeInit");
    41105968
    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);
    41205976
    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);
    41255983
    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                                }
    41495988
    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);
    41716000                                }
    41726001                        }
    4173                         uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
    4174                 }
    41756002
    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;
    41816006
    4182                 if (!uri.path) {
    4183                         uri.path = "/";
    4184                 }
     6007                        Transporter.prototype = EventTarget.instance;
    41856008
    4186                 delete uri.source;
     6009                        return Transporter;
     6010                });
    41876011
    4188                 return uri;
    4189         };
     6012// Included from: src/javascript/image/Image.js
    41906013
    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                 */
    41936023
    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.
    42066041
    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',
    42096048
    4210         /**
    4211         Check if specified url has the same origin as the current document
     6049                                /**
     6050                Dispatched when loading is complete.
    42126051
    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',
    42286056
    4229         return {
    4230                 parseUrl: parseUrl,
    4231                 resolveUrl: resolveUrl,
    4232                 hasSameOrigin: hasSameOrigin
    4233         };
    4234 });
     6057                                'error',
    42356058
    4236 // Included from: src/javascript/runtime/RuntimeTarget.js
     6059                                /**
     6060                Dispatched when resize operation is complete.
    42376061
    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',
    42476066
    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.
    42566070
    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                        ];
    42726076
    4273         RuntimeTarget.prototype = EventTarget.instance;
     6077                        function Image() {
    42746078
    4275         return RuntimeTarget;
    4276 });
     6079                                RuntimeClient.call(this);
    42776080
    4278 // Included from: src/javascript/file/FileReaderSync.js
     6081                                Basic.extend(this, {
     6082                                        /**
     6083                        Unique id of the component
    42796084
    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_'),
    42896089
    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.
    42996092
    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,
    43066097
    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.
    43096100
    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: "",
    43266106
    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.
    43506109
    4351 // Included from: src/javascript/xhr/FormData.js
     6110                        @property size
     6111                        @type {Number}
     6112                        @default 0
     6113                                         */
     6114                                        size: 0,
    43526115
    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.
    43626118
    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,
    43706124
    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.
    43766127
    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,
    43806133
    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.
    43966136
    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: "",
    44136142
    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.
    44166145
    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: {},
    44236151
    4424                         /**
    4425                         Retrieves blob.
     6152                                        /**
     6153                        Alias for load method, that takes another moxie.image.Image object as a source (see load).
    44266154
    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.
    44336168
    4434                         /**
    4435                         Retrieves blob field name.
     6169                        @example
     6170                                var img = new moxie.image.Image();
     6171                                img.onload = function() {
     6172                                        var blob = img.getAsBlob();
    44366173
    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);
    44436176
    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)
    44466185
    4447                         @method each
    4448                         @param {Function} cb Callback to call for each field
    4449                         */
    4450                         each: function(cb) {
    4451                                 Basic.each(_fields, function(field) {
    4452                                         cb(field.value, field.name);
    4453                                 });
    44546186
    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);
    44596236
    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                                                        }
    44666241
    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                                                        }
    44696246
    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;
    44716249
    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                                                        }
    44816255
    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);
    45546258
    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);
    45606263
    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);
    45636269
    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                                                                }
    45716337
    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);
    45736343
    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                                                        }
    45756349
    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                                        },
    45776356
    4578                 'load',
     6357                                        /**
     6358                        Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
    45796359
    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;
    45816374
    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                                                }
    45836386
    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                                        },
    45956389
    4596                                 @property timeout
    4597                                 @type Number
    4598                                 @default 0
    4599                                 */
    4600                                 timeout: 0,
     6390                                        /**
     6391                        Alias for downsize(width, height, true). (see downsize)
    46016392
    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                                        },
    46066408
    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                                        },
    46096424
    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).
    46126428
    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                                        },
    46156440
    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).
    46176444
    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).
    46236459
    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                                                        }
    46276499
    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                                                        }
    46336504
    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();
    46366511
    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);
    46426514
    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                                                                });*/
    46456533
    4646                                 @property statusText
    4647                                 @type String
    4648                                 */
    4649                                 statusText: "",
     6534                                                                                runtime = null; // release
     6535                                                                        }, 999);
    46506536
    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                                                                });
    46596540
    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                                                }
    46646550
    4665                                 @property responseXML
    4666                                 @type Document
    4667                                 */
    4668                                 responseXML: null,
     6551                                                try {
     6552                                                        if (!(el = Dom.get(el))) {
     6553                                                                throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);
     6554                                                        }
    46696555
    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                                                        }
    46746559
    4675                                 @property responseText
    4676                                 @type String
    4677                                 */
    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                                                        }
    46796564
    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();
    46896566
    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                                                        });
    47196570
    4720                
    4721                 Basic.extend(this, props, {
    4722                         /**
    4723                         Unique id of the component
     6571                                                        imgCopy.bind("Load", function() {
     6572                                                                this.downsize(opts);
     6573                                                        });
    47246574
    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                                                        }
    47326581
    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                                        },
    47386588
    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.
    47416592
    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                                });
    47436607
    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.
    47486608
    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);
    47506611
    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);
    47546615
    47556616
    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                                                }
    47756622
    4776                                 // 3
    4777                                 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 risk
    4783                                 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                                                }
    47866633
    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                                        }
    48016639                                }
    48026640
    4803                                 _user = user || urlp.user;
    4804                                 _password = password || urlp.pass;
    4805                                
    4806                                 // 11
    4807                                 _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                                 // 18
    4818                                 _sync_flag = !_async;
    4819                                 _send_flag = false;
    4820                                 _headers = {};
    4821                                 _reset.call(this);
    4822 
    4823                                 // 19
    4824                                 _p('readyState', XMLHttpRequest.OPENED);
    4825                                
    4826                                 // 20
    4827                                 this.dispatchEvent('readystatechange');
    4828                         },
    4829                        
    4830                         /**
    4831                         Appends an header to the list of author request headers, or if header is already
    4832                         in the list of author request headers, combines its value with value.
    48336641
    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);
    48716644
    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                                        }
    48756686                                }
    48766687
    4877                                 // 4
    4878                                 /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values
    4879                                 if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {
    4880                                         throw new x.DOMException(x.DOMException.SYNTAX_ERR);
    4881                                 }*/
    48826688
    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));
    48886693                                }
    48896694
    4890                                 // camelize
    4891                                 // 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                         },
    49026695
    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;
    49056698
    4906                         @method getAllResponseHeaders
    4907                         @return {String} reponse headers or empty string
    4908                         */
    4909                         getAllResponseHeaders: function() {
    4910                                 return _responseHeaders || '';
    4911                         },
     6699                                        self.name = blob.name || '';
    49126700
    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                                        }
    49166705
    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                                                });
    49236710
    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                                                }
    49276715
    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
    49406720                                                        }
    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));
    49456724                                        }
    49466725                                }
    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.
    49546726
    4955                         @method overrideMimeType
    4956                         @param String mime Mime type to set
    4957                         */
    4958                         overrideMimeType: function(mime) {
    4959                                 var matches, charset;
    4960                        
    4961                                 // 1
    4962                                 if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
    4963                                         throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
    4964                                 }
    49656727
    4966                                 // 2
    4967                                 mime = Basic.trim(mime.toLowerCase());
     6728                                function _loadFromUrl(url, options) {
     6729                                        var self = this, xhr;
    49686730
    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();
    49756732
    4976                                 if (!Mime.mimes[mime]) {
    4977                                         throw new x.DOMException(x.DOMException.SYNTAX_ERR);
    4978                                 }
     6733                                        xhr.open('get', url);
     6734                                        xhr.responseType = 'blob';
    49796735
    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                                        };
    49886739
    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                                        };
    49906743
    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                                        };
    50386747
    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);
    50566757                                }
    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                        }
    50736759
    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                /**
     6784Defines constructor for HTML5 runtime.
    50796785
    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                                ;
    50856803
    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                                );
    50936879
    5094                                 this.unbindAll();
     6880                                Runtime.call(this, options, (arguments[1] || type), caps);
    50956881
    5096                                 if (this.upload) {
    5097                                         this.upload.unbindAll();
    5098                                         this.upload = null;
    5099                                 }
    5100                         }
    5101                 });
    51026882
    5103                 this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons
    5104                 this.upload.handleEventProps(dispatches);
     6883                                Basic.extend(this, {
    51056884
    5106                 /* this is nice, but maybe too lengthy
     6885                                        init : function() {
     6886                                                this.trigger("Init");
     6887                                        },
    51076888
    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                                });
    51116896
    5112                         get: function() {
    5113                                 return _p('readyState');
     6897                                Basic.extend(this.getShim(), extensions);
    51146898                        }
     6899
     6900                        Runtime.addConstructor(type, Html5Runtime);
     6901
     6902                        return extensions;
    51156903                });
    51166904
    5117                 o.defineProperty(this, 'timeout', {
    5118                         configurable: false,
     6905// Included from: src/javascript/runtime/html5/file/Blob.js
    51196906
    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                 */
    51236916
    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;
    51256929
    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                                        }
    51286944                                }
    51296945
    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                                };
    51326949
    5133                                 _p('timeout', value);
     6950                                this.destroy = function() {
     6951                                        this.getRuntime().getShim().removeInstance(this.uid);
     6952                                };
    51346953                        }
    5135                 });
    51366954
    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                });
    51406957
    5141                         get: function() {
    5142                                 return _p('withCredentials');
    5143                         },
     6958// Included from: src/javascript/core/utils/Events.js
    51446959
    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                 */
    51506969
    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                 */
    51556975
    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;
    51586984                        }
    5159                 });
    5160 
    5161                 o.defineProperty(this, 'status', {
    5162                         configurable: false,
    51636985
    5164                         get: function() {
    5165                                 return _p('status');
     6986                        function stopPropagation() {
     6987                                this.cancelBubble = true;
    51666988                        }
    5167                 });
    51686989
    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).
    51716993
    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;
    51767014
    5177                 o.defineProperty(this, 'responseType', {
    5178                         configurable: false,
     7015                                                if (!evt.target) {
     7016                                                        evt.target = evt.srcElement;
     7017                                                }
    51797018
    5180                         get: function() {
    5181                                 return _p('responseType');
    5182                         },
     7019                                                evt.preventDefault = preventDefault;
     7020                                                evt.stopPropagation = stopPropagation;
    51837021
    5184                         set: function(value) {
    5185                                 // 1
    5186                                 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);
    51887026                                }
    51897027
    5190                                 // 2
    5191                                 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();
    51937031                                }
    51947032
    5195                                 // 3
    5196                                 _p('responseType', value.toLowerCase());
    5197                         }
    5198                 });
     7033                                if (!eventhash.hasOwnProperty(obj[uid])) {
     7034                                        eventhash[obj[uid]] = {};
     7035                                }
    51997036
    5200                 o.defineProperty(this, 'responseText', {
    5201                         configurable: false,
     7037                                events = eventhash[obj[uid]];
    52027038
    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] = [];
    52077041                                }
    52087042
    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                        };
    52137049
    5214                                 return _p('responseText');
    5215                         }
    5216                 });
    52177050
    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.
    52207054
    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;
    52267063
    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;
    52307070                                }
    52317071
    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                                                }
    52357080
    5236                 o.defineProperty(this, 'response', {
    5237                         configurable: false,
     7081                                                type[i].orig = null;
     7082                                                type[i].func = null;
     7083                                                type.splice(i, 1);
    52387084
    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                                                }
    52437089                                        }
    52447090                                }
    52457091
    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];
    52487095                                }
    52497096
    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]];
    52537100
    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                        };
    52557109
    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;
    52677122                                }
    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);
    53137126                                });
    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%'
    53227190                                                });
    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                                                        });
    53467216                                                }
    5347                                                 self.dispatchEvent(e);
    5348                                         } else {
    5349                                                 _error_flag = true;
    5350                                                 self.dispatchEvent('error');
    5351                                         }
    5352                                         loadEnd();
    5353                                 });
    53547217
    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;
    53687221
    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                                                                }
    53887254
    5389                         _options.required_caps = Basic.extend({}, _options.required_caps, {
    5390                                 return_response_type: self.responseType
    5391                         });
     7255                                                                if (file.webkitRelativePath) {
     7256                                                                        relativePath = '/' + file.webkitRelativePath.replace(/^\//, '');
     7257                                                                }
    53927258
    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;
    53967303
    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;
    54007313
    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                                                                }
    54057320
    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                                        },
    54297323
    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;
    54377324
    5438         return XMLHttpRequest;
    5439 });
     7325                                        disable: function(state) {
     7326                                                var I = this.getRuntime(), input;
    54407327
    5441 // Included from: src/javascript/runtime/Transporter.js
     7328                                                if ((input = Dom.get(I.uid))) {
     7329                                                        input.disabled = !!state;
     7330                                                }
     7331                                        },
    54427332
    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                                                ;
    54527340
    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                                                }
    54617344
    5462                 RuntimeClient.call(this);
     7345                                                if (browseButton) {
     7346                                                        Events.removeAllEvents(browseButton, this.uid);
     7347                                                        browseButton.style.zIndex = _browseBtnZIndex; // reset to original value
     7348                                                }
    54637349
    5464                 Basic.extend(this, {
    5465                         uid: Basic.guid('uid_'),
     7350                                                if (shimContainer) {
     7351                                                        Events.removeAllEvents(shimContainer, this.uid);
     7352                                                        shimContainer.innerHTML = '';
     7353                                                }
    54667354
    5467                         state: Transporter.IDLE,
     7355                                                shim.removeInstance(this.uid);
    54687356
    5469                         result: null,
     7357                                                _options = shimContainer = container = browseButton = shim = null;
     7358                                        }
     7359                                });
     7360                        }
    54707361
    5471                         transport: function(data, type, options) {
    5472                                 var self = this;
     7362                        return (extensions.FileInput = FileInput);
     7363                });
    54737364
    5474                                 options = Basic.extend({
    5475                                         chunk_size: 204798
    5476                                 }, options);
     7365// Included from: src/javascript/runtime/html5/file/FileDrop.js
    54777366
    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                 */
    54827376
    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;
    54847401
    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);
    54887409
    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();
    55017415
    5502                         abort: function() {
    5503                                 var self = this;
     7416                                                        _files = [];
    55047417
    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);
    55107432
    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                                });
    55137448
    55147449
    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                                        }
    55227454
    5523                 function _reset() {
    5524                         _size = _pos = 0;
    5525                         _data = this.result = null;
    5526                 }
     7455                                        var types = Basic.toArray(e.dataTransfer.types || []);
    55277456
    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                                }
    55307462
    5531                         _runtime = runtime;
    55327463
    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                                }
    55347471
    5535                         self.bind("TransportingProgress", function(e) {
    5536                                 _pos = e.loaded;
    55377472
    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 : [];
    55407479                                }
    5541                         }, 999);
    55427480
    5543                         self.bind("TransportingComplete", function() {
    5544                                 _pos = _size;
    5545                                 self.state = Transporter.DONE;
    5546                                 _data = null; // clean a bit
    5547                                 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                 }
    55547481
    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                                }
    55597489
    5560                         if (_chunk_size > bytesLeft) {
    5561                                 _chunk_size = bytesLeft;
    5562                         }
    55637490
    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                                        });
    55687505
    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                                }
    55727512
    5573         Transporter.prototype = EventTarget.instance;
    55747513
    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                                }
    55777525
    5578 // Included from: src/javascript/image/Image.js
    55797526
    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                                }
    55897542
    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.
    56077543
    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();
    56147546
    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                                        }
    56177558
    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                        }
    56227565
    5623                 'error',
     7566                        return (extensions.FileDrop = FileDrop);
     7567                });
    56247568
    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
    56327570
    56337571                /**
    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                 */
    56367580
    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) {
    56427590
    5643         function Image() {
     7591                        function FileReader() {
     7592                                var _fr, _convertToBinary = false;
    56447593
    5645                 RuntimeClient.call(this);
     7594                                Basic.extend(this, {
    56467595
    5647                 Basic.extend(this, {
    5648                         /**
    5649                         Unique id of the component
     7596                                        read: function(op, blob) {
     7597                                                var comp = this;
    56507598
    5651                         @property uid
    5652                         @type {String}
    5653                         */
    5654                         uid: Basic.guid('uid_'),
     7599                                                comp.result = '';
    56557600
    5656                         /**
    5657                         Unique id of the connected runtime, if any.
     7601                                                _fr = new window.FileReader();
    56587602
    5659                         @property ruid
    5660                         @type {String}
    5661                         */
    5662                         ruid: null,
     7603                                                _fr.addEventListener('progress', function(e) {
     7604                                                        comp.trigger(e);
     7605                                                });
    56637606
    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                                                });
    56667611
    5667                         @property name
    5668                         @type {String}
    5669                         @default ""
    5670                         */
    5671                         name: "",
     7612                                                _fr.addEventListener('error', function(e) {
     7613                                                        comp.trigger(e, _fr.error);
     7614                                                });
    56727615
    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                                                });
    56757620
    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                                        },
    56817629
    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                                        },
    56847635
    5685                         @property width
    5686                         @type {Number}
    5687                         @default 0
    5688                         */
    5689                         width: 0,
     7636                                        destroy: function() {
     7637                                                _fr = null;
     7638                                                this.getRuntime().getShim().removeInstance(this.uid);
     7639                                        }
     7640                                });
    56907641
    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                        }
    56937646
    5694                         @property height
    5695                         @type {Number}
    5696                         @default 0
    5697                         */
    5698                         height: 0,
     7647                        return (extensions.FileReader = FileReader);
     7648                });
    56997649
    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
    57027651
    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                 */
    57087661
    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 */
    57117663
    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) {
    57177679
    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                                ;
    57207685
    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) {
    57287708
    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                                                        }
    57337720
    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                                                }
    57417734
    5742                                         var xhr = new mOxie.XMLHttpRequest();
    5743                                         xhr.onload = function() {
    5744                                                 // upload complete
    5745                                         };
    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                        
    57517735
    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                                                        }
    57597741
    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                                                        });
    57627745
    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                                                        });
    57817749
    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                                                        });
    57937754
    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() {
    57987765
    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) {
    58037768
    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) {}
    58107812
    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                                                }
    58227818
    5823                         getAsCanvas: function() {
    5824                                 if (!Env.can('create_canvas')) {
    5825                                         throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
    5826                                 }
    58277819
    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                                                }
    58317826
    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                                                }
    58357835
    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                                                }
    58477853
    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                                        },
    58517856
    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                                        },
    58637866
    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();
    58677869
    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;
    58777885
    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;
    58827891
    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;
    58967897
    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);
    59197900
    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                                        },
    59247908
    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                                        },
    59317915
    5932                                                 tr.bind("TransportingComplete", function() {
    5933                                                         runtime = self.connectRuntime(this.result.ruid);
     7916                                        abort: function() {
     7917                                                if (_xhr) {
     7918                                                        _xhr.abort();
     7919                                                }
     7920                                        },
    59347921
    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                                });
    59447927
    5945                                                                 // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's
    5946                                                                 // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and
    5947                                                                 // sometimes 8 and they do not have this problem, we can comment this for now
    5948                                                                 /*tr.bind("RuntimeInit", function(e, runtime) {
    5949                                                                         tr.destroy();
    5950                                                                         runtime.destroy();
    5951                                                                         onResize.call(self); // re-feed our image data
    5952                                                                 });*/
    59537928
    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                                }
    59567949
    5957                                                         runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);
    5958                                                         img.destroy();
    5959                                                 });
    59607950
    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                                                })();
    59687963                                        }
    59697964                                }
    59707965
    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;
    59757970
    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);
    59837977                                        }
    59847978
    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                                }
    59867987
    5987                                         imgCopy.bind("Resize", function() {
    5988                                                 render.call(this, opts.type, opts.quality);
    5989                                         });
    59907988
    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                                        ;
    59947996
    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);
    60007999                                        }
    60018000
    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);
    60088002
    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                                        });
    60118019
    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;
    60188023                                }
    6019                                 this.unbindAll();
    60208024                        }
     8025
     8026                        return (extensions.XMLHttpRequest = XMLHttpRequest);
    60218027                });
    60228028
     8029// Included from: src/javascript/runtime/html5/utils/BinaryReader.js
    60238030
    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                 */
    60268040
    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) {
    60308048
    60318049
    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                                }
    60358056                        }
    60368057
    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, {
    60428059
    6043                         // update file name, only if empty
    6044                         if (this.name === '') {
    6045                                 this.name = info.name;
    6046                         }
    6047                 }
    6048                
     8060                                littleEndian: false,
    60498061
    6050                 function _load(src) {
    6051                         var srcType = Basic.typeOf(src);
    60528062
    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.");
    60778068                                        }
    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));
    60818077                                        }
    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                                },
    60958080
    60968081
    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 = '';
    61028084
     8085                                        if (idx > this.length()) {
     8086                                                throw new Error("You are trying to write outside the source boundaries.");
     8087                                        }
    61038088
    6104                 function _loadFromBlob(blob, options) {
    6105                         var self = this;
     8089                                        mv = this.littleEndian
     8090                                                ? 0
     8091                                                : -8 * (size - 1)
     8092                                        ;
    61068093
    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                                },
    61088098
    6109                         function exec(runtime) {
    6110                                 self.ruid = runtime.uid;
    6111                                 runtime.exec.call(self, 'Image', 'loadFromBlob', blob);
    6112                         }
    61138099
    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                                },
    61188103
    6119                                 // convert to object representation
    6120                                 if (options && typeof(options.required_caps) === 'string') {
    6121                                         options.required_caps = Runtime.parseCaps(options.required_caps);
    6122                                 }
    61238104
    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                                },
    61348108
    61358109
    6136                 function _loadFromUrl(url, options) {
    6137                         var self = this, xhr;
     8110                                LONG: function(idx) {
     8111                                        return this.read(idx, 4);
     8112                                },
    61388113
    6139                         xhr = new XMLHttpRequest();
    61408114
    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                                },
    61438119
    6144                         xhr.onprogress = function(e) {
    6145                                 self.trigger(e);
    6146                         };
    61478120
    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                                },
    61518124
    6152                         xhr.onerror = function(e) {
    6153                                 self.trigger(e);
    6154                         };
    61558125
    6156                         xhr.onloadend = function() {
    6157                                 xhr.destroy();
    6158                         };
     8126                                STRING: function(idx, count) {
     8127                                        return this.asArray('CHAR', idx, count).join('');
     8128                                },
    61598129
    6160                         xhr.bind('RuntimeError', function(e, err) {
    6161                                 self.trigger('RuntimeError', err);
    6162                         });
    61638130
    6164                         xhr.send(null, options);
    6165                 }
    6166         }
     8131                                asArray: function(type, idx, count) {
     8132                                        var values = [];
    61678133
    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                        });
    61718140
    6172         Image.prototype = EventTarget.instance;
    61738141
    6174         return Image;
    6175 });
     8142                        function ArrayBufferReader(data) {
     8143                                var _dv = new DataView(data);
    61768144
    6177 // Included from: src/javascript/runtime/html5/Runtime.js
     8145                                Basic.extend(this, {
    61788146
    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                                        },
    61888150
    6189 /*global File:true */
    61908151
    6191 /**
    6192 Defines constructor for HTML5 runtime.
     8152                                        writeByteAt: function(idx, value) {
     8153                                                _dv.setUint8(idx, value);
     8154                                        },
    61938155
    6194 @class moxie/runtime/html5/Runtime
    6195 @private
    6196 */
    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 = this
    6208                 , Test = Runtime.capTest
    6209                 , True = Runtime.capTrue
    6210                 ;
    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 desktop
    6223                                         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 suggest
    6227                                         return (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '>=')) ||
    6228                                                 (Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) ||
    6229                                                 (Env.browser === 'Safari' && Env.verComp(Env.version, 7, '>='));
    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 supported
    6234                                                 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 iOS
    6251                                         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: True
    6273                         },
    6274                         arguments[2]
    6275                 );
    62768156
    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);
    62788161
     8162                                                        case 1:
     8163                                                                return data.slice(idx);
    62798164
    6280                 Basic.extend(this, {
     8165                                                        case 3:
     8166                                                                if (value === null) {
     8167                                                                        value = new ArrayBuffer();
     8168                                                                }
    62818169
    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);
    62858177
    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                                                                }
    62938183
    6294                 Basic.extend(this.getShim(), extensions);
    6295         }
     8184                                                        default: return data;
     8185                                                }
     8186                                        },
    62968187
    6297         Runtime.addConstructor(type, Html5Runtime);
    62988188
    6299         return extensions;
    6300 });
     8189                                        length: function() {
     8190                                                return data ? data.byteLength : 0;
     8191                                        },
    63018192
    6302 // Included from: src/javascript/core/utils/Events.js
    63038193
    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                        }
    63138199
    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 funcs
    6320         function preventDefault() {
    6321                 this.returnValue = false;
    6322         }
    63238200
    6324         function stopPropagation() {
    6325                 this.cancelBubble = true;
    6326         }
     8201                        function UTF16StringReader(data) {
     8202                                Basic.extend(this, {
    63278203
    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                                        },
    63448226
    6345                 // Add event listener
    6346                 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;
    63538227
    6354                                 if (!evt.target) {
    6355                                         evt.target = evt.srcElement;
    6356                                 }
     8228                                        length: function() {
     8229                                                return data ? data.length : 0;
     8230                                        },
    63578231
    6358                                 evt.preventDefault = preventDefault;
    6359                                 evt.stopPropagation = stopPropagation;
     8232                                        clear: function() {
     8233                                                data = null;
     8234                                        }
     8235                                });
    63608236
    6361                                 callback(evt);
    6362                         };
    63638237
    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);
    64278241                                }
    64288242                        }
    6429                 }
    6430                
    6431                 // If event array got empty, remove it
    6432                 if (!type.length) {
    6433                         delete eventhash[obj[uid]][name];
    6434                 }
    6435                
    6436                 // If mOxie registry has become empty, remove it
    6437                 if (Basic.isEmptyObj(eventhash[obj[uid]])) {
    6438                         delete eventhash[obj[uid]];
    6439                        
    6440                         // IE doesn't let you remove DOM object property with - delete
    6441                         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 object
    6452        
    6453         @method removeAllEvents
    6454         @static
    6455         @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         };
    64678243
    6468         return {
    6469                 addEvent: addEvent,
    6470                 removeEvent: removeEvent,
    6471                 removeAllEvents: removeAllEvents
    6472         };
    6473 });
    64748244
    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
    64768249
    6477 /**
    6478  * FileInput.js
    6479  *
    6480  * Copyright 2013, Moxiecode Systems AB
    6481  * Released under GPL License.
    6482  *
    6483  * License: http://www.plupload.com/license
    6484  * Contributing: http://www.plupload.com/contributing
    6485  */
     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                */
    64868259
    6487 /**
    6488 @class moxie/runtime/html5/file/FileInput
     8260                /**
     8261@class moxie/runtime/html5/image/JPEGHeaders
    64898262@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                                }
    65308279
     8280                                idx = 2;
    65318281
    6532                                 browseButton = Dom.get(_options.browse_button);
     8282                                while (idx <= _br.length()) {
     8283                                        marker = _br.SHORT(idx);
    65338284
    6534                                 // Route click event to the input[type=file] element for browsers that support such behavior
    6535                                 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;
    65388289                                        }
    65398290
    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                                        }
    65418295
    6542                                         browseButton.style.zIndex = zIndex;
    6543                                         shimContainer.style.zIndex = zIndex - 1;
     8296                                        length = _br.SHORT(idx + 2) + 2;
    65448297
    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                                        }
    65538308
    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                                }
    65578311
    6558                                 Events.addEvent(top, 'mouseover', function() {
    6559                                         comp.trigger('mouseenter');
    6560                                 }, comp.uid);
     8312                                _br.clear();
    65618313
    6562                                 Events.addEvent(top, 'mouseout', function() {
    6563                                         comp.trigger('mouseleave');
    6564                                 }, comp.uid);
     8314                                return {
     8315                                        headers: headers,
    65658316
    6566                                 Events.addEvent(top, 'mousedown', function() {
    6567                                         comp.trigger('mousedown');
    6568                                 }, comp.uid);
     8317                                        restore: function(data) {
     8318                                                var max, i, br;
    65698319
    6570                                 Events.addEvent(Dom.get(_options.container), 'mouseup', function() {
    6571                                         comp.trigger('mouseup');
    6572                                 }, comp.uid);
     8320                                                br = new BinaryReader(data);
    65738321
     8322                                                idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2;
    65748323
    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                                                }
    65778328
    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                                                }
    65808347
    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);
    65868359                                                        }
    65878360                                                }
     8361                                                return array;
     8362                                        },
     8363
     8364                                        set: function(name, segment) {
     8365                                                var array = [], i, ii, max;
    65888366
    6589                                                 if (file.webkitRelativePath) {
    6590                                                         relativePath = '/' + file.webkitRelativePath.replace(/^\//, '');
     8367                                                if (typeof(segment) === 'string') {
     8368                                                        array.push(segment);
     8369                                                } else {
     8370                                                        array = segment;
    65918371                                                }
    6592                                                
    6593                                                 file = new File(I.uid, file);
    6594                                                 file.relativePath = relativePath;
    65958372
    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                                        },
    65988384
    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 = [];
    66078387                                        }
     8388                                };
     8389                        };
     8390                });
    66088391
    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'
    66118475                                        }
    66128476                                };
    66138477
    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                                };
    66198590
    6620                                 shimContainer = null;
    6621                         },
     8591                                offsets = {
     8592                                        tiffHeader: 10
     8593                                };
    66228594
     8595                                idx = offsets.tiffHeader;
    66238596
    6624                         disable: function(state) {
    6625                                 var I = this.getRuntime(), input;
     8597                                __super__ = {
     8598                                        clear: this.clear
     8599                                };
    66268600
    6627                                 if ((input = Dom.get(I.uid))) {
    6628                                         input.disabled = !!state;
    6629                                 }
    6630                         },
     8601                                // Public functions
     8602                                Basic.extend(this, {
    66318603
    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                                        },
    66458611
    6646                                 shim.removeInstance(this.uid);
    66478612
    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                                        },
    66528620
    6653         return (extensions.FileInput = FileInput);
    6654 });
    66558621
    6656 // Included from: src/javascript/runtime/html5/file/Blob.js
     8622                                        UNDEFINED: function() {
     8623                                                return this.BYTE.apply(this, arguments);
     8624                                        },
    66578625
    6658 /**
    6659  * Blob.js
    6660  *
    6661  * Copyright 2013, Moxiecode Systems AB
    6662  * Released under GPL License.
    6663  *
    6664  * License: http://www.plupload.com/license
    6665  * Contributing: http://www.plupload.com/contributing
    6666  */
    66678626
    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                                        },
    66808630
    6681                         if (window.File.prototype.slice) {
    6682                                 try {
    6683                                         blob.slice();   // depricated version will throw WRONG_ARGUMENTS_ERR exception
    6684                                         return blob.slice(start, end);
    6685                                 } catch (e) {
    6686                                         // depricated slice method
    6687                                         return blob.slice(start, end - start);
    6688                                 }
    6689                         // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
    6690                         } 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 exception
    6694                         }
    6695                 }
    66968631
    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                                        },
    67018635
    6702         return (extensions.Blob = HTML5Blob);
    6703 });
     8636                                        ASCII: function(idx) {
     8637                                                return this.CHAR(idx);
     8638                                        },
    67048639
    6705 // Included from: src/javascript/runtime/html5/file/FileDrop.js
     8640                                        TIFF: function() {
     8641                                                return Tiff || null;
     8642                                        },
    67068643
    6707 /**
    6708  * FileDrop.js
    6709  *
    6710  * Copyright 2013, Moxiecode Systems AB
    6711  * Released under GPL License.
    6712  *
    6713  * License: http://www.plupload.com/license
    6714  * Contributing: http://www.plupload.com/contributing
    6715  */
    67168644
    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;
    67418647
    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                                                        }
    67498654
    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                                                }
    67558663
    6756                                         _files = [];
     8664                                                return Exif;
     8665                                        },
    67578666
    6758                                         // Chrome 21+ accepts folders via Drag'n'Drop
    6759                                         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);
    67728667
    6773                                 Events.addEvent(dropZone, 'dragenter', function(e) {
    6774                                         comp.trigger("dragenter");
    6775                                 }, comp.uid);
     8668                                        GPS: function() {
     8669                                                var GPS = null;
    67768670
    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                                                        }
    67818677
    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                                                }
    67878683
     8684                                                return GPS;
     8685                                        },
    67888686
    6789                 function _hasFiles(e) {
    6790                         if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover
    6791                                 return false;
    6792                         }
    67938687
    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);
    67958692
    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                                        },
    68018700
    68028701
    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; }
    68108705
    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                                        },
    68198708
    68208709
    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                                });
    68288715
    68298716
    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);
    68428720                                }
    6843                         });
    68448721
    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);
    68518724
     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                                }
    68528729
    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);
    68648732
     8733                                if ('ExifIFDPointer' in Tiff) {
     8734                                        offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
     8735                                        delete Tiff.ExifIFDPointer;
     8736                                }
    68658737
    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                                }
    68818742
     8743                                if (Basic.isEmptyObj(Tiff)) {
     8744                                        Tiff = null;
     8745                                }
    68828746
    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                                }
    68858752
    6886                         // keep quering recursively till no more entries
    6887                         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                         }
    68978753
    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 = {};
    69048757
    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                                        };
    69078768
    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                                        };
    69098779
    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);
    69198781
    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.
    69378783
    6938                                 comp.result = '';
     8784                                        for (i = 0; i < length; i++) {
     8785                                                values = [];
    69398786
    6940                                 _fr = new window.FileReader();
     8787                                                // Set binary reader pointer to beginning of the next tag
     8788                                                offset = IFD_offset + 2 + i*12;
    69418789
    6942                                 _fr.addEventListener('progress', function(e) {
    6943                                         comp.trigger(e);
    6944                                 });
     8790                                                tag = tags2extract[data.SHORT(offset)];
    69458791
    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                                                }
    69508795
    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];
    69548799
    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                                                }
    69598803
    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);
    69688824
    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;
    69728834                                }
    6973                         },
    69748835
    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);
    69798852
    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                                        }
    69848861
    6985         return (extensions.FileReader = FileReader);
    6986 });
     8862                                        if (!valueOffset) {
     8863                                                return false;
     8864                                        }
    69878865
    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                                        }
    69898871
    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                        }
    69998875
    7000 /*global ActiveXObject:true */
     8876                        ExifParser.prototype = BinaryReader.prototype;
    70018877
    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                 */
    70318892
    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) {
    70348904
    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;
    70378907
     8908                                _br = new BinaryReader(data);
    70388909
    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);
    70718913                                }
    70728914
     8915                                // backup headers
     8916                                _hm = new JPEGHeaders(data);
    70738917
    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) {}
    70798922
    7080                                         _xhr.addEventListener('load', function(e) {
    7081                                                 target.trigger(e);
    7082                                         });
     8923                                // get dimensions
     8924                                _info = _getDimensions.call(this);
    70838925
    7084                                         _xhr.addEventListener('error', function(e) {
    7085                                                 target.trigger(e);
    7086                                         });
     8926                                Basic.extend(this, {
     8927                                        type: 'image/jpeg',
    70878928
    7088                                         // additionally listen to progress events
    7089                                         _xhr.addEventListener('progress', function(e) {
    7090                                                 target.trigger(e);
    7091                                         });
     8929                                        size: _br.length(),
    70928930
    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,
    71238932
    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,
    71308934
    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
    71508938                                                }
    7151                                         };
    7152                                 }
    7153                                
    7154 
    7155                                 // set request headers
    7156                                 if (!Basic.isEmptyObj(meta.headers)) {
    7157                                         Basic.each(meta.headers, function(value, header) {
    7158                                                 _xhr.setRequestHeader(header, value);
    7159                                         });
    7160                                 }
    71618939
    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                                                }
    71708947
    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                                        },
    71888959
    7189                                 target.trigger('loadstart');
    7190                         },
     8960                                        stripHeaders: function(data) {
     8961                                                return _hm.strip(data);
     8962                                        },
    71918963
    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);
    71978966                                        }
    7198                                 } catch(ex) {}
    7199                                 return 0;
    7200                         },
     8967                                });
    72018968
    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                                }
    72048977
    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 available
    7214                                                                 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 response
    7222                                                         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;
    72328978
    7233                                                 case 'document':
    7234                                                         return _getDocument(_xhr);
     8979                                function _getDimensions(br) {
     8980                                        var idx = 0
     8981                                                , marker
     8982                                                , length
     8983                                        ;
    72358984
    7236                                                 default:
    7237                                                         return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
     8985                                        if (!br) {
     8986                                                br = _br;
    72388987                                        }
    7239                                 } catch(ex) {
    7240                                         return null;
    7241                                 }                               
    7242                         },
    72438988
    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;
    72549004                                }
    7255                         },
    7256 
    7257                         destroy: function() {
    7258                                 self = _filename = null;
    7259                         }
    7260                 });
    72619005
    72629006
    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                                        ;
    72839012
    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                                                }
    72959022                                        }
    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 document
    7314                         if (rXML) {
    7315                                 if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
    73169023                                        return null;
    73179024                                }
    7318                         }
    7319                         return rXML;
    7320                 }
    73219025
    73229026
    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;
    73519035                                }
    7352                         });
    7353 
    7354                         multipart += dashdash + boundary + dashdash + crlf;
    7355 
    7356                         return multipart;
    7357                 }
    7358         }
     9036                        }
    73599037
    7360         return (extensions.XMLHttpRequest = XMLHttpRequest);
    7361 });
     9038                        return JPEG;
     9039                });
    73629040
    7363 // Included from: src/javascript/runtime/html5/utils/BinaryReader.js
     9041// Included from: src/javascript/runtime/html5/image/PNG.js
    73649042
    7365 /**
    7366  * BinaryReader.js
    7367  *
    7368  * Copyright 2013, Moxiecode Systems AB
    7369  * Released under GPL License.
    7370  *
    7371  * License: http://www.plupload.com/license
    7372  * Contributing: http://www.plupload.com/contributing
    7373  */
     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                */
    73749052
    7375 /**
    7376 @class moxie/runtime/html5/utils/BinaryReader
     9053                /**
     9054@class moxie/runtime/html5/image/PNG
    73779055@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) {
    73929062
    7393         Basic.extend(BinaryReader.prototype, {
    7394                
    7395                 littleEndian: false,
     9063                        function PNG(data) {
     9064                                var _br, _hm, _ep, _info;
    73969065
     9066                                _br = new BinaryReader(data);
    73979067
    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                                        ;
    74009073
    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                                }());
    74099080
    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;
    74159083
     9084                                        chunk = _getChunkAt.call(this, 8);
    74169085
    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                                }
    74199095
    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                                }
    74239103
    7424                         mv = this.littleEndian
    7425                                 ? 0
    7426                                 : -8 * (size - 1)
    7427                         ;
     9104                                _info = _getDimensions.call(this);
    74289105
    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',
    74339108
     9109                                        size: _br.length(),
    74349110
    7435                 BYTE: function(idx) {
    7436                         return this.read(idx, 1);
    7437                 },
     9111                                        width: _info.width,
    74389112
     9113                                        height: _info.height,
    74399114
    7440                 SHORT: function(idx) {
    7441                         return this.read(idx, 2);
    7442                 },
     9115                                        purge: function() {
     9116                                                _purge.call(this);
     9117                                        }
     9118                                });
    74439119
     9120                                // for PNG we can safely trigger purge automatically, as we do not keep any data for later
     9121                                _purge.call(this);
    74449122
    7445                 LONG: function(idx) {
    7446                         return this.read(idx, 4);
    7447                 },
     9123                                function _getChunkAt(idx) {
     9124                                        var length, type, start, CRC;
    74489125
     9126                                        length = _br.LONG(idx);
     9127                                        type = _br.STRING(idx += 4, 4);
     9128                                        start = idx += 4;
     9129                                        CRC = _br.LONG(idx + length);
    74499130
    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                        }
    74549139
     9140                        return PNG;
     9141                });
    74559142
    7456                 CHAR: function(idx) {
    7457                         return String.fromCharCode(this.read(idx, 1));
    7458                 },
     9143// Included from: src/javascript/runtime/html5/image/ImageInfo.js
    74599144
     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                 */
    74609154
    7461                 STRING: function(idx, count) {
    7462                         return this.asArray('CHAR', idx, count).join('');
    7463                 },
     9155                /**
     9156Optional 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
    74649162
     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                                }());
    74659188
    7466                 asArray: function(type, idx, count) {
    7467                         var values = [];
     9189                                Basic.extend(this, {
     9190                                        /**
     9191                        Image Mime Type extracted from it's depths
    74689192
    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: '',
    74759198
     9199                                        /**
     9200                        Image size in bytes
    74769201
    7477         function ArrayBufferReader(data) {
    7478                 var _dv = new DataView(data);
     9202                        @property size
     9203                        @type {Number}
     9204                        @default 0
     9205                                         */
     9206                                        size: 0,
    74799207
    7480                 Basic.extend(this, {
    7481                        
    7482                         readByteAt: function(idx) {
    7483                                 return _dv.getUint8(idx);
    7484                         },
     9208                                        /**
     9209                        Image width extracted from image source
    74859210
     9211                        @property width
     9212                        @type {Number}
     9213                        @default 0
     9214                                         */
     9215                                        width: 0,
    74869216
    7487                         writeByteAt: function(idx, value) {
    7488                                 _dv.setUint8(idx, value);
    7489                         },
    7490                        
     9217                                        /**
     9218                        Image height extracted from image source
    74919219
    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,
    74969225
    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.
    74999228
    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() {},
    75049234
    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.
    75129237
    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                                        },
    75189245
    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                                        },
    75229256
     9257                                        /**
     9258                        Dispose resources.
    75239259
    7524                         length: function() {
    7525                                 return data ? data.byteLength : 0;
    7526                         },
     9260                        @method purge
     9261                                         */
     9262                                        purge: function() {
     9263                                                data = null;
     9264                                        }
     9265                                });
    75279266
     9267                                Basic.extend(this, _img);
    75289268
    7529                         clear: function() {
    7530                                 _dv = data = null;
    7531                         }
     9269                                this.purge = function() {
     9270                                        _img.purge();
     9271                                        _img = null;
     9272                                };
     9273                        };
    75329274                });
    7533         }
    75349275
     9276// Included from: src/javascript/runtime/html5/image/ResizerCanvas.js
    75359277
    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() {
    75429292
     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;
    75439297
    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                                }
    75479302
     9303                                var tCanvas = _scale(image, ratio);
    75489304
    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;
    75599309                                }
    7560                         },
     9310                        }
    75619311
    75629312
    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);
    75669318
    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);
    75719323
     9324                                image = null; // just in case
     9325                                return canvas;
     9326                        }
    75729327
    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                        };
    75789331
     9332                });
    75799333
    7580         return BinaryReader;
    7581 });
     9334// Included from: src/javascript/runtime/html5/image/Image.js
    75829335
    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                 */
    75849345
    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
    75979348@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                                ;
    76149369
    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                                                ;
    76169375
    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                                                }
    76199379
    7620                         // omit RST (restart) markers
    7621                         if (marker >= 0xFFD0 && marker <= 0xFFD7) {
    7622                                 idx += 2;
    7623                                 continue;
    7624                         }
     9380                                                _blob = blob;
    76259381
    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                                        },
    76309395
    7631                         length = _br.SHORT(idx + 2) + 2;
     9396                                        loadFromImage: function(img, exact) {
     9397                                                this.meta = img.meta;
    76329398
    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                                                });
    76439404
    7644                         idx += length;
    7645                 }
     9405                                                _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
     9406                                        },
    76469407
    7647                 _br.clear();
     9408                                        getInfo: function() {
     9409                                                var I = this.getRuntime(), info;
    76489410
    7649                 return {
    7650                         headers: headers,
     9411                                                if (!_imgInfo && _binStr && I.can('access_image_binary')) {
     9412                                                        _imgInfo = new ImageInfo(_binStr);
     9413                                                }
    76519414
    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                                                };
    76549424
    7655                                 br = new BinaryReader(data);
     9425                                                if (_preserveHeaders) {
     9426                                                        info.meta = _imgInfo && _imgInfo.meta || this.meta || {};
    76569427
    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                                                }
    76589436
    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                                        },
    76639439
    7664                                 data = br.SEGMENT();
    7665                                 br.clear();
    7666                                 return data;
    7667                         },
    76689440
    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;
    76719445
    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);
    76759447
    7676                                 br = new BinaryReader(data);
     9448                                                _canvas = ResizerCanvas.scale(canvas, ratio);
    76779449
    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;
    76879451
    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                                                }
    76909457
    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;
    76989460
    7699                         set: function(name, segment) {
    7700                                 var array = [], i, ii, max;
     9461                                                _modified = true;
    77019462
    7702                                 if (typeof(segment) === 'string') {
    7703                                         array.push(segment);
    7704                                 } else {
    7705                                         array = segment;
    7706                                 }
     9463                                                this.trigger('Resize');
     9464                                        },
    77079465
    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                                        },
    77199489
    7720                         purge: function() {
    7721                                 this.headers = headers = [];
    7722                         }
    7723                 };
    7724         };
    7725 });
     9490                                        getAsDataURL: function(type) {
     9491                                                var quality = arguments[1] || 90;
    77269492
    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                                                }
    77289497
    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();
    77389500
    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                                        },
    77539512
    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                                                }
    77589522
    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;
    78069527
    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                                                        }
    78189532
    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();
    78299535
    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                                                        }
    78529542
    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);
    78779544
    7878                         'ExposureMode': {
    7879                                 0: 'Auto exposure',
    7880                                 1: 'Manual exposure',
    7881                                 2: 'Auto bracket'
    7882                         },
     9545                                                        if (_imgInfo) {
     9546                                                                _binStr = _imgInfo.stripHeaders(_binStr);
    78839547
    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                                                                        }
    78889556
    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                                                                }
    78959560
    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                                                }
    79019566
    7902                         'Saturation': {
    7903                                 0: 'Normal',
    7904                                 1: 'Low saturation',
    7905                                 2: 'High saturation'
    7906                         },
     9567                                                _modified = false;
    79079568
    7908                         'Sharpness': {
    7909                                 0: 'Normal',
    7910                                 1: 'Soft',
    7911                                 2: 'Hard'
    7912                         },
     9569                                                return _binStr;
     9570                                        },
    79139571
    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                                });
    79199578
    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;
    79449585                                }
    7945                         },
    79469586
    79479587
    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;
    79539598                                }
    7954                         },
    79559599
    79569600
    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                                }
    79619604
    7962                         RATIONAL: function(idx) {
    7963                                 return this.LONG(idx) / this.LONG(idx + 4)
    7964                         },
    79659605
     9606                                function _toDataUrl(str, type) {
     9607                                        return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
     9608                                }
    79669609
    7967                         SRATIONAL: function(idx) {
    7968                                 return this.SLONG(idx) / this.SLONG(idx + 4)
    7969                         },
    79709610
    7971                         ASCII: function(idx) {
    7972                                 return this.CHAR(idx);
    7973                         },
     9611                                function _preload(str) {
     9612                                        var comp = this;
    79749613
    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                                        };
    79789622
     9623                                        _img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
     9624                                }
    79799625
    7980                         EXIF: function() {
    7981                                 var Exif = null;
    79829626
    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;
    79899629
    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());
    79969642                                        }
    79979643                                }
    79989644
    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;
    80119663                                        }
    80129664
    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;
    80169712                                        }
    8017                                 }
    8018 
    8019                                 return GPS;
    8020                         },
    8021 
    80229713
    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;
    80329716                                }
    8033                                 return null;
    8034                         },
    8035 
    8036 
    8037                         setExif: function(tag, value) {
    8038                                 // Right now only setting of width/height is possible
    8039                                 if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; }
    80409717
    8041                                 return setTag.call(this, 'exif', tag, value);
    8042                         },
    80439718
     9719                                function _purge() {
     9720                                        if (_imgInfo) {
     9721                                                _imgInfo.purge();
     9722                                                _imgInfo = null;
     9723                                        }
    80449724
    8045                         clear: function() {
    8046                                 __super__.clear();
    8047                                 data = tags = tagDescs = Tiff = offsets = __super__ = null;
     9725                                        _binStr = _img = _canvas = _blob = null;
     9726                                        _modified = false;
     9727                                }
    80489728                        }
     9729
     9730                        return (extensions.Image = HTML5Image);
    80499731                });
    80509732
     9733// Included from: src/javascript/runtime/flash/Runtime.js
    80519734
    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                 */
    80569744
    8057                 // Set read order of multi-byte data
    8058                 this.littleEndian = (this.SHORT(idx) == 0x4949);
     9745                /*global ActiveXObject:true */
    80599746
    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                /**
     9748Defines constructor for Flash runtime.
    80649749
    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) {
    80679760
    8068                 if ('ExifIFDPointer' in Tiff) {
    8069                         offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
    8070                         delete Tiff.ExifIFDPointer;
    8071                 }
     9761                        var type = 'flash', extensions = {};
    80729762
    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
    80779765
    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;
    80819772
    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                        }
    80879786
    80889787
    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
    81039791
    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                        }
    81149814
    8115                         length = data.SHORT(IFD_offset);
    81169815
    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                        }
    81189827
    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');
    81219921
    8122                                 // Set binary reader pointer to beginning of the next tag
    8123                                 offset = IFD_offset + 2 + i*12;
    81249922
    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                                        }
    81269928
    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
    81299930                                }
    81309931
    8131                                 type = types[data.SHORT(offset+=2)];
    8132                                 count = data.LONG(offset+=2);
    8133                                 size = sizes[type];
    81349932
    8135                                 if (!size) {
    8136                                         throw new x.ImageError(x.ImageError.INVALID_META_ERR);
    8137                                 }
     9933                                Basic.extend(this, {
    81389934
    8139                                 offset += 4;
     9935                                        getShim: function() {
     9936                                                return Dom.get(this.uid);
     9937                                        },
    81409938
    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                                        },
    81469943
    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;
    81519946
    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();
    81599948
    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                                                });
    81679958
    8168                         return hash;
    8169                 }
     9959                                                // insert flash object
     9960                                                html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' +  options.swf_url + '" ';
    81709961
    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                                                }
    81879965
    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                                                }
    81909981
    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));
    81969986
    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                                        },
    82009993
    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
    82069997
    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))
    821010003
    8211         ExifParser.prototype = BinaryReader.prototype;
     10004                                }, extensions);
     10005                        }
    821210006
    8213         return ExifParser;
    8214 });
     10007                        Runtime.addConstructor(type, FlashRuntime);
    821510008
    8216 // Included from: src/javascript/runtime/html5/image/JPEG.js
     10009                        return extensions;
     10010                });
    821710011
    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
    822710013
    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
    823010026@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) {
    824910032
    8250                 // backup headers
    8251                 _hm = new JPEGHeaders(data);
     10033                        var FlashBlob = {
     10034                                slice: function(blob, start, end, type) {
     10035                                        var self = this.getRuntime();
    825210036
    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                                        }
    825710042
    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                                        }
    826010048
    8261                 Basic.extend(this, {
    8262                         type: 'image/jpeg',
     10049                                        blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || '');
    826310050
    8264                         size: _br.length(),
     10051                                        if (blob) {
     10052                                                blob = new Blob(self.uid, blob);
     10053                                        }
     10054                                        return blob;
     10055                                }
     10056                        };
    826510057
    8266                         width: _info && _info.width || 0,
     10058                        return (extensions.Blob = FlashBlob);
     10059                });
    826710060
    8268                         height: _info && _info.height || 0,
     10061// Included from: src/javascript/runtime/flash/file/FileInput.js
    826910062
    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                 */
    827410072
    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);
    828210101
    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                                        });
    828610106
    8287                         writeHeaders: function() {
    8288                                 if (!arguments.length) {
    8289                                         // if no arguments passed, update headers internally
    8290                                         return _hm.restore(data);
     10107                                        this.trigger('ready');
    829110108                                }
    8292                                 return _hm.restore(arguments[0]);
    8293                         },
    8294 
    8295                         stripHeaders: function(data) {
    8296                                 return _hm.strip(data);
    8297                         },
     10109                        };
    829810110
    8299                         purge: function() {
    8300                                 _purge.call(this);
    8301                         }
     10111                        return (extensions.FileInput = FileInput);
    830210112                });
    830310113
    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
    831210115
     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                 */
    831310125
    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) {
    832710134
    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;
    833410143                                }
    8335                                 length = br.SHORT(idx += 2);
    8336                                 idx += length - 2;
     10144                                return null;
    833710145                        }
    8338                         return null;
    8339                 }
    834010146
     10147                        var FileReader = {
     10148                                read: function(op, blob) {
     10149                                        var comp = this;
    834110150
    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 = '';
    835210152
    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                                        }
    836010157
     10158                                        comp.bind('Progress', function(e, data) {
     10159                                                if (data) {
     10160                                                        comp.result += _formatData(data, op);
     10161                                                }
     10162                                        }, 999);
    836110163
    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                        };
    837210167
    8373         return JPEG;
    8374 });
     10168                        return (extensions.FileReader = FileReader);
     10169                });
    837510170
    8376 // Included from: src/javascript/runtime/html5/image/PNG.js
     10171// Included from: src/javascript/runtime/flash/file/FileReaderSync.js
    837710172
    8378 /**
    8379  * PNG.js
    8380  *
    8381  * Copyright 2013, Moxiecode Systems AB
    8382  * Released under GPL License.
    8383  *
    8384  * License: http://www.plupload.com/license
    8385  * Contributing: http://www.plupload.com/contributing
    8386  */
     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                */
    838710182
    8388 /**
    8389 @class moxie/runtime/html5/image/PNG
     10183                /**
     10184@class moxie/runtime/flash/file/FileReaderSync
    839010185@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) {
    840810191
    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;
    841210200                                }
     10201                                return null;
    841310202                        }
    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 requests
    8434                         }
    8435                         _br.clear();
    8436                         data = _info = _hm = _ep = _br = null;
    8437                 }
    8438 
    8439                 _info = _getDimensions.call(this);
    844010203
    8441                 Basic.extend(this, {
    8442                         type: 'image/png',
     10204                        var FileReaderSync = {
     10205                                read: function(op, blob) {
     10206                                        var result, self = this.getRuntime();
    844310207
    8444                         size: _br.length(),
     10208                                        result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid);
     10209                                        if (!result) {
     10210                                                return null; // or throw ex
     10211                                        }
    844510212
    8446                         width: _info.width,
     10213                                        // special prefix for DataURL read mode
     10214                                        if (op === 'readAsDataURL') {
     10215                                                result = 'data:' + (blob.type || '') + ';base64,' + result;
     10216                                        }
    844710217
    8448                         height: _info.height,
     10218                                        return _formatData(result, op, blob.type);
     10219                                }
     10220                        };
    844910221
    8450                         purge: function() {
    8451                                 _purge.call(this);
    8452                         }
     10222                        return (extensions.FileReaderSync = FileReaderSync);
    845310223                });
    845410224
    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
    845710226
    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                 */
    846510236
    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                                }
    847110256                        };
    8472                 }
    8473         }
    847410257
    8475         return PNG;
    8476 });
     10258                        return (extensions.Transporter = Transporter);
     10259                });
    847710260
    8478 // Included from: src/javascript/runtime/html5/image/ImageInfo.js
     10261// Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js
    847910262
    8480 /**
    8481  * ImageInfo.js
    8482  *
    8483  * Copyright 2013, Moxiecode Systems AB
    8484  * Released under GPL License.
    8485  *
    8486  * License: http://www.plupload.com/license
    8487  * Contributing: http://www.plupload.com/contributing
    8488  */
     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                */
    848910272
    8490 /**
    8491 @class moxie/runtime/html5/image/ImageInfo
     10273                /**
     10274@class moxie/runtime/flash/xhr/XMLHttpRequest
    849210275@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) {
    850710288
    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 = {
    852610290
    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();
    853010293
    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                                        }
    853610298
    8537                         /**
    8538                         Image size in bytes
    853910299
    8540                         @property size
    8541                         @type {Number}
    8542                         @default 0
    8543                         */
    8544                         size: 0,
     10300                                        function appendBlob(name, blob) {
     10301                                                self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid);
     10302                                                data = null;
     10303                                                send();
     10304                                        }
    854510305
    8546                         /**
    8547                         Image width extracted from image source
    854810306
    8549                         @property width
    8550                         @type {Number}
    8551                         @default 0
    8552                         */
    8553                         width: 0,
     10307                                        function attachBlob(blob, cb) {
     10308                                                var tr = new Transporter();
    855410309
    8555                         /**
    8556                         Image height extracted from image source
     10310                                                tr.bind("TransportingComplete", function() {
     10311                                                        cb(this.result);
     10312                                                });
    855710313
    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                                        }
    856310318
    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                                        }
    856610325
    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                                                });
    857210336
    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                                },
    857510366
    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();
    858310369
    8584                         /**
    8585                         Strip all headers from the source.
     10370                                        blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob');
    858610371
    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);
    859410374
    8595                         /**
    8596                         Dispose resources.
     10375                                                if ('blob' === responseType) {
     10376                                                        return blob;
     10377                                                }
    859710378
    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                                },
    860410393
    8605                 Basic.extend(this, _img);
     10394                                abort: function(upload_complete_flag) {
     10395                                        var self = this.getRuntime();
    860610396
    8607                 this.purge = function() {
    8608                         _img.purge();
    8609                         _img = null;
    8610                 };
    8611         };
    8612 });
     10397                                        self.shimExec.call(this, 'XMLHttpRequest', 'abort');
    861310398
    8614 // Included from: src/javascript/runtime/html5/image/MegaPixel.js
     10399                                        this.dispatchEvent('readystatechange');
     10400                                        // this.dispatchEvent('progress');
     10401                                        this.dispatchEvent('abort');
    861510402
    8616 /**
    8617 (The MIT License)
     10403                                        //if (!upload_complete_flag) {
     10404                                        // this.dispatchEvent('uploadprogress');
     10405                                        //}
     10406                                }
     10407                        };
    861810408
    8619 Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>;
     10409                        return (extensions.XMLHttpRequest = XMLHttpRequest);
     10410                });
    862010411
    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
    864010413
    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                 */
    865110423
    8652 /**
    8653 @class moxie/runtime/html5/image/MegaPixel
     10424                /**
     10425@class moxie/runtime/flash/image/Image
    865410426@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                                        }
    865710444
    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                                },
    869410455
    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                                },
    871410460
     10461                                getInfo: function() {
     10462                                        var self = this.getRuntime()
     10463                                                , info = self.shimExec.call(this, 'Image', 'getInfo')
     10464                                        ;
    871510465
    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                                },
    874410471
    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                                },
    875010481
    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                        };
    875210494
    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                 */
    876210509
    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 */
    879210511
    8793                                 if (!I.can('access_binary')) {
    8794                                         throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
    8795                                 }
     10512                /**
     10513Defines constructor for Silverlight runtime.
    879610514
    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;
    879810531
    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;
    880710538                                                }
    8808                                                 _preload.call(comp, dataUrl);
    8809                                         });
    8810                                 }
    8811                         },
    881210539
    8813                         loadFromImage: function(img, exact) {
    8814                                 this.meta = img.meta;
     10540                                                control = null;
     10541                                        } catch (e) {
     10542                                                var plugin = navigator.plugins["Silverlight Plug-In"];
    881510543
    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;
    882110546
    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                                                        }
    882410550
    8825                         getInfo: function() {
    8826                                 var I = this.getRuntime(), info;
     10551                                                        actualVerArray = actualVer.split(".");
    882710552
    8828                                 if (!_imgInfo && _binStr && I.can('access_image_binary')) {
    8829                                         _imgInfo = new ImageInfo(_binStr);
    8830                                 }
     10553                                                        while (actualVerArray.length > 3) {
     10554                                                                actualVerArray.pop();
     10555                                                        }
    883110556
    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                                                        }
    884010560
    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(".");
    884810562
    8849                                 return info;
    8850                         },
     10563                                                        while (reqVerArray.length > 4) {
     10564                                                                reqVerArray.pop();
     10565                                                        }
    885110566
    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);
    885510572
    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;
    885910580                                }
    8860                                 return _canvas;
    8861                         },
    886210581
    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                        }
    887410584
    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                                });
    887710649
    8878                                 // if image has not been modified, return the source right away
    8879                                 if (!_modified) {
    8880                                         return _img.src;
    8881                                 }
    888210650
    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).");
    889110655                                        }
    8892                                 }
    8893                         },
    889410656
    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;
    890310658                                }
    890410659
    8905                                 if ('image/jpeg' !== type) {
    8906                                         _binStr = _toBinary(me.getAsDataURL(type, quality));
    8907                                 } else {
    8908                                         var dataUrl;
    890910660
    8910                                         // if jpeg
    8911                                         if (!quality) {
    8912                                                 quality = 90;
    8913                                         }
     10661                                Basic.extend(this, {
     10662                                        getShim: function() {
     10663                                                return Dom.get(this.uid).content.Moxie;
     10664                                        },
    891410665
    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                                        },
    892110670
    8922                                         _binStr = _toBinary(dataUrl);
     10671                                        init : function() {
     10672                                                var container;
    892310673
    8924                                         if (_imgInfo) {
    8925                                                 _binStr = _imgInfo.stripHeaders(_binStr);
     10674                                                container = this.getShimContainer();
    892610675
    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                                                                }
    893410692                                                        }
     10693                                                }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac)
     10694                                        },
    893510695
    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))
    893910703
    8940                                                 // will be re-created from fresh on next getInfo call
    8941                                                 _imgInfo.purge();
    8942                                                 _imgInfo = null;
    8943                                         }
    8944                                 }
     10704                                }, extensions);
     10705                        }
    894510706
    8946                                 _modified = false;
     10707                        Runtime.addConstructor(type, SilverlightRuntime);
    894710708
    8948                                 return _binStr;
    8949                         },
     10709                        return extensions;
     10710                });
    895010711
    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));
    895610734                });
    895710735
     10736// Included from: src/javascript/runtime/silverlight/file/FileInput.js
    895810737
    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                 */
    896510747
     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) {
    896610758
    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                        }
    897010766
    897110767
    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);
    897510772
     10773                                        if (browseButton) {
     10774                                                browseButton.setAttribute('tabindex', -1);
     10775                                                browseButton = null;
     10776                                        }
    897610777
    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);
    897910785
    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                                }
    898710796                        };
    898810797
    8989                         _img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
    8990                 }
     10798                        return (extensions.FileInput = FileInput);
     10799                });
    899110800
     10801// Included from: src/javascript/runtime/silverlight/file/FileDrop.js
    899210802
    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                 */
    899510812
    8996                         // use FileReader if it's available
    8997                         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;
    901010827
    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();
    902210829
    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);
    902410835
    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);
    902710844
    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);
    903410853
    9035                         img = _getImg();
     10854                                        return self.shimExec.call(this, 'FileDrop', 'init');
     10855                                }
     10856                        };
    903610857
    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                });
    904410860
    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
    905310862
    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                 */
    905810872
    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                });
    906210884
    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
    906710886
    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                 */
    907210896
    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                });
    908010908
    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
    908510910
    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                 */
    908710920
    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                });
    909010932
    9091                         _modified = true;
    9092                         self.trigger('Resize');
    9093                 }
     10933// Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js
    909410934
     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                 */
    909510944
    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                });
    910510958
     10959// Included from: src/javascript/runtime/silverlight/image/Image.js
    910610960
    910710961                /**
    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                 */
    913610970
    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                                        ;
    917710989
     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                                                });
    917811015
    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                                        }
    918811021
    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;
    919111027
    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                                },
    920011030
    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                });
    920911036
    921011037// Included from: src/javascript/runtime/html4/Runtime.js
    921111038
    9212 /**
    9213  * Runtime.js
    9214  *
    9215  * Copyright 2013, Moxiecode Systems AB
    9216  * Released under GPL License.
    9217  *
    9218  * License: http://www.plupload.com/license
    9219  * Contributing: http://www.plupload.com/contributing
    9220  */
     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                */
    922111048
    9222 /*global File:true */
     11049                /*global File:true */
    922311050
    9224 /**
     11051                /**
    922511052Defines constructor for HTML4 runtime.
    922611053
    922711054@class moxie/runtime/html4/Runtime
    922811055@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);
    929211144                        }
     11145
     11146                        Runtime.addConstructor(type, Html4Runtime);
     11147
     11148                        return extensions;
    929311149                });
    929411150
     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;
    929511179
    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;
    930011182
    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_');
    930811184
    9309                 Basic.extend(this.getShim(), extensions);
    9310         }
     11185                                        shimContainer = I.getShimContainer(); // we get new ref every time to avoid memory leaks in IE
    931111186
    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                                        }
    931311195
    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');
    931611202
    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                                        });
    931811211
    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(','));
    932811216
    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                                        }
    935911220
    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                                        });
    937511225
    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);
    938611228
    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                                        });
    938911237
    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                                        }
    939811243
    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;
    940411246
    9405                         input.onchange = function() { // there should be only one handler for this
    9406                                 var file;
     11247                                                if (!this.value) {
     11248                                                        return;
     11249                                                }
    940711250
    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                                                }
    941111258
    9412                                 if (this.files) { // check if browser is fresh enough
    9413                                         file = this.files[0];
     11259                                                file = new File(I.uid, file);
    941411260
    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;
    942311274                                        };
    9424                                 }
    942511275
    9426                                 file = new File(I.uid, file);
    942711276
    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;
    943111290
    9432                                 comp.files = [file];
     11291                                        shimContainer = currForm = browseButton = null;
     11292                                }
    943311293
    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;
    943911297
    9440                                 input = form = null;
    9441                         };
     11298                                                // figure out accept string
     11299                                                _options = options;
     11300                                                _mimes = Mime.extList2mimes(options.accept, I.can('filter_by_extension'));
    944211301
     11302                                                shimContainer = I.getShimContainer();
    944311303
    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;
    945511306
    9456                         _uid = uid;
     11307                                                        browseButton = Dom.get(options.browse_button);
     11308                                                        _browseBtnZIndex = Dom.getStyle(browseButton, 'z-index') || 'auto';
    945711309
    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                                                                }
    946011315
    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;
    946811318
    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                                                        }
    947011326
    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;
    947311330
    9474                                         browseButton = Dom.get(options.browse_button);
     11331                                                        Events.addEvent(top, 'mouseover', function() {
     11332                                                                comp.trigger('mouseenter');
     11333                                                        }, comp.uid);
    947511334
    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);
    948111338
    9482                                                 zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
     11339                                                        Events.addEvent(top, 'mousedown', function() {
     11340                                                                comp.trigger('mousedown');
     11341                                                        }, comp.uid);
    948311342
    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);
    948711346
    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                                                }());
    949111349
    9492                                         Events.addEvent(top, 'mouseover', function() {
    9493                                                 comp.trigger('mouseenter');
    9494                                         }, comp.uid);
     11350                                                addInput.call(this);
    949511351
    9496                                         Events.addEvent(top, 'mouseout', function() {
    9497                                                 comp.trigger('mouseleave');
    9498                                         }, comp.uid);
     11352                                                shimContainer = null;
    949911353
    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                                        },
    950311360
    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;
    950711364
    9508                                         browseButton = null;
    9509                                 }());
     11365                                                if (name == 'accept') {
     11366                                                        _mimes = value.mimes || Mime.extList2mimes(value, I.can('filter_by_extension'));
     11367                                                }
    951011368
    9511                                 addInput.call(this);
     11369                                                // update current input
     11370                                                input = Dom.get(_uid)
     11371                                                if (input) {
     11372                                                        input.setAttribute('accept', _mimes.join(','));
     11373                                                }
     11374                                        },
    951211375
    9513                                 shimContainer = null;
    951411376
    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                                        },
    952111384
     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                                                ;
    952211392
    9523                         disable: function(state) {
    9524                                 var input;
     11393                                                if (container) {
     11394                                                        Events.removeAllEvents(container, this.uid);
     11395                                                }
    952511396
    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                                                }
    953011401
    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                                                }
    954411406
    9545                                 shim.removeInstance(this.uid);
     11407                                                shim.removeInstance(this.uid);
    954611408
    9547                                 _uid = _mimes = _options = shimContainer = shim = null;
     11409                                                _uid = _mimes = _options = shimContainer = container = browseButton = shim = null;
     11410                                        }
     11411                                });
    954811412                        }
    9549                 });
    9550         }
    955111413
    9552         return (extensions.FileInput = FileInput);
    9553 });
     11414                        return (extensions.FileInput = FileInput);
     11415                });
    955411416
    955511417// Included from: src/javascript/runtime/html4/file/FileReader.js
    955611418
    9557 /**
    9558  * FileReader.js
    9559  *
    9560  * Copyright 2013, Moxiecode Systems AB
    9561  * Released under GPL License.
    9562  *
    9563  * License: http://www.plupload.com/license
    9564  * Contributing: http://www.plupload.com/contributing
    9565  */
     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                */
    956611428
    9567 /**
     11429                /**
    956811430@class moxie/runtime/html4/file/FileReader
    956911431@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                });
    957711439
    957811440// Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js
    957911441
    9580 /**
    9581  * XMLHttpRequest.js
    9582  *
    9583  * Copyright 2013, Moxiecode Systems AB
    9584  * Released under GPL License.
    9585  *
    9586  * License: http://www.plupload.com/license
    9587  * Contributing: http://www.plupload.com/contributing
    9588  */
     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                */
    958911451
    9590 /**
     11452                /**
    959111453@class moxie/runtime/html4/xhr/XMLHttpRequest
    959211454@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) {
    962111466
    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 later
    9629                                                         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;
    963011475                                        }
    9631                                 }
    9632                                 inputs = [];
    963311476
    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$/, '');
    963911478
    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 = [];
    964611495
    9647                                 // check if shim container has any other children, if - not, remove it as well
    9648                                 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                                        }
    965211501
    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                                                }
    965711508
    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.body
    9666                                         , 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                                }
    966811519
    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:&quot;&quot;" 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:&quot;&quot;" style="display:none"></iframe>';
     11533                                                        _iframe = temp.firstChild;
     11534                                                        container.appendChild(_iframe);
    967311535
    9674                                         /* _iframe.onreadystatechange = function() {
     11536                                                        /* _iframe.onreadystatechange = function() {
    967511537                                                console.info(_iframe.readyState);
    967611538                                        };*/
    967711539
    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;
    969111542
    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;
    969811545
    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                                                                        }
    970511580                                                                }
    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
    971311582                                                                cleanup.call(target, function() {
    9714                                                                         target.trigger('error');
     11583                                                                        target.trigger('load');
    971511584                                                                });
    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);
    971711596                                                        }
    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_');
    973711599
    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');
    974311605
    9744                                         I.getShimContainer().appendChild(form);
    9745                                 }
     11606                                                        I.getShimContainer().appendChild(form);
     11607                                                }
    974611608
    9747                                 // set upload target
    9748                                 form.setAttribute('target', uid + '_iframe');
     11609                                                // set upload target
     11610                                                form.setAttribute('target', uid + '_iframe');
    974911611
    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');
    975811620
    9759                                                         Basic.extend(hidden, {
    9760                                                                 type : 'hidden',
    9761                                                                 name : name,
    9762                                                                 value : value
    9763                                                         });
     11621                                                                        Basic.extend(hidden, {
     11622                                                                                type : 'hidden',
     11623                                                                                name : name,
     11624                                                                                value : value
     11625                                                                        });
    976411626
    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                                                        });
    977111635                                                }
    9772                                         });
    9773                                 }
    977411636
    9775                                 // set destination url
    9776                                 form.setAttribute("action", meta.url);
     11637                                                // set destination url
     11638                                                form.setAttribute("action", meta.url);
    977711639
    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) {
    978611660
    9787                         getResponse: function(responseType) {
    9788                                 if ('json' === responseType) {
    9789                                         // strip off <pre>..</pre> tags that might be enclosing the response
    9790                                         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;
    979511661                                                }
    9796                                         }
    9797                                 } else if ('document' === responseType) {
     11662                                                return _response;
     11663                                        },
    979811664
    9799                                 }
    9800                                 return _response;
    9801                         },
     11665                                        abort: function() {
     11666                                                var target = this;
    980211667
    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                                                }
    980511677
    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                                        },
    981511683
    9816                                 cleanup.call(this, function() {
    9817                                         // target.dispatchEvent('readystatechange');
    9818                                         target.dispatchEvent('abort');
     11684                                        destroy: function() {
     11685                                                this.getRuntime().getShim().removeInstance(this.uid);
     11686                                        }
    981911687                                });
    982011688                        }
    9821                 });
    9822         }
    982311689
    9824         return (extensions.XMLHttpRequest = XMLHttpRequest);
    9825 });
     11690                        return (extensions.XMLHttpRequest = XMLHttpRequest);
     11691                });
    982611692
    982711693// Included from: src/javascript/runtime/html4/image/Image.js
    982811694
    9829 /**
    9830  * Image.js
    9831  *
    9832  * Copyright 2013, Moxiecode Systems AB
    9833  * Released under GPL License.
    9834  *
    9835  * License: http://www.plupload.com/license
    9836  * Contributing: http://www.plupload.com/contributing
    9837  */
     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                */
    983811704
    9839 /**
     11705                /**
    984011706@class moxie/runtime/html4/image/Image
    984111707@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                });
    988911715
    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

     
    11/**
    22 * Plupload - multi-runtime File Uploader
    3  * v2.1.9
     3 * v3.1.2
    44 *
    5  * Copyright 2013, Moxiecode Systems AB
    6  * Released under GPL License.
     5 * Copyright 2018, Ephox
     6 * Released under AGPLv3 License.
    77 *
    88 * License: http://www.plupload.com/license
    99 * Contributing: http://www.plupload.com/contributing
    1010 *
    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
    2112 */
     13;(function (global, factory) {
     14        var extract = function() {
     15                var ctx = {};
     16                factory.apply(ctx, arguments);
     17                return ctx.plupload;
     18        };
    2219
    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         */
    2731
    28 /*global mOxie:true */
     32        /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
     33        /*globals $code */
    2934
    30 ;(function(window, o, undef) {
     35        (function(exports, undefined) {
     36                "use strict";
    3137
    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         }