diff options
Diffstat (limited to 'libgpl')
87 files changed, 15189 insertions, 0 deletions
diff --git a/libgpl/CHANGELOG b/libgpl/CHANGELOG new file mode 100644 index 0000000..9defcc5 --- /dev/null +++ b/libgpl/CHANGELOG @@ -0,0 +1,39 @@ +VERSION COMMENT
+----------------------------------------------------------------------------------
+1.0 - Initial release
+1.0.1 - Added log option to CalDAV client
+1.0.2 - Added date.js toolbox
+ (http://www.mattkruse.com/javascript/date)
+1.0.3 - Added sync interval property to caldav sync client
+1.0.4 - Moved ical_sync to libgpl
+1.0.5 - Include querystring.js for tasklist
+1.0.6 - Replace the big close button in jquery dialogs
+1.0.7 - 1.0.9 - Fetch reminders almost immediately after page
+ initialization and not with a delay of 1 minute
+1.0.10 - 1.0.12 - Include jquery contexmenu
+ (http://medialize.github.io/jQuery-contextMenu/demo.html)
+1.0.13 - Include date.js for sticky_notes
+1.0.14 - Larry skin improvements
+1.0.15 - Implement contextmenu for sticky_notes
+1.0.16 - Include fancybox
+1.0.17 - Re-organize folder structure
+1.0.18 - Clean up larry skin images
+1.0.19 - Include jquery timepicker
+1.0.20 - Include http_request
+1.0.21 - Make sure jqueryui plugin is loaded first of all
+1.0.22 - 1.0.23 - Include qtip
+1.0.24 - Fix javascript error in libcalendaring.js if date format
+ is undefined
+1.0.25 - Move label overwrites to libgpl
+1.0.26 - Add password.js overwrite
+1.0.27 - CalDAV: Send User-Agent header
+1.0.28 - 1.0.29 - Implement gzip decompression in ical driver
+1.0.30 - css fix: min-width for jqueryui dialogs (calendar/
+ carddav plugins)
+1.0.31 - CalDAV: Implemented digest authentication
+1.0.32 - 1.0.33 - CardDAV: Overwrite default subscribed label
+1.0.34 - Header User-Agent: MyRoundcube-SabreDAV
+1.0.35 - Move SabreDAV components to libcalendaring plugin
+1.0.36 - CalDAV: Don't use gmdate for UTC timezone conversion
+1.0.37 - CalDAV: Make cURL verify host configurable
+1.0.38 - CalDAV: Implement DELETE request
\ No newline at end of file diff --git a/libgpl/LICENSE b/libgpl/LICENSE new file mode 100644 index 0000000..56c3b5b --- /dev/null +++ b/libgpl/LICENSE @@ -0,0 +1,671 @@ +
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+ GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<http://www.gnu.org/licenses/>. diff --git a/libgpl/README b/libgpl/README new file mode 100644 index 0000000..df9059f --- /dev/null +++ b/libgpl/README @@ -0,0 +1,8 @@ +libgpl
+------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com
\ No newline at end of file diff --git a/libgpl/caldav/caldav-client.php b/libgpl/caldav/caldav-client.php new file mode 100644 index 0000000..417c42b --- /dev/null +++ b/libgpl/caldav/caldav-client.php @@ -0,0 +1,468 @@ +<?php + +/** + * CalDAV Client + * + * @version @package_version@ + * @author Daniel Morlock <daniel.morlock@awesome-it.de> + * + * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +require_once (dirname(__FILE__).'/../../libcalendaring/SabreDAV/vendor/autoload.php'); +require_once (dirname(__FILE__).'/vobject_sanitize.php'); + + +class caldav_client extends Sabre\DAV\Client +{ + const CLARK_GETCTAG = '{http://calendarserver.org/ns/}getctag'; + const CLARK_GETETAG = '{DAV:}getetag'; + const CLARK_CALDATA = '{urn:ietf:params:xml:ns:caldav}calendar-data'; + + public $base_uri; + public $path; + private $libvcal; + private $rc; + private $user_agent; + + /** + * Default constructor for CalDAV client. + * + * @param string Caldav URI to appropriate calendar. + * @param string Username for HTTP basic auth. + * @param string Password for HTTP basic auth. + * @param boolean Verify SSL cert. // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1) + */ + public function __construct($uri, $user = null, $pass = null, $verifySSL = array(true, true)) // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1) + { + $this->user_agent = 'MyRoundcube-SabreDAV/' . Sabre\DAV\Version::VERSION; + + // Include libvcalendar on demand ... + if(!class_exists("libvcalendar")) + require_once (dirname(__FILE__).'/../../libcalendaring/libvcalendar.php'); + + $this->libvcal = new libvcalendar(); + $this->rc = rcube::get_instance(); + + $tokens = parse_url($uri); + $this->base_uri = $tokens['scheme']."://".$tokens['host'].($tokens['port'] ? ":".$tokens['port'] : null); + $this->path = $tokens['path'].($tokens['query'] ? "?".$tokens['query'] : null); + $settings = array( + 'baseUri' => $this->base_uri, + 'authType' => Sabre\DAV\Client::AUTH_BASIC + ); + + if ($user) $settings['userName'] = $user; + if ($pass) $settings['password'] = $pass; + + parent::__construct($settings); + + $this->verifyPeer = $verifySSL[0]; + $this->verifyHost = $verifySSL[1]; + $this->authType = CURLAUTH_BASIC | CURLAUTH_ANY; + } + + /** + * Fetches calendar ctag. + * + * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Retrieving_calendar_information + * @return Calendar ctag or null on error. + */ + public function get_ctag() + { + try + { + $arr = $this->propFind($this->path, array(self::CLARK_GETCTAG)); + + if (isset($arr[self::CLARK_GETCTAG])) + return $arr[self::CLARK_GETCTAG]; + } + catch(Sabre\DAV\Exception $err) + { + rcube::raise_error(array( + 'code' => $err->getHTTPCode(), + 'type' => 'DAV', + 'file' => $err->getFile(), + 'line' => $err->getLine(), + 'message' => $err->getMessage() + ), true, false); + } + + return null; + } + + /** + * Fetches event etags and urls. + * + * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Finding_out_if_anything_changed + * + * @param array Optional list of relative event URL's to retrieve specific etags. If not specified, all etags of the current calendar are returned. + * @return array List of etag properties with keys: + * url: Event ical path relative to the calendar URL. + * etag: Current event etag. + */ + public function get_etags(array $event_urls = array()) + { + $etags = array(); + + try + { + $arr = $this->prop_report($this->path, array(self::CLARK_GETETAG), $event_urls); + foreach ($arr as $path => $data) + { + // Some caldav server return an empty calendar as event where etag is missing. Skip this! + if($data[self::CLARK_GETETAG]) + { + array_push($etags, array( + "url" => $path, + "etag" => str_replace('"', null, $data[self::CLARK_GETETAG]) + )); + } + } + } + catch(Sabre\DAV\Exception $err) + { + rcube::raise_error(array( + 'code' => $err->getHTTPCode(), + 'type' => 'DAV', + 'file' => $err->getFile(), + 'line' => $err->getLine(), + 'message' => $err->getMessage() + ), true, false); + } + + return $etags; + } + + /** + * Fetches calendar events. + * + * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Downloading_objects + * @param array $urls = array() Optional list of event URL's to fetch. If non is specified, all + * events from the appropriate calendar will be fetched. + * @return Array hash list that maps the events URL to the appropriate event properties. + */ + public function get_events($urls = array()) + { + $events = array(); + + try + { + $vcals = $this->prop_report($this->path, array( + self::CLARK_GETETAG, + self::CLARK_CALDATA + ), $urls); + + foreach ($vcals as $path => $response) + { + $vcal = $response[self::CLARK_CALDATA]; + $vobject_sanitize = new vobject_sanitize($vcal, array('CATEGORIES'), 'serialize'); + $vcal = $vobject_sanitize->vobject; + $vobject_sanitize = new vobject_sanitize($vcal, array('RDATE'), 'unserialize'); + $vcal = $vobject_sanitize->vobject; + foreach ($this->libvcal->import($vcal) as $event) { + $events[$path] = $event; + } + } + } + catch(Sabre\DAV\Exception $err) + { + rcube::raise_error(array( + 'code' => $err->getHTTPCode(), + 'type' => 'DAV', + 'file' => $err->getFile(), + 'line' => $err->getLine(), + 'message' => $err->getMessage() + ), true, false); + } + return $events; + } + + /** + * Does a REPORT request + * + * @param string $url + * @param array $properties List of requested properties must be specified as an array, in clark + * notation. + * @param array $event_urls If specified, a multiget report request will be initiated with the + * specified event urls. + * @param int $depth = 1 Depth should be either 0 or 1. A depth of 1 will cause a request to be + * made to the server to also return all child resources. + * @return array Hash with ics event path as key and a hash array with properties and appropriate values. + */ + public function prop_report($url, array $properties, array $event_urls = array(), $depth = 1) + { + $url = slashify($url); // iCloud + + $parent_tag = sizeof($event_urls) > 0 ? "c:calendar-multiget" : "d:propfind"; + $method = sizeof($event_urls) > 0 ? 'REPORT' : 'PROPFIND'; + + $body = '<?xml version="1.0"?>'."\n".'<'.$parent_tag.' xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">'."\n"; + + $body .= ' <d:prop>'."\n"; + foreach ($properties as $property) + { + + list($namespace, $elementName) = Sabre\DAV\XMLUtil::parseClarkNotation($property); + + if ($namespace === 'DAV:') + { + $body .= ' <d:'.$elementName.' />'."\n"; + } + else + { + $body .= ' <x:'.$elementName.' xmlns:x="'.$namespace.'"/>'."\n"; + } + } + $body .= ' </d:prop>'."\n"; + + // http://tools.ietf.org/html/rfc4791#page-90 + // http://www.bedework.org/trac/bedework/wiki/Bedework/DevDocs/Filters + /* + if($start && $end) + { + $body.= ' <c:filter>'."\n". + ' <c:comp-filter name="VCALENDAR">'."\n". + ' <c:comp-filter name="VEVENT">'."\n". + ' <c:time-range start="'.$start.'" end="'.$end.'" />'."\n". + ' </c:comp-filter>'."\n". + ' </c:comp-filter>'."\n". + ' </c:filter>' . "\n"; + } + */ + + foreach ($event_urls as $event_url) + { + $body .= '<d:href>'.$event_url.'</d:href>'."\n"; + } + + $body .= '</'.$parent_tag.'>'; + + $response = $this->request($method, $url, $body, array( + 'Depth' => $depth, + 'Content-Type' => 'application/xml', + 'User-Agent' => $this->user_agent + )); + + $result = $this->parseMultiStatus($response['body']); + + // If depth was 0, we only return the top item + if ($depth === 0) + { + reset($result); + $result = current($result); + return isset($result[200]) ? $result[200] : array(); + } + + $new_result = array(); + foreach ($result as $href => $status_list) + { + $new_result[$href] = isset($status_list[200]) ? $status_list[200] : array(); + } + + return $new_result; + } + + /** + * Updates or creates a calendar event. + * + * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Updating_a_calendar_object + * @param string Event ics path for the event. + * @param array Hash array with event properties. + * @param string Current event etag to match against server data. Pass null for new events. + * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error. + */ + public function put_event($path, $event, $etag = null) + { + try + { + $headers = array( + 'Content-Type' => 'text/calendar; charset=utf-8', + 'User-Agent' => $this->user_agent + ); + if ($etag) $headers["If-Match"] = '"'.$etag.'"'; + + // Temporarily disable error reporting since libvcal seems not checking array key properly. + // TODO: Remove this todo if we could ensure that those errors come not from incomplete event properties. + //$err_rep = error_reporting(E_ERROR); + $vcal = $this->libvcal->export(array($event)); + if (is_array($vcal)) + $vcal = array_shift($vcal); + + //error_reporting($err_rep); + $response = $this->request('PUT', $path, $vcal, $headers); + + // Following http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Creating_a_calendar_object, the + // caldav server must not always return the new etag. + + return $response["statusCode"] == 201 || // 201 (created, successfully created) + $response["statusCode"] == 204; // 204 (no content, successfully updated) + } + catch(Sabre\DAV\Exception\PreconditionFailed $err) + { + // Event tag not up to date, must be updated first ... + return -1; + } + catch(Sabre\DAV\Exception $err) + { + rcube::raise_error(array( + 'code' => $err->getHTTPCode(), + 'type' => 'DAV', + 'file' => $err->getFile(), + 'line' => $err->getLine(), + 'message' => $err->getMessage() + ), true, false); + } + return false; + } + + /** + * Removes event of given URL. + * + * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object + * @param string Event ics path for the event. + * @param string Current event etag to match against server data. Pass null to force removing the event. + * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error. + **/ + public function remove_event($path, $etag = null) + { + return $this->delete_request($path, $etag); + } + + /** + * Fires a DELETE request to a given URL. + * + * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object + * @param string Path. + * @param string Current etag to match against server data or null. + * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error. + **/ + public function delete_request($path, $etag = null) + { + try + { + $headers = array( + 'Content-Type' => 'text/calendar; charset=utf-8', + 'User-Agent' => $this->user_agent + ); + if ($etag) $headers["If-Match"] = '"'.$etag.'"'; + + $response = $this->request('DELETE', $path, null, $headers); + return $response["statusCode"] == 204; // 204 (no content, successfully deleted); + } + catch(Sabre\DAV\Exception\PreconditionFailed $err) + { + // Event tag not up to date, must be updated first ... + return -1; + } + catch(Sabre\DAV\Exception $err) + { + rcube::raise_error(array( + 'code' => $err->getHTTPCode(), + 'type' => 'DAV', + 'file' => $err->getFile(), + 'line' => $err->getLine(), + 'message' => $err->getMessage() + ), true, false); + } + return false; + } + + /** + * Make a propFind query to caldav server + * @param string $path absolute or relative URL to Resource + * @param array $props list of properties to use for the query. Properties must have clark-notation. + * @param int $depth 0 means no recurse while 1 means recurse + * @param boolean $log log exception + * @return array + */ + public function prop_find($path, $props, $depth, $log = true) + { + try { + $response = $this->propFind($path, $props, $depth); + } + catch(Sabre\DAV\Exception $err) + { + rcube::raise_error(array( + 'code' => $err->getHTTPCode(), + 'type' => 'DAV', + 'file' => $err->getFile(), + 'line' => $err->getLine(), + 'message' => $err->getMessage() + ), $log, false); + } + return $response; + } + + /** + * Add a caldendar collection + * @param string collection URL + * @parma string displayname + * @param string resource type + * @param string namespace + * @return array response + */ + public function add_collection($url, $displayname, $resourcetype, $namespace) + { + $body = '<?xml version="1.0" encoding="utf-8" ?>' . + '<D:mkcol xmlns:D="DAV:"xmlns:C="urn:ietf:params:xml:ns:' . $namespace . '">' . + ' <D:set>' . + ' <D:prop>' . + ' <D:resourcetype>' . + ' <D:collection/> ' . + ' <C:' . $resourcetype . '/>' . + ' </D:resourcetype>' . + ' <D:displayname>' . $displayname . '</D:displayname>' . + ' </D:prop>' . + ' </D:set>' . + ' </D:mkcol>'; + + try { + $response = $this->request('MKCOL', $url, $body, array( + 'Content-Type' => 'application/xml', + 'User-Agent' => $this->user_agent + )); + } + catch(Sabre\DAV\Exception $err) + { + return false; + } + return $response; + } + + /** + * Freebusy request for a given user + * @param string username + * @param path relative path to base uri + * @param integer unix timestamp + * @param integer unix timestamp + * @retrun array List of busy timeslots within the requested range + */ + public function freebusy($user, $path, $start, $end) + { + $body = '<?xml version="1.0" encoding="utf-8" ?>' . + '<C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">' . + '<C:time-range start="' . gmdate("Ymd\THis\Z", $start) . '"' . + ' end="' . gmdate("Ymd\THis\Z", $end) . '"/>' . + '</C:free-busy-query>'; + return $this->request('REPORT', $path, $body, array( + 'Content-Type' => 'application/xml', + 'Depth' => 1, + 'User-Agent' => $this->user_agent + )); + } +}; +?> diff --git a/libgpl/caldav/caldav_sync.php b/libgpl/caldav/caldav_sync.php new file mode 100644 index 0000000..0266af4 --- /dev/null +++ b/libgpl/caldav/caldav_sync.php @@ -0,0 +1,284 @@ +<?php +/** + * CalDAV sync for the Calendar plugin + * + * @version @package_version@ + * @author Daniel Morlock <daniel.morlock@awesome-it.de> + * + * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +require_once (dirname(__FILE__) . '/caldav-client.php'); + +class caldav_sync +{ + const ACTION_NONE = 1; + const ACTION_UPDATE = 2; + const ACTION_CREATE = 4; + + private $cal_id = null; + private $ctag = null; + private $user = null; + private $pass = null; + private $url = null; + private $env; + + public $sync = 0; + + /** + * Default constructor for calendar synchronization adapter. + * + * @param int Calendar id. + * @param array Hash array with caldav properties: + * url: Caldav calendar URL. + * user: Caldav http basic auth user. + * pass: Password für caldav user. + * ctag: Caldav ctag for calendar. + * @param boolean verify SSL Cert // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1) + */ + public function __construct($cal_id, $props, $verifySSL, $env) + { + $this->env = $env; + $this->cal_id = $cal_id; + + $this->url = $props["url"]; + $this->ctag = isset($props["tag"]) ? $props["tag"] : null; + $this->user = isset($props["user"]) ? $props["user"] : null; + $this->pass = isset($props["pass"]) ? $props["pass"] : null; + $this->sync = isset($props["sync"]) ? $props["sync"] : 0; + + $this->caldav = new caldav_client($this->url, $this->user, $this->pass, $verifySSL); // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1) + } + + /** + * Getter for current calendar ctag. + * @return string + */ + public function get_ctag() + { + return $this->ctag; + } + + /** + * Determines whether current calendar needs to be synced + * regarding the CalDAV ctag. + * + * @return True if the current calendar ctag differs from the CalDAV tag which + * indicates that there are changes that must be synched. Returns false + * if the calendar is up to date, no sync necesarry. + */ + public function is_synced($force = false) + { + $is_synced = $this->ctag == $this->caldav->get_ctag() && $this->ctag; + $env = $this->env; + $env::debug_log("Ctag indicates that calendar \"$this->cal_id\" ".($is_synced ? "is synced." : "needs update!")); + + return $is_synced; + } + + /** + * Synchronizes given events with caldav server and returns updates. + * + * @param array List of local events. + * @param array List of caldav properties for each event. + * @return array Tuple containing the following lists: + * + * Caldav properties for events to be created or to be updated with the keys: + * url: Event ical URL relative to calendar URL + * etag: Remote etag of the event + * local_event: The local event in case of an update. + * remote_event: The current event retrieved from caldav server. + * + * A list of event ids that are in sync. + */ + public function get_updates($events, $caldav_props) + { + $ctag = $this->caldav->get_ctag(); + + if($ctag) + { + $this->ctag = $ctag; + $etags = $this->caldav->get_etags(); + list($updates, $synced_event_ids) = $this->_get_event_updates($events, $caldav_props, $etags); + return array($this->_get_event_data($updates), $synced_event_ids); + } + else + { + $env = $this->env; + $env::debug_log("Unkown error while fetching calendar ctag for calendar \"$this->cal_id\"!"); + } + + return null; + } + + /** + * Determines sync status and requried updates for the given events using given list of etags. + * + * @param array List of local events. + * @param array List of caldav properties for each event. + * @param array List of current remote etags. + * @return array Tuple containing the following lists: + * + * Caldav properties for events to be created or to be updated with the keys: + * url: Event ical URL relative to calendar URL + * etag: Remote etag of the event + * local_event: The local event in case of an update. + * + * A list of event ids that are in sync. + */ + private function _get_event_updates($events, $caldav_props, $etags) + { + $updates = array(); + $in_sync = array(); + + foreach ($etags as $etag) + { + $url = $etag["url"]; + $etag = $etag["etag"]; + $event_found = false; + for($i = 0; $i < sizeof($events); $i ++) + { + if ($caldav_props[$i]["url"] == $url) + { + $event_found = true; + + if ($caldav_props[$i]["tag"] != $etag) + { + $env = $this->env; + $env::debug_log("Event ".$events[$i]["uid"]." needs update."); + + array_push($updates, array( + "local_event" => $events[$i], + "etag" => $etag, + "url" => $url + )); + } + else + { + array_push($in_sync, $events[$i]["id"]); + } + } + } + + if (!$event_found) + { + $env = $this->env; + $env::debug_log("Found new event ".$url); + + array_push($updates, array( + "url" => $url, + "etag" => $etag + )); + } + } + + return array($updates, $in_sync); + } + + /** + * Fetches event data and attaches it to the given update properties. + * + * @param $updates List of update properties. + * @return array List of update properties with additional key "remote_event" containing the current caldav event. + */ + private function _get_event_data($updates) + { + $urls = array(); + + foreach ($updates as $update) + { + array_push($urls, $update["url"]); + } + + $events = $this->caldav->get_events($urls); + + foreach($updates as &$update) + { + // Attach remote events to the appropriate updates. + // Note that this assumes unique event URL's! + $url = $update["url"]; + if($events[$url]) { + $update["remote_event"] = $events[$url]; + $update["remote_event"]["calendar"] = $this->cal_id; + } + } + + return $updates; + } + + /** + * Creates the given event on the caldav server. + * + * @param array Hash array with event properties. + * @return Caldav properties with created URL on success, false on error. + */ + public function create_event($event) + { + $props = array( + "url" => parse_url($this->url, PHP_URL_PATH)."/".$event["uid"].".ics", + "tag" => null + ); + + $env = $this->env; + $env::debug_log("Push new event to url ".$props["url"]); + $result = $this->caldav->put_event($props["url"], $event); + + if($result == false || $result < 0) return false; + return $props; + } + + /** + * Updates the given event on the caldav server. + * + * @param array Hash array with event properties to update. + * @param array Hash array with caldav properties "url" and "tag" for the event. + * @return True on success, false on error, -1 if the given event/etag is not up to date. + */ + public function update_event($event, $props) + { + $env = $this->env; + $env::debug_log("Updating event uid \"".$event["uid"]."\"."); + return $this->caldav->put_event($props["url"], $event, $props["tag"]); + } + + /** + * Removes the given event from the caldav server. + * + * @param array Hash array with caldav properties "url" and "tag" for the event. + * @return True on success, false on error. + */ + public function remove_event($props) + { + $env = $this->env; + $env::debug_log("Removing event url \"".$props["url"]."\"."); + return $this->caldav->remove_event($props["url"]); + } + + /** + * Freebusy request for a given user. + * + * @param string username + * @param string relative path to caldav base uri + * @param integer unix timestamp + * @param integer unix timestamp + * @retrun array List of busy timeslots within the requested range + */ + public function freebusy($user, $path, $start, $end) + { + return $this->caldav->freebusy($user, $path, $start, $end); + } +}; +?>
\ No newline at end of file diff --git a/libgpl/caldav/vobject_sanitize.php b/libgpl/caldav/vobject_sanitize.php new file mode 100644 index 0000000..9db4b41 --- /dev/null +++ b/libgpl/caldav/vobject_sanitize.php @@ -0,0 +1,110 @@ +<?php
+class vobject_sanitize
+{
+ public $vobject;
+ private $components = array('VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VTIMEZONE', 'VCARD', 'VALARM');
+ private $properties = array();
+
+ public function __construct($vobject, $properties = array(), $method = 'serialize')
+ {
+ $this->vobject = $vobject;
+ $this->properties = (array) $properties;
+ $this->_unfoald();
+ $this->_eol();
+ switch($method){
+ case 'serialize':
+ $this->_serialize();
+ break;
+ case 'unserialize':
+ $this->_unserialize();
+ break;
+ }
+ }
+
+ private function _unfoald()
+ {
+ $data = array();
+ $content = explode("\n", $this->vobject);
+ for($i = 0; $i < count($content); $i++){
+ $line = rtrim($content[$i]);
+ while(isset($content[$i + 1]) && strlen($content[$i + 1]) > 0 && ($content[$i+1]{0} == ' ' || $content[$i + 1]{0} == "\t" )){
+ $line .= rtrim(substr($content[++$i], 1));
+ }
+ $data[] = $line;
+ }
+ $this->vobject = implode(PHP_EOL, $data);
+ }
+
+ private function _eol()
+ {
+ $this->vobject = preg_replace('/\s\s+/', PHP_EOL, $this->vobject);
+ }
+
+ private function _serialize()
+ {
+ $tokens = array();
+ foreach($this->components as $component){
+ $regex = '#BEGIN:' . $component . '(?:(?!BEGIN:' . $component . ').)*?END:' . $component . '#si';
+ preg_match_all($regex, $this->vobject, $matches);
+ foreach($matches as $part){
+ foreach($part as $match){
+ $token = md5($match);
+ $tokens[$token] = $match;
+ $this->vobject = str_replace($match, '***' . $token . '***', $this->vobject);
+ }
+ }
+ foreach($tokens as $token => $content){
+ foreach($this->properties as $property){
+ $content = preg_replace('#' . PHP_EOL . $property . ':#i', PHP_EOL . 'X-ICAL-SANITIZE-' . $property . ':', $content, 1);
+ $content = preg_replace('#' . PHP_EOL . $property . ':#i', ',', $content);
+ $content = str_replace(PHP_EOL . 'X-ICAL-SANITIZE-' . $property . ':', PHP_EOL . $property . ':', $content);
+ $this->vobject = str_replace('***' . $token . '***', $content, $this->vobject);
+ }
+ }
+ }
+ }
+
+ private function _unserialize()
+ {
+ foreach($this->properties as $property){
+ preg_match_all('#' . PHP_EOL . $property . '.*:.*,.*' . PHP_EOL . '#i', $this->vobject, $matches);
+ $content = $this->vobject;
+ if(is_array($matches)){
+ foreach($matches[0] as $match){
+ $temp = explode(':', $match, 2);
+ $field = $temp[0];
+ $values = $temp[1];
+ $properties = explode(';', $field);
+ $tz = false;
+ foreach($properties as $idx => $property){
+ if(strtolower(substr($property, 0, 5)) == 'tzid='){
+ $temp = explode('=', $property, 2);
+ $tz = $temp[1];
+ unset($properties[$idx]);
+ }
+ if(strtolower(substr($property, 0, 6)) == 'value='){
+ $temp = explode('=', $property, 2);
+ $daot = $temp[1];
+ }
+ }
+ $field = implode(';', $properties);
+ $values = explode(',', $values);
+ $line = '';
+ foreach($values as $value){
+ if($tz){
+ $datetime = new DateTime($value, new DateTimeZone($tz));
+ if(strtolower($daot) == 'date-time'){
+ $ts = $datetime->format('U');
+ $value = gmdate('Ymd\THis\Z', $ts);
+ }
+ }
+ $line .= $field . ':' . $value . PHP_EOL;
+ }
+ $content = preg_replace('/\s\s+/', PHP_EOL, str_replace($match, $line, $content));
+ }
+ }
+ $this->vobject = $content;
+ }
+ }
+}
+?>
\ No newline at end of file diff --git a/libgpl/contextmenu/jquery.contextMenu.js b/libgpl/contextmenu/jquery.contextMenu.js new file mode 100644 index 0000000..103a585 --- /dev/null +++ b/libgpl/contextmenu/jquery.contextMenu.js @@ -0,0 +1,1686 @@ +/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: git-master + * + * Authors: Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://medialize.github.com/jQuery-contextMenu/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ + +(function($, undefined){ + + // TODO: - + // ARIA stuff: menuitem, menuitemcheckbox und menuitemradio + // create <menu> structure if $.support[htmlCommand || htmlMenuitem] and !opt.disableNative + +// determine html5 compatibility +$.support.htmlMenuitem = ('HTMLMenuItemElement' in window); +$.support.htmlCommand = ('HTMLCommandElement' in window); +$.support.eventSelectstart = ("onselectstart" in document.documentElement); +/* // should the need arise, test for css user-select +$.support.cssUserSelect = (function(){ + var t = false, + e = document.createElement('div'); + + $.each('Moz|Webkit|Khtml|O|ms|Icab|'.split('|'), function(i, prefix) { + var propCC = prefix + (prefix ? 'U' : 'u') + 'serSelect', + prop = (prefix ? ('-' + prefix.toLowerCase() + '-') : '') + 'user-select'; + + e.style.cssText = prop + ': text;'; + if (e.style[propCC] == 'text') { + t = true; + return false; + } + + return true; + }); + + return t; +})(); +*/ + +if (!$.ui || !$.ui.widget) { + // duck punch $.cleanData like jQueryUI does to get that remove event + // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js#L16-24 + var _cleanData = $.cleanData; + $.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); + }; +} + +var // currently active contextMenu trigger + $currentTrigger = null, + // is contextMenu initialized with at least one menu? + initialized = false, + // window handle + $win = $(window), + // number of registered menus + counter = 0, + // mapping selector to namespace + namespaces = {}, + // mapping namespace to options + menus = {}, + // custom command type handlers + types = {}, + // default values + defaults = { + // selector of contextMenu trigger + selector: null, + // where to append the menu to + appendTo: null, + // method to trigger context menu ["right", "left", "hover"] + trigger: "right", + // hide menu when mouse leaves trigger / menu elements + autoHide: false, + // ms to wait before showing a hover-triggered context menu + delay: 200, + // flag denoting if a second trigger should simply move (true) or rebuild (false) an open menu + // as long as the trigger happened on one of the trigger-element's child nodes + reposition: true, + // determine position to show menu at + determinePosition: function($menu) { + // position to the lower middle of the trigger element + if ($.ui && $.ui.position) { + // .position() is provided as a jQuery UI utility + // (...and it won't work on hidden elements) + $menu.css('display', 'block').position({ + my: "center top", + at: "center bottom", + of: this, + offset: "0 5", + collision: "fit" + }).css('display', 'none'); + } else { + // determine contextMenu position + var offset = this.offset(); + offset.top += this.outerHeight(); + offset.left += this.outerWidth() / 2 - $menu.outerWidth() / 2; + $menu.css(offset); + } + }, + // position menu + position: function(opt, x, y) { + var $this = this, + offset; + // determine contextMenu position + if (!x && !y) { + opt.determinePosition.call(this, opt.$menu); + return; + } else if (x === "maintain" && y === "maintain") { + // x and y must not be changed (after re-show on command click) + offset = opt.$menu.position(); + } else { + // x and y are given (by mouse event) + offset = {top: y, left: x}; + } + + // correct offset if viewport demands it + var bottom = $win.scrollTop() + $win.height(), + right = $win.scrollLeft() + $win.width(), + height = opt.$menu.height(), + width = opt.$menu.width(); + + if (offset.top + height > bottom) { + offset.top -= height; + } + + if (offset.left + width > right) { + offset.left -= width; + } + + opt.$menu.css(offset); + }, + // position the sub-menu + positionSubmenu: function($menu) { + if ($.ui && $.ui.position) { + // .position() is provided as a jQuery UI utility + // (...and it won't work on hidden elements) + $menu.css('display', 'block').position({ + my: "left top", + at: "right top", + of: this, + collision: "flipfit fit" + }).css('display', ''); + } else { + // determine contextMenu position + var offset = { + top: 0, + left: this.outerWidth() + }; + $menu.css(offset); + } + }, + // offset to add to zIndex + zIndex: 1, + // show hide animation settings + animation: { + duration: 50, + show: 'slideDown', + hide: 'slideUp' + }, + // events + events: { + show: $.noop, + hide: $.noop + }, + // default callback + callback: null, + // list of contextMenu items + items: {} + }, + // mouse position for hover activation + hoveract = { + timer: null, + pageX: null, + pageY: null + }, + // determine zIndex + zindex = function($t) { + var zin = 0, + $tt = $t; + + while (true) { + zin = Math.max(zin, parseInt($tt.css('z-index'), 10) || 0); + $tt = $tt.parent(); + if (!$tt || !$tt.length || "html body".indexOf($tt.prop('nodeName').toLowerCase()) > -1 ) { + break; + } + } + + return zin; + }, + // event handlers + handle = { + // abort anything + abortevent: function(e){ + e.preventDefault(); + e.stopImmediatePropagation(); + }, + + // contextmenu show dispatcher + contextmenu: function(e) { + var $this = $(this); + + // disable actual context-menu + e.preventDefault(); + e.stopImmediatePropagation(); + + // abort native-triggered events unless we're triggering on right click + if (e.data.trigger != 'right' && e.originalEvent) { + return; + } + + // abort event if menu is visible for this trigger + if ($this.hasClass('context-menu-active')) { + return; + } + + if (!$this.hasClass('context-menu-disabled')) { + // theoretically need to fire a show event at <menu> + // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus + // var evt = jQuery.Event("show", { data: data, pageX: e.pageX, pageY: e.pageY, relatedTarget: this }); + // e.data.$menu.trigger(evt); + + $currentTrigger = $this; + if (e.data.build) { + var built = e.data.build($currentTrigger, e); + // abort if build() returned false + if (built === false) { + return; + } + + // dynamically build menu on invocation + e.data = $.extend(true, {}, defaults, e.data, built || {}); + + // abort if there are no items to display + if (!e.data.items || $.isEmptyObject(e.data.items)) { + // Note: jQuery captures and ignores errors from event handlers + if (window.console) { + (console.error || console.log)("No items specified to show in contextMenu"); + } + + throw new Error('No Items specified'); + } + + // backreference for custom command type creation + e.data.$trigger = $currentTrigger; + + op.create(e.data); + } + // show menu + op.show.call($this, e.data, e.pageX, e.pageY); + } + }, + // contextMenu left-click trigger + click: function(e) { + e.preventDefault(); + e.stopImmediatePropagation(); + $(this).trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY })); + }, + // contextMenu right-click trigger + mousedown: function(e) { + // register mouse down + var $this = $(this); + + // hide any previous menus + if ($currentTrigger && $currentTrigger.length && !$currentTrigger.is($this)) { + $currentTrigger.data('contextMenu').$menu.trigger('contextmenu:hide'); + } + + // activate on right click + if (e.button == 2) { + $currentTrigger = $this.data('contextMenuActive', true); + } + }, + // contextMenu right-click trigger + mouseup: function(e) { + // show menu + var $this = $(this); + if ($this.data('contextMenuActive') && $currentTrigger && $currentTrigger.length && $currentTrigger.is($this) && !$this.hasClass('context-menu-disabled')) { + e.preventDefault(); + e.stopImmediatePropagation(); + $currentTrigger = $this; + $this.trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY })); + } + + $this.removeData('contextMenuActive'); + }, + // contextMenu hover trigger + mouseenter: function(e) { + var $this = $(this), + $related = $(e.relatedTarget), + $document = $(document); + + // abort if we're coming from a menu + if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) { + return; + } + + // abort if a menu is shown + if ($currentTrigger && $currentTrigger.length) { + return; + } + + hoveract.pageX = e.pageX; + hoveract.pageY = e.pageY; + hoveract.data = e.data; + $document.on('mousemove.contextMenuShow', handle.mousemove); + hoveract.timer = setTimeout(function() { + hoveract.timer = null; + $document.off('mousemove.contextMenuShow'); + $currentTrigger = $this; + $this.trigger($.Event("contextmenu", { data: hoveract.data, pageX: hoveract.pageX, pageY: hoveract.pageY })); + }, e.data.delay ); + }, + // contextMenu hover trigger + mousemove: function(e) { + hoveract.pageX = e.pageX; + hoveract.pageY = e.pageY; + }, + // contextMenu hover trigger + mouseleave: function(e) { + // abort if we're leaving for a menu + var $related = $(e.relatedTarget); + if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) { + return; + } + + try { + clearTimeout(hoveract.timer); + } catch(e) {} + + hoveract.timer = null; + }, + + // click on layer to hide contextMenu + layerClick: function(e) { + var $this = $(this), + root = $this.data('contextMenuRoot'), + mouseup = false, + button = e.button, + x = e.pageX, + y = e.pageY, + target, + offset, + selectors; + + e.preventDefault(); + e.stopImmediatePropagation(); + + setTimeout(function() { + var $window, hideshow, possibleTarget; + var triggerAction = ((root.trigger == 'left' && button === 0) || (root.trigger == 'right' && button === 2)); + + // find the element that would've been clicked, wasn't the layer in the way + if (document.elementFromPoint) { + root.$layer.hide(); + target = document.elementFromPoint(x - $win.scrollLeft(), y - $win.scrollTop()); + root.$layer.show(); + } + + if (root.reposition && triggerAction) { + if (document.elementFromPoint) { + if (root.$trigger.is(target) || root.$trigger.has(target).length) { + root.position.call(root.$trigger, root, x, y); + return; + } + } else { + offset = root.$trigger.offset(); + $window = $(window); + // while this looks kinda awful, it's the best way to avoid + // unnecessarily calculating any positions + offset.top += $window.scrollTop(); + if (offset.top <= e.pageY) { + offset.left += $window.scrollLeft(); + if (offset.left <= e.pageX) { + offset.bottom = offset.top + root.$trigger.outerHeight(); + if (offset.bottom >= e.pageY) { + offset.right = offset.left + root.$trigger.outerWidth(); + if (offset.right >= e.pageX) { + // reposition + root.position.call(root.$trigger, root, x, y); + return; + } + } + } + } + } + } + + if (target && triggerAction) { + root.$trigger.one('contextmenu:hidden', function() { + $(target).contextMenu({x: x, y: y}); + }); + } + + root.$menu.trigger('contextmenu:hide'); + }, 50); + }, + // key handled :hover + keyStop: function(e, opt) { + if (!opt.isInput) { + e.preventDefault(); + } + + e.stopPropagation(); + }, + key: function(e) { + var opt = $currentTrigger.data('contextMenu') || {}; + + switch (e.keyCode) { + case 9: + case 38: // up + handle.keyStop(e, opt); + // if keyCode is [38 (up)] or [9 (tab) with shift] + if (opt.isInput) { + if (e.keyCode == 9 && e.shiftKey) { + e.preventDefault(); + opt.$selected && opt.$selected.find('input, textarea, select').blur(); + opt.$menu.trigger('prevcommand'); + return; + } else if (e.keyCode == 38 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') { + // checkboxes don't capture this key + e.preventDefault(); + return; + } + } else if (e.keyCode != 9 || e.shiftKey) { + opt.$menu.trigger('prevcommand'); + return; + } + // omitting break; + + // case 9: // tab - reached through omitted break; + case 40: // down + handle.keyStop(e, opt); + if (opt.isInput) { + if (e.keyCode == 9) { + e.preventDefault(); + opt.$selected && opt.$selected.find('input, textarea, select').blur(); + opt.$menu.trigger('nextcommand'); + return; + } else if (e.keyCode == 40 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') { + // checkboxes don't capture this key + e.preventDefault(); + return; + } + } else { + opt.$menu.trigger('nextcommand'); + return; + } + break; + + case 37: // left + handle.keyStop(e, opt); + if (opt.isInput || !opt.$selected || !opt.$selected.length) { + break; + } + + if (!opt.$selected.parent().hasClass('context-menu-root')) { + var $parent = opt.$selected.parent().parent(); + opt.$selected.trigger('contextmenu:blur'); + opt.$selected = $parent; + return; + } + break; + + case 39: // right + handle.keyStop(e, opt); + if (opt.isInput || !opt.$selected || !opt.$selected.length) { + break; + } + + var itemdata = opt.$selected.data('contextMenu') || {}; + if (itemdata.$menu && opt.$selected.hasClass('context-menu-submenu')) { + opt.$selected = null; + itemdata.$selected = null; + itemdata.$menu.trigger('nextcommand'); + return; + } + break; + + case 35: // end + case 36: // home + if (opt.$selected && opt.$selected.find('input, textarea, select').length) { + return; + } else { + (opt.$selected && opt.$selected.parent() || opt.$menu) + .children(':not(.disabled, .not-selectable)')[e.keyCode == 36 ? 'first' : 'last']() + .trigger('contextmenu:focus'); + e.preventDefault(); + return; + } + break; + + case 13: // enter + handle.keyStop(e, opt); + if (opt.isInput) { + if (opt.$selected && !opt.$selected.is('textarea, select')) { + e.preventDefault(); + return; + } + break; + } + opt.$selected && opt.$selected.trigger('mouseup'); + return; + + case 32: // space + case 33: // page up + case 34: // page down + // prevent browser from scrolling down while menu is visible + handle.keyStop(e, opt); + return; + + case 27: // esc + handle.keyStop(e, opt); + opt.$menu.trigger('contextmenu:hide'); + return; + + default: // 0-9, a-z + var k = (String.fromCharCode(e.keyCode)).toUpperCase(); + if (opt.accesskeys[k]) { + // according to the specs accesskeys must be invoked immediately + opt.accesskeys[k].$node.trigger(opt.accesskeys[k].$menu + ? 'contextmenu:focus' + : 'mouseup' + ); + return; + } + break; + } + // pass event to selected item, + // stop propagation to avoid endless recursion + e.stopPropagation(); + opt.$selected && opt.$selected.trigger(e); + }, + + // select previous possible command in menu + prevItem: function(e) { + e.stopPropagation(); + var opt = $(this).data('contextMenu') || {}; + + // obtain currently selected menu + if (opt.$selected) { + var $s = opt.$selected; + opt = opt.$selected.parent().data('contextMenu') || {}; + opt.$selected = $s; + } + + var $children = opt.$menu.children(), + $prev = !opt.$selected || !opt.$selected.prev().length ? $children.last() : opt.$selected.prev(), + $round = $prev; + + // skip disabled + while ($prev.hasClass('disabled') || $prev.hasClass('not-selectable')) { + if ($prev.prev().length) { + $prev = $prev.prev(); + } else { + $prev = $children.last(); + } + if ($prev.is($round)) { + // break endless loop + return; + } + } + + // leave current + if (opt.$selected) { + handle.itemMouseleave.call(opt.$selected.get(0), e); + } + + // activate next + handle.itemMouseenter.call($prev.get(0), e); + + // focus input + var $input = $prev.find('input, textarea, select'); + if ($input.length) { + $input.focus(); + } + }, + // select next possible command in menu + nextItem: function(e) { + e.stopPropagation(); + var opt = $(this).data('contextMenu') || {}; + + // obtain currently selected menu + if (opt.$selected) { + var $s = opt.$selected; + opt = opt.$selected.parent().data('contextMenu') || {}; + opt.$selected = $s; + } + + var $children = opt.$menu.children(), + $next = !opt.$selected || !opt.$selected.next().length ? $children.first() : opt.$selected.next(), + $round = $next; + + // skip disabled + while ($next.hasClass('disabled') || $next.hasClass('not-selectable')) { + if ($next.next().length) { + $next = $next.next(); + } else { + $next = $children.first(); + } + if ($next.is($round)) { + // break endless loop + return; + } + } + + // leave current + if (opt.$selected) { + handle.itemMouseleave.call(opt.$selected.get(0), e); + } + + // activate next + handle.itemMouseenter.call($next.get(0), e); + + // focus input + var $input = $next.find('input, textarea, select'); + if ($input.length) { + $input.focus(); + } + }, + + // flag that we're inside an input so the key handler can act accordingly + focusInput: function(e) { + var $this = $(this).closest('.context-menu-item'), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + root.$selected = opt.$selected = $this; + root.isInput = opt.isInput = true; + }, + // flag that we're inside an input so the key handler can act accordingly + blurInput: function(e) { + var $this = $(this).closest('.context-menu-item'), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + root.isInput = opt.isInput = false; + }, + + // :hover on menu + menuMouseenter: function(e) { + var root = $(this).data().contextMenuRoot; + root.hovering = true; + }, + // :hover on menu + menuMouseleave: function(e) { + var root = $(this).data().contextMenuRoot; + if (root.$layer && root.$layer.is(e.relatedTarget)) { + root.hovering = false; + } + }, + + // :hover done manually so key handling is possible + itemMouseenter: function(e) { + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + root.hovering = true; + + // abort if we're re-entering + if (e && root.$layer && root.$layer.is(e.relatedTarget)) { + e.preventDefault(); + e.stopImmediatePropagation(); + } + + // make sure only one item is selected + (opt.$menu ? opt : root).$menu + .children('.hover').trigger('contextmenu:blur'); + + if ($this.hasClass('disabled') || $this.hasClass('not-selectable')) { + opt.$selected = null; + return; + } + + $this.trigger('contextmenu:focus'); + }, + // :hover done manually so key handling is possible + itemMouseleave: function(e) { + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + if (root !== opt && root.$layer && root.$layer.is(e.relatedTarget)) { + root.$selected && root.$selected.trigger('contextmenu:blur'); + e.preventDefault(); + e.stopImmediatePropagation(); + root.$selected = opt.$selected = opt.$node; + return; + } + + $this.trigger('contextmenu:blur'); + }, + // contextMenu item click + itemClick: function(e) { + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot, + key = data.contextMenuKey, + callback; + + // abort if the key is unknown or disabled or is a menu + if (!opt.items[key] || $this.is('.disabled, .context-menu-submenu, .context-menu-separator, .not-selectable')) { + return; + } + + e.preventDefault(); + e.stopImmediatePropagation(); + + if ($.isFunction(root.callbacks[key]) && Object.prototype.hasOwnProperty.call(root.callbacks, key)) { + // item-specific callback + callback = root.callbacks[key]; + } else if ($.isFunction(root.callback)) { + // default callback + callback = root.callback; + } else { + // no callback, no action + return; + } + + // hide menu if callback doesn't stop that + if (callback.call(root.$trigger, key, root) !== false) { + root.$menu.trigger('contextmenu:hide'); + } else if (root.$menu.parent().length) { + op.update.call(root.$trigger, root); + } + }, + // ignore click events on input elements + inputClick: function(e) { + e.stopImmediatePropagation(); + }, + + // hide <menu> + hideMenu: function(e, data) { + var root = $(this).data('contextMenuRoot'); + op.hide.call(root.$trigger, root, data && data.force); + }, + // focus <command> + focusItem: function(e) { + e.stopPropagation(); + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + $this.addClass('hover') + .siblings('.hover').trigger('contextmenu:blur'); + + // remember selected + opt.$selected = root.$selected = $this; + + // position sub-menu - do after show so dumb $.ui.position can keep up + if (opt.$node) { + root.positionSubmenu.call(opt.$node, opt.$menu); + } + }, + // blur <command> + blurItem: function(e) { + e.stopPropagation(); + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + $this.removeClass('hover'); + opt.$selected = null; + } + }, + // operations + op = { + show: function(opt, x, y) { + var $trigger = $(this), + offset, + css = {}; + + // hide any open menus + $('#context-menu-layer').trigger('mousedown'); + + // backreference for callbacks + opt.$trigger = $trigger; + + // show event + if (opt.events.show.call($trigger, opt) === false) { + $currentTrigger = null; + return; + } + + // create or update context menu + op.update.call($trigger, opt); + + // position menu + opt.position.call($trigger, opt, x, y); + + // make sure we're in front + if (opt.zIndex) { + css.zIndex = zindex($trigger) + opt.zIndex; + } + + // add layer + op.layer.call(opt.$menu, opt, css.zIndex); + + // adjust sub-menu zIndexes + opt.$menu.find('ul').css('zIndex', css.zIndex + 1); + + // position and show context menu + opt.$menu.css( css )[opt.animation.show](opt.animation.duration, function() { + $trigger.trigger('contextmenu:visible'); + }); + // make options available and set state + $trigger + .data('contextMenu', opt) + .addClass("context-menu-active"); + + // register key handler + $(document).off('keydown.contextMenu').on('keydown.contextMenu', handle.key); + // register autoHide handler + if (opt.autoHide) { + // mouse position handler + $(document).on('mousemove.contextMenuAutoHide', function(e) { + // need to capture the offset on mousemove, + // since the page might've been scrolled since activation + var pos = $trigger.offset(); + pos.right = pos.left + $trigger.outerWidth(); + pos.bottom = pos.top + $trigger.outerHeight(); + + if (opt.$layer && !opt.hovering && (!(e.pageX >= pos.left && e.pageX <= pos.right) || !(e.pageY >= pos.top && e.pageY <= pos.bottom))) { + // if mouse in menu... + opt.$menu.trigger('contextmenu:hide'); + } + }); + } + }, + hide: function(opt, force) { + var $trigger = $(this); + if (!opt) { + opt = $trigger.data('contextMenu') || {}; + } + + // hide event + if (!force && opt.events && opt.events.hide.call($trigger, opt) === false) { + return; + } + + // remove options and revert state + $trigger + .removeData('contextMenu') + .removeClass("context-menu-active"); + + if (opt.$layer) { + // keep layer for a bit so the contextmenu event can be aborted properly by opera + setTimeout((function($layer) { + return function(){ + $layer.remove(); + }; + })(opt.$layer), 10); + + try { + delete opt.$layer; + } catch(e) { + opt.$layer = null; + } + } + + // remove handle + $currentTrigger = null; + // remove selected + opt.$menu.find('.hover').trigger('contextmenu:blur'); + opt.$selected = null; + // unregister key and mouse handlers + //$(document).off('.contextMenuAutoHide keydown.contextMenu'); // http://bugs.jquery.com/ticket/10705 + $(document).off('.contextMenuAutoHide').off('keydown.contextMenu'); + // hide menu + opt.$menu && opt.$menu[opt.animation.hide](opt.animation.duration, function (){ + // tear down dynamically built menu after animation is completed. + if (opt.build) { + opt.$menu.remove(); + $.each(opt, function(key, value) { + switch (key) { + case 'ns': + case 'selector': + case 'build': + case 'trigger': + return true; + + default: + opt[key] = undefined; + try { + delete opt[key]; + } catch (e) {} + return true; + } + }); + } + + setTimeout(function() { + $trigger.trigger('contextmenu:hidden'); + }, 10); + }); + }, + create: function(opt, root) { + if (root === undefined) { + root = opt; + } + // create contextMenu + opt.$menu = $('<ul class="context-menu-list"></ul>').addClass(opt.className || "").data({ + 'contextMenu': opt, + 'contextMenuRoot': root + }); + + $.each(['callbacks', 'commands', 'inputs'], function(i,k){ + opt[k] = {}; + if (!root[k]) { + root[k] = {}; + } + }); + + root.accesskeys || (root.accesskeys = {}); + + // create contextMenu items + $.each(opt.items, function(key, item){ + var $t = $('<li class="context-menu-item"></li>').addClass(item.className || ""), + $label = null, + $input = null; + + // iOS needs to see a click-event bound to an element to actually + // have the TouchEvents infrastructure trigger the click event + $t.on('click', $.noop); + + item.$node = $t.data({ + 'contextMenu': opt, + 'contextMenuRoot': root, + 'contextMenuKey': key + }); + + // register accesskey + // NOTE: the accesskey attribute should be applicable to any element, but Safari5 and Chrome13 still can't do that + if (item.accesskey) { + var aks = splitAccesskey(item.accesskey); + for (var i=0, ak; ak = aks[i]; i++) { + if (!root.accesskeys[ak]) { + root.accesskeys[ak] = item; + item._name = item.name.replace(new RegExp('(' + ak + ')', 'i'), '<span class="context-menu-accesskey">$1</span>'); + break; + } + } + } + + if (typeof item == "string") { + $t.addClass('context-menu-separator not-selectable'); + } else if (item.type && types[item.type]) { + // run custom type handler + types[item.type].call($t, item, opt, root); + // register commands + $.each([opt, root], function(i,k){ + k.commands[key] = item; + if ($.isFunction(item.callback)) { + k.callbacks[key] = item.callback; + } + }); + } else { + // add label for input + if (item.type == 'html') { + $t.addClass('context-menu-html not-selectable'); + } else if (item.type) { + $label = $('<label></label>').appendTo($t); + $('<span></span>').html(item._name || item.name).appendTo($label); + $t.addClass('context-menu-input'); + opt.hasTypes = true; + $.each([opt, root], function(i,k){ + k.commands[key] = item; + k.inputs[key] = item; + }); + } else if (item.items) { + item.type = 'sub'; + } + + switch (item.type) { + case 'text': + $input = $('<input type="text" value="1" name="" value="">') + .attr('name', 'context-menu-input-' + key) + .val(item.value || "") + .appendTo($label); + break; + + case 'textarea': + $input = $('<textarea name=""></textarea>') + .attr('name', 'context-menu-input-' + key) + .val(item.value || "") + .appendTo($label); + + if (item.height) { + $input.height(item.height); + } + break; + + case 'checkbox': + $input = $('<input type="checkbox" value="1" name="" value="">') + .attr('name', 'context-menu-input-' + key) + .val(item.value || "") + .prop("checked", !!item.selected) + .prependTo($label); + break; + + case 'radio': + $input = $('<input type="radio" value="1" name="" value="">') + .attr('name', 'context-menu-input-' + item.radio) + .val(item.value || "") + .prop("checked", !!item.selected) + .prependTo($label); + break; + + case 'select': + $input = $('<select name="">') + .attr('name', 'context-menu-input-' + key) + .appendTo($label); + if (item.options) { + $.each(item.options, function(value, text) { + $('<option></option>').val(value).text(text).appendTo($input); + }); + $input.val(item.selected); + } + break; + + case 'sub': + // FIXME: shouldn't this .html() be a .text()? + $('<span></span>').html(item._name || item.name).appendTo($t); + item.appendTo = item.$node; + op.create(item, root); + $t.data('contextMenu', item).addClass('context-menu-submenu'); + item.callback = null; + break; + + case 'html': + $(item.html).appendTo($t); + break; + + default: + $.each([opt, root], function(i,k){ + k.commands[key] = item; + if ($.isFunction(item.callback)) { + k.callbacks[key] = item.callback; + } + }); + // FIXME: shouldn't this .html() be a .text()? + $('<span></span>').html(item._name || item.name || "").appendTo($t); + break; + } + + // disable key listener in <input> + if (item.type && item.type != 'sub' && item.type != 'html') { + $input + .on('focus', handle.focusInput) + .on('blur', handle.blurInput); + + if (item.events) { + $input.on(item.events, opt); + } + } + + // add icons + if (item.icon) { + $t.addClass("icon icon-" + item.icon); + } + } + + // cache contained elements + item.$input = $input; + item.$label = $label; + + // attach item to menu + $t.appendTo(opt.$menu); + + // Disable text selection + if (!opt.hasTypes && $.support.eventSelectstart) { + // browsers support user-select: none, + // IE has a special event for text-selection + // browsers supporting neither will not be preventing text-selection + $t.on('selectstart.disableTextSelect', handle.abortevent); + } + }); + // attach contextMenu to <body> (to bypass any possible overflow:hidden issues on parents of the trigger element) + if (!opt.$node) { + opt.$menu.css('display', 'none').addClass('context-menu-root'); + } + opt.$menu.appendTo(opt.appendTo || document.body); + }, + resize: function($menu, nested) { + // determine widths of submenus, as CSS won't grow them automatically + // position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100; + // kinda sucks hard... + + // determine width of absolutely positioned element + $menu.css({position: 'absolute', display: 'block'}); + // don't apply yet, because that would break nested elements' widths + // add a pixel to circumvent word-break issue in IE9 - #80 + $menu.data('width', Math.ceil($menu.width()) + 1); + // reset styles so they allow nested elements to grow/shrink naturally + $menu.css({ + position: 'static', + minWidth: '0px', + maxWidth: '100000px' + }); + // identify width of nested menus + $menu.find('> li > ul').each(function() { + op.resize($(this), true); + }); + // reset and apply changes in the end because nested + // elements' widths wouldn't be calculatable otherwise + if (!nested) { + $menu.find('ul').andSelf().css({ + position: '', + display: '', + minWidth: '', + maxWidth: '' + }).width(function() { + return $(this).data('width'); + }); + } + }, + update: function(opt, root) { + var $trigger = this; + if (root === undefined) { + root = opt; + op.resize(opt.$menu); + } + // re-check disabled for each item + opt.$menu.children().each(function(){ + var $item = $(this), + key = $item.data('contextMenuKey'), + item = opt.items[key], + disabled = ($.isFunction(item.disabled) && item.disabled.call($trigger, key, root)) || item.disabled === true; + + // dis- / enable item + $item[disabled ? 'addClass' : 'removeClass']('disabled'); + + if (item.type) { + // dis- / enable input elements + $item.find('input, select, textarea').prop('disabled', disabled); + + // update input states + switch (item.type) { + case 'text': + case 'textarea': + item.$input.val(item.value || ""); + break; + + case 'checkbox': + case 'radio': + item.$input.val(item.value || "").prop('checked', !!item.selected); + break; + + case 'select': + item.$input.val(item.selected || ""); + break; + } + } + + if (item.$menu) { + // update sub-menu + op.update.call($trigger, item, root); + } + }); + }, + layer: function(opt, zIndex) { + // add transparent layer for click area + // filter and background for Internet Explorer, Issue #23 + var $layer = opt.$layer = $('<div id="context-menu-layer" style="position:fixed; z-index:' + zIndex + '; top:0; left:0; opacity: 0; filter: alpha(opacity=0); background-color: #000;"></div>') + .css({height: $win.height(), width: $win.width(), display: 'block'}) + .data('contextMenuRoot', opt) + .insertBefore(this) + .on('contextmenu', handle.abortevent) + .on('mousedown', handle.layerClick); + + // IE6 doesn't know position:fixed; + if (!$.support.fixedPosition) { + $layer.css({ + 'position' : 'absolute', + 'height' : $(document).height() + }); + } + + return $layer; + } + }; + +// split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key +function splitAccesskey(val) { + var t = val.split(/\s+/), + keys = []; + + for (var i=0, k; k = t[i]; i++) { + k = k[0].toUpperCase(); // first character only + // theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it. + // a map to look up already used access keys would be nice + keys.push(k); + } + + return keys; +} + +// handle contextMenu triggers +$.fn.contextMenu = function(operation) { + if (operation === undefined) { + this.first().trigger('contextmenu'); + } else if (operation.x && operation.y) { + this.first().trigger($.Event("contextmenu", {pageX: operation.x, pageY: operation.y})); + } else if (operation === "hide") { + var $menu = this.data('contextMenu').$menu; + $menu && $menu.trigger('contextmenu:hide'); + } else if (operation === "destroy") { + $.contextMenu("destroy", {context: this}); + } else if ($.isPlainObject(operation)) { + operation.context = this; + $.contextMenu("create", operation); + } else if (operation) { + this.removeClass('context-menu-disabled'); + } else if (!operation) { + this.addClass('context-menu-disabled'); + } + + return this; +}; + +// manage contextMenu instances +$.contextMenu = function(operation, options) { + if (typeof operation != 'string') { + options = operation; + operation = 'create'; + } + + if (typeof options == 'string') { + options = {selector: options}; + } else if (options === undefined) { + options = {}; + } + + // merge with default options + var o = $.extend(true, {}, defaults, options || {}); + var $document = $(document); + var $context = $document; + var _hasContext = false; + + if (!o.context || !o.context.length) { + o.context = document; + } else { + // you never know what they throw at you... + $context = $(o.context).first(); + o.context = $context.get(0); + _hasContext = o.context !== document; + } + + switch (operation) { + case 'create': + // no selector no joy + if (!o.selector) { + throw new Error('No selector specified'); + } + // make sure internal classes are not bound to + if (o.selector.match(/.context-menu-(list|item|input)($|\s)/)) { + throw new Error('Cannot bind to selector "' + o.selector + '" as it contains a reserved className'); + } + if (!o.build && (!o.items || $.isEmptyObject(o.items))) { + throw new Error('No Items specified'); + } + counter ++; + o.ns = '.contextMenu' + counter; + if (!_hasContext) { + namespaces[o.selector] = o.ns; + } + menus[o.ns] = o; + + // default to right click + if (!o.trigger) { + o.trigger = 'right'; + } + + if (!initialized) { + // make sure item click is registered first + $document + .on({ + 'contextmenu:hide.contextMenu': handle.hideMenu, + 'prevcommand.contextMenu': handle.prevItem, + 'nextcommand.contextMenu': handle.nextItem, + 'contextmenu.contextMenu': handle.abortevent, + 'mouseenter.contextMenu': handle.menuMouseenter, + 'mouseleave.contextMenu': handle.menuMouseleave + }, '.context-menu-list') + .on('mouseup.contextMenu', '.context-menu-input', handle.inputClick) + .on({ + 'mouseup.contextMenu': handle.itemClick, + 'contextmenu:focus.contextMenu': handle.focusItem, + 'contextmenu:blur.contextMenu': handle.blurItem, + 'contextmenu.contextMenu': handle.abortevent, + 'mouseenter.contextMenu': handle.itemMouseenter, + 'mouseleave.contextMenu': handle.itemMouseleave + }, '.context-menu-item'); + + initialized = true; + } + + // engage native contextmenu event + $context + .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu); + + if (_hasContext) { + // add remove hook, just in case + $context.on('remove' + o.ns, function() { + $(this).contextMenu("destroy"); + }); + } + + switch (o.trigger) { + case 'hover': + $context + .on('mouseenter' + o.ns, o.selector, o, handle.mouseenter) + .on('mouseleave' + o.ns, o.selector, o, handle.mouseleave); + break; + + case 'left': + $context.on('click' + o.ns, o.selector, o, handle.click); + break; + /* + default: + // http://www.quirksmode.org/dom/events/contextmenu.html + $document + .on('mousedown' + o.ns, o.selector, o, handle.mousedown) + .on('mouseup' + o.ns, o.selector, o, handle.mouseup); + break; + */ + } + + // create menu + if (!o.build) { + op.create(o); + } + break; + + case 'destroy': + var $visibleMenu; + if (_hasContext) { + // get proper options + var context = o.context; + $.each(menus, function(ns, o) { + if (o.context !== context) { + return true; + } + + $visibleMenu = $('.context-menu-list').filter(':visible'); + if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is($(o.context).find(o.selector))) { + $visibleMenu.trigger('contextmenu:hide', {force: true}); + } + + try { + if (menus[o.ns].$menu) { + menus[o.ns].$menu.remove(); + } + + delete menus[o.ns]; + } catch(e) { + menus[o.ns] = null; + } + + $(o.context).off(o.ns); + + return true; + }); + } else if (!o.selector) { + $document.off('.contextMenu .contextMenuAutoHide'); + $.each(menus, function(ns, o) { + $(o.context).off(o.ns); + }); + + namespaces = {}; + menus = {}; + counter = 0; + initialized = false; + + $('#context-menu-layer, .context-menu-list').remove(); + } else if (namespaces[o.selector]) { + $visibleMenu = $('.context-menu-list').filter(':visible'); + if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is(o.selector)) { + $visibleMenu.trigger('contextmenu:hide', {force: true}); + } + + try { + if (menus[namespaces[o.selector]].$menu) { + menus[namespaces[o.selector]].$menu.remove(); + } + + delete menus[namespaces[o.selector]]; + } catch(e) { + menus[namespaces[o.selector]] = null; + } + + $document.off(namespaces[o.selector]); + } + break; + + case 'html5': + // if <command> or <menuitem> are not handled by the browser, + // or options was a bool true, + // initialize $.contextMenu for them + if ((!$.support.htmlCommand && !$.support.htmlMenuitem) || (typeof options == "boolean" && options)) { + $('menu[type="context"]').each(function() { + if (this.id) { + $.contextMenu({ + selector: '[contextmenu=' + this.id +']', + items: $.contextMenu.fromMenu(this) + }); + } + }).css('display', 'none'); + } + break; + + default: + throw new Error('Unknown operation "' + operation + '"'); + } + + return this; +}; + +// import values into <input> commands +$.contextMenu.setInputValues = function(opt, data) { + if (data === undefined) { + data = {}; + } + + $.each(opt.inputs, function(key, item) { + switch (item.type) { + case 'text': + case 'textarea': + item.value = data[key] || ""; + break; + + case 'checkbox': + item.selected = data[key] ? true : false; + break; + + case 'radio': + item.selected = (data[item.radio] || "") == item.value ? true : false; + break; + + case 'select': + item.selected = data[key] || ""; + break; + } + }); +}; + +// export values from <input> commands +$.contextMenu.getInputValues = function(opt, data) { + if (data === undefined) { + data = {}; + } + + $.each(opt.inputs, function(key, item) { + switch (item.type) { + case 'text': + case 'textarea': + case 'select': + data[key] = item.$input.val(); + break; + + case 'checkbox': + data[key] = item.$input.prop('checked'); + break; + + case 'radio': + if (item.$input.prop('checked')) { + data[item.radio] = item.value; + } + break; + } + }); + + return data; +}; + +// find <label for="xyz"> +function inputLabel(node) { + return (node.id && $('label[for="'+ node.id +'"]').val()) || node.name; +} + +// convert <menu> to items object +function menuChildren(items, $children, counter) { + if (!counter) { + counter = 0; + } + + $children.each(function() { + var $node = $(this), + node = this, + nodeName = this.nodeName.toLowerCase(), + label, + item; + + // extract <label><input> + if (nodeName == 'label' && $node.find('input, textarea, select').length) { + label = $node.text(); + $node = $node.children().first(); + node = $node.get(0); + nodeName = node.nodeName.toLowerCase(); + } + + /* + * <menu> accepts flow-content as children. that means <embed>, <canvas> and such are valid menu items. + * Not being the sadistic kind, $.contextMenu only accepts: + * <command>, <menuitem>, <hr>, <span>, <p> <input [text, radio, checkbox]>, <textarea>, <select> and of course <menu>. + * Everything else will be imported as an html node, which is not interfaced with contextMenu. + */ + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#concept-command + switch (nodeName) { + // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#the-menu-element + case 'menu': + item = {name: $node.attr('label'), items: {}}; + counter = menuChildren(item.items, $node.children(), counter); + break; + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-a-element-to-define-a-command + case 'a': + // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-button-element-to-define-a-command + case 'button': + item = { + name: $node.text(), + disabled: !!$node.attr('disabled'), + callback: (function(){ return function(){ $node.click(); }; })() + }; + break; + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-command-element-to-define-a-command + + case 'menuitem': + case 'command': + switch ($node.attr('type')) { + case undefined: + case 'command': + case 'menuitem': + item = { + name: $node.attr('label'), + disabled: !!$node.attr('disabled'), + callback: (function(){ return function(){ $node.click(); }; })() + }; + break; + + case 'checkbox': + item = { + type: 'checkbox', + disabled: !!$node.attr('disabled'), + name: $node.attr('label'), + selected: !!$node.attr('checked') + }; + break; + + case 'radio': + item = { + type: 'radio', + disabled: !!$node.attr('disabled'), + name: $node.attr('label'), + radio: $node.attr('radiogroup'), + value: $node.attr('id'), + selected: !!$node.attr('checked') + }; + break; + + default: + item = undefined; + } + break; + + case 'hr': + item = '-------'; + break; + + case 'input': + switch ($node.attr('type')) { + case 'text': + item = { + type: 'text', + name: label || inputLabel(node), + disabled: !!$node.attr('disabled'), + value: $node.val() + }; + break; + + case 'checkbox': + item = { + type: 'checkbox', + name: label || inputLabel(node), + disabled: !!$node.attr('disabled'), + selected: !!$node.attr('checked') + }; + break; + + case 'radio': + item = { + type: 'radio', + name: label || inputLabel(node), + disabled: !!$node.attr('disabled'), + radio: !!$node.attr('name'), + value: $node.val(), + selected: !!$node.attr('checked') + }; + break; + + default: + item = undefined; + break; + } + break; + + case 'select': + item = { + type: 'select', + name: label || inputLabel(node), + disabled: !!$node.attr('disabled'), + selected: $node.val(), + options: {} + }; + $node.children().each(function(){ + item.options[this.value] = $(this).text(); + }); + break; + + case 'textarea': + item = { + type: 'textarea', + name: label || inputLabel(node), + disabled: !!$node.attr('disabled'), + value: $node.val() + }; + break; + + case 'label': + break; + + default: + item = {type: 'html', html: $node.clone(true)}; + break; + } + + if (item) { + counter++; + items['key' + counter] = item; + } + }); + + return counter; +} + +// convert html5 menu +$.contextMenu.fromMenu = function(element) { + var $this = $(element), + items = {}; + + menuChildren(items, $this.children()); + + return items; +}; + +// make defaults accessible +$.contextMenu.defaults = defaults; +$.contextMenu.types = types; +// export internal functions - undocumented, for hacking only! +$.contextMenu.handle = handle; +$.contextMenu.op = op; +$.contextMenu.menus = menus; + +})(jQuery); diff --git a/libgpl/contextmenu/jquery.ui.position.js b/libgpl/contextmenu/jquery.ui.position.js new file mode 100644 index 0000000..08ce445 --- /dev/null +++ b/libgpl/contextmenu/jquery.ui.position.js @@ -0,0 +1,497 @@ +/*! + * jQuery UI Position v1.10.0 + * http://jqueryui.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/position/ + */ +(function( $, undefined ) { + +$.ui = $.ui || {}; + +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), + overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowX ? $.position.scrollbarWidth() : 0, + height: hasOverflowY ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ); + return { + element: withinElement, + isWindow: isWindow, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: isWindow ? withinElement.width() : withinElement.outerWidth(), + height: isWindow ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !$.support.offsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem : elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } + else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { + position.top += myOffset + atOffset + offset; + } + } + else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function () { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +}( jQuery ) ); diff --git a/libgpl/date/date.js b/libgpl/date/date.js new file mode 100644 index 0000000..984adb5 --- /dev/null +++ b/libgpl/date/date.js @@ -0,0 +1,335 @@ +// ===================================================================
+// Author: Matt Kruse <matt@mattkruse.com>
+// WWW: http://www.mattkruse.com/
+//
+// NOTICE: You may use this code for any purpose, commercial or
+// private, without any further permission from the author. You may
+// remove this notice from your final code if you wish, however it is
+// appreciated by the author if at least my web site address is kept.
+//
+// You may *NOT* re-distribute this code in any way except through its
+// use. That means, you can include it in your product, or your web
+// site, or any other form where the code is actually being used. You
+// may not put the plain javascript up on your site for download or
+// include it in your javascript libraries for download.
+// If you wish to share this code with others, please just point them
+// to the URL instead.
+// Please DO NOT link directly to my .js files from your site. Copy
+// the files to your server and use them there. Thank you.
+// ===================================================================
+
+// HISTORY
+// ------------------------------------------------------------------
+// May 17, 2003: Fixed bug in parseDate() for dates <1970
+// March 11, 2003: Added parseDate() function
+// March 11, 2003: Added "NNN" formatting option. Doesn't match up
+// perfectly with SimpleDateFormat formats, but
+// backwards-compatability was required.
+
+// ------------------------------------------------------------------
+// These functions use the same 'format' strings as the
+// java.text.SimpleDateFormat class, with minor exceptions.
+// The format string consists of the following abbreviations:
+//
+// Field | Full Form | Short Form
+// -------------+--------------------+-----------------------
+// Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
+// Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
+// | NNN (abbr.) |
+// Day of Month | dd (2 digits) | d (1 or 2 digits)
+// Day of Week | EE (name) | E (abbr)
+// Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
+// Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
+// Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
+// Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
+// Minute | mm (2 digits) | m (1 or 2 digits)
+// Second | ss (2 digits) | s (1 or 2 digits)
+// AM/PM | a |
+//
+// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
+// Examples:
+// "MMM d, y" matches: January 01, 2000
+// Dec 1, 1900
+// Nov 20, 00
+// "M/d/yy" matches: 01/20/00
+// 9/2/00
+// "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
+// ------------------------------------------------------------------
+
+var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
+var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+function LZ(x) {return(x<0||x>9?"":"0")+x}
+
+// ------------------------------------------------------------------
+// isDate ( date_string, format_string )
+// Returns true if date string matches format of format string and
+// is a valid date. Else returns false.
+// It is recommended that you trim whitespace around the value before
+// passing it to this function, as whitespace is NOT ignored!
+// ------------------------------------------------------------------
+function isDate(val,format) {
+ var date=getDateFromFormat(val,format);
+ if (date==0) { return false; }
+ return true;
+ }
+
+// -------------------------------------------------------------------
+// compareDates(date1,date1format,date2,date2format)
+// Compare two date strings to see which is greater.
+// Returns:
+// 1 if date1 is greater than date2
+// 0 if date2 is greater than date1 of if they are the same
+// -1 if either of the dates is in an invalid format
+// -------------------------------------------------------------------
+function compareDates(date1,dateformat1,date2,dateformat2) {
+ var d1=getDateFromFormat(date1,dateformat1);
+ var d2=getDateFromFormat(date2,dateformat2);
+ if (d1==0 || d2==0) {
+ return -1;
+ }
+ else if (d1 > d2) {
+ return 1;
+ }
+ return 0;
+ }
+
+// ------------------------------------------------------------------
+// formatDate (date_object, format)
+// Returns a date in the output format specified.
+// The format string uses the same abbreviations as in getDateFromFormat()
+// ------------------------------------------------------------------
+function formatDate(date,format) {
+ format=format+"";
+ var result="";
+ var i_format=0;
+ var c="";
+ var token="";
+ var y=date.getYear()+"";
+ var M=date.getMonth()+1;
+ var d=date.getDate();
+ var E=date.getDay();
+ var H=date.getHours();
+ var m=date.getMinutes();
+ var s=date.getSeconds();
+ var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
+ // Convert real date parts into formatted versions
+ var value=new Object();
+ if (y.length < 4) {y=""+(y-0+1900);}
+ value["y"]=""+y;
+ value["yyyy"]=y;
+ value["yy"]=y.substring(2,4);
+ value["M"]=M;
+ value["MM"]=LZ(M);
+ value["MMM"]=MONTH_NAMES[M-1];
+ value["NNN"]=MONTH_NAMES[M+11];
+ value["d"]=d;
+ value["dd"]=LZ(d);
+ value["E"]=DAY_NAMES[E+7];
+ value["EE"]=DAY_NAMES[E];
+ value["H"]=H;
+ value["HH"]=LZ(H);
+ if (H==0){value["h"]=12;}
+ else if (H>12){value["h"]=H-12;}
+ else {value["h"]=H;}
+ value["hh"]=LZ(value["h"]);
+ if (H>11){value["K"]=H-12;} else {value["K"]=H;}
+ value["k"]=H+1;
+ value["KK"]=LZ(value["K"]);
+ value["kk"]=LZ(value["k"]);
+ if (H > 11) { value["a"]="PM"; }
+ else { value["a"]="AM"; }
+ value["m"]=m;
+ value["mm"]=LZ(m);
+ value["s"]=s;
+ value["ss"]=LZ(s);
+ while (i_format < format.length) {
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+ token += format.charAt(i_format++);
+ }
+ if (value[token] != null) { result=result + value[token]; }
+ else { result=result + token; }
+ }
+ return result;
+ }
+
+// ------------------------------------------------------------------
+// Utility functions for parsing in getDateFromFormat()
+// ------------------------------------------------------------------
+function _isInteger(val) {
+ var digits="1234567890";
+ for (var i=0; i < val.length; i++) {
+ if (digits.indexOf(val.charAt(i))==-1) { return false; }
+ }
+ return true;
+ }
+function _getInt(str,i,minlength,maxlength) {
+ for (var x=maxlength; x>=minlength; x--) {
+ var token=str.substring(i,i+x);
+ if (token.length < minlength) { return null; }
+ if (_isInteger(token)) { return token; }
+ }
+ return null;
+ }
+
+// ------------------------------------------------------------------
+// getDateFromFormat( date_string , format_string )
+//
+// This function takes a date string and a format string. It matches
+// If the date string matches the format string, it returns the
+// getTime() of the date. If it does not match, it returns 0.
+// ------------------------------------------------------------------
+function getDateFromFormat(val,format) {
+ val=val+"";
+ format=format+"";
+ var i_val=0;
+ var i_format=0;
+ var c="";
+ var token="";
+ var token2="";
+ var x,y;
+ var now=new Date();
+ var year=now.getYear();
+ var month=now.getMonth()+1;
+ var date=1;
+ var hh=now.getHours();
+ var mm=now.getMinutes();
+ var ss=now.getSeconds();
+ var ampm="";
+
+ while (i_format < format.length) {
+ // Get next token from format string
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+ token += format.charAt(i_format++);
+ }
+ // Extract contents of value based on format token
+ if (token=="yyyy" || token=="yy" || token=="y") {
+ if (token=="yyyy") { x=4;y=4; }
+ if (token=="yy") { x=2;y=2; }
+ if (token=="y") { x=2;y=4; }
+ year=_getInt(val,i_val,x,y);
+ if (year==null) { return 0; }
+ i_val += year.length;
+ if (year.length==2) {
+ if (year > 70) { year=1900+(year-0); }
+ else { year=2000+(year-0); }
+ }
+ }
+ else if (token=="MMM"||token=="NNN"){
+ month=0;
+ for (var i=0; i<MONTH_NAMES.length; i++) {
+ var month_name=MONTH_NAMES[i];
+ if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
+ if (token=="MMM"||(token=="NNN"&&i>11)) {
+ month=i+1;
+ if (month>12) { month -= 12; }
+ i_val += month_name.length;
+ break;
+ }
+ }
+ }
+ if ((month < 1)||(month>12)){return 0;}
+ }
+ else if (token=="EE"||token=="E"){
+ for (var i=0; i<DAY_NAMES.length; i++) {
+ var day_name=DAY_NAMES[i];
+ if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
+ i_val += day_name.length;
+ break;
+ }
+ }
+ }
+ else if (token=="MM"||token=="M") {
+ month=_getInt(val,i_val,token.length,2);
+ if(month==null||(month<1)||(month>12)){return 0;}
+ i_val+=month.length;}
+ else if (token=="dd"||token=="d") {
+ date=_getInt(val,i_val,token.length,2);
+ if(date==null||(date<1)||(date>31)){return 0;}
+ i_val+=date.length;}
+ else if (token=="hh"||token=="h") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<1)||(hh>12)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="HH"||token=="H") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<0)||(hh>23)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="KK"||token=="K") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<0)||(hh>11)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="kk"||token=="k") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<1)||(hh>24)){return 0;}
+ i_val+=hh.length;hh--;}
+ else if (token=="mm"||token=="m") {
+ mm=_getInt(val,i_val,token.length,2);
+ if(mm==null||(mm<0)||(mm>59)){return 0;}
+ i_val+=mm.length;}
+ else if (token=="ss"||token=="s") {
+ ss=_getInt(val,i_val,token.length,2);
+ if(ss==null||(ss<0)||(ss>59)){return 0;}
+ i_val+=ss.length;}
+ else if (token=="a") {
+ if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
+ else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
+ else {return 0;}
+ i_val+=2;}
+ else {
+ if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
+ else {i_val+=token.length;}
+ }
+ }
+ // If there are any trailing characters left in the value, it doesn't match
+ if (i_val != val.length) { return 0; }
+ // Is date valid for month?
+ if (month==2) {
+ // Check for leap year
+ if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+ if (date > 29){ return 0; }
+ }
+ else { if (date > 28) { return 0; } }
+ }
+ if ((month==4)||(month==6)||(month==9)||(month==11)) {
+ if (date > 30) { return 0; }
+ }
+ // Correct hours value
+ if (hh<12 && ampm=="PM") { hh=hh-0+12; }
+ else if (hh>11 && ampm=="AM") { hh-=12; }
+ var newdate=new Date(year,month-1,date,hh,mm,ss);
+ return newdate.getTime();
+ }
+
+// ------------------------------------------------------------------
+// parseDate( date_string [, prefer_euro_format] )
+//
+// This function takes a date string and tries to match it to a
+// number of possible date formats to get the value. It will try to
+// match against the following international formats, in this order:
+// y-M-d MMM d, y MMM d,y y-MMM-d d-MMM-y MMM d
+// M/d/y M-d-y M.d.y MMM-d M/d M-d
+// d/M/y d-M-y d.M.y d-MMM d/M d-M
+// A second argument may be passed to instruct the method to search
+// for formats like d/M/y (european format) before M/d/y (American).
+// Returns a Date object or null if no patterns match.
+// ------------------------------------------------------------------
+function parseDate(val) {
+ var preferEuro=(arguments.length==2)?arguments[1]:false;
+ generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
+ monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
+ dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
+ var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
+ var d=null;
+ for (var i=0; i<checkList.length; i++) {
+ var l=window[checkList[i]];
+ for (var j=0; j<l.length; j++) {
+ d=getDateFromFormat(val,l[j]);
+ if (d!=0) { return new Date(d); }
+ }
+ }
+ return null;
+ }
\ No newline at end of file diff --git a/libgpl/dialogextend/jquery.dialogextend.js b/libgpl/dialogextend/jquery.dialogextend.js new file mode 100644 index 0000000..f633829 --- /dev/null +++ b/libgpl/dialogextend/jquery.dialogextend.js @@ -0,0 +1,509 @@ +(function() { + var $; + + $ = jQuery; + + $.widget("ui.dialogExtend", { + version: "2.0.0", + modes: {}, + options: { + "closable": true, + "dblclick": false, + "titlebar": false, + "icons": { + "close": "ui-icon-closethick", + "restore": "ui-icon-newwin" + }, + "load": null, + "beforeRestore": null, + "restore": null + }, + _create: function() { + this._state = "normal"; + if (!$(this.element[0]).data("ui-dialog")) { + $.error("jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted"); + } + this._verifyOptions(); + this._initStyles(); + this._initButtons(); + this._initTitleBar(); + this._setState("normal"); + this._on("load", function(e) { + return console.log("test", e); + }); + return this._trigger("load"); + }, + _setState: function(state) { + $(this.element[0]).removeClass("ui-dialog-" + this._state).addClass("ui-dialog-" + state); + return this._state = state; + }, + _verifyOptions: function() { + var name, _ref, _results; + + if (this.options.dblclick && !(this.options.dblclick in this.modes)) { + $.error("jQuery.dialogExtend Error : Invalid <dblclick> value '" + this.options.dblclick + "'"); + this.options.dblclick = false; + } + if (this.options.titlebar && ((_ref = this.options.titlebar) !== "none" && _ref !== "transparent")) { + $.error("jQuery.dialogExtend Error : Invalid <titlebar> value '" + this.options.titlebar + "'"); + this.options.titlebar = false; + } + _results = []; + for (name in this.modes) { + if (this["_verifyOptions_" + name]) { + _results.push(this["_verifyOptions_" + name]()); + } else { + _results.push(void 0); + } + } + return _results; + }, + _initStyles: function() { + var name, style, _results; + + if (!$(".dialog-extend-css").length) { + style = ''; + style += '<style class="dialog-extend-css" type="text/css">'; + style += '.ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }'; + style += '.ui-dialog .ui-dialog-titlebar-restore { width: 19px; height: 18px; }'; + style += '.ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }'; + style += '.ui-dialog .ui-dialog-titlebar-restore:hover,'; + style += '.ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }'; + style += '.ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }'; + style += '</style>'; + $(style).appendTo("body"); + } + _results = []; + for (name in this.modes) { + _results.push(this["_initStyles_" + name]()); + } + return _results; + }, + _initButtons: function() { + var buttonPane, mode, name, titlebar, _ref, + _this = this; + + titlebar = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar"); + buttonPane = $('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(titlebar); + buttonPane.css({ + "position": "absolute", + "top": "50%", + "right": "0.3em", + "margin-top": "-10px", + "height": "18px" + }); + titlebar.find(".ui-dialog-titlebar-close").css({ + "position": "relative", + "float": "right", + "top": "auto", + "right": "auto", + "margin": 0 + }).find(".ui-icon").removeClass("ui-icon-closethick").addClass(this.options.icons.close).end().appendTo(buttonPane).end(); + buttonPane.append('<a class="ui-dialog-titlebar-restore ui-corner-all ui-state-default" href="#"><span class="ui-icon ' + this.options.icons.restore + '" title="restore">restore</span></a>').find('.ui-dialog-titlebar-restore').attr("role", "button").mouseover(function() { + return $(this).addClass("ui-state-hover"); + }).mouseout(function() { + return $(this).removeClass("ui-state-hover"); + }).focus(function() { + return $(this).addClass("ui-state-focus"); + }).blur(function() { + return $(this).removeClass("ui-state-focus"); + }).end().find(".ui-dialog-titlebar-close").toggle(this.options.closable).end().find(".ui-dialog-titlebar-restore").hide().click(function(e) { + e.preventDefault(); + return _this.restore(); + }).end(); + _ref = this.modes; + for (name in _ref) { + mode = _ref[name]; + this._initModuleButton(name, mode); + } + return titlebar.dblclick(function(evt) { + if (_this.options.dblclick) { + if (_this._state !== "normal") { + return _this.restore(); + } else { + return _this[_this.options.dblclick](); + } + } + }).select(function() { + return false; + }); + }, + _initModuleButton: function(name, mode) { + var buttonPane, + _this = this; + + buttonPane = $(this.element[0]).dialog("widget").find('.ui-dialog-titlebar-buttonpane'); + return buttonPane.append('<a class="ui-dialog-titlebar-' + name + ' ui-corner-all ui-state-default" href="#" title="' + name + '"><span class="ui-icon ' + this.options.icons[name] + '">' + name + '</span></a>').find(".ui-dialog-titlebar-" + name).attr("role", "button").mouseover(function() { + return $(this).addClass("ui-state-hover"); + }).mouseout(function() { + return $(this).removeClass("ui-state-hover"); + }).focus(function() { + return $(this).addClass("ui-state-focus"); + }).blur(function() { + return $(this).removeClass("ui-state-focus"); + }).end().find(".ui-dialog-titlebar-" + name).toggle(this.options[mode.option]).click(function(e) { + e.preventDefault(); + return _this[name](); + }).end(); + }, + _initTitleBar: function() { + var handle; + + switch (this.options.titlebar) { + case false: + return 0; + case "none": + if ($(this.element[0]).dialog("option", "draggable")) { + handle = $("<div />").addClass("ui-dialog-draggable-handle").css("cursor", "move").height(5); + $(this.element[0]).dialog("widget").prepend(handle).draggable("option", "handle", handle); + } + return $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").find(".ui-dialog-title").html(" ").end().css({ + "background-color": "transparent", + "background-image": "none", + "border": 0, + "position": "absolute", + "right": 0, + "top": 0, + "z-index": 9999 + }).end(); + case "transparent": + return $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css({ + "background-color": "transparent", + "background-image": "none", + "border": 0 + }); + default: + return $.error("jQuery.dialogExtend Error : Invalid <titlebar> value '" + this.options.titlebar + "'"); + } + }, + state: function() { + return this._state; + }, + restore: function() { + this._trigger("beforeRestore"); + this._restore(); + this._toggleButtons(); + return this._trigger("restore"); + }, + _restore: function() { + if (this._state !== "normal") { + this["_restore_" + this._state](); + this._setState("normal"); + return $(this.element[0]).dialog("widget").focus(); + } + }, + _saveSnapshot: function() { + if (this._state === "normal") { + this.original_config_resizable = $(this.element[0]).dialog("option", "resizable"); + this.original_config_draggable = $(this.element[0]).dialog("option", "draggable"); + this.original_size_height = $(this.element[0]).dialog("widget").outerHeight(); + this.original_size_width = $(this.element[0]).dialog("option", "width"); + this.original_size_maxHeight = $(this.element[0]).dialog("option", "maxHeight"); + this.original_position_mode = $(this.element[0]).dialog("widget").css("position"); + this.original_position_left = $(this.element[0]).dialog("widget").offset().left - $('body').scrollLeft(); + this.original_position_top = $(this.element[0]).dialog("widget").offset().top - $('body').scrollTop(); + return this.original_titlebar_wrap = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css("white-space"); + } + }, + _loadSnapshot: function() { + return { + "config": { + "resizable": this.original_config_resizable, + "draggable": this.original_config_draggable + }, + "size": { + "height": this.original_size_height, + "width": this.original_size_width, + "maxHeight": this.original_size_maxHeight + }, + "position": { + "mode": this.original_position_mode, + "left": this.original_position_left, + "top": this.original_position_top + }, + "titlebar": { + "wrap": this.original_titlebar_wrap + } + }; + }, + _toggleButtons: function(newstate) { + var mode, name, state, _ref, _ref1, _results; + + state = newstate || this._state; + $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").toggle(state !== "normal").css({ + "right": "1.4em" + }).end(); + _ref = this.modes; + for (name in _ref) { + mode = _ref[name]; + $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-" + name).toggle(state !== mode.state && this.options[mode.option]); + } + _ref1 = this.modes; + _results = []; + for (name in _ref1) { + mode = _ref1[name]; + if (mode.state === state) { + _results.push($(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").insertAfter($(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-" + name)).end()); + } else { + _results.push(void 0); + } + } + return _results; + } + }); + +}).call(this); + +(function() { + var $; + + $ = jQuery; + + $.extend(true, $.ui.dialogExtend.prototype, { + modes: { + "collapse": { + option: "collapsable", + state: "collapsed" + } + }, + options: { + "collapsable": false, + "icons": { + "collapse": "ui-icon-triangle-1-s" + }, + "beforeCollapse": null, + "collapse": null + }, + collapse: function() { + var newHeight, pos; + + newHeight = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").height() + 15; + this._trigger("beforeCollapse"); + if (this._state !== "normal") { + this._restore(); + } + this._saveSnapshot(); + pos = $(this.element[0]).dialog("widget").position(); + $(this.element[0]).dialog("option", { + "resizable": false, + "height": newHeight, + "maxHeight": newHeight, + "position": [pos.left - $(document).scrollLeft(), pos.top - $(document).scrollTop()] + }).on('dialogclose', this._collapse_restore).hide().dialog("widget").find(".ui-dialog-buttonpane:visible").hide().end().find(".ui-dialog-titlebar").css("white-space", "nowrap").end().find(".ui-dialog-content"); + this._setState("collapsed"); + this._toggleButtons(); + return this._trigger("collapse"); + }, + _restore_collapsed: function() { + var original; + + original = this._loadSnapshot(); + return $(this.element[0]).show().dialog("widget").find(".ui-dialog-buttonpane:hidden").show().end().find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end().find(".ui-dialog-content").dialog("option", { + "resizable": original.config.resizable, + "height": original.size.height, + "maxHeight": original.size.maxHeight + }).off('dialogclose', this._collapse_restore); + }, + _initStyles_collapse: function() { + var style; + + if (!$(".dialog-extend-collapse-css").length) { + style = ''; + style += '<style class="dialog-extend-collapse-css" type="text/css">'; + style += '.ui-dialog .ui-dialog-titlebar-collapse { width: 19px; height: 18px; }'; + style += '.ui-dialog .ui-dialog-titlebar-collapse span { display: block; margin: 1px; }'; + style += '.ui-dialog .ui-dialog-titlebar-collapse:hover,'; + style += '.ui-dialog .ui-dialog-titlebar-collapse:focus { padding: 0; }'; + style += '</style>'; + return $(style).appendTo("body"); + } + }, + _collapse_restore: function() { + return $(this).dialogExtend("restore"); + } + }); + +}).call(this); + +(function() { + var $; + + $ = jQuery; + + $.extend(true, $.ui.dialogExtend.prototype, { + modes: { + "maximize": { + option: "maximizable", + state: "maximized" + } + }, + options: { + "maximizable": false, + "icons": { + "maximize": "ui-icon-extlink" + }, + "beforeMaximize": null, + "maximize": null + }, + maximize: function() { + var newHeight, newWidth; + + newHeight = $(window).height() - 11; + newWidth = $(window).width() - 11; + this._trigger("beforeMaximize"); + if (this._state !== "normal") { + this._restore(); + } + this._saveSnapshot(); + if ($(this.element[0]).dialog("option", "draggable")) { + $(this.element[0]).dialog("widget").draggable("option", "handle", null).find(".ui-dialog-draggable-handle").css("cursor", "text").end(); + } + $(this.element[0]).dialog("widget").css("position", "fixed").find(".ui-dialog-content").show().dialog("widget").find(".ui-dialog-buttonpane").show().end().find(".ui-dialog-content").dialog("option", { + "resizable": false, + "draggable": false, + "height": newHeight, + "width": newWidth, + "position": { + my: "left top", + at: "left top", + of: window + } + }); + this._setState("maximized"); + this._toggleButtons(); + return this._trigger("maximize"); + }, + _restore_maximized: function() { + var original; + + original = this._loadSnapshot(); + $(this.element[0]).dialog("widget").css("position", original.position.mode).find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end().find(".ui-dialog-content").dialog("option", { + "resizable": original.config.resizable, + "draggable": original.config.draggable, + "height": original.size.height, + "width": original.size.width, + "maxHeight": original.size.maxHeight, + "position": { + my: "left top", + at: "left+" + original.position.left + " top+" + original.position.top, + of: window + } + }); + if ($(this.element[0]).dialog("option", "draggable")) { + return $(this.element[0]).dialog("widget").draggable("option", "handle", $(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle").length ? $(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle") : ".ui-dialog-titlebar").find(".ui-dialog-draggable-handle").css("cursor", "move"); + } + }, + _initStyles_maximize: function() { + var style; + + if (!$(".dialog-extend-maximize-css").length) { + style = ''; + style += '<style class="dialog-extend-maximize-css" type="text/css">'; + style += '.ui-dialog .ui-dialog-titlebar-maximize { width: 19px; height: 18px; }'; + style += '.ui-dialog .ui-dialog-titlebar-maximize span { display: block; margin: 1px; }'; + style += '.ui-dialog .ui-dialog-titlebar-maximize:hover,'; + style += '.ui-dialog .ui-dialog-titlebar-maximize:focus { padding: 0; }'; + style += '</style>'; + return $(style).appendTo("body"); + } + } + }); + +}).call(this); + +(function() { + var $; + + $ = jQuery; + + $.extend(true, $.ui.dialogExtend.prototype, { + modes: { + "minimize": { + option: "minimizable", + state: "minimized" + } + }, + options: { + "minimizable": false, + "minimizeLocation": "left", + "icons": { + "minimize": "ui-icon-minus" + }, + "beforeMinimize": null, + "minimize": null + }, + minimize: function() { + var dialogcontrols, fixedContainer, newWidth; + + this._trigger("beforeMinimize"); + if (this._state !== "normal") { + this._restore(); + } + newWidth = 200; + if ($("#dialog-extend-fixed-container").length) { + fixedContainer = $("#dialog-extend-fixed-container"); + } else { + fixedContainer = $('<div id="dialog-extend-fixed-container"></div>').appendTo("body"); + fixedContainer.css({ + "position": "fixed", + "bottom": 1, + "left": 1, + "right": 1, + "z-index": 9999 + }); + } + this._toggleButtons("minimized"); + dialogcontrols = $(this.element[0]).dialog("widget").clone().children().remove().end(); + $(this.element[0]).dialog("widget").find('.ui-dialog-titlebar').clone(true, true).appendTo(dialogcontrols); + dialogcontrols.css({ + "float": this.options.minimizeLocation, + "margin": 1 + }); + fixedContainer.append(dialogcontrols); + $(this.element[0]).data("dialog-extend-minimize-controls", dialogcontrols); + if ($(this.element[0]).dialog("option", "draggable")) { + dialogcontrols.removeClass("ui-draggable"); + } + dialogcontrols.css({ + "height": "auto", + "width": newWidth, + "position": "static" + }); + $(this.element[0]).on('dialogbeforeclose', this._minimize_restoreOnClose).dialog("widget").hide(); + this._setState("minimized"); + return this._trigger("minimize"); + }, + _restore_minimized: function() { + $(this.element[0]).dialog("widget").show(); + $(this.element[0]).off('dialogbeforeclose', this._minimize_restoreOnClose); + $(this.element[0]).data("dialog-extend-minimize-controls").remove(); + return $(this.element[0]).removeData("dialog-extend-minimize-controls"); + }, + _initStyles_minimize: function() { + var style; + + if (!$(".dialog-extend-minimize-css").length) { + style = ''; + style += '<style class="dialog-extend-minimize-css" type="text/css">'; + style += '.ui-dialog .ui-dialog-titlebar-minimize { width: 19px; height: 18px; }'; + style += '.ui-dialog .ui-dialog-titlebar-minimize span { display: block; margin: 1px; }'; + style += '.ui-dialog .ui-dialog-titlebar-minimize:hover,'; + style += '.ui-dialog .ui-dialog-titlebar-minimize:focus { padding: 0; }'; + style += '</style>'; + return $(style).appendTo("body"); + } + }, + _verifyOptions_minimize: function() { + var _ref; + + if (!this.options.minimizeLocation || ((_ref = this.options.minimizeLocation) !== 'left' && _ref !== 'right')) { + $.error("jQuery.dialogExtend Error : Invalid <minimizeLocation> value '" + this.options.minimizeLocation + "'"); + return this.options.minimizeLocation = "left"; + } + }, + _minimize_restoreOnClose: function() { + return $(this).dialogExtend("restore"); + } + }); + +}).call(this); diff --git a/libgpl/dialogextend/jquery.dialogextend.min.js b/libgpl/dialogextend/jquery.dialogextend.min.js new file mode 100644 index 0000000..0d943a1 --- /dev/null +++ b/libgpl/dialogextend/jquery.dialogextend.min.js @@ -0,0 +1,2 @@ +/*! jquery-dialogextend 2.0.3 2014-07-08 */ +(function(){var i;i=jQuery,i.widget("ui.dialogExtend",{version:"2.0.0",modes:{},options:{closable:!0,dblclick:!1,titlebar:!1,icons:{close:"ui-icon-closethick",restore:"ui-icon-newwin"},load:null,beforeRestore:null,restore:null},_create:function(){return this._state="normal",i(this.element[0]).data("ui-dialog")||i.error("jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted"),this._verifyOptions(),this._initStyles(),this._initButtons(),this._initTitleBar(),this._setState("normal"),this._on("load",function(i){return console.log("test",i)}),this._trigger("load")},_setState:function(t){return i(this.element[0]).removeClass("ui-dialog-"+this._state).addClass("ui-dialog-"+t),this._state=t},_verifyOptions:function(){var t,e,o;!this.options.dblclick||this.options.dblclick in this.modes||(i.error("jQuery.dialogExtend Error : Invalid <dblclick> value '"+this.options.dblclick+"'"),this.options.dblclick=!1),this.options.titlebar&&"none"!==(e=this.options.titlebar)&&"transparent"!==e&&(i.error("jQuery.dialogExtend Error : Invalid <titlebar> value '"+this.options.titlebar+"'"),this.options.titlebar=!1),o=[];for(t in this.modes)this["_verifyOptions_"+t]?o.push(this["_verifyOptions_"+t]()):o.push(void 0);return o},_initStyles:function(){var t,e,o;i(".dialog-extend-css").length||(e="",e+='<style class="dialog-extend-css" type="text/css">',e+=".ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }",e+=".ui-dialog .ui-dialog-titlebar-restore { width: 19px; height: 18px; }",e+=".ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }",e+=".ui-dialog .ui-dialog-titlebar-restore:hover,",e+=".ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }",e+=".ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }",e+="</style>",i(e).appendTo("body")),o=[];for(t in this.modes)o.push(this["_initStyles_"+t]());return o},_initButtons:function(){var t,e,o,n,a,l=this;n=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar"),t=i('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(n),t.css({position:"absolute",top:"50%",right:"0.3em","margin-top":"-10px",height:"18px"}),n.find(".ui-dialog-titlebar-close").css({position:"relative","float":"right",top:"auto",right:"auto",margin:0}).find(".ui-icon").removeClass("ui-icon-closethick").addClass(this.options.icons.close).end().appendTo(t).end(),t.append('<a class="ui-dialog-titlebar-restore ui-corner-all ui-state-default" href="#"><span class="ui-icon '+this.options.icons.restore+'" title="restore">restore</span></a>').find(".ui-dialog-titlebar-restore").attr("role","button").mouseover(function(){return i(this).addClass("ui-state-hover")}).mouseout(function(){return i(this).removeClass("ui-state-hover")}).focus(function(){return i(this).addClass("ui-state-focus")}).blur(function(){return i(this).removeClass("ui-state-focus")}).end().find(".ui-dialog-titlebar-close").toggle(this.options.closable).end().find(".ui-dialog-titlebar-restore").hide().click(function(i){return i.preventDefault(),l.restore()}).end(),a=this.modes;for(o in a)e=a[o],this._initModuleButton(o,e);return n.dblclick(function(){return l.options.dblclick?"normal"!==l._state?l.restore():l[l.options.dblclick]():void 0}).select(function(){return!1})},_initModuleButton:function(t,e){var o,n=this;return o=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-buttonpane"),o.append('<a class="ui-dialog-titlebar-'+t+' ui-corner-all ui-state-default" href="#" title="'+t+'"><span class="ui-icon '+this.options.icons[t]+'">'+t+"</span></a>").find(".ui-dialog-titlebar-"+t).attr("role","button").mouseover(function(){return i(this).addClass("ui-state-hover")}).mouseout(function(){return i(this).removeClass("ui-state-hover")}).focus(function(){return i(this).addClass("ui-state-focus")}).blur(function(){return i(this).removeClass("ui-state-focus")}).end().find(".ui-dialog-titlebar-"+t).toggle(this.options[e.option]).click(function(i){return i.preventDefault(),n[t]()}).end()},_initTitleBar:function(){var t;switch(this.options.titlebar){case!1:return 0;case"none":return i(this.element[0]).dialog("option","draggable")&&(t=i("<div />").addClass("ui-dialog-draggable-handle").css("cursor","move").height(5),i(this.element[0]).dialog("widget").prepend(t).draggable("option","handle",t)),i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").find(".ui-dialog-title").html(" ").end().css({"background-color":"transparent","background-image":"none",border:0,position:"absolute",right:0,top:0,"z-index":9999}).end();case"transparent":return i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css({"background-color":"transparent","background-image":"none",border:0});default:return i.error("jQuery.dialogExtend Error : Invalid <titlebar> value '"+this.options.titlebar+"'")}},state:function(){return this._state},restore:function(){return this._trigger("beforeRestore"),this._restore(),this._toggleButtons(),this._trigger("restore")},_restore:function(){return"normal"!==this._state?(this["_restore_"+this._state](),this._setState("normal"),i(this.element[0]).dialog("widget").focus()):void 0},_saveSnapshot:function(){return"normal"===this._state?(this.original_config_resizable=i(this.element[0]).dialog("option","resizable"),this.original_config_draggable=i(this.element[0]).dialog("option","draggable"),this.original_size_height=i(this.element[0]).dialog("widget").outerHeight(),this.original_size_width=i(this.element[0]).dialog("option","width"),this.original_size_maxHeight=i(this.element[0]).dialog("option","maxHeight"),this.original_position_mode=i(this.element[0]).dialog("widget").css("position"),this.original_position_left=i(this.element[0]).dialog("widget").offset().left-i("body").scrollLeft(),this.original_position_top=i(this.element[0]).dialog("widget").offset().top-i("body").scrollTop(),this.original_titlebar_wrap=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css("white-space")):void 0},_loadSnapshot:function(){return{config:{resizable:this.original_config_resizable,draggable:this.original_config_draggable},size:{height:this.original_size_height,width:this.original_size_width,maxHeight:this.original_size_maxHeight},position:{mode:this.original_position_mode,left:this.original_position_left,top:this.original_position_top},titlebar:{wrap:this.original_titlebar_wrap}}},_toggleButtons:function(t){var e,o,n,a,l,s;n=t||this._state,i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").toggle("normal"!==n).css({right:"1.4em"}).end(),a=this.modes;for(o in a)e=a[o],i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-"+o).toggle(n!==e.state&&this.options[e.option]);l=this.modes,s=[];for(o in l)e=l[o],e.state===n?s.push(i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").insertAfter(i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-"+o)).end()):s.push(void 0);return s}})}).call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{collapse:{option:"collapsable",state:"collapsed"}},options:{collapsable:!1,icons:{collapse:"ui-icon-triangle-1-s"},beforeCollapse:null,collapse:null},collapse:function(){var t,e;return t=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").height()+15,this._trigger("beforeCollapse"),"normal"!==this._state&&this._restore(),this._saveSnapshot(),e=i(this.element[0]).dialog("widget").position(),i(this.element[0]).dialog("option",{resizable:!1,height:t,maxHeight:t,position:[e.left-i(document).scrollLeft(),e.top-i(document).scrollTop()]}).on("dialogclose",this._collapse_restore).hide().dialog("widget").find(".ui-dialog-buttonpane:visible").hide().end().find(".ui-dialog-titlebar").css("white-space","nowrap").end().find(".ui-dialog-content"),this._setState("collapsed"),this._toggleButtons(),this._trigger("collapse")},_restore_collapsed:function(){var t;return t=this._loadSnapshot(),i(this.element[0]).show().dialog("widget").find(".ui-dialog-buttonpane:hidden").show().end().find(".ui-dialog-titlebar").css("white-space",t.titlebar.wrap).end().find(".ui-dialog-content").dialog("option",{resizable:t.config.resizable,height:t.size.height,maxHeight:t.size.maxHeight}).off("dialogclose",this._collapse_restore)},_initStyles_collapse:function(){var t;return i(".dialog-extend-collapse-css").length?void 0:(t="",t+='<style class="dialog-extend-collapse-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-collapse { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-collapse span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-collapse:hover,",t+=".ui-dialog .ui-dialog-titlebar-collapse:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))},_collapse_restore:function(){return i(this).dialogExtend("restore")}})}.call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{maximize:{option:"maximizable",state:"maximized"}},options:{maximizable:!1,icons:{maximize:"ui-icon-extlink"},beforeMaximize:null,maximize:null},maximize:function(){var t,e;return t=i(window).height()-11,e=i(window).width()-11,this._trigger("beforeMaximize"),"normal"!==this._state&&this._restore(),this._saveSnapshot(),i(this.element[0]).dialog("option","draggable")&&i(this.element[0]).dialog("widget").draggable("option","handle",null).find(".ui-dialog-draggable-handle").css("cursor","text").end(),i(this.element[0]).dialog("widget").css("position","fixed").find(".ui-dialog-content").show().dialog("widget").find(".ui-dialog-buttonpane").show().end().find(".ui-dialog-content").dialog("option",{resizable:!1,draggable:!1,height:t,width:e,position:{my:"left top",at:"left top",of:window}}),this._setState("maximized"),this._toggleButtons(),this._trigger("maximize")},_restore_maximized:function(){var t;return t=this._loadSnapshot(),i(this.element[0]).dialog("widget").css("position",t.position.mode).find(".ui-dialog-titlebar").css("white-space",t.titlebar.wrap).end().find(".ui-dialog-content").dialog("option",{resizable:t.config.resizable,draggable:t.config.draggable,height:t.size.height,width:t.size.width,maxHeight:t.size.maxHeight,position:{my:"left top",at:"left+"+t.position.left+" top+"+t.position.top,of:window}}),i(this.element[0]).dialog("option","draggable")?i(this.element[0]).dialog("widget").draggable("option","handle",i(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle").length?i(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle"):".ui-dialog-titlebar").find(".ui-dialog-draggable-handle").css("cursor","move"):void 0},_initStyles_maximize:function(){var t;return i(".dialog-extend-maximize-css").length?void 0:(t="",t+='<style class="dialog-extend-maximize-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-maximize { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-maximize span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-maximize:hover,",t+=".ui-dialog .ui-dialog-titlebar-maximize:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))}})}.call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{minimize:{option:"minimizable",state:"minimized"}},options:{minimizable:!1,minimizeLocation:"left",icons:{minimize:"ui-icon-minus"},beforeMinimize:null,minimize:null},minimize:function(){var t,e,o;return this._trigger("beforeMinimize"),"normal"!==this._state&&this._restore(),o=200,i("#dialog-extend-fixed-container").length?e=i("#dialog-extend-fixed-container"):(e=i('<div id="dialog-extend-fixed-container"></div>').appendTo("body"),e.css({position:"fixed",bottom:1,left:1,right:1,"z-index":9999})),this._toggleButtons("minimized"),t=i(this.element[0]).dialog("widget").clone().children().remove().end(),i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").clone(!0,!0).appendTo(t),t.css({"float":this.options.minimizeLocation,margin:1}),e.append(t),i(this.element[0]).data("dialog-extend-minimize-controls",t),i(this.element[0]).dialog("option","draggable")&&t.removeClass("ui-draggable"),t.css({height:"auto",width:o,position:"static"}),i(this.element[0]).on("dialogbeforeclose",this._minimize_restoreOnClose).dialog("widget").hide(),this._setState("minimized"),this._trigger("minimize")},_restore_minimized:function(){return i(this.element[0]).dialog("widget").show(),i(this.element[0]).off("dialogbeforeclose",this._minimize_restoreOnClose),i(this.element[0]).data("dialog-extend-minimize-controls").remove(),i(this.element[0]).removeData("dialog-extend-minimize-controls")},_initStyles_minimize:function(){var t;return i(".dialog-extend-minimize-css").length?void 0:(t="",t+='<style class="dialog-extend-minimize-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-minimize { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-minimize span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-minimize:hover,",t+=".ui-dialog .ui-dialog-titlebar-minimize:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))},_verifyOptions_minimize:function(){var t;return!this.options.minimizeLocation||"left"!==(t=this.options.minimizeLocation)&&"right"!==t?(i.error("jQuery.dialogExtend Error : Invalid <minimizeLocation> value '"+this.options.minimizeLocation+"'"),this.options.minimizeLocation="left"):void 0},_minimize_restoreOnClose:function(){return i(this).dialogExtend("restore")}})}.call(this);
\ No newline at end of file diff --git a/libgpl/encryption/encryption.php b/libgpl/encryption/encryption.php new file mode 100644 index 0000000..c503109 --- /dev/null +++ b/libgpl/encryption/encryption.php @@ -0,0 +1,166 @@ +<?php +/** + * A class to handle secure encryption and decryption of arbitrary data + * Copyright http://stackoverflow.com/users/338665/ircmaxell + * http://stackoverflow.com/questions/5089841/php-2-way-encryption-i-need-to-store-passwords-that-can-be-retrieved + * + * + * Note that this is not just straight encryption. It also has a few other + * features in it to make the encrypted data far more secure. Note that any + * other implementations used to decrypt data will have to do the same exact + * operations. + * + * Security Benefits: + * + * - Uses Key stretching + * - Hides the Initialization Vector + * - Does HMAC verification of source data + * + */ +class Encryption { + + /** + * @var string $cipher The mcrypt cipher to use for this instance + */ + protected $cipher = ''; + + /** + * @var int $mode The mcrypt cipher mode to use + */ + protected $mode = ''; + + /** + * @var int $rounds The number of rounds to feed into PBKDF2 for key generation + */ + protected $rounds = 100; + + /** + * Constructor! + * + * @param string $cipher The MCRYPT_* cypher to use for this instance + * @param int $mode The MCRYPT_MODE_* mode to use for this instance + * @param int $rounds The number of PBKDF2 rounds to do on the key + */ + public function __construct($cipher, $mode, $rounds = 100) { + $this->cipher = $cipher; + $this->mode = $mode; + $this->rounds = (int) $rounds; + } + + /** + * Decrypt the data with the provided key + * + * @param string $data The encrypted datat to decrypt + * @param string $key The key to use for decryption + * + * @returns string|false The returned string if decryption is successful + * false if it is not + */ + public function decrypt($data, $key) { + $salt = substr($data, 0, 128); + $enc = substr($data, 128, -64); + $mac = substr($data, -64); + + list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); + + if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) { + return false; + } + + $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv); + + $data = $this->unpad($dec); + + return $data; + } + + /** + * Encrypt the supplied data using the supplied key + * + * @param string $data The data to encrypt + * @param string $key The key to encrypt with + * + * @returns string The encrypted data + */ + public function encrypt($data, $key) { + $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM); + list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); + + $data = $this->pad($data); + + $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv); + + $mac = hash_hmac('sha512', $enc, $macKey, true); + return $salt . $enc . $mac; + } + + /** + * Generates a set of keys given a random salt and a master key + * + * @param string $salt A random string to change the keys each encryption + * @param string $key The supplied key to encrypt with + * + * @returns array An array of keys (a cipher key, a mac key, and a IV) + */ + protected function getKeys($salt, $key) { + $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode); + $keySize = mcrypt_get_key_size($this->cipher, $this->mode); + $length = 2 * $keySize + $ivSize; + + $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length); + + $cipherKey = substr($key, 0, $keySize); + $macKey = substr($key, $keySize, $keySize); + $iv = substr($key, 2 * $keySize); + return array($cipherKey, $macKey, $iv); + } + + /** + * Stretch the key using the PBKDF2 algorithm + * + * @see http://en.wikipedia.org/wiki/PBKDF2 + * + * @param string $algo The algorithm to use + * @param string $key The key to stretch + * @param string $salt A random salt + * @param int $rounds The number of rounds to derive + * @param int $length The length of the output key + * + * @returns string The derived key. + */ + protected function pbkdf2($algo, $key, $salt, $rounds, $length) { + $size = strlen(hash($algo, '', true)); + $len = ceil($length / $size); + $result = ''; + for ($i = 1; $i <= $len; $i++) { + $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true); + $res = $tmp; + for ($j = 1; $j < $rounds; $j++) { + $tmp = hash_hmac($algo, $tmp, $key, true); + $res ^= $tmp; + } + $result .= $res; + } + return substr($result, 0, $length); + } + + protected function pad($data) { + $length = mcrypt_get_block_size($this->cipher, $this->mode); + $padAmount = $length - strlen($data) % $length; + if ($padAmount == 0) { + $padAmount = $length; + } + return $data . str_repeat(chr($padAmount), $padAmount); + } + + protected function unpad($data) { + $length = mcrypt_get_block_size($this->cipher, $this->mode); + $last = ord($data[strlen($data) - 1]); + if ($last > $length) return false; + if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) { + return false; + } + return substr($data, 0, -1 * $last); + } +} +?> diff --git a/libgpl/fancybox/blank.gif b/libgpl/fancybox/blank.gif Binary files differnew file mode 100644 index 0000000..35d42e8 --- /dev/null +++ b/libgpl/fancybox/blank.gif diff --git a/libgpl/fancybox/fancy_close.png b/libgpl/fancybox/fancy_close.png Binary files differnew file mode 100644 index 0000000..0703530 --- /dev/null +++ b/libgpl/fancybox/fancy_close.png diff --git a/libgpl/fancybox/fancy_closebox.png b/libgpl/fancybox/fancy_closebox.png Binary files differnew file mode 100644 index 0000000..4de4396 --- /dev/null +++ b/libgpl/fancybox/fancy_closebox.png diff --git a/libgpl/fancybox/fancy_left.png b/libgpl/fancybox/fancy_left.png Binary files differnew file mode 100644 index 0000000..61494e6 --- /dev/null +++ b/libgpl/fancybox/fancy_left.png diff --git a/libgpl/fancybox/fancy_loading.png b/libgpl/fancybox/fancy_loading.png Binary files differnew file mode 100644 index 0000000..2503017 --- /dev/null +++ b/libgpl/fancybox/fancy_loading.png diff --git a/libgpl/fancybox/fancy_nav_left.png b/libgpl/fancybox/fancy_nav_left.png Binary files differnew file mode 100644 index 0000000..ebaa6a4 --- /dev/null +++ b/libgpl/fancybox/fancy_nav_left.png diff --git a/libgpl/fancybox/fancy_nav_right.png b/libgpl/fancybox/fancy_nav_right.png Binary files differnew file mode 100644 index 0000000..873294e --- /dev/null +++ b/libgpl/fancybox/fancy_nav_right.png diff --git a/libgpl/fancybox/fancy_progress.png b/libgpl/fancybox/fancy_progress.png Binary files differnew file mode 100644 index 0000000..06b7c89 --- /dev/null +++ b/libgpl/fancybox/fancy_progress.png diff --git a/libgpl/fancybox/fancy_right.png b/libgpl/fancybox/fancy_right.png Binary files differnew file mode 100644 index 0000000..0a56042 --- /dev/null +++ b/libgpl/fancybox/fancy_right.png diff --git a/libgpl/fancybox/fancy_shadow_e.png b/libgpl/fancybox/fancy_shadow_e.png Binary files differnew file mode 100644 index 0000000..2eda089 --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_e.png diff --git a/libgpl/fancybox/fancy_shadow_n.png b/libgpl/fancybox/fancy_shadow_n.png Binary files differnew file mode 100644 index 0000000..69aa10e --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_n.png diff --git a/libgpl/fancybox/fancy_shadow_ne.png b/libgpl/fancybox/fancy_shadow_ne.png Binary files differnew file mode 100644 index 0000000..79f6980 --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_ne.png diff --git a/libgpl/fancybox/fancy_shadow_nw.png b/libgpl/fancybox/fancy_shadow_nw.png Binary files differnew file mode 100644 index 0000000..7182cd9 --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_nw.png diff --git a/libgpl/fancybox/fancy_shadow_s.png b/libgpl/fancybox/fancy_shadow_s.png Binary files differnew file mode 100644 index 0000000..d8858bf --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_s.png diff --git a/libgpl/fancybox/fancy_shadow_se.png b/libgpl/fancybox/fancy_shadow_se.png Binary files differnew file mode 100644 index 0000000..541e3ff --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_se.png diff --git a/libgpl/fancybox/fancy_shadow_sw.png b/libgpl/fancybox/fancy_shadow_sw.png Binary files differnew file mode 100644 index 0000000..b451689 --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_sw.png diff --git a/libgpl/fancybox/fancy_shadow_w.png b/libgpl/fancybox/fancy_shadow_w.png Binary files differnew file mode 100644 index 0000000..8a4e4a8 --- /dev/null +++ b/libgpl/fancybox/fancy_shadow_w.png diff --git a/libgpl/fancybox/fancy_title_left.png b/libgpl/fancybox/fancy_title_left.png Binary files differnew file mode 100644 index 0000000..6049223 --- /dev/null +++ b/libgpl/fancybox/fancy_title_left.png diff --git a/libgpl/fancybox/fancy_title_main.png b/libgpl/fancybox/fancy_title_main.png Binary files differnew file mode 100644 index 0000000..8044271 --- /dev/null +++ b/libgpl/fancybox/fancy_title_main.png diff --git a/libgpl/fancybox/fancy_title_over.png b/libgpl/fancybox/fancy_title_over.png Binary files differnew file mode 100644 index 0000000..d9f458f --- /dev/null +++ b/libgpl/fancybox/fancy_title_over.png diff --git a/libgpl/fancybox/fancy_title_right.png b/libgpl/fancybox/fancy_title_right.png Binary files differnew file mode 100644 index 0000000..e36d9db --- /dev/null +++ b/libgpl/fancybox/fancy_title_right.png diff --git a/libgpl/fancybox/fancybox-x.png b/libgpl/fancybox/fancybox-x.png Binary files differnew file mode 100644 index 0000000..c2130f8 --- /dev/null +++ b/libgpl/fancybox/fancybox-x.png diff --git a/libgpl/fancybox/fancybox-y.png b/libgpl/fancybox/fancybox-y.png Binary files differnew file mode 100644 index 0000000..7ef399b --- /dev/null +++ b/libgpl/fancybox/fancybox-y.png diff --git a/libgpl/fancybox/fancybox.png b/libgpl/fancybox/fancybox.png Binary files differnew file mode 100644 index 0000000..65e14f6 --- /dev/null +++ b/libgpl/fancybox/fancybox.png diff --git a/libgpl/fancybox/jquery.easing-1.3.pack.js b/libgpl/fancybox/jquery.easing-1.3.pack.js new file mode 100644 index 0000000..9028179 --- /dev/null +++ b/libgpl/fancybox/jquery.easing-1.3.pack.js @@ -0,0 +1,72 @@ +/* + * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + * + * Uses the built in easing capabilities added In jQuery 1.1 + * to offer multiple easing options + * + * TERMS OF USE - jQuery Easing + * + * Open source under the BSD License. + * + * Copyright © 2008 George McGinley Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +// t: current time, b: begInnIng value, c: change In value, d: duration +eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{})) + +/* + * + * TERMS OF USE - EASING EQUATIONS + * + * Open source under the BSD License. + * + * Copyright © 2001 Robert Penner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.css b/libgpl/fancybox/jquery.fancybox-1.3.4.css new file mode 100644 index 0000000..6f53d8f --- /dev/null +++ b/libgpl/fancybox/jquery.fancybox-1.3.4.css @@ -0,0 +1,359 @@ +/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ margin-left: -20px;
+ cursor: pointer;
+ overflow: hidden;
+ z-index: 1104;
+ display: none;
+}
+
+#fancybox-loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 1100;
+ display: none;
+}
+
+#fancybox-tmp {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ overflow: auto;
+ display: none;
+}
+
+#fancybox-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 20px;
+ z-index: 1101;
+ outline: none;
+ display: none;
+}
+
+#fancybox-outer {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+}
+
+#fancybox-content {
+ width: 0;
+ height: 0;
+ padding: 0;
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ z-index: 1102;
+ border: 0px solid #fff;
+}
+
+#fancybox-hide-sel-frame {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ z-index: 1101;
+}
+
+#fancybox-close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ width: 30px;
+ height: 30px;
+ background: transparent url('fancybox.png') -40px 0px;
+ cursor: pointer;
+ z-index: 1103;
+ display: none;
+}
+
+#fancybox-error {
+ color: #444;
+ font: normal 12px/20px Arial;
+ padding: 14px;
+ margin: 0;
+}
+
+#fancybox-img {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+ line-height: 0;
+ vertical-align: top;
+}
+
+#fancybox-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
+
+#fancybox-left, #fancybox-right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ outline: none;
+ background: transparent url('blank.gif');
+ z-index: 1102;
+ display: none;
+}
+
+#fancybox-left {
+ left: 0px;
+}
+
+#fancybox-right {
+ right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+ position: absolute;
+ top: 50%;
+ left: -9999px;
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ cursor: pointer;
+ z-index: 1102;
+ display: block;
+}
+
+#fancybox-left-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+ visibility: visible; /* IE6 */
+}
+
+#fancybox-left:hover span {
+ left: 20px;
+}
+
+#fancybox-right:hover span {
+ left: auto;
+ right: 20px;
+}
+
+.fancybox-bg {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ border: 0;
+ width: 20px;
+ height: 20px;
+ z-index: 1001;
+}
+
+#fancybox-bg-n {
+ top: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+}
+
+#fancybox-bg-ne {
+ top: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -162px;
+}
+
+#fancybox-bg-e {
+ top: 0;
+ right: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+ background-position: -20px 0px;
+}
+
+#fancybox-bg-se {
+ bottom: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -182px;
+}
+
+#fancybox-bg-s {
+ bottom: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+ background-position: 0px -20px;
+}
+
+#fancybox-bg-sw {
+ bottom: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -142px;
+}
+
+#fancybox-bg-w {
+ top: 0;
+ left: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+}
+
+#fancybox-bg-nw {
+ top: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -122px;
+}
+
+#fancybox-title {
+ font-family: Helvetica;
+ font-size: 12px;
+ z-index: 1102;
+}
+
+.fancybox-title-inside {
+ padding-bottom: 10px;
+ text-align: center;
+ color: #333;
+ background: #fff;
+ position: relative;
+}
+
+.fancybox-title-outside {
+ padding-top: 10px;
+ color: #fff;
+}
+
+.fancybox-title-over {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ color: #FFF;
+ text-align: left;
+}
+
+#fancybox-title-over {
+ padding: 10px;
+ background-image: url('fancy_title_over.png');
+ display: block;
+}
+
+.fancybox-title-float {
+ position: absolute;
+ left: 0;
+ bottom: -20px;
+ height: 32px;
+}
+
+#fancybox-title-float-wrap {
+ border: none;
+ border-collapse: collapse;
+ width: auto;
+}
+
+#fancybox-title-float-wrap td {
+ border: none;
+ white-space: nowrap;
+}
+
+#fancybox-title-float-left {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -40px -90px no-repeat;
+}
+
+#fancybox-title-float-main {
+ color: #FFF;
+ line-height: 29px;
+ font-weight: bold;
+ padding: 0 0 3px 0;
+ background: url('fancybox-x.png') 0px -40px;
+}
+
+#fancybox-title-float-right {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -55px -90px no-repeat;
+}
+
+/* IE6 */
+
+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
+ height: expression(this.parentNode.clientHeight + "px");
+}
+
+#fancybox-loading.fancybox-ie6 {
+ position: absolute; margin-top: 0;
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
+}
+
+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+
+/* IE6, IE7, IE8 */
+
+.fancybox-ie .fancybox-bg { background: transparent !important; }
+
+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
\ No newline at end of file diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.js b/libgpl/fancybox/jquery.fancybox-1.3.4.js new file mode 100644 index 0000000..be77275 --- /dev/null +++ b/libgpl/fancybox/jquery.fancybox-1.3.4.js @@ -0,0 +1,1156 @@ +/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function($) {
+ var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,
+
+ selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
+
+ ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
+
+ loadingTimer, loadingFrame = 1,
+
+ titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),
+
+ isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
+
+ /*
+ * Private methods
+ */
+
+ _abort = function() {
+ loading.hide();
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ if (ajaxLoader) {
+ ajaxLoader.abort();
+ }
+
+ tmp.empty();
+ },
+
+ _error = function() {
+ if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
+ loading.hide();
+ busy = false;
+ return;
+ }
+
+ selectedOpts.titleShow = false;
+
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+
+ tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' );
+
+ _process_inline();
+ },
+
+ _start = function() {
+ var obj = selectedArray[ selectedIndex ],
+ href,
+ type,
+ title,
+ str,
+ emb,
+ ret;
+
+ _abort();
+
+ selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
+
+ ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);
+
+ if (ret === false) {
+ busy = false;
+ return;
+ } else if (typeof ret == 'object') {
+ selectedOpts = $.extend(selectedOpts, ret);
+ }
+
+ title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';
+
+ if (obj.nodeName && !selectedOpts.orig) {
+ selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
+ }
+
+ if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
+ title = selectedOpts.orig.attr('alt');
+ }
+
+ href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;
+
+ if ((/^(?:javascript)/i).test(href) || href == '#') {
+ href = null;
+ }
+
+ if (selectedOpts.type) {
+ type = selectedOpts.type;
+
+ if (!href) {
+ href = selectedOpts.content;
+ }
+
+ } else if (selectedOpts.content) {
+ type = 'html';
+
+ } else if (href) {
+ if (href.match(imgRegExp)) {
+ type = 'image';
+
+ } else if (href.match(swfRegExp)) {
+ type = 'swf';
+
+ } else if ($(obj).hasClass("iframe")) {
+ type = 'iframe';
+
+ } else if (href.indexOf("#") === 0) {
+ type = 'inline';
+
+ } else {
+ type = 'ajax';
+ }
+ }
+
+ if (!type) {
+ _error();
+ return;
+ }
+
+ if (type == 'inline') {
+ obj = href.substr(href.indexOf("#"));
+ type = $(obj).length > 0 ? 'inline' : 'ajax';
+ }
+
+ selectedOpts.type = type;
+ selectedOpts.href = href;
+ selectedOpts.title = title;
+
+ if (selectedOpts.autoDimensions) {
+ if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+ } else {
+ selectedOpts.autoDimensions = false;
+ }
+ }
+
+ if (selectedOpts.modal) {
+ selectedOpts.overlayShow = true;
+ selectedOpts.hideOnOverlayClick = false;
+ selectedOpts.hideOnContentClick = false;
+ selectedOpts.enableEscapeButton = false;
+ selectedOpts.showCloseButton = false;
+ }
+
+ selectedOpts.padding = parseInt(selectedOpts.padding, 10);
+ selectedOpts.margin = parseInt(selectedOpts.margin, 10);
+
+ tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));
+
+ $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
+ $(this).replaceWith(content.children());
+ });
+
+ switch (type) {
+ case 'html' :
+ tmp.html( selectedOpts.content );
+ _process_inline();
+ break;
+
+ case 'inline' :
+ if ( $(obj).parent().is('#fancybox-content') === true) {
+ busy = false;
+ return;
+ }
+
+ $('<div class="fancybox-inline-tmp" />')
+ .hide()
+ .insertBefore( $(obj) )
+ .bind('fancybox-cleanup', function() {
+ $(this).replaceWith(content.children());
+ }).bind('fancybox-cancel', function() {
+ $(this).replaceWith(tmp.children());
+ });
+
+ $(obj).appendTo(tmp);
+
+ _process_inline();
+ break;
+
+ case 'image':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ imgPreloader = new Image();
+
+ imgPreloader.onerror = function() {
+ _error();
+ };
+
+ imgPreloader.onload = function() {
+ busy = true;
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ _process_image();
+ };
+
+ imgPreloader.src = href;
+ break;
+
+ case 'swf':
+ selectedOpts.scrolling = 'no';
+
+ str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
+ emb = '';
+
+ $.each(selectedOpts.swf, function(name, val) {
+ str += '<param name="' + name + '" value="' + val + '"></param>';
+ emb += ' ' + name + '="' + val + '"';
+ });
+
+ str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
+
+ tmp.html(str);
+
+ _process_inline();
+ break;
+
+ case 'ajax':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ selectedOpts.ajax.win = selectedOpts.ajax.success;
+
+ ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
+ url : href,
+ data : selectedOpts.ajax.data || {},
+ error : function(XMLHttpRequest, textStatus, errorThrown) {
+ if ( XMLHttpRequest.status > 0 ) {
+ _error();
+ }
+ },
+ success : function(data, textStatus, XMLHttpRequest) {
+ var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
+ if (o.status == 200) {
+ if ( typeof selectedOpts.ajax.win == 'function' ) {
+ ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);
+
+ if (ret === false) {
+ loading.hide();
+ return;
+ } else if (typeof ret == 'string' || typeof ret == 'object') {
+ data = ret;
+ }
+ }
+
+ tmp.html( data );
+ _process_inline();
+ }
+ }
+ }));
+
+ break;
+
+ case 'iframe':
+ _show();
+ break;
+ }
+ },
+
+ _process_inline = function() {
+ var
+ w = selectedOpts.width,
+ h = selectedOpts.height;
+
+ if (w.toString().indexOf('%') > -1) {
+ w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';
+
+ } else {
+ w = w == 'auto' ? 'auto' : w + 'px';
+ }
+
+ if (h.toString().indexOf('%') > -1) {
+ h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';
+
+ } else {
+ h = h == 'auto' ? 'auto' : h + 'px';
+ }
+
+ tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');
+
+ selectedOpts.width = tmp.width();
+ selectedOpts.height = tmp.height();
+
+ _show();
+ },
+
+ _process_image = function() {
+ selectedOpts.width = imgPreloader.width;
+ selectedOpts.height = imgPreloader.height;
+
+ $("<img />").attr({
+ 'id' : 'fancybox-img',
+ 'src' : imgPreloader.src,
+ 'alt' : selectedOpts.title
+ }).appendTo( tmp );
+
+ _show();
+ },
+
+ _show = function() {
+ var pos, equal;
+
+ loading.hide();
+
+ if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ $.event.trigger('fancybox-cancel');
+
+ busy = false;
+ return;
+ }
+
+ busy = true;
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
+ wrap.css('height', wrap.height());
+ }
+
+ currentArray = selectedArray;
+ currentIndex = selectedIndex;
+ currentOpts = selectedOpts;
+
+ if (currentOpts.overlayShow) {
+ overlay.css({
+ 'background-color' : currentOpts.overlayColor,
+ 'opacity' : currentOpts.overlayOpacity,
+ 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
+ 'height' : $(document).height()
+ });
+
+ if (!overlay.is(':visible')) {
+ if (isIE6) {
+ $('select:not(#fancybox-tmp select)').filter(function() {
+ return this.style.visibility !== 'hidden';
+ }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {
+ this.style.visibility = 'inherit';
+ });
+ }
+
+ overlay.show();
+ }
+ } else {
+ overlay.hide();
+ }
+
+ final_pos = _get_zoom_to();
+
+ _process_title();
+
+ if (wrap.is(":visible")) {
+ $( close.add( nav_left ).add( nav_right ) ).hide();
+
+ pos = wrap.position(),
+
+ start_pos = {
+ top : pos.top,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
+
+ content.fadeTo(currentOpts.changeFade, 0.3, function() {
+ var finish_resizing = function() {
+ content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);
+ };
+
+ $.event.trigger('fancybox-change');
+
+ content
+ .empty()
+ .removeAttr('filter')
+ .css({
+ 'border-width' : currentOpts.padding,
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ });
+
+ if (equal) {
+ finish_resizing();
+
+ } else {
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.changeSpeed,
+ easing : currentOpts.easingChange,
+ step : _draw,
+ complete : finish_resizing
+ });
+ }
+ });
+
+ return;
+ }
+
+ wrap.removeAttr("style");
+
+ content.css('border-width', currentOpts.padding);
+
+ if (currentOpts.transitionIn == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ content.html( tmp.contents() );
+
+ wrap.show();
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 0;
+ }
+
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.speedIn,
+ easing : currentOpts.easingIn,
+ step : _draw,
+ complete : _finish
+ });
+
+ return;
+ }
+
+ if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
+ title.show();
+ }
+
+ content
+ .css({
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ })
+ .html( tmp.contents() );
+
+ wrap
+ .css(final_pos)
+ .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
+ },
+
+ _format_title = function(title) {
+ if (title && title.length) {
+ if (currentOpts.titlePosition == 'float') {
+ return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
+ }
+
+ return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
+ }
+
+ return false;
+ },
+
+ _process_title = function() {
+ titleStr = currentOpts.title || '';
+ titleHeight = 0;
+
+ title
+ .empty()
+ .removeAttr('style')
+ .removeClass();
+
+ if (currentOpts.titleShow === false) {
+ title.hide();
+ return;
+ }
+
+ titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);
+
+ if (!titleStr || titleStr === '') {
+ title.hide();
+ return;
+ }
+
+ title
+ .addClass('fancybox-title-' + currentOpts.titlePosition)
+ .html( titleStr )
+ .appendTo( 'body' )
+ .show();
+
+ switch (currentOpts.titlePosition) {
+ case 'inside':
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'marginLeft' : currentOpts.padding,
+ 'marginRight' : currentOpts.padding
+ });
+
+ titleHeight = title.outerHeight(true);
+
+ title.appendTo( outer );
+
+ final_pos.height += titleHeight;
+ break;
+
+ case 'over':
+ title
+ .css({
+ 'marginLeft' : currentOpts.padding,
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'bottom' : currentOpts.padding
+ })
+ .appendTo( outer );
+ break;
+
+ case 'float':
+ title
+ .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)
+ .appendTo( wrap );
+ break;
+
+ default:
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'paddingLeft' : currentOpts.padding,
+ 'paddingRight' : currentOpts.padding
+ })
+ .appendTo( wrap );
+ break;
+ }
+
+ title.hide();
+ },
+
+ _set_navigation = function() {
+ if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
+ $(document).bind('keydown.fb', function(e) {
+ if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
+ e.preventDefault();
+ $.fancybox.close();
+
+ } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
+ e.preventDefault();
+ $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!currentOpts.showNavArrows) {
+ nav_left.hide();
+ nav_right.hide();
+ return;
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
+ nav_left.show();
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
+ nav_right.show();
+ }
+ },
+
+ _finish = function () {
+ if (!$.support.opacity) {
+ content.get(0).style.removeAttribute('filter');
+ wrap.get(0).style.removeAttribute('filter');
+ }
+
+ if (selectedOpts.autoDimensions) {
+ content.css('height', 'auto');
+ }
+
+ wrap.css('height', 'auto');
+
+ if (titleStr && titleStr.length) {
+ title.show();
+ }
+
+ if (currentOpts.showCloseButton) {
+ close.show();
+ }
+
+ _set_navigation();
+
+ if (currentOpts.hideOnContentClick) {
+ content.bind('click', $.fancybox.close);
+ }
+
+ if (currentOpts.hideOnOverlayClick) {
+ overlay.bind('click', $.fancybox.close);
+ }
+
+ $(window).bind("resize.fb", $.fancybox.resize);
+
+ if (currentOpts.centerOnScroll) {
+ $(window).bind("scroll.fb", $.fancybox.center);
+ }
+
+ if (currentOpts.type == 'iframe') {
+ $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
+ }
+
+ wrap.show();
+
+ busy = false;
+
+ $.fancybox.center();
+
+ currentOpts.onComplete(currentArray, currentIndex, currentOpts);
+
+ _preload_images();
+ },
+
+ _preload_images = function() {
+ var href,
+ objNext;
+
+ if ((currentArray.length -1) > currentIndex) {
+ href = currentArray[ currentIndex + 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+
+ if (currentIndex > 0) {
+ href = currentArray[ currentIndex - 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+ },
+
+ _draw = function(pos) {
+ var dim = {
+ width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
+ height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),
+
+ top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
+ left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
+ };
+
+ if (typeof final_pos.opacity !== 'undefined') {
+ dim.opacity = pos < 0.5 ? 0.5 : pos;
+ }
+
+ wrap.css(dim);
+
+ content.css({
+ 'width' : dim.width - currentOpts.padding * 2,
+ 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2
+ });
+ },
+
+ _get_viewport = function() {
+ return [
+ $(window).width() - (currentOpts.margin * 2),
+ $(window).height() - (currentOpts.margin * 2),
+ $(document).scrollLeft() + currentOpts.margin,
+ $(document).scrollTop() + currentOpts.margin
+ ];
+ },
+
+ _get_zoom_to = function () {
+ var view = _get_viewport(),
+ to = {},
+ resize = currentOpts.autoScale,
+ double_padding = currentOpts.padding * 2,
+ ratio;
+
+ if (currentOpts.width.toString().indexOf('%') > -1) {
+ to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
+ } else {
+ to.width = currentOpts.width + double_padding;
+ }
+
+ if (currentOpts.height.toString().indexOf('%') > -1) {
+ to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
+ } else {
+ to.height = currentOpts.height + double_padding;
+ }
+
+ if (resize && (to.width > view[0] || to.height > view[1])) {
+ if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
+ ratio = (currentOpts.width ) / (currentOpts.height );
+
+ if ((to.width ) > view[0]) {
+ to.width = view[0];
+ to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
+ }
+
+ if ((to.height) > view[1]) {
+ to.height = view[1];
+ to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
+ }
+
+ } else {
+ to.width = Math.min(to.width, view[0]);
+ to.height = Math.min(to.height, view[1]);
+ }
+ }
+
+ to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
+ to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);
+
+ return to;
+ },
+
+ _get_obj_pos = function(obj) {
+ var pos = obj.offset();
+
+ pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;
+ pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;
+
+ pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;
+ pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;
+
+ pos.width = obj.width();
+ pos.height = obj.height();
+
+ return pos;
+ },
+
+ _get_zoom_from = function() {
+ var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
+ from = {},
+ pos,
+ view;
+
+ if (orig && orig.length) {
+ pos = _get_obj_pos(orig);
+
+ from = {
+ width : pos.width + (currentOpts.padding * 2),
+ height : pos.height + (currentOpts.padding * 2),
+ top : pos.top - currentOpts.padding - 20,
+ left : pos.left - currentOpts.padding - 20
+ };
+
+ } else {
+ view = _get_viewport();
+
+ from = {
+ width : currentOpts.padding * 2,
+ height : currentOpts.padding * 2,
+ top : parseInt(view[3] + view[1] * 0.5, 10),
+ left : parseInt(view[2] + view[0] * 0.5, 10)
+ };
+ }
+
+ return from;
+ },
+
+ _animate_loading = function() {
+ if (!loading.is(':visible')){
+ clearInterval(loadingTimer);
+ return;
+ }
+
+ $('div', loading).css('top', (loadingFrame * -40) + 'px');
+
+ loadingFrame = (loadingFrame + 1) % 12;
+ };
+
+ /*
+ * Public methods
+ */
+
+ $.fn.fancybox = function(options) {
+ if (!$(this).length) {
+ return this;
+ }
+
+ $(this)
+ .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
+ .unbind('click.fb')
+ .bind('click.fb', function(e) {
+ e.preventDefault();
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $(this).blur();
+
+ selectedArray = [];
+ selectedIndex = 0;
+
+ var rel = $(this).attr('rel') || '';
+
+ if (!rel || rel == '' || rel === 'nofollow') {
+ selectedArray.push(this);
+
+ } else {
+ selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
+ selectedIndex = selectedArray.index( this );
+ }
+
+ _start();
+
+ return;
+ });
+
+ return this;
+ };
+
+ $.fancybox = function(obj) {
+ var opts;
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+ opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
+
+ selectedArray = [];
+ selectedIndex = parseInt(opts.index, 10) || 0;
+
+ if ($.isArray(obj)) {
+ for (var i = 0, j = obj.length; i < j; i++) {
+ if (typeof obj[i] == 'object') {
+ $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
+ } else {
+ obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
+ }
+ }
+
+ selectedArray = jQuery.merge(selectedArray, obj);
+
+ } else {
+ if (typeof obj == 'object') {
+ $(obj).data('fancybox', $.extend({}, opts, obj));
+ } else {
+ obj = $({}).data('fancybox', $.extend({content : obj}, opts));
+ }
+
+ selectedArray.push(obj);
+ }
+
+ if (selectedIndex > selectedArray.length || selectedIndex < 0) {
+ selectedIndex = 0;
+ }
+
+ _start();
+ };
+
+ $.fancybox.showActivity = function() {
+ clearInterval(loadingTimer);
+
+ loading.show();
+ loadingTimer = setInterval(_animate_loading, 66);
+ };
+
+ $.fancybox.hideActivity = function() {
+ loading.hide();
+ };
+
+ $.fancybox.next = function() {
+ return $.fancybox.pos( currentIndex + 1);
+ };
+
+ $.fancybox.prev = function() {
+ return $.fancybox.pos( currentIndex - 1);
+ };
+
+ $.fancybox.pos = function(pos) {
+ if (busy) {
+ return;
+ }
+
+ pos = parseInt(pos);
+
+ selectedArray = currentArray;
+
+ if (pos > -1 && pos < currentArray.length) {
+ selectedIndex = pos;
+ _start();
+
+ } else if (currentOpts.cyclic && currentArray.length > 1) {
+ selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
+ _start();
+ }
+
+ return;
+ };
+
+ $.fancybox.cancel = function() {
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $.event.trigger('fancybox-cancel');
+
+ _abort();
+
+ selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
+
+ busy = false;
+ };
+
+ // Note: within an iframe use - parent.$.fancybox.close();
+ $.fancybox.close = function() {
+ if (busy || wrap.is(':hidden')) {
+ return;
+ }
+
+ busy = true;
+
+ if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ busy = false;
+ return;
+ }
+
+ _abort();
+
+ $(close.add( nav_left ).add( nav_right )).hide();
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
+
+ if (currentOpts.titlePosition !== 'inside') {
+ title.empty();
+ }
+
+ wrap.stop();
+
+ function _cleanup() {
+ overlay.fadeOut('fast');
+
+ title.empty().hide();
+ wrap.hide();
+
+ $.event.trigger('fancybox-cleanup');
+
+ content.empty();
+
+ currentOpts.onClosed(currentArray, currentIndex, currentOpts);
+
+ currentArray = selectedOpts = [];
+ currentIndex = selectedIndex = 0;
+ currentOpts = selectedOpts = {};
+
+ busy = false;
+ }
+
+ if (currentOpts.transitionOut == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ var pos = wrap.position();
+
+ final_pos = {
+ top : pos.top ,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 1;
+ }
+
+ title.empty().hide();
+
+ fx.prop = 1;
+
+ $(fx).animate({ prop: 0 }, {
+ duration : currentOpts.speedOut,
+ easing : currentOpts.easingOut,
+ step : _draw,
+ complete : _cleanup
+ });
+
+ } else {
+ wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
+ }
+ };
+
+ $.fancybox.resize = function() {
+ if (overlay.is(':visible')) {
+ overlay.css('height', $(document).height());
+ }
+
+ $.fancybox.center(true);
+ };
+
+ $.fancybox.center = function() {
+ var view, align;
+
+ if (busy) {
+ return;
+ }
+
+ align = arguments[0] === true ? 1 : 0;
+ view = _get_viewport();
+
+ if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
+ return;
+ }
+
+ wrap
+ .stop()
+ .animate({
+ 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
+ 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
+ }, typeof arguments[0] == 'number' ? arguments[0] : 200);
+ };
+
+ $.fancybox.init = function() {
+ if ($("#fancybox-wrap").length) {
+ return;
+ }
+
+ $('body').append(
+ tmp = $('<div id="fancybox-tmp"></div>'),
+ loading = $('<div id="fancybox-loading"><div></div></div>'),
+ overlay = $('<div id="fancybox-overlay"></div>'),
+ wrap = $('<div id="fancybox-wrap"></div>')
+ );
+
+ outer = $('<div id="fancybox-outer"></div>')
+ .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>')
+ .appendTo( wrap );
+
+ outer.append(
+ content = $('<div id="fancybox-content"></div>'),
+ close = $('<a id="fancybox-close"></a>'),
+ title = $('<div id="fancybox-title"></div>'),
+
+ nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
+ nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
+ );
+
+ close.click($.fancybox.close);
+ loading.click($.fancybox.cancel);
+
+ nav_left.click(function(e) {
+ e.preventDefault();
+ $.fancybox.prev();
+ });
+
+ nav_right.click(function(e) {
+ e.preventDefault();
+ $.fancybox.next();
+ });
+
+ if ($.fn.mousewheel) {
+ wrap.bind('mousewheel.fb', function(e, delta) {
+ if (busy) {
+ e.preventDefault();
+
+ } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
+ e.preventDefault();
+ $.fancybox[ delta > 0 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!$.support.opacity) {
+ wrap.addClass('fancybox-ie');
+ }
+
+ if (isIE6) {
+ loading.addClass('fancybox-ie6');
+ wrap.addClass('fancybox-ie6');
+
+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
+ }
+ };
+
+ $.fn.fancybox.defaults = {
+ padding : 10,
+ margin : 40,
+ opacity : false,
+ modal : false,
+ cyclic : false,
+ scrolling : 'auto', // 'auto', 'yes' or 'no'
+
+ width : 560,
+ height : 340,
+
+ autoScale : true,
+ autoDimensions : true,
+ centerOnScroll : false,
+
+ ajax : {},
+ swf : { wmode: 'transparent' },
+
+ hideOnOverlayClick : true,
+ hideOnContentClick : false,
+
+ overlayShow : true,
+ overlayOpacity : 0.7,
+ overlayColor : '#777',
+
+ titleShow : true,
+ titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'
+ titleFormat : null,
+ titleFromAlt : false,
+
+ transitionIn : 'fade', // 'elastic', 'fade' or 'none'
+ transitionOut : 'fade', // 'elastic', 'fade' or 'none'
+
+ speedIn : 300,
+ speedOut : 300,
+
+ changeSpeed : 300,
+ changeFade : 'fast',
+
+ easingIn : 'swing',
+ easingOut : 'swing',
+
+ showCloseButton : true,
+ showNavArrows : true,
+ enableEscapeButton : true,
+ enableKeyboardNav : true,
+
+ onStart : function(){},
+ onCancel : function(){},
+ onComplete : function(){},
+ onCleanup : function(){},
+ onClosed : function(){},
+ onError : function(){}
+ };
+
+ $(document).ready(function() {
+ $.fancybox.init();
+ });
+
+})(jQuery);
\ No newline at end of file diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js b/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js new file mode 100644 index 0000000..1373ed0 --- /dev/null +++ b/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js @@ -0,0 +1,46 @@ +/* + * FancyBox - jQuery Plugin + * Simple and fancy lightbox alternative + * + * Examples and documentation at: http://fancybox.net + * + * Copyright (c) 2008 - 2010 Janis Skarnelis + * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated. + * + * Version: 1.3.4 (11/11/2010) + * Requires: jQuery v1.3+ + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + */ + +;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>'); +F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)|| +c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick= +false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel", +function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+ +'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win== +"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+ +";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor, +opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length? +d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding}); +y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height== +i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents()); +f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode== +37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto"); +s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j); +f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c); +j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type== +"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"), +10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)}; +b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k= +0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+ +1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h= +true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1; +b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5- +d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f); +D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()}); +b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}}; +b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing", +easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);
\ No newline at end of file diff --git a/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js b/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js new file mode 100644 index 0000000..cb66588 --- /dev/null +++ b/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js @@ -0,0 +1,14 @@ +/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) +* Licensed under the MIT License (LICENSE.txt). +* +* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. +* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. +* Thanks to: Seamus Leahy for adding deltaX and deltaY +* +* Version: 3.0.4 +* +* Requires: 1.2.2+ +*/ + +(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a= +f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
\ No newline at end of file diff --git a/libgpl/flashclipboard/clipboard.swf b/libgpl/flashclipboard/clipboard.swf Binary files differnew file mode 100644 index 0000000..13bf8e3 --- /dev/null +++ b/libgpl/flashclipboard/clipboard.swf diff --git a/libgpl/flashclipboard/flashclipboard_libgpl.js b/libgpl/flashclipboard/flashclipboard_libgpl.js new file mode 100644 index 0000000..cdbb2ed --- /dev/null +++ b/libgpl/flashclipboard/flashclipboard_libgpl.js @@ -0,0 +1,309 @@ +$(window).load(function(){
+ $(function() {
+ $(".zclip").each(function() {
+ //Create a new clipboard client
+ var clip = new ZeroClipboard.Client();
+
+ clip.glue($(this).get(0));
+
+ var txt = $(this).prev().val();
+ clip.setText(txt);
+
+ clip.addEventListener('complete', function(client, text) {
+ $('#zclipdialog').html(txt);
+ $('#zclipdialog').dialog({ height : 110, width : 'auto' });
+ });
+ });
+ });
+});
+
+// Simple Set Clipboard System
+// Author: Joseph Huckaby
+
+var ZeroClipboard = {
+
+ version: "1.0.4",
+ clients: {}, // registered upload clients on page, indexed by id
+ moviePath: 'plugins/libgpl/flashclipboard/clipboard.swf', // URL to movie
+ nextId: 1, // ID of next movie
+
+ $: function(thingy) {
+ // simple DOM lookup utility function
+ if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
+ if (!thingy.addClass) {
+ // extend element with a few useful methods
+ thingy.hide = function() { this.style.display = 'none'; };
+ thingy.show = function() { this.style.display = ''; };
+ thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
+ thingy.removeClass = function(name) {
+ this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
+ };
+ thingy.hasClass = function(name) {
+ return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
+ }
+ }
+ return thingy;
+ },
+
+ setMoviePath: function(path) {
+ // set path to ZeroClipboard.swf
+ this.moviePath = path;
+ },
+
+ dispatch: function(id, eventName, args) {
+ // receive event from flash movie, send to client
+ var client = this.clients[id];
+ if (client) {
+ client.receiveEvent(eventName, args);
+ }
+ },
+
+ register: function(id, client) {
+ // register new client to receive events
+ this.clients[id] = client;
+ },
+
+ getDOMObjectPosition: function(obj) {
+ // get absolute coordinates for dom element
+ var info = {
+ left: 0,
+ top: 0,
+ width: obj.width ? obj.width : obj.offsetWidth,
+ height: obj.height ? obj.height : obj.offsetHeight
+ };
+
+ while (obj) {
+ info.left += obj.offsetLeft;
+ info.top += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ return info;
+ },
+
+ Client: function(elem) {
+ // constructor for new simple upload client
+ this.handlers = {};
+
+ // unique ID
+ this.id = ZeroClipboard.nextId++;
+ this.movieId = 'ZeroClipboardMovie_' + this.id;
+
+ // register client with singleton to receive flash events
+ ZeroClipboard.register(this.id, this);
+
+ // create movie
+ if (elem) this.glue(elem);
+ }
+};
+
+ZeroClipboard.Client.prototype = {
+
+ id: 0, // unique ID for us
+ ready: false, // whether movie is ready to receive events or not
+ movie: null, // reference to movie object
+ clipText: '', // text to copy to clipboard
+ handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
+ cssEffects: true, // enable CSS mouse effects on dom container
+ handlers: null, // user event handlers
+
+ glue: function(elem) {
+ // glue to DOM element
+ // elem can be ID or actual DOM element object
+ this.domElement = ZeroClipboard.$(elem);
+
+ // float just above object, or zIndex 99 if dom element isn't set
+ var zIndex = 99;
+ if (this.domElement.style.zIndex) {
+ zIndex = parseInt(this.domElement.style.zIndex) + 1;
+ }
+
+ // find X/Y position of domElement
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+
+ // create floating DIV above element
+ this.div = document.createElement('div');
+ var style = this.div.style;
+ style.position = 'absolute';
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ style.width = '' + box.width + 'px';
+ style.height = '' + box.height + 'px';
+ style.zIndex = zIndex;
+
+ // style.backgroundColor = '#f00'; // debug
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(this.div);
+
+ this.div.innerHTML = this.getHTML( box.width, box.height );
+ },
+
+ getHTML: function(width, height) {
+ // return HTML for movie
+ var html = '';
+ var flashvars = 'id=' + this.id +
+ '&width=' + width +
+ '&height=' + height;
+
+ if (navigator.userAgent.match(/MSIE/)) {
+ // IE gets an OBJECT tag
+ var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
+ }
+ else {
+ // all other browsers get an EMBED tag
+ html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
+ }
+ return html;
+ },
+
+ hide: function() {
+ // temporarily hide floater offscreen
+ if (this.div) {
+ this.div.style.left = '-2000px';
+ }
+ },
+
+ show: function() {
+ // show ourselves after a call to hide()
+ this.reposition();
+ },
+
+ destroy: function() {
+ // destroy control and floater
+ if (this.domElement && this.div) {
+ this.hide();
+ this.div.innerHTML = '';
+
+ var body = document.getElementsByTagName('body')[0];
+ try { body.removeChild( this.div ); } catch(e) {;}
+
+ this.domElement = null;
+ this.div = null;
+ }
+ },
+
+ reposition: function(elem) {
+ // reposition our floating div, optionally to new container
+ // warning: container CANNOT change size, only position
+ if (elem) {
+ this.domElement = ZeroClipboard.$(elem);
+ if (!this.domElement) this.hide();
+ }
+
+ if (this.domElement && this.div) {
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+ var style = this.div.style;
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ }
+ },
+
+ setText: function(newText) {
+ // set text to be copied to clipboard
+ this.clipText = newText;
+ if (this.ready) this.movie.setText(newText);
+ },
+
+ addEventListener: function(eventName, func) {
+ // add user event listener for event
+ // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+ if (!this.handlers[eventName]) this.handlers[eventName] = [];
+ this.handlers[eventName].push(func);
+ },
+
+ setHandCursor: function(enabled) {
+ // enable hand cursor (true), or default arrow cursor (false)
+ this.handCursorEnabled = enabled;
+ if (this.ready) this.movie.setHandCursor(enabled);
+ },
+
+ setCSSEffects: function(enabled) {
+ // enable or disable CSS effects on DOM container
+ this.cssEffects = !!enabled;
+ },
+
+ receiveEvent: function(eventName, args) {
+ // receive event from flash
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+
+ // special behavior for certain events
+ switch (eventName) {
+ case 'load':
+ // movie claims it is ready, but in IE this isn't always the case...
+ // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
+ this.movie = document.getElementById(this.movieId);
+ if (!this.movie) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 1 );
+ return;
+ }
+
+ // firefox on pc needs a "kick" in order to set these in certain cases
+ if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 100 );
+ this.ready = true;
+ return;
+ }
+
+ this.ready = true;
+ this.movie.setText( this.clipText );
+ this.movie.setHandCursor( this.handCursorEnabled );
+ break;
+
+ case 'mouseover':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('hover');
+ if (this.recoverActive) this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseout':
+ if (this.domElement && this.cssEffects) {
+ this.recoverActive = false;
+ if (this.domElement.hasClass('active')) {
+ this.domElement.removeClass('active');
+ this.recoverActive = true;
+ }
+ this.domElement.removeClass('hover');
+ }
+ break;
+
+ case 'mousedown':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseup':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.removeClass('active');
+ this.recoverActive = false;
+ }
+ break;
+ } // switch eventName
+
+ if (this.handlers[eventName]) {
+ for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
+ var func = this.handlers[eventName][idx];
+
+ if (typeof(func) == 'function') {
+ // actual function reference
+ func(this, args);
+ }
+ else if ((typeof(func) == 'object') && (func.length == 2)) {
+ // PHP style object + method, i.e. [myObject, 'myMethod']
+ func[0][ func[1] ](this, args);
+ }
+ else if (typeof(func) == 'string') {
+ // name of function
+ window[func](this, args);
+ }
+ } // foreach event handler defined
+ } // user defined handler for event
+ }
+
+};
diff --git a/libgpl/flashclipboard/flashclipboard_moreuserinfo.js b/libgpl/flashclipboard/flashclipboard_moreuserinfo.js new file mode 100644 index 0000000..46042c1 --- /dev/null +++ b/libgpl/flashclipboard/flashclipboard_moreuserinfo.js @@ -0,0 +1,290 @@ +// Simple Set Clipboard System
+// Author: Joseph Huckaby
+
+var ZeroClipboard = {
+
+ version: "1.0.4",
+ clients: {}, // registered upload clients on page, indexed by id
+ moviePath: 'plugins/libgpl/flashclipboard/clipboard.swf', // URL to movie
+ nextId: 1, // ID of next movie
+
+ $: function(thingy) {
+ // simple DOM lookup utility function
+ if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
+ if (!thingy.addClass) {
+ // extend element with a few useful methods
+ thingy.hide = function() { this.style.display = 'none'; };
+ thingy.show = function() { this.style.display = ''; };
+ thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
+ thingy.removeClass = function(name) {
+ this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
+ };
+ thingy.hasClass = function(name) {
+ return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
+ }
+ }
+ return thingy;
+ },
+
+ setMoviePath: function(path) {
+ // set path to ZeroClipboard.swf
+ this.moviePath = path;
+ },
+
+ dispatch: function(id, eventName, args) {
+ // receive event from flash movie, send to client
+ var client = this.clients[id];
+ if (client) {
+ client.receiveEvent(eventName, args);
+ }
+ },
+
+ register: function(id, client) {
+ // register new client to receive events
+ this.clients[id] = client;
+ },
+
+ getDOMObjectPosition: function(obj) {
+ // get absolute coordinates for dom element
+ var info = {
+ left: 0,
+ top: 0,
+ width: obj.width ? obj.width : obj.offsetWidth,
+ height: obj.height ? obj.height : obj.offsetHeight
+ };
+
+ while (obj) {
+ info.left += obj.offsetLeft;
+ info.top += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ return info;
+ },
+
+ Client: function(elem) {
+ // constructor for new simple upload client
+ this.handlers = {};
+
+ // unique ID
+ this.id = ZeroClipboard.nextId++;
+ this.movieId = 'ZeroClipboardMovie_' + this.id;
+
+ // register client with singleton to receive flash events
+ ZeroClipboard.register(this.id, this);
+
+ // create movie
+ if (elem) this.glue(elem);
+ }
+};
+
+ZeroClipboard.Client.prototype = {
+
+ id: 0, // unique ID for us
+ ready: false, // whether movie is ready to receive events or not
+ movie: null, // reference to movie object
+ clipText: '', // text to copy to clipboard
+ handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
+ cssEffects: true, // enable CSS mouse effects on dom container
+ handlers: null, // user event handlers
+
+ glue: function(elem) {
+ // glue to DOM element
+ // elem can be ID or actual DOM element object
+ this.domElement = ZeroClipboard.$(elem);
+
+ // float just above object, or zIndex 99 if dom element isn't set
+ var zIndex = 99;
+ if (this.domElement.style.zIndex) {
+ zIndex = parseInt(this.domElement.style.zIndex) + 1;
+ }
+
+ // find X/Y position of domElement
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+
+ // create floating DIV above element
+ this.div = document.createElement('div');
+ var style = this.div.style;
+ style.position = 'absolute';
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ style.width = '' + box.width + 'px';
+ style.height = '' + box.height + 'px';
+ style.zIndex = zIndex;
+
+ // style.backgroundColor = '#f00'; // debug
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(this.div);
+
+ this.div.innerHTML = this.getHTML( box.width, box.height );
+ },
+
+ getHTML: function(width, height) {
+ // return HTML for movie
+ var html = '';
+ var flashvars = 'id=' + this.id +
+ '&width=' + width +
+ '&height=' + height;
+
+ if (navigator.userAgent.match(/MSIE/)) {
+ // IE gets an OBJECT tag
+ var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
+ }
+ else {
+ // all other browsers get an EMBED tag
+ html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
+ }
+ return html;
+ },
+
+ hide: function() {
+ // temporarily hide floater offscreen
+ if (this.div) {
+ this.div.style.left = '-2000px';
+ }
+ },
+
+ show: function() {
+ // show ourselves after a call to hide()
+ this.reposition();
+ },
+
+ destroy: function() {
+ // destroy control and floater
+ if (this.domElement && this.div) {
+ this.hide();
+ this.div.innerHTML = '';
+
+ var body = document.getElementsByTagName('body')[0];
+ try { body.removeChild( this.div ); } catch(e) {;}
+
+ this.domElement = null;
+ this.div = null;
+ }
+ },
+
+ reposition: function(elem) {
+ // reposition our floating div, optionally to new container
+ // warning: container CANNOT change size, only position
+ if (elem) {
+ this.domElement = ZeroClipboard.$(elem);
+ if (!this.domElement) this.hide();
+ }
+
+ if (this.domElement && this.div) {
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+ var style = this.div.style;
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ }
+ },
+
+ setText: function(newText) {
+ // set text to be copied to clipboard
+ this.clipText = newText;
+ if (this.ready) this.movie.setText(newText);
+ },
+
+ addEventListener: function(eventName, func) {
+ // add user event listener for event
+ // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+ if (!this.handlers[eventName]) this.handlers[eventName] = [];
+ this.handlers[eventName].push(func);
+ },
+
+ setHandCursor: function(enabled) {
+ // enable hand cursor (true), or default arrow cursor (false)
+ this.handCursorEnabled = enabled;
+ if (this.ready) this.movie.setHandCursor(enabled);
+ },
+
+ setCSSEffects: function(enabled) {
+ // enable or disable CSS effects on DOM container
+ this.cssEffects = !!enabled;
+ },
+
+ receiveEvent: function(eventName, args) {
+ // receive event from flash
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+
+ // special behavior for certain events
+ switch (eventName) {
+ case 'load':
+ // movie claims it is ready, but in IE this isn't always the case...
+ // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
+ this.movie = document.getElementById(this.movieId);
+ if (!this.movie) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 1 );
+ return;
+ }
+
+ // firefox on pc needs a "kick" in order to set these in certain cases
+ if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 100 );
+ this.ready = true;
+ return;
+ }
+
+ this.ready = true;
+ this.movie.setText( this.clipText );
+ this.movie.setHandCursor( this.handCursorEnabled );
+ break;
+
+ case 'mouseover':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('hover');
+ if (this.recoverActive) this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseout':
+ if (this.domElement && this.cssEffects) {
+ this.recoverActive = false;
+ if (this.domElement.hasClass('active')) {
+ this.domElement.removeClass('active');
+ this.recoverActive = true;
+ }
+ this.domElement.removeClass('hover');
+ }
+ break;
+
+ case 'mousedown':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseup':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.removeClass('active');
+ this.recoverActive = false;
+ }
+ break;
+ } // switch eventName
+
+ if (this.handlers[eventName]) {
+ for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
+ var func = this.handlers[eventName][idx];
+
+ if (typeof(func) == 'function') {
+ // actual function reference
+ func(this, args);
+ }
+ else if ((typeof(func) == 'object') && (func.length == 2)) {
+ // PHP style object + method, i.e. [myObject, 'myMethod']
+ func[0][ func[1] ](this, args);
+ }
+ else if (typeof(func) == 'string') {
+ // name of function
+ window[func](this, args);
+ }
+ } // foreach event handler defined
+ } // user defined handler for event
+ }
+
+};
diff --git a/libgpl/gibberish/GibberishAES.php b/libgpl/gibberish/GibberishAES.php new file mode 100644 index 0000000..8ce069a --- /dev/null +++ b/libgpl/gibberish/GibberishAES.php @@ -0,0 +1,213 @@ +<?php
+
+/**
+ * Gibberish AES, a PHP Implementation
+ *
+ * @author Ivan Tcholakov <ivantcholakov@gmail.com>, 2012-2013.
+ * @link https://github.com/ivantcholakov/gibberish-aes-php
+ *
+ * @license The MIT License (MIT)
+ * @link http://opensource.org/licenses/MIT
+ *
+ * This class is based on initial code proposed by nbari at dalmp dot com
+ * @link http://www.php.net/manual/en/function.openssl-decrypt.php#107210
+ *
+ * See also Gibberish AES javascript encryption library
+ * @link https://github.com/mdp/gibberish-aes
+ *
+ * Requirements:
+ *
+ * OpenSSL functions installed and PHP version >= 5.3.3 (preferred case)
+ * or
+ * Mcrypt functions installed.
+ *
+ * Usage:
+ *
+ * // This is a secret key, keep it in a safe place and don't loose it.
+ * $key = 'my secret key';
+ *
+ * // The string to be encrypted.
+ * $string = 'my secret message';
+ *
+ * // This is the result after encryption of the given string.
+ * $encrypted_string = GibberishAES::enc($string, $key);
+ *
+ * // This is the result after decryption of the previously encrypted string.
+ * // $decrypted_string == $string (should be).
+ * $decrypted_string = GibberishAES::dec($encrypted_string, $key);
+ *
+ */
+
+class GibberishAES {
+
+ protected static $openssl_random_pseudo_bytes_exists;
+ protected static $openssl_encrypt_exists;
+ protected static $openssl_decrypt_exists;
+
+ // This is a static class, instances are disabled.
+ final private function __construct() {}
+ final private function __clone() {}
+
+ /**
+ * Crypt AES 256
+ *
+ * @param data $string
+ * @param string $pass
+ * @return base64 encrypted string
+ */
+ public static function enc($string, $pass) {
+
+ // Set a random salt.
+ $salt = self::random_pseudo_bytes(8);
+
+ $salted = '';
+ $dx = '';
+
+ // Salt the key(32) and iv(16) = 48
+ while (strlen($salted) < 48) {
+ $dx = md5($dx.$pass.$salt, true);
+ $salted .= $dx;
+ }
+
+ $key = substr($salted, 0, 32);
+ $iv = substr($salted, 32, 16);
+
+ return base64_encode('Salted__' . $salt . self::aes_256_cbc_encrypt($string, $key, $iv));
+ }
+
+ /**
+ * Decrypt AES 256
+ *
+ * @param data $string
+ * @param string $pass
+ * @return dencrypted string
+ */
+ public static function dec($string, $pass) {
+
+ $data = base64_decode($string);
+ $salt = substr($data, 8, 8);
+ $ct = substr($data, 16);
+
+ /**
+ * From https://github.com/mdp/gibberish-aes
+ *
+ * Number of rounds depends on the size of the AES in use
+ * 3 rounds for 256
+ * 2 rounds for the key, 1 for the IV
+ * 2 rounds for 128
+ * 1 round for the key, 1 round for the IV
+ * 3 rounds for 192 since it's not evenly divided by 128 bits
+ */
+ $rounds = 3;
+ $data00 = $pass.$salt;
+ $md5_hash = array();
+ $md5_hash[0] = md5($data00, true);
+ $result = $md5_hash[0];
+ for ($i = 1; $i < $rounds; $i++) {
+ $md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true);
+ $result .= $md5_hash[$i];
+ }
+ $key = substr($result, 0, 32);
+ $iv = substr($result, 32, 16);
+
+ return self::aes_256_cbc_decrypt($ct, $key, $iv);
+ }
+
+ // Non-public methods ------------------------------------------------------
+
+ protected static function random_pseudo_bytes($length) {
+
+ if (!isset(self::$openssl_random_pseudo_bytes_exists)) {
+ self::$openssl_random_pseudo_bytes_exists = function_exists('openssl_random_pseudo_bytes');
+ }
+
+ if (self::$openssl_random_pseudo_bytes_exists) {
+ return openssl_random_pseudo_bytes($length);
+ }
+
+ // Borrowed from http://phpseclib.com/
+ $rnd = '';
+ for ($i = 0; $i < $length; $i++) {
+ $sha = hash('sha256', mt_rand());
+ $char = mt_rand(0, 30);
+ $rnd .= chr(hexdec($sha[$char].$sha[$char + 1]));
+ }
+ return $rnd;
+ }
+
+ protected static function aes_256_cbc_encrypt($string, $key, $iv) {
+
+ if (!isset(self::$openssl_encrypt_exists)) {
+ self::$openssl_encrypt_exists = function_exists('openssl_encrypt')
+ && version_compare(PHP_VERSION, '5.3.3', '>='); // We need $iv parameter.
+ }
+
+ if (self::$openssl_encrypt_exists) {
+ return openssl_encrypt($string, 'aes-256-cbc', $key, true, $iv);
+ }
+
+ // Info: http://www.chilkatsoft.com/p/php_aes.asp
+ $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+
+ if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
+ $encrypted = mcrypt_generic($cipher, self::pkcs7_pad($string));
+ mcrypt_generic_deinit($cipher);
+ mcrypt_module_close($cipher);
+ return $encrypted;
+ }
+
+ return false;
+ }
+
+ protected static function aes_256_cbc_decrypt($crypted, $key, $iv) {
+
+ if (!isset(self::$openssl_decrypt_exists)) {
+ self::$openssl_decrypt_exists = function_exists('openssl_decrypt')
+ && version_compare(PHP_VERSION, '5.3.3', '>='); // We need $iv parameter.
+ }
+
+ if (self::$openssl_decrypt_exists) {
+ return openssl_decrypt($crypted, 'aes-256-cbc', $key, true, $iv);
+ }
+
+ $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+
+ if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
+ $decrypted = mdecrypt_generic($cipher, $crypted);
+ mcrypt_generic_deinit($cipher);
+ mcrypt_module_close($cipher);
+ return self::remove_pkcs7_pad($decrypted);
+ }
+
+ return false;
+ }
+
+ // See http://www.php.net/manual/en/function.mcrypt-decrypt.php#105985
+ protected static function pkcs7_pad($string) {
+
+ $blocksize = 16; // 128 bits: $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+ $pad = $blocksize - (strlen($string) % $blocksize);
+ return $string.str_repeat(chr($pad), $pad);
+ }
+
+ protected static function remove_pkcs7_pad($string) {
+
+ $blocksize = 16; // 128 bits: $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+ $len = strlen($string);
+ $pad = ord($string[$len - 1]);
+ if ($pad > 0 && $pad <= $blocksize) {
+ $valid_pad = true;
+ for ($i = 1; $i <= $pad; $i++) {
+ if (ord($string[$len - $i]) != $pad) {
+ $valid_pad = false;
+ break;
+ }
+ }
+ if ($valid_pad) {
+ $string = substr($string, 0, $len - $pad);
+ }
+ }
+ return $string;
+ }
+
+}
\ No newline at end of file diff --git a/libgpl/gibberish/gibberish-aes.js b/libgpl/gibberish/gibberish-aes.js new file mode 100644 index 0000000..f1b836b --- /dev/null +++ b/libgpl/gibberish/gibberish-aes.js @@ -0,0 +1,36 @@ +/* + Gibberish-AES + A lightweight Javascript Libray for OpenSSL compatible AES CBC encryption. + + Author: Mark Percival + Email: mark@mpercival.com + Copyright: Mark Percival - http://mpercival.com 2008 + + With thanks to: + Josh Davis - http://www.josh-davis.org/ecmaScrypt + Chris Veness - http://www.movable-type.co.uk/scripts/aes.html + Michel I. Gallant - http://www.jensign.com/ + Jean-Luc Cooke <jlcooke@certainkey.com> 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString, also made the MD5 routine more easlier compressible using yuicompressor. + + License: MIT + + Usage: GibberishAES.enc("secret", "password") + Outputs: AES Encrypted text encoded in Base64 +*/ +(function(r,n){"object"===typeof exports?module.exports=n():"function"===typeof define&&define.amd?define(n):r.GibberishAES=n()})(this,function(){var r=14,n=8,u=!1,O=function(a,d){var b="",c,k;if(d){c=a[15];if(16<c)throw"Decryption error: Maybe bad key";if(16===c)return"";for(k=0;k<16-c;k++)b+=String.fromCharCode(a[k])}else for(k=0;16>k;k++)b+=String.fromCharCode(a[k]);return b},z=function(a,d){var b=[],c;if(!d)try{a=unescape(encodeURIComponent(a))}catch(k){throw"Error on UTF-8 encode";}for(c=0;c< +a.length;c++)b[c]=a.charCodeAt(c);return b},K=function(a,d){var b=12<=r?3:2,c=[],k=[],c=[],k=[],m=a.concat(d),p;c[0]=J(m);k=c[0];for(p=1;p<b;p++)c[p]=J(c[p-1].concat(m)),k=k.concat(c[p]);c=k.slice(0,4*n);k=k.slice(4*n,4*n+16);return{key:c,iv:k}},Q=function(a,d,b){d=L(d);var c=Math.ceil(a.length/16),k=[],m,p=[];for(m=0;m<c;m++){var j=k,t=m,n=a.slice(16*m,16*m+16),s=[],q=void 0,q=void 0;16>n.length&&(q=16-n.length,s=[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]);for(q=0;q<n.length;q++)s[q]=n[q];j[t]=s}0===a.length% +16&&k.push([16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);for(m=0;m<k.length;m++)k[m]=0===m?A(k[m],b):A(k[m],p[m-1]),p[m]=P(k[m],d);return p},S=function(a,d,b,c){d=L(d);var k=a.length/16,m=[],p,j=[],t="";for(p=0;p<k;p++)m.push(a.slice(16*p,16*(p+1)));for(p=m.length-1;0<=p;p--)j[p]=R(m[p],d),j[p]=0===p?A(j[p],b):A(j[p],m[p-1]);for(p=0;p<k-1;p++)t+=O(j[p]);var t=t+O(j[p],!0),n;if(c)n=t;else try{n=decodeURIComponent(escape(t))}catch(s){throw"Bad Key";}return n},P=function(a,d){u=!1;var b=B(a,d,0), +c;for(c=1;c<r+1;c++)b=T(b),b=U(b),c<r&&(b=V(b)),b=B(b,d,c);return b},R=function(a,d){u=!0;var b=B(a,d,r),c;for(c=r-1;-1<c;c--)b=U(b),b=T(b),b=B(b,d,c),0<c&&(b=V(b));return b},T=function(a){var d=u?W:M,b=[],c;for(c=0;16>c;c++)b[c]=d[a[c]];return b},U=function(a){var d=[],b=u?[0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3]:[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11],c;for(c=0;16>c;c++)d[c]=a[b[c]];return d},V=function(a){var d=[],b;if(u)for(b=0;4>b;b++)d[4*b]=C[a[4*b]]^D[a[1+4*b]]^E[a[2+4*b]]^F[a[3+4*b]],d[1+4* +b]=F[a[4*b]]^C[a[1+4*b]]^D[a[2+4*b]]^E[a[3+4*b]],d[2+4*b]=E[a[4*b]]^F[a[1+4*b]]^C[a[2+4*b]]^D[a[3+4*b]],d[3+4*b]=D[a[4*b]]^E[a[1+4*b]]^F[a[2+4*b]]^C[a[3+4*b]];else for(b=0;4>b;b++)d[4*b]=G[a[4*b]]^H[a[1+4*b]]^a[2+4*b]^a[3+4*b],d[1+4*b]=a[4*b]^G[a[1+4*b]]^H[a[2+4*b]]^a[3+4*b],d[2+4*b]=a[4*b]^a[1+4*b]^G[a[2+4*b]]^H[a[3+4*b]],d[3+4*b]=H[a[4*b]]^a[1+4*b]^a[2+4*b]^G[a[3+4*b]];return d},B=function(a,d,b){var c=[],k;for(k=0;16>k;k++)c[k]=a[k]^d[b][k];return c},A=function(a,d){var b=[],c;for(c=0;16>c;c++)b[c]= +a[c]^d[c];return b},L=function(a){var d=[],b=[],c,k,m=[];for(c=0;c<n;c++)k=[a[4*c],a[4*c+1],a[4*c+2],a[4*c+3]],d[c]=k;for(c=n;c<4*(r+1);c++){d[c]=[];for(a=0;4>a;a++)b[a]=d[c-1][a];if(0===c%n){a=b[0];k=void 0;for(k=0;3>k;k++)b[k]=b[k+1];b[3]=a;b=X(b);b[0]^=$[c/n-1]}else 6<n&&4===c%n&&(b=X(b));for(a=0;4>a;a++)d[c][a]=d[c-n][a]^b[a]}for(c=0;c<r+1;c++){m[c]=[];for(b=0;4>b;b++)m[c].push(d[4*c+b][0],d[4*c+b][1],d[4*c+b][2],d[4*c+b][3])}return m},X=function(a){for(var d=0;4>d;d++)a[d]=M[a[d]];return a}, +N=function(a,d){var b,c=[];for(b=0;b<a.length;b+=d)c[b/d]=parseInt(a.substr(b,d),16);return c},v=function(a){var d,b=[];for(d=0;256>d;d++){for(var c=b,k=d,m=a,p=d,j=void 0,n=void 0,j=n=0;8>j;j++)n=1===(p&1)?n^m:n,m=127<m?283^m<<1:m<<1,p>>>=1;c[k]=n}return b},M=N("637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16", +2),W,Y=M,x,Z=[];for(x=0;x<Y.length;x++)Z[Y[x]]=x;W=Z;var $=N("01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591",2),G=v(2),H=v(3),F=v(9),D=v(11),E=v(13),C=v(14),J=function(a){function d(a,b){var c,d,e,g,f;e=a&2147483648;g=b&2147483648;c=a&1073741824;d=b&1073741824;f=(a&1073741823)+(b&1073741823);return c&d?f^2147483648^e^g:c|d?f&1073741824?f^3221225472^e^g:f^1073741824^e^g:f^e^g}function b(a,b,c,e,f,g,h){a=d(a,d(d(b&c|~b&e,f),h));return d(a<<g|a>>>32-g,b)}function c(a,b,c,e,g,f,h){a=d(a, +d(d(b&e|c&~e,g),h));return d(a<<f|a>>>32-f,b)}function k(a,b,c,e,f,g,h){a=d(a,d(d(b^c^e,f),h));return d(a<<g|a>>>32-g,b)}function m(a,b,c,e,g,f,h){a=d(a,d(d(c^(b|~e),g),h));return d(a<<f|a>>>32-f,b)}function p(a){var b,c,d=[];for(c=0;3>=c;c++)b=a>>>8*c&255,d=d.concat(b);return d}var j=[],n,r,s,q,e,g,f,h,l=N("67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391", +8),j=a.length;n=j+8;r=16*((n-n%64)/64+1);s=[];for(e=q=0;e<j;)n=(e-e%4)/4,q=8*(e%4),s[n]|=a[e]<<q,e++;n=(e-e%4)/4;s[n]|=128<<8*(e%4);s[r-2]=j<<3;s[r-1]=j>>>29;j=s;e=l[0];g=l[1];f=l[2];h=l[3];for(a=0;a<j.length;a+=16)n=e,r=g,s=f,q=h,e=b(e,g,f,h,j[a+0],7,l[4]),h=b(h,e,g,f,j[a+1],12,l[5]),f=b(f,h,e,g,j[a+2],17,l[6]),g=b(g,f,h,e,j[a+3],22,l[7]),e=b(e,g,f,h,j[a+4],7,l[8]),h=b(h,e,g,f,j[a+5],12,l[9]),f=b(f,h,e,g,j[a+6],17,l[10]),g=b(g,f,h,e,j[a+7],22,l[11]),e=b(e,g,f,h,j[a+8],7,l[12]),h=b(h,e,g,f,j[a+9], +12,l[13]),f=b(f,h,e,g,j[a+10],17,l[14]),g=b(g,f,h,e,j[a+11],22,l[15]),e=b(e,g,f,h,j[a+12],7,l[16]),h=b(h,e,g,f,j[a+13],12,l[17]),f=b(f,h,e,g,j[a+14],17,l[18]),g=b(g,f,h,e,j[a+15],22,l[19]),e=c(e,g,f,h,j[a+1],5,l[20]),h=c(h,e,g,f,j[a+6],9,l[21]),f=c(f,h,e,g,j[a+11],14,l[22]),g=c(g,f,h,e,j[a+0],20,l[23]),e=c(e,g,f,h,j[a+5],5,l[24]),h=c(h,e,g,f,j[a+10],9,l[25]),f=c(f,h,e,g,j[a+15],14,l[26]),g=c(g,f,h,e,j[a+4],20,l[27]),e=c(e,g,f,h,j[a+9],5,l[28]),h=c(h,e,g,f,j[a+14],9,l[29]),f=c(f,h,e,g,j[a+3],14,l[30]), +g=c(g,f,h,e,j[a+8],20,l[31]),e=c(e,g,f,h,j[a+13],5,l[32]),h=c(h,e,g,f,j[a+2],9,l[33]),f=c(f,h,e,g,j[a+7],14,l[34]),g=c(g,f,h,e,j[a+12],20,l[35]),e=k(e,g,f,h,j[a+5],4,l[36]),h=k(h,e,g,f,j[a+8],11,l[37]),f=k(f,h,e,g,j[a+11],16,l[38]),g=k(g,f,h,e,j[a+14],23,l[39]),e=k(e,g,f,h,j[a+1],4,l[40]),h=k(h,e,g,f,j[a+4],11,l[41]),f=k(f,h,e,g,j[a+7],16,l[42]),g=k(g,f,h,e,j[a+10],23,l[43]),e=k(e,g,f,h,j[a+13],4,l[44]),h=k(h,e,g,f,j[a+0],11,l[45]),f=k(f,h,e,g,j[a+3],16,l[46]),g=k(g,f,h,e,j[a+6],23,l[47]),e=k(e,g, +f,h,j[a+9],4,l[48]),h=k(h,e,g,f,j[a+12],11,l[49]),f=k(f,h,e,g,j[a+15],16,l[50]),g=k(g,f,h,e,j[a+2],23,l[51]),e=m(e,g,f,h,j[a+0],6,l[52]),h=m(h,e,g,f,j[a+7],10,l[53]),f=m(f,h,e,g,j[a+14],15,l[54]),g=m(g,f,h,e,j[a+5],21,l[55]),e=m(e,g,f,h,j[a+12],6,l[56]),h=m(h,e,g,f,j[a+3],10,l[57]),f=m(f,h,e,g,j[a+10],15,l[58]),g=m(g,f,h,e,j[a+1],21,l[59]),e=m(e,g,f,h,j[a+8],6,l[60]),h=m(h,e,g,f,j[a+15],10,l[61]),f=m(f,h,e,g,j[a+6],15,l[62]),g=m(g,f,h,e,j[a+13],21,l[63]),e=m(e,g,f,h,j[a+4],6,l[64]),h=m(h,e,g,f,j[a+ +11],10,l[65]),f=m(f,h,e,g,j[a+2],15,l[66]),g=m(g,f,h,e,j[a+9],21,l[67]),e=d(e,n),g=d(g,r),f=d(f,s),h=d(h,q);return p(e).concat(p(g),p(f),p(h))},I,w="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",y=w.split("");"function"===typeof Array.indexOf&&(w=y);I={encode:function(a){var d=[],b="",c;for(c=0;c<16*a.length;c++)d.push(a[Math.floor(c/16)][c%16]);for(c=0;c<d.length;c+=3)b+=y[d[c]>>2],b+=y[(d[c]&3)<<4|d[c+1]>>4],b=void 0!==d[c+1]?b+y[(d[c+1]&15)<<2|d[c+2]>>6]:b+"=",b=void 0!==d[c+ +2]?b+y[d[c+2]&63]:b+"=";a=b.slice(0,64)+"\n";for(c=1;c<Math.ceil(b.length/64);c++)a+=b.slice(64*c,64*c+64)+(Math.ceil(b.length/64)===c+1?"":"\n");return a},decode:function(a){a=a.replace(/\n/g,"");var d=[],b=[],c=[],k;for(k=0;k<a.length;k+=4)b[0]=w.indexOf(a.charAt(k)),b[1]=w.indexOf(a.charAt(k+1)),b[2]=w.indexOf(a.charAt(k+2)),b[3]=w.indexOf(a.charAt(k+3)),c[0]=b[0]<<2|b[1]>>4,c[1]=(b[1]&15)<<4|b[2]>>2,c[2]=(b[2]&3)<<6|b[3],d.push(c[0],c[1],c[2]);return d=d.slice(0,d.length-d.length%16)}};return{size:function(a){switch(a){case 128:r= +10;n=4;break;case 192:r=12;n=6;break;case 256:r=14;n=8;break;default:throw"Invalid Key Size Specified:"+a;}},h2a:function(a){var d=[];a.replace(/(..)/g,function(a){d.push(parseInt(a,16))});return d},expandKey:L,encryptBlock:P,decryptBlock:R,Decrypt:u,s2a:z,rawEncrypt:Q,rawDecrypt:S,dec:function(a,d,b){a=I.decode(a);var c=a.slice(8,16),c=K(z(d,b),c);d=c.key;c=c.iv;a=a.slice(16,a.length);return a=S(a,d,c,b)},openSSLKey:K,a2h:function(a){var d="",b;for(b=0;b<a.length;b++)d+=(16>a[b]?"0":"")+a[b].toString(16); +return d},enc:function(a,d,b){var c;c=[];var k;for(k=0;8>k;k++)c=c.concat(Math.floor(256*Math.random()));k=K(z(d,b),c);d=k.key;k=k.iv;c=[[83,97,108,116,101,100,95,95].concat(c)];a=z(a,b);a=Q(a,d,k);a=c.concat(a);return I.encode(a)},Hash:{MD5:J},Base64:I}});
\ No newline at end of file diff --git a/libgpl/gibberish/gibberish-aes.js.comp.src b/libgpl/gibberish/gibberish-aes.js.comp.src new file mode 100644 index 0000000..ca7f01f --- /dev/null +++ b/libgpl/gibberish/gibberish-aes.js.comp.src @@ -0,0 +1,1017 @@ +/**
+* @license Gibberish-AES
+* A lightweight Javascript Libray for OpenSSL compatible AES CBC encryption.
+*
+* Author: Mark Percival
+* Email: mark@mpercival.com
+* Copyright: Mark Percival - http://mpercival.com 2008
+*
+* With thanks to:
+* Josh Davis - http://www.josh-davis.org/ecmaScrypt
+* Chris Veness - http://www.movable-type.co.uk/scripts/aes.html
+* Michel I. Gallant - http://www.jensign.com/
+* Jean-Luc Cooke <jlcooke@certainkey.com> 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString, also made the MD5 routine more easlier compressible using yuicompressor.
+*
+* License: MIT
+*
+* Usage: GibberishAES.enc("secret", "password")
+* Outputs: AES Encrypted text encoded in Base64
+*/
+
+
+(function (root, factory) {
+ if (typeof exports === 'object') {
+ // Node.
+ module.exports = factory();
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(factory);
+ } else {
+ // Browser globals (root is window)
+ root.GibberishAES = factory();
+ }
+}(this, function () {
+ 'use strict';
+
+ var Nr = 14,
+ /* Default to 256 Bit Encryption */
+ Nk = 8,
+ Decrypt = false,
+
+ enc_utf8 = function(s)
+ {
+ try {
+ return unescape(encodeURIComponent(s));
+ }
+ catch(e) {
+ throw 'Error on UTF-8 encode';
+ }
+ },
+
+ dec_utf8 = function(s)
+ {
+ try {
+ return decodeURIComponent(escape(s));
+ }
+ catch(e) {
+ throw ('Bad Key');
+ }
+ },
+
+ padBlock = function(byteArr)
+ {
+ var array = [], cpad, i;
+ if (byteArr.length < 16) {
+ cpad = 16 - byteArr.length;
+ array = [cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad];
+ }
+ for (i = 0; i < byteArr.length; i++)
+ {
+ array[i] = byteArr[i];
+ }
+ return array;
+ },
+
+ block2s = function(block, lastBlock)
+ {
+ var string = '', padding, i;
+ if (lastBlock) {
+ padding = block[15];
+ if (padding > 16) {
+ throw ('Decryption error: Maybe bad key');
+ }
+ if (padding === 16) {
+ return '';
+ }
+ for (i = 0; i < 16 - padding; i++) {
+ string += String.fromCharCode(block[i]);
+ }
+ } else {
+ for (i = 0; i < 16; i++) {
+ string += String.fromCharCode(block[i]);
+ }
+ }
+ return string;
+ },
+
+ a2h = function(numArr)
+ {
+ var string = '', i;
+ for (i = 0; i < numArr.length; i++) {
+ string += (numArr[i] < 16 ? '0': '') + numArr[i].toString(16);
+ }
+ return string;
+ },
+
+ h2a = function(s)
+ {
+ var ret = [];
+ s.replace(/(..)/g,
+ function(s) {
+ ret.push(parseInt(s, 16));
+ });
+ return ret;
+ },
+
+ s2a = function(string, binary) {
+ var array = [], i;
+
+ if (! binary) {
+ string = enc_utf8(string);
+ }
+
+ for (i = 0; i < string.length; i++)
+ {
+ array[i] = string.charCodeAt(i);
+ }
+
+ return array;
+ },
+
+ size = function(newsize)
+ {
+ switch (newsize)
+ {
+ case 128:
+ Nr = 10;
+ Nk = 4;
+ break;
+ case 192:
+ Nr = 12;
+ Nk = 6;
+ break;
+ case 256:
+ Nr = 14;
+ Nk = 8;
+ break;
+ default:
+ throw ('Invalid Key Size Specified:' + newsize);
+ }
+ },
+
+ randArr = function(num) {
+ var result = [], i;
+ for (i = 0; i < num; i++) {
+ result = result.concat(Math.floor(Math.random() * 256));
+ }
+ return result;
+ },
+
+ openSSLKey = function(passwordArr, saltArr) {
+ // Number of rounds depends on the size of the AES in use
+ // 3 rounds for 256
+ // 2 rounds for the key, 1 for the IV
+ // 2 rounds for 128
+ // 1 round for the key, 1 round for the IV
+ // 3 rounds for 192 since it's not evenly divided by 128 bits
+ var rounds = Nr >= 12 ? 3: 2,
+ key = [],
+ iv = [],
+ md5_hash = [],
+ result = [],
+ data00 = passwordArr.concat(saltArr),
+ i;
+ md5_hash[0] = MD5(data00);
+ result = md5_hash[0];
+ for (i = 1; i < rounds; i++) {
+ md5_hash[i] = MD5(md5_hash[i - 1].concat(data00));
+ result = result.concat(md5_hash[i]);
+ }
+ key = result.slice(0, 4 * Nk);
+ iv = result.slice(4 * Nk, 4 * Nk + 16);
+ return {
+ key: key,
+ iv: iv
+ };
+ },
+
+ rawEncrypt = function(plaintext, key, iv) {
+ // plaintext, key and iv as byte arrays
+ key = expandKey(key);
+ var numBlocks = Math.ceil(plaintext.length / 16),
+ blocks = [],
+ i,
+ cipherBlocks = [];
+ for (i = 0; i < numBlocks; i++) {
+ blocks[i] = padBlock(plaintext.slice(i * 16, i * 16 + 16));
+ }
+ if (plaintext.length % 16 === 0) {
+ blocks.push([16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]);
+ // CBC OpenSSL padding scheme
+ numBlocks++;
+ }
+ for (i = 0; i < blocks.length; i++) {
+ blocks[i] = (i === 0) ? xorBlocks(blocks[i], iv) : xorBlocks(blocks[i], cipherBlocks[i - 1]);
+ cipherBlocks[i] = encryptBlock(blocks[i], key);
+ }
+ return cipherBlocks;
+ },
+
+ rawDecrypt = function(cryptArr, key, iv, binary) {
+ // cryptArr, key and iv as byte arrays
+ key = expandKey(key);
+ var numBlocks = cryptArr.length / 16,
+ cipherBlocks = [],
+ i,
+ plainBlocks = [],
+ string = '';
+ for (i = 0; i < numBlocks; i++) {
+ cipherBlocks.push(cryptArr.slice(i * 16, (i + 1) * 16));
+ }
+ for (i = cipherBlocks.length - 1; i >= 0; i--) {
+ plainBlocks[i] = decryptBlock(cipherBlocks[i], key);
+ plainBlocks[i] = (i === 0) ? xorBlocks(plainBlocks[i], iv) : xorBlocks(plainBlocks[i], cipherBlocks[i - 1]);
+ }
+ for (i = 0; i < numBlocks - 1; i++) {
+ string += block2s(plainBlocks[i]);
+ }
+ string += block2s(plainBlocks[i], true);
+ return binary ? string : dec_utf8(string);
+ },
+
+ encryptBlock = function(block, words) {
+ Decrypt = false;
+ var state = addRoundKey(block, words, 0),
+ round;
+ for (round = 1; round < (Nr + 1); round++) {
+ state = subBytes(state);
+ state = shiftRows(state);
+ if (round < Nr) {
+ state = mixColumns(state);
+ }
+ //last round? don't mixColumns
+ state = addRoundKey(state, words, round);
+ }
+
+ return state;
+ },
+
+ decryptBlock = function(block, words) {
+ Decrypt = true;
+ var state = addRoundKey(block, words, Nr),
+ round;
+ for (round = Nr - 1; round > -1; round--) {
+ state = shiftRows(state);
+ state = subBytes(state);
+ state = addRoundKey(state, words, round);
+ if (round > 0) {
+ state = mixColumns(state);
+ }
+ //last round? don't mixColumns
+ }
+
+ return state;
+ },
+
+ subBytes = function(state) {
+ var S = Decrypt ? SBoxInv: SBox,
+ temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = S[state[i]];
+ }
+ return temp;
+ },
+
+ shiftRows = function(state) {
+ var temp = [],
+ shiftBy = Decrypt ? [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3] : [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = state[shiftBy[i]];
+ }
+ return temp;
+ },
+
+ mixColumns = function(state) {
+ var t = [],
+ c;
+ if (!Decrypt) {
+ for (c = 0; c < 4; c++) {
+ t[c * 4] = G2X[state[c * 4]] ^ G3X[state[1 + c * 4]] ^ state[2 + c * 4] ^ state[3 + c * 4];
+ t[1 + c * 4] = state[c * 4] ^ G2X[state[1 + c * 4]] ^ G3X[state[2 + c * 4]] ^ state[3 + c * 4];
+ t[2 + c * 4] = state[c * 4] ^ state[1 + c * 4] ^ G2X[state[2 + c * 4]] ^ G3X[state[3 + c * 4]];
+ t[3 + c * 4] = G3X[state[c * 4]] ^ state[1 + c * 4] ^ state[2 + c * 4] ^ G2X[state[3 + c * 4]];
+ }
+ }else {
+ for (c = 0; c < 4; c++) {
+ t[c*4] = GEX[state[c*4]] ^ GBX[state[1+c*4]] ^ GDX[state[2+c*4]] ^ G9X[state[3+c*4]];
+ t[1+c*4] = G9X[state[c*4]] ^ GEX[state[1+c*4]] ^ GBX[state[2+c*4]] ^ GDX[state[3+c*4]];
+ t[2+c*4] = GDX[state[c*4]] ^ G9X[state[1+c*4]] ^ GEX[state[2+c*4]] ^ GBX[state[3+c*4]];
+ t[3+c*4] = GBX[state[c*4]] ^ GDX[state[1+c*4]] ^ G9X[state[2+c*4]] ^ GEX[state[3+c*4]];
+ }
+ }
+
+ return t;
+ },
+
+ addRoundKey = function(state, words, round) {
+ var temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = state[i] ^ words[round][i];
+ }
+ return temp;
+ },
+
+ xorBlocks = function(block1, block2) {
+ var temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = block1[i] ^ block2[i];
+ }
+ return temp;
+ },
+
+ expandKey = function(key) {
+ // Expects a 1d number array
+ var w = [],
+ temp = [],
+ i,
+ r,
+ t,
+ flat = [],
+ j;
+
+ for (i = 0; i < Nk; i++) {
+ r = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]];
+ w[i] = r;
+ }
+
+ for (i = Nk; i < (4 * (Nr + 1)); i++) {
+ w[i] = [];
+ for (t = 0; t < 4; t++) {
+ temp[t] = w[i - 1][t];
+ }
+ if (i % Nk === 0) {
+ temp = subWord(rotWord(temp));
+ temp[0] ^= Rcon[i / Nk - 1];
+ } else if (Nk > 6 && i % Nk === 4) {
+ temp = subWord(temp);
+ }
+ for (t = 0; t < 4; t++) {
+ w[i][t] = w[i - Nk][t] ^ temp[t];
+ }
+ }
+ for (i = 0; i < (Nr + 1); i++) {
+ flat[i] = [];
+ for (j = 0; j < 4; j++) {
+ flat[i].push(w[i * 4 + j][0], w[i * 4 + j][1], w[i * 4 + j][2], w[i * 4 + j][3]);
+ }
+ }
+ return flat;
+ },
+
+ subWord = function(w) {
+ // apply SBox to 4-byte word w
+ for (var i = 0; i < 4; i++) {
+ w[i] = SBox[w[i]];
+ }
+ return w;
+ },
+
+ rotWord = function(w) {
+ // rotate 4-byte word w left by one byte
+ var tmp = w[0],
+ i;
+ for (i = 0; i < 3; i++) {
+ w[i] = w[i + 1];
+ }
+ w[3] = tmp;
+ return w;
+ },
+
+// jlcooke: 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString
+ strhex = function(str,size) {
+ var i, ret = [];
+ for (i=0; i<str.length; i+=size){
+ ret[i/size] = parseInt(str.substr(i,size), 16);
+ }
+ return ret;
+ },
+ invertArr = function(arr) {
+ var i, ret = [];
+ for (i=0; i<arr.length; i++){
+ ret[arr[i]] = i;
+ }
+ return ret;
+ },
+ Gxx = function(a, b) {
+ var i, ret;
+
+ ret = 0;
+ for (i=0; i<8; i++) {
+ ret = ((b&1)===1) ? ret^a : ret;
+ /* xmult */
+ a = (a>0x7f) ? 0x11b^(a<<1) : (a<<1);
+ b >>>= 1;
+ }
+
+ return ret;
+ },
+ Gx = function(x) {
+ var i, r = [];
+ for (i=0; i<256; i++){
+ r[i] = Gxx(x, i);
+ }
+ return r;
+ },
+
+ // S-box
+/*
+ SBox = [
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
+ 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
+ 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
+ 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
+ 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
+ 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
+ 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
+ 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
+ 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
+ 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
+ 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
+ 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
+ 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
+ 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
+ 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
+ 22], //*/ SBox = strhex('637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16',2),
+
+ // Precomputed lookup table for the inverse SBox
+/* SBoxInv = [
+ 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215,
+ 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222,
+ 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66,
+ 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73,
+ 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92,
+ 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21,
+ 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247,
+ 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220,
+ 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173,
+ 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29,
+ 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75,
+ 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168,
+ 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81,
+ 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160,
+ 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12,
+ 125], //*/ SBoxInv = invertArr(SBox),
+
+ // Rijndael Rcon
+/*
+ Rcon = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47, 94,
+ 188, 99, 198, 151, 53, 106, 212, 179, 125, 250, 239, 197, 145],
+//*/ Rcon = strhex('01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591',2),
+
+/*
+ G2X = [
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16,
+ 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
+ 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46,
+ 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76,
+ 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
+ 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6,
+ 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6,
+ 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
+ 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d,
+ 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
+ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d,
+ 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55,
+ 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d,
+ 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
+ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d,
+ 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5,
+ 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd,
+ 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
+ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed,
+ 0xe3, 0xe1, 0xe7, 0xe5
+ ], //*/ G2X = Gx(2),
+
+/* G3X = [
+ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d,
+ 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39,
+ 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65,
+ 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
+ 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d,
+ 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9,
+ 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5,
+ 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
+ 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd,
+ 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99,
+ 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e,
+ 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
+ 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6,
+ 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2,
+ 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce,
+ 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
+ 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46,
+ 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62,
+ 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e,
+ 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
+ 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16,
+ 0x1f, 0x1c, 0x19, 0x1a
+ ], //*/ G3X = Gx(3),
+
+/*
+ G9X = [
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53,
+ 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf,
+ 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20,
+ 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8,
+ 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49,
+ 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd,
+ 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
+ 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e,
+ 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2,
+ 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7,
+ 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
+ 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f,
+ 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8,
+ 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c,
+ 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
+ 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9,
+ 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35,
+ 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba,
+ 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
+ 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62,
+ 0x5d, 0x54, 0x4f, 0x46
+ ], //*/ G9X = Gx(9),
+
+/* GBX = [
+ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45,
+ 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81,
+ 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66,
+ 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
+ 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e,
+ 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7,
+ 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b,
+ 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
+ 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8,
+ 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c,
+ 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea,
+ 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
+ 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02,
+ 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd,
+ 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21,
+ 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
+ 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44,
+ 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80,
+ 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67,
+ 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
+ 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f,
+ 0xbe, 0xb5, 0xa8, 0xa3
+ ], //*/ GBX = Gx(0xb),
+
+/*
+ GDX = [
+ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f,
+ 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3,
+ 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac,
+ 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
+ 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14,
+ 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e,
+ 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa,
+ 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
+ 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9,
+ 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25,
+ 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd,
+ 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
+ 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75,
+ 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42,
+ 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6,
+ 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
+ 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8,
+ 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44,
+ 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b,
+ 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
+ 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3,
+ 0x80, 0x8d, 0x9a, 0x97
+ ], //*/ GDX = Gx(0xd),
+
+/*
+ GEX = [
+ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62,
+ 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca,
+ 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9,
+ 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
+ 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59,
+ 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87,
+ 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f,
+ 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
+ 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14,
+ 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc,
+ 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53,
+ 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
+ 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3,
+ 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0,
+ 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68,
+ 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
+ 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e,
+ 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26,
+ 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25,
+ 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
+ 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5,
+ 0x9f, 0x91, 0x83, 0x8d
+ ], //*/ GEX = Gx(0xe),
+
+ enc = function(string, pass, binary) {
+ // string, password in plaintext
+ var salt = randArr(8),
+ pbe = openSSLKey(s2a(pass, binary), salt),
+ key = pbe.key,
+ iv = pbe.iv,
+ cipherBlocks,
+ saltBlock = [[83, 97, 108, 116, 101, 100, 95, 95].concat(salt)];
+ string = s2a(string, binary);
+ cipherBlocks = rawEncrypt(string, key, iv);
+ // Spells out 'Salted__'
+ cipherBlocks = saltBlock.concat(cipherBlocks);
+ return Base64.encode(cipherBlocks);
+ },
+
+ dec = function(string, pass, binary) {
+ // string, password in plaintext
+ var cryptArr = Base64.decode(string),
+ salt = cryptArr.slice(8, 16),
+ pbe = openSSLKey(s2a(pass, binary), salt),
+ key = pbe.key,
+ iv = pbe.iv;
+ cryptArr = cryptArr.slice(16, cryptArr.length);
+ // Take off the Salted__ffeeddcc
+ string = rawDecrypt(cryptArr, key, iv, binary);
+ return string;
+ },
+
+ MD5 = function(numArr) {
+
+ function rotateLeft(lValue, iShiftBits) {
+ return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
+ }
+
+ function addUnsigned(lX, lY) {
+ var lX4,
+ lY4,
+ lX8,
+ lY8,
+ lResult;
+ lX8 = (lX & 0x80000000);
+ lY8 = (lY & 0x80000000);
+ lX4 = (lX & 0x40000000);
+ lY4 = (lY & 0x40000000);
+ lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
+ if (lX4 & lY4) {
+ return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
+ }
+ if (lX4 | lY4) {
+ if (lResult & 0x40000000) {
+ return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
+ } else {
+ return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
+ }
+ } else {
+ return (lResult ^ lX8 ^ lY8);
+ }
+ }
+
+ function f(x, y, z) {
+ return (x & y) | ((~x) & z);
+ }
+ function g(x, y, z) {
+ return (x & z) | (y & (~z));
+ }
+ function h(x, y, z) {
+ return (x ^ y ^ z);
+ }
+ function funcI(x, y, z) {
+ return (y ^ (x | (~z)));
+ }
+
+ function ff(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function gg(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function hh(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function ii(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(funcI(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function convertToWordArray(numArr) {
+ var lWordCount,
+ lMessageLength = numArr.length,
+ lNumberOfWords_temp1 = lMessageLength + 8,
+ lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64,
+ lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16,
+ lWordArray = [],
+ lBytePosition = 0,
+ lByteCount = 0;
+ while (lByteCount < lMessageLength) {
+ lWordCount = (lByteCount - (lByteCount % 4)) / 4;
+ lBytePosition = (lByteCount % 4) * 8;
+ lWordArray[lWordCount] = (lWordArray[lWordCount] | (numArr[lByteCount] << lBytePosition));
+ lByteCount++;
+ }
+ lWordCount = (lByteCount - (lByteCount % 4)) / 4;
+ lBytePosition = (lByteCount % 4) * 8;
+ lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
+ lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
+ lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
+ return lWordArray;
+ }
+
+ function wordToHex(lValue) {
+ var lByte,
+ lCount,
+ wordToHexArr = [];
+ for (lCount = 0; lCount <= 3; lCount++) {
+ lByte = (lValue >>> (lCount * 8)) & 255;
+ wordToHexArr = wordToHexArr.concat(lByte);
+ }
+ return wordToHexArr;
+ }
+
+ /*function utf8Encode(string) {
+ string = string.replace(/\r\n/g, "\n");
+ var utftext = "",
+ n,
+ c;
+
+ for (n = 0; n < string.length; n++) {
+
+ c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if ((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ }*/
+
+ var x = [],
+ k,
+ AA,
+ BB,
+ CC,
+ DD,
+ a,
+ b,
+ c,
+ d,
+ rnd = strhex('67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391',8);
+
+ x = convertToWordArray(numArr);
+
+ a = rnd[0];
+ b = rnd[1];
+ c = rnd[2];
+ d = rnd[3];
+
+ for (k = 0; k < x.length; k += 16) {
+ AA = a;
+ BB = b;
+ CC = c;
+ DD = d;
+ a = ff(a, b, c, d, x[k + 0], 7, rnd[4]);
+ d = ff(d, a, b, c, x[k + 1], 12, rnd[5]);
+ c = ff(c, d, a, b, x[k + 2], 17, rnd[6]);
+ b = ff(b, c, d, a, x[k + 3], 22, rnd[7]);
+ a = ff(a, b, c, d, x[k + 4], 7, rnd[8]);
+ d = ff(d, a, b, c, x[k + 5], 12, rnd[9]);
+ c = ff(c, d, a, b, x[k + 6], 17, rnd[10]);
+ b = ff(b, c, d, a, x[k + 7], 22, rnd[11]);
+ a = ff(a, b, c, d, x[k + 8], 7, rnd[12]);
+ d = ff(d, a, b, c, x[k + 9], 12, rnd[13]);
+ c = ff(c, d, a, b, x[k + 10], 17, rnd[14]);
+ b = ff(b, c, d, a, x[k + 11], 22, rnd[15]);
+ a = ff(a, b, c, d, x[k + 12], 7, rnd[16]);
+ d = ff(d, a, b, c, x[k + 13], 12, rnd[17]);
+ c = ff(c, d, a, b, x[k + 14], 17, rnd[18]);
+ b = ff(b, c, d, a, x[k + 15], 22, rnd[19]);
+ a = gg(a, b, c, d, x[k + 1], 5, rnd[20]);
+ d = gg(d, a, b, c, x[k + 6], 9, rnd[21]);
+ c = gg(c, d, a, b, x[k + 11], 14, rnd[22]);
+ b = gg(b, c, d, a, x[k + 0], 20, rnd[23]);
+ a = gg(a, b, c, d, x[k + 5], 5, rnd[24]);
+ d = gg(d, a, b, c, x[k + 10], 9, rnd[25]);
+ c = gg(c, d, a, b, x[k + 15], 14, rnd[26]);
+ b = gg(b, c, d, a, x[k + 4], 20, rnd[27]);
+ a = gg(a, b, c, d, x[k + 9], 5, rnd[28]);
+ d = gg(d, a, b, c, x[k + 14], 9, rnd[29]);
+ c = gg(c, d, a, b, x[k + 3], 14, rnd[30]);
+ b = gg(b, c, d, a, x[k + 8], 20, rnd[31]);
+ a = gg(a, b, c, d, x[k + 13], 5, rnd[32]);
+ d = gg(d, a, b, c, x[k + 2], 9, rnd[33]);
+ c = gg(c, d, a, b, x[k + 7], 14, rnd[34]);
+ b = gg(b, c, d, a, x[k + 12], 20, rnd[35]);
+ a = hh(a, b, c, d, x[k + 5], 4, rnd[36]);
+ d = hh(d, a, b, c, x[k + 8], 11, rnd[37]);
+ c = hh(c, d, a, b, x[k + 11], 16, rnd[38]);
+ b = hh(b, c, d, a, x[k + 14], 23, rnd[39]);
+ a = hh(a, b, c, d, x[k + 1], 4, rnd[40]);
+ d = hh(d, a, b, c, x[k + 4], 11, rnd[41]);
+ c = hh(c, d, a, b, x[k + 7], 16, rnd[42]);
+ b = hh(b, c, d, a, x[k + 10], 23, rnd[43]);
+ a = hh(a, b, c, d, x[k + 13], 4, rnd[44]);
+ d = hh(d, a, b, c, x[k + 0], 11, rnd[45]);
+ c = hh(c, d, a, b, x[k + 3], 16, rnd[46]);
+ b = hh(b, c, d, a, x[k + 6], 23, rnd[47]);
+ a = hh(a, b, c, d, x[k + 9], 4, rnd[48]);
+ d = hh(d, a, b, c, x[k + 12], 11, rnd[49]);
+ c = hh(c, d, a, b, x[k + 15], 16, rnd[50]);
+ b = hh(b, c, d, a, x[k + 2], 23, rnd[51]);
+ a = ii(a, b, c, d, x[k + 0], 6, rnd[52]);
+ d = ii(d, a, b, c, x[k + 7], 10, rnd[53]);
+ c = ii(c, d, a, b, x[k + 14], 15, rnd[54]);
+ b = ii(b, c, d, a, x[k + 5], 21, rnd[55]);
+ a = ii(a, b, c, d, x[k + 12], 6, rnd[56]);
+ d = ii(d, a, b, c, x[k + 3], 10, rnd[57]);
+ c = ii(c, d, a, b, x[k + 10], 15, rnd[58]);
+ b = ii(b, c, d, a, x[k + 1], 21, rnd[59]);
+ a = ii(a, b, c, d, x[k + 8], 6, rnd[60]);
+ d = ii(d, a, b, c, x[k + 15], 10, rnd[61]);
+ c = ii(c, d, a, b, x[k + 6], 15, rnd[62]);
+ b = ii(b, c, d, a, x[k + 13], 21, rnd[63]);
+ a = ii(a, b, c, d, x[k + 4], 6, rnd[64]);
+ d = ii(d, a, b, c, x[k + 11], 10, rnd[65]);
+ c = ii(c, d, a, b, x[k + 2], 15, rnd[66]);
+ b = ii(b, c, d, a, x[k + 9], 21, rnd[67]);
+ a = addUnsigned(a, AA);
+ b = addUnsigned(b, BB);
+ c = addUnsigned(c, CC);
+ d = addUnsigned(d, DD);
+ }
+
+ return wordToHex(a).concat(wordToHex(b), wordToHex(c), wordToHex(d));
+ },
+
+ encString = function(plaintext, key, iv) {
+ var i;
+ plaintext = s2a(plaintext);
+
+ key = s2a(key);
+ for (i=key.length; i<32; i++){
+ key[i] = 0;
+ }
+
+ if (iv === undefined) {
+ // TODO: This is not defined anywhere... commented out...
+ // iv = genIV();
+ } else {
+ iv = s2a(iv);
+ for (i=iv.length; i<16; i++){
+ iv[i] = 0;
+ }
+ }
+
+ var ct = rawEncrypt(plaintext, key, iv);
+ var ret = [iv];
+ for (i=0; i<ct.length; i++){
+ ret[ret.length] = ct[i];
+ }
+ return Base64.encode(ret);
+ },
+
+ decString = function(ciphertext, key) {
+ var tmp = Base64.decode(ciphertext);
+ var iv = tmp.slice(0, 16);
+ var ct = tmp.slice(16, tmp.length);
+ var i;
+
+ key = s2a(key);
+ for (i=key.length; i<32; i++){
+ key[i] = 0;
+ }
+
+ var pt = rawDecrypt(ct, key, iv, false);
+ return pt;
+ },
+
+ Base64 = (function(){
+ // Takes a Nx16x1 byte array and converts it to Base64
+ var _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
+ chars = _chars.split(''),
+
+ encode = function(b, withBreaks) {
+ var flatArr = [],
+ b64 = '',
+ i,
+ broken_b64,
+ totalChunks = Math.floor(b.length * 16 / 3);
+ for (i = 0; i < b.length * 16; i++) {
+ flatArr.push(b[Math.floor(i / 16)][i % 16]);
+ }
+ for (i = 0; i < flatArr.length; i = i + 3) {
+ b64 += chars[flatArr[i] >> 2];
+ b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)];
+ if ( flatArr[i + 1] !== undefined ) {
+ b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)];
+ } else {
+ b64 += '=';
+ }
+ if ( flatArr[i + 2] !== undefined ) {
+ b64 += chars[flatArr[i + 2] & 63];
+ } else {
+ b64 += '=';
+ }
+ }
+ // OpenSSL is super particular about line breaks
+ broken_b64 = b64.slice(0, 64) + '\n';
+ for (i = 1; i < (Math.ceil(b64.length / 64)); i++) {
+ broken_b64 += b64.slice(i * 64, i * 64 + 64) + (Math.ceil(b64.length / 64) === i + 1 ? '': '\n');
+ }
+ return broken_b64;
+ },
+
+ decode = function(string) {
+ string = string.replace(/\n/g, '');
+ var flatArr = [],
+ c = [],
+ b = [],
+ i;
+ for (i = 0; i < string.length; i = i + 4) {
+ c[0] = _chars.indexOf(string.charAt(i));
+ c[1] = _chars.indexOf(string.charAt(i + 1));
+ c[2] = _chars.indexOf(string.charAt(i + 2));
+ c[3] = _chars.indexOf(string.charAt(i + 3));
+
+ b[0] = (c[0] << 2) | (c[1] >> 4);
+ b[1] = ((c[1] & 15) << 4) | (c[2] >> 2);
+ b[2] = ((c[2] & 3) << 6) | c[3];
+ flatArr.push(b[0], b[1], b[2]);
+ }
+ flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16));
+ return flatArr;
+ };
+
+ //internet explorer
+ if(typeof Array.indexOf === "function") {
+ _chars = chars;
+ }
+
+ /*
+ //other way to solve internet explorer problem
+ if(!Array.indexOf){
+ Array.prototype.indexOf = function(obj){
+ for(var i=0; i<this.length; i++){
+ if(this[i]===obj){
+ return i;
+ }
+ }
+ return -1;
+ }
+ }
+ */
+
+
+ return {
+ "encode": encode,
+ "decode": decode
+ };
+ })();
+
+ return {
+ "size": size,
+ "h2a":h2a,
+ "expandKey":expandKey,
+ "encryptBlock":encryptBlock,
+ "decryptBlock":decryptBlock,
+ "Decrypt":Decrypt,
+ "s2a":s2a,
+ "rawEncrypt":rawEncrypt,
+ "rawDecrypt":rawDecrypt,
+ "dec":dec,
+ "openSSLKey":openSSLKey,
+ "a2h":a2h,
+ "enc":enc,
+ "Hash":{"MD5":MD5},
+ "Base64":Base64
+ };
+
+}));
\ No newline at end of file diff --git a/libgpl/http_request/class.http.php b/libgpl/http_request/class.http.php new file mode 100644 index 0000000..a41d070 --- /dev/null +++ b/libgpl/http_request/class.http.php @@ -0,0 +1,1190 @@ +<?php
+
+/**
+ * HTTP Class
+ *
+ * This is a wrapper HTTP class that uses either cURL or fsockopen to
+ * harvest resources from web. This can be used with scripts that need
+ * a way to communicate with various APIs who support REST.
+ *
+ * @author Md Emran Hasan <phpfour@gmail.com>
+ * @package HTTP Library
+ * @copyright 2007-2008 Md Emran Hasan
+ * @link http://www.phpfour.com/lib/http
+ * @since Version 0.1
+ */
+
+class MyRCHttp
+{
+ /**
+ * Contains the target URL
+ *
+ * @var string
+ */
+ var $target;
+
+ /**
+ * Contains the target host
+ *
+ * @var string
+ */
+ var $host;
+
+ /**
+ * Contains the target port
+ *
+ * @var integer
+ */
+ var $port;
+
+ /**
+ * Contains the target path
+ *
+ * @var string
+ */
+ var $path;
+
+ /**
+ * Contains the target schema
+ *
+ * @var string
+ */
+ var $schema;
+
+ /**
+ * Contains the http method (GET or POST)
+ *
+ * @var string
+ */
+ var $method;
+
+ /**
+ * Contains the parameters for request
+ *
+ * @var array
+ */
+ var $params;
+
+ /**
+ * Contains the cookies for request
+ *
+ * @var array
+ */
+ var $cookies;
+
+ /**
+ * Contains the cookies retrieved from response
+ *
+ * @var array
+ */
+ var $_cookies;
+
+ /**
+ * Number of seconds to timeout
+ *
+ * @var integer
+ */
+ var $timeout;
+
+ /**
+ * Whether to use cURL or not
+ *
+ * @var boolean
+ */
+ var $useCurl;
+
+ /**
+ * Contains the referrer URL
+ *
+ * @var string
+ */
+ var $referrer;
+
+ /**
+ * Contains the User agent string
+ *
+ * @var string
+ */
+ var $userAgent;
+
+ /**
+ * Contains the cookie path (to be used with cURL)
+ *
+ * @var string
+ */
+ var $cookiePath;
+
+ /**
+ * Whether to use cookie at all
+ *
+ * @var boolean
+ */
+ var $useCookie;
+
+ /**
+ * Whether to store cookie for subsequent requests
+ *
+ * @var boolean
+ */
+ var $saveCookie;
+
+ /**
+ * Contains the Username (for authentication)
+ *
+ * @var string
+ */
+ var $username;
+
+ /**
+ * Contains the Password (for authentication)
+ *
+ * @var string
+ */
+ var $password;
+
+ /**
+ * Contains the fetched web source
+ *
+ * @var string
+ */
+ var $result;
+
+ /**
+ * Contains the last headers
+ *
+ * @var string
+ */
+ var $headers;
+
+ /**
+ * Contains the last call's http status code
+ *
+ * @var string
+ */
+ var $status;
+
+ /**
+ * Whether to follow http redirect or not
+ *
+ * @var boolean
+ */
+ var $redirect;
+
+ /**
+ * The maximum number of redirect to follow
+ *
+ * @var integer
+ */
+ var $maxRedirect;
+
+ /**
+ * The current number of redirects
+ *
+ * @var integer
+ */
+ var $curRedirect;
+
+ /**
+ * Contains any error occurred
+ *
+ * @var string
+ */
+ var $error;
+
+ /**
+ * Store the next token
+ *
+ * @var string
+ */
+ var $nextToken;
+
+ /**
+ * Whether to keep debug messages
+ *
+ * @var boolean
+ */
+ var $debug;
+
+ /**
+ * Stores the debug messages
+ *
+ * @var array
+ * @todo will keep debug messages
+ */
+ var $debugMsg;
+
+ /**
+ * Constructor for initializing the class with default values.
+ *
+ * @return void
+ */
+ function Http()
+ {
+ $this->clear();
+ }
+
+ /**
+ * Initialize preferences
+ *
+ * This function will take an associative array of config values and
+ * will initialize the class variables using them.
+ *
+ * Example use:
+ *
+ * <pre>
+ * $httpConfig['method'] = 'GET';
+ * $httpConfig['target'] = 'http://www.somedomain.com/index.html';
+ * $httpConfig['referrer'] = 'http://www.somedomain.com';
+ * $httpConfig['user_agent'] = 'My Crawler';
+ * $httpConfig['timeout'] = '30';
+ * $httpConfig['params'] = array('var1' => 'testvalue', 'var2' => 'somevalue');
+ *
+ * $http = new Http();
+ * $http->initialize($httpConfig);
+ * </pre>
+ *
+ * @param array Config values as associative array
+ * @return void
+ */
+ function initialize($config = array())
+ {
+ $this->clear();
+ foreach ($config as $key => $val)
+ {
+ if (isset($this->$key))
+ {
+ $method = 'set' . ucfirst(str_replace('_', '', $key));
+
+ if (method_exists($this, $method))
+ {
+ $this->$method($val);
+ }
+ else
+ {
+ $this->$key = $val;
+ }
+ }
+ }
+ }
+
+ /**
+ * Clear Everything
+ *
+ * Clears all the properties of the class and sets the object to
+ * the beginning state. Very handy if you are doing subsequent calls
+ * with different data.
+ *
+ * @return void
+ */
+ function clear()
+ {
+ // Set the request defaults
+ $this->host = '';
+ $this->port = 0;
+ $this->path = '';
+ $this->target = '';
+ $this->method = 'GET';
+ $this->schema = 'http';
+ $this->params = array();
+ $this->headers = array();
+ $this->cookies = array();
+ $this->_cookies = array();
+
+ // Set the config details
+ $this->debug = FALSE;
+ $this->error = '';
+ $this->status = 0;
+ $this->timeout = '25';
+ $this->useCurl = TRUE;
+ $this->referrer = '';
+ $this->username = '';
+ $this->password = '';
+ $this->redirect = TRUE;
+
+ // Set the cookie and agent defaults
+ $this->nextToken = '';
+ $this->useCookie = TRUE;
+ $this->saveCookie = TRUE;
+ $this->maxRedirect = 3;
+ $this->cookiePath = 'cookie.txt';
+ $this->userAgent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.9';
+ }
+
+ /**
+ * Set target URL
+ *
+ * @param string URL of target resource
+ * @return void
+ */
+ function setTarget($url)
+ {
+ if ($url)
+ {
+ $this->target = $url;
+ }
+ }
+
+ /**
+ * Set http method
+ *
+ * @param string HTTP method to use (GET or POST)
+ * @return void
+ */
+ function setMethod($method)
+ {
+ if ($method == 'GET' || $method == 'POST')
+ {
+ $this->method = $method;
+ }
+ }
+
+ /**
+ * Set referrer URL
+ *
+ * @param string URL of referrer page
+ * @return void
+ */
+ function setReferrer($referrer)
+ {
+ if ($referrer)
+ {
+ $this->referrer = $referrer;
+ }
+ }
+
+ /**
+ * Set User agent string
+ *
+ * @param string Full user agent string
+ * @return void
+ */
+ function setUseragent($agent)
+ {
+ if ($agent)
+ {
+ $this->userAgent = $agent;
+ }
+ }
+
+ /**
+ * Set timeout of execution
+ *
+ * @param integer Timeout delay in seconds
+ * @return void
+ */
+ function setTimeout($seconds)
+ {
+ if ($seconds > 0)
+ {
+ $this->timeout = $seconds;
+ }
+ }
+
+ /**
+ * Set cookie path (cURL only)
+ *
+ * @param string File location of cookiejar
+ * @return void
+ */
+ function setCookiepath($path)
+ {
+ if ($path)
+ {
+ $this->cookiePath = $path;
+ }
+ }
+
+ /**
+ * Set request parameters
+ *
+ * @param array All the parameters for GET or POST
+ * @return void
+ */
+ function setParams($dataArray)
+ {
+ if (is_array($dataArray))
+ {
+ $this->params = array_merge($this->params, $dataArray);
+ }
+ }
+
+ /**
+ * Set basic http authentication realm
+ *
+ * @param string Username for authentication
+ * @param string Password for authentication
+ * @return void
+ */
+ function setAuth($username, $password)
+ {
+ if (!empty($username) && !empty($password))
+ {
+ $this->username = $username;
+ $this->password = $password;
+ }
+ }
+
+ /**
+ * Set maximum number of redirection to follow
+ *
+ * @param integer Maximum number of redirects
+ * @return void
+ */
+ function setMaxredirect($value)
+ {
+ if (!empty($value))
+ {
+ $this->maxRedirect = $value;
+ }
+ }
+
+ /**
+ * Add request parameters
+ *
+ * @param string Name of the parameter
+ * @param string Value of the parameter
+ * @return void
+ */
+ function addParam($name, $value)
+ {
+ if (!empty($name) && !empty($value))
+ {
+ $this->params[$name] = $value;
+ }
+ }
+
+ /**
+ * Add a cookie to the request
+ *
+ * @param string Name of cookie
+ * @param string Value of cookie
+ * @return void
+ */
+ function addCookie($name, $value)
+ {
+ if (!empty($name) && !empty($value))
+ {
+ $this->cookies[$name] = $value;
+ }
+ }
+
+ /**
+ * Whether to use cURL or not
+ *
+ * @param boolean Whether to use cURL or not
+ * @return void
+ */
+ function useCurl($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->useCurl = $value;
+ }
+ }
+
+ /**
+ * Whether to use cookies or not
+ *
+ * @param boolean Whether to use cookies or not
+ * @return void
+ */
+ function useCookie($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->useCookie = $value;
+ }
+ }
+
+ /**
+ * Whether to save persistent cookies in subsequent calls
+ *
+ * @param boolean Whether to save persistent cookies or not
+ * @return void
+ */
+ function saveCookie($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->saveCookie = $value;
+ }
+ }
+
+ /**
+ * Whether to follow HTTP redirects
+ *
+ * @param boolean Whether to follow HTTP redirects or not
+ * @return void
+ */
+ function followRedirects($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->redirect = $value;
+ }
+ }
+
+ /**
+ * Get execution result body
+ *
+ * @return string output of execution
+ */
+ function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * Get execution result headers
+ *
+ * @return array last headers of execution
+ */
+ function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Get execution status code
+ *
+ * @return integer last http status code
+ */
+ function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * Get last execution error
+ *
+ * @return string last error message (if any)
+ */
+ function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Execute a HTTP request
+ *
+ * Executes the http fetch using all the set properties. Intellegently
+ * switch to fsockopen if cURL is not present. And be smart to follow
+ * redirects (if asked so).
+ *
+ * @param string URL of the target page (optional)
+ * @param string URL of the referrer page (optional)
+ * @param string The http method (GET or POST) (optional)
+ * @param array Parameter array for GET or POST (optional)
+ * @return string Response body of the target page
+ */
+ function execute($target = '', $referrer = '', $method = '', $data = array())
+ {
+ // Populate the properties
+ $this->target = ($target) ? $target : $this->target;
+ $this->method = ($method) ? $method : $this->method;
+
+ $this->referrer = ($referrer) ? $referrer : $this->referrer;
+
+ // Add the new params
+ if (is_array($data) && count($data) > 0)
+ {
+ $this->params = array_merge($this->params, $data);
+ }
+
+ // Process data, if presented
+ if(is_array($this->params) && count($this->params) > 0)
+ {
+ // Get a blank slate
+ $tempString = array();
+
+ // Convert data array into a query string (ie animal=dog&sport=baseball)
+ foreach ($this->params as $key => $value)
+ {
+ if(strlen(trim($value))>0)
+ {
+ $tempString[] = $key . "=" . urlencode($value);
+ }
+ }
+
+ $queryString = join('&', $tempString);
+ }
+
+ // If cURL is not installed, we'll force fscokopen
+ $this->useCurl = $this->useCurl && in_array('curl', get_loaded_extensions());
+
+ // GET method configuration
+ if($this->method == 'GET')
+ {
+ if(isset($queryString))
+ {
+ $this->target = $this->target . "?" . $queryString;
+ }
+ }
+
+ // Parse target URL
+ $urlParsed = parse_url($this->target);
+
+ // Handle SSL connection request
+ if ($urlParsed['scheme'] == 'https')
+ {
+ $this->host = 'ssl://' . $urlParsed['host'];
+ $this->port = ($this->port != 0) ? $this->port : 443;
+ }
+ else
+ {
+ $this->host = $urlParsed['host'];
+ $this->port = ($this->port != 0) ? $this->port : 80;
+ }
+
+ // Finalize the target path
+ $this->path = (isset($urlParsed['path']) ? $urlParsed['path'] : '/') . (isset($urlParsed['query']) ? '?' . $urlParsed['query'] : '');
+ $this->schema = $urlParsed['scheme'];
+
+ // Pass the requred cookies
+ $this->_passCookies();
+
+ // Process cookies, if requested
+ if(is_array($this->cookies) && count($this->cookies) > 0)
+ {
+ // Get a blank slate
+ $tempString = array();
+
+ // Convert cookiesa array into a query string (ie animal=dog&sport=baseball)
+ foreach ($this->cookies as $key => $value)
+ {
+ if(strlen(trim($value)) > 0)
+ {
+ $tempString[] = $key . "=" . urlencode($value);
+ }
+ }
+
+ $cookieString = join('&', $tempString);
+ }
+
+ // Do we need to use cURL
+ if ($this->useCurl)
+ {
+ // Initialize PHP cURL handle
+ $ch = curl_init();
+
+ // GET method configuration
+ if($this->method == 'GET')
+ {
+ curl_setopt ($ch, CURLOPT_HTTPGET, TRUE);
+ curl_setopt ($ch, CURLOPT_POST, FALSE);
+ }
+ // POST method configuration
+ else
+ {
+ if(isset($queryString))
+ {
+ curl_setopt ($ch, CURLOPT_POSTFIELDS, $queryString);
+ }
+
+ curl_setopt ($ch, CURLOPT_POST, TRUE);
+ curl_setopt ($ch, CURLOPT_HTTPGET, FALSE);
+ }
+
+ // Basic Authentication configuration
+ if ($this->username && $this->password)
+ {
+ curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password);
+ }
+
+ // Custom cookie configuration
+ if($this->useCookie && isset($cookieString))
+ {
+ curl_setopt ($ch, CURLOPT_COOKIE, $cookieString);
+ }
+
+ curl_setopt($ch, CURLOPT_HEADER, TRUE); // No need of headers
+ curl_setopt($ch, CURLOPT_NOBODY, FALSE); // Return body
+
+ curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookiePath); // Cookie management.
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); // Timeout
+ curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent); // Webbot name
+ curl_setopt($ch, CURLOPT_URL, $this->target); // Target site
+ curl_setopt($ch, CURLOPT_REFERER, $this->referrer); // Referer value
+
+ curl_setopt($ch, CURLOPT_VERBOSE, FALSE); // Minimize logs
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // No certificate
+ if(!ini_get('safe_mode') && !ini_get('open_basedir')){
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->redirect); // Follow redirects
+ }
+ curl_setopt($ch, CURLOPT_MAXREDIRS, $this->maxRedirect); // Limit redirections to four
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Return in string
+
+ // Get the target contents
+ $content = curl_exec($ch);
+ $contentArray = explode("\r\n\r\n", $content);
+
+ // Get the request info
+ $status = curl_getinfo($ch);
+
+ // Store the contents
+ $this->result = $contentArray[count($contentArray) - 1];
+
+ // Parse the headers
+ $this->_parseHeaders($contentArray[count($contentArray) - 2]);
+
+ // Store the error (is any)
+ $this->_setError(curl_error($ch));
+
+ // Close PHP cURL handle
+ curl_close($ch);
+ }
+ else
+ {
+ // Get a file pointer
+ $filePointer = fsockopen($this->host, $this->port, $errorNumber, $errorString, $this->timeout);
+
+ // We have an error if pointer is not there
+ if (!$filePointer)
+ {
+ $this->_setError('Failed opening http socket connection: ' . $errorString . ' (' . $errorNumber . ')');
+ return FALSE;
+ }
+
+ // Set http headers with host, user-agent and content type
+ $requestHeader = $this->method . " " . $this->path . " HTTP/1.1\r\n";
+ $requestHeader .= "Host: " . $urlParsed['host'] . "\r\n";
+ $requestHeader .= "User-Agent: " . $this->userAgent . "\r\n";
+ $requestHeader .= "Content-Type: application/x-www-form-urlencoded\r\n";
+
+ // Specify the custom cookies
+ if ($this->useCookie && $cookieString != '')
+ {
+ $requestHeader.= "Cookie: " . $cookieString . "\r\n";
+ }
+
+ // POST method configuration
+ if ($this->method == "POST")
+ {
+ $requestHeader.= "Content-Length: " . strlen($queryString) . "\r\n";
+ }
+
+ // Specify the referrer
+ if ($this->referrer != '')
+ {
+ $requestHeader.= "Referer: " . $this->referrer . "\r\n";
+ }
+
+ // Specify http authentication (basic)
+ if ($this->username && $this->password)
+ {
+ $requestHeader.= "Authorization: Basic " . base64_encode($this->username . ':' . $this->password) . "\r\n";
+ }
+
+ $requestHeader.= "Connection: close\r\n\r\n";
+
+ // POST method configuration
+ if ($this->method == "POST")
+ {
+ $requestHeader .= $queryString;
+ }
+
+ // We're ready to launch
+ fwrite($filePointer, $requestHeader);
+
+ // Clean the slate
+ $responseHeader = '';
+ $responseContent = '';
+
+ // 3...2...1...Launch !
+ do
+ {
+ $responseHeader .= fread($filePointer, 1);
+ }
+ while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));
+
+ // Parse the headers
+ $this->_parseHeaders($responseHeader);
+
+ // Do we have a 301/302 redirect ?
+ if (($this->status == '301' || $this->status == '302') && $this->redirect == TRUE)
+ {
+ if ($this->curRedirect < $this->maxRedirect)
+ {
+ // Let's find out the new redirect URL
+ $newUrlParsed = parse_url($this->headers['location']);
+
+ if ($newUrlParsed['host'])
+ {
+ $newTarget = $this->headers['location'];
+ }
+ else
+ {
+ $newTarget = $this->schema . '://' . $this->host . '/' . $this->headers['location'];
+ }
+
+ // Reset some of the properties
+ $this->port = 0;
+ $this->status = 0;
+ $this->params = array();
+ $this->method = 'GET';
+ $this->referrer = $this->target;
+
+ // Increase the redirect counter
+ $this->curRedirect++;
+
+ // Let's go, go, go !
+ $this->result = $this->execute($newTarget);
+ }
+ else
+ {
+ $this->_setError('Too many redirects.');
+ return FALSE;
+ }
+ }
+ else
+ {
+ // Nope...so lets get the rest of the contents (non-chunked)
+ if ($this->headers['transfer-encoding'] != 'chunked')
+ {
+ while (!feof($filePointer))
+ {
+ $responseContent .= fgets($filePointer, 128);
+ }
+ }
+ else
+ {
+ // Get the contents (chunked)
+ while ($chunkLength = hexdec(fgets($filePointer)))
+ {
+ $responseContentChunk = '';
+ $readLength = 0;
+
+ while ($readLength < $chunkLength)
+ {
+ $responseContentChunk .= fread($filePointer, $chunkLength - $readLength);
+ $readLength = strlen($responseContentChunk);
+ }
+
+ $responseContent .= $responseContentChunk;
+ fgets($filePointer);
+ }
+ }
+
+ // Store the target contents
+ $this->result = chop($responseContent);
+ }
+ }
+
+ // There it is! We have it!! Return to base !!!
+ return $this->result;
+ }
+
+ /**
+ * Parse Headers (internal)
+ *
+ * Parse the response headers and store them for finding the resposne
+ * status, redirection location, cookies, etc.
+ *
+ * @param string Raw header response
+ * @return void
+ * @access private
+ */
+ function _parseHeaders($responseHeader)
+ {
+ // Break up the headers
+ $headers = explode("\r\n", $responseHeader);
+
+ // Clear the header array
+ $this->_clearHeaders();
+
+ // Get response status
+ if($this->status == 0)
+ {
+
+ // Oooops!
+ if(!preg_match("/^http\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i", $headers[0], $matches))
+ {
+ $this->_setError('Unexpected HTTP response status');
+ return FALSE;
+ }
+
+ // Gotcha!
+ $this->status = $matches[1];
+ array_shift($headers);
+ }
+
+ // Prepare all the other headers
+ foreach ($headers as $header)
+ {
+ // Get name and value
+ $headerName = strtolower($this->_tokenize($header, ':'));
+ $headerValue = trim(chop($this->_tokenize("\r\n")));
+
+ // If its already there, then add as an array. Otherwise, just keep there
+ if(isset($this->headers[$headerName]))
+ {
+ if(gettype($this->headers[$headerName]) == "string")
+ {
+ $this->headers[$headerName] = array($this->headers[$headerName]);
+ }
+
+ $this->headers[$headerName][] = $headerValue;
+ }
+ else
+ {
+ $this->headers[$headerName] = $headerValue;
+ }
+ }
+
+ // Save cookies if asked
+ if ($this->saveCookie && isset($this->headers['set-cookie']))
+ {
+ $this->_parseCookie();
+ }
+ }
+
+ /**
+ * Clear the headers array (internal)
+ *
+ * @return void
+ * @access private
+ */
+ function _clearHeaders()
+ {
+ $this->headers = array();
+ }
+
+ /**
+ * Parse Cookies (internal)
+ *
+ * Parse the set-cookie headers from response and add them for inclusion.
+ *
+ * @return void
+ * @access private
+ */
+ function _parseCookie()
+ {
+ // Get the cookie header as array
+ if(gettype($this->headers['set-cookie']) == "array")
+ {
+ $cookieHeaders = $this->headers['set-cookie'];
+ }
+ else
+ {
+ $cookieHeaders = array($this->headers['set-cookie']);
+ }
+
+ // Loop through the cookies
+ for ($cookie = 0; $cookie < count($cookieHeaders); $cookie++)
+ {
+ $cookieName = trim($this->_tokenize($cookieHeaders[$cookie], "="));
+ $cookieValue = $this->_tokenize(";");
+
+ $urlParsed = parse_url($this->target);
+
+ $domain = $urlParsed['host'];
+ $secure = '0';
+
+ $path = "/";
+ $expires = "";
+
+ while(($name = trim(urldecode($this->_tokenize("=")))) != "")
+ {
+ $value = urldecode($this->_tokenize(";"));
+
+ switch($name)
+ {
+ case "path" : $path = $value; break;
+ case "domain" : $domain = $value; break;
+ case "secure" : $secure = ($value != '') ? '1' : '0'; break;
+ }
+ }
+
+ $this->_setCookie($cookieName, $cookieValue, $expires, $path , $domain, $secure);
+ }
+ }
+
+ /**
+ * Set cookie (internal)
+ *
+ * Populate the internal _cookies array for future inclusion in
+ * subsequent requests. This actually validates and then populates
+ * the object properties with a dimensional entry for cookie.
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param string Cookie expire date
+ * @param string Cookie path
+ * @param string Cookie domain
+ * @param string Cookie security (0 = non-secure, 1 = secure)
+ * @return void
+ * @access private
+ */
+ function _setCookie($name, $value, $expires = "" , $path = "/" , $domain = "" , $secure = 0)
+ {
+ if(strlen($name) == 0)
+ {
+ return($this->_setError("No valid cookie name was specified."));
+ }
+
+ if(strlen($path) == 0 || strcmp($path[0], "/"))
+ {
+ return($this->_setError("$path is not a valid path for setting cookie $name."));
+ }
+
+ if($domain == "" || !strpos($domain, ".", $domain[0] == "." ? 1 : 0))
+ {
+ return($this->_setError("$domain is not a valid domain for setting cookie $name."));
+ }
+
+ $domain = strtolower($domain);
+
+ if(!strcmp($domain[0], "."))
+ {
+ $domain = substr($domain, 1);
+ }
+
+ $name = $this->_encodeCookie($name, true);
+ $value = $this->_encodeCookie($value, false);
+
+ $secure = intval($secure);
+
+ $this->_cookies[] = array( "name" => $name,
+ "value" => $value,
+ "domain" => $domain,
+ "path" => $path,
+ "expires" => $expires,
+ "secure" => $secure
+ );
+ }
+
+ /**
+ * Encode cookie name/value (internal)
+ *
+ * @param string Value of cookie to encode
+ * @param string Name of cookie to encode
+ * @return string encoded string
+ * @access private
+ */
+ function _encodeCookie($value, $name)
+ {
+ return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
+ }
+
+ /**
+ * Pass Cookies (internal)
+ *
+ * Get the cookies which are valid for the current request. Checks
+ * domain and path to decide the return.
+ *
+ * @return void
+ * @access private
+ */
+ function _passCookies()
+ {
+ if (is_array($this->_cookies) && count($this->_cookies) > 0)
+ {
+ $urlParsed = parse_url($this->target);
+ $tempCookies = array();
+
+ foreach($this->_cookies as $cookie)
+ {
+ if ($this->_domainMatch($urlParsed['host'], $cookie['domain']) && (0 === strpos($urlParsed['path'], $cookie['path']))
+ && (empty($cookie['secure']) || $urlParsed['protocol'] == 'https'))
+ {
+ $tempCookies[$cookie['name']][strlen($cookie['path'])] = $cookie['value'];
+ }
+ }
+
+ // cookies with longer paths go first
+ foreach ($tempCookies as $name => $values)
+ {
+ krsort($values);
+ foreach ($values as $value)
+ {
+ $this->addCookie($name, $value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if cookie domain matches a request host (internal)
+ *
+ * Cookie domain can begin with a dot, it also must contain at least
+ * two dots.
+ *
+ * @param string Request host
+ * @param string Cookie domain
+ * @return bool Match success
+ * @access private
+ */
+ function _domainMatch($requestHost, $cookieDomain)
+ {
+ if ('.' != $cookieDomain{0})
+ {
+ return $requestHost == $cookieDomain;
+ }
+ elseif (substr_count($cookieDomain, '.') < 2)
+ {
+ return false;
+ }
+ else
+ {
+ return substr('.'. $requestHost, - strlen($cookieDomain)) == $cookieDomain;
+ }
+ }
+
+ /**
+ * Tokenize String (internal)
+ *
+ * Tokenize string for various internal usage. Omit the second parameter
+ * to tokenize the previous string that was provided in the prior call to
+ * the function.
+ *
+ * @param string The string to tokenize
+ * @param string The seperator to use
+ * @return string Tokenized string
+ * @access private
+ */
+ function _tokenize($string, $separator = '')
+ {
+ if(!strcmp($separator, ''))
+ {
+ $separator = $string;
+ $string = $this->nextToken;
+ }
+
+ for($character = 0; $character < strlen($separator); $character++)
+ {
+ if(gettype($position = strpos($string, $separator[$character])) == "integer")
+ {
+ $found = (isset($found) ? min($found, $position) : $position);
+ }
+ }
+
+ if(isset($found))
+ {
+ $this->nextToken = substr($string, $found + 1);
+ return(substr($string, 0, $found));
+ }
+ else
+ {
+ $this->nextToken = '';
+ return($string);
+ }
+ }
+
+ /**
+ * Set error message (internal)
+ *
+ * @param string Error message
+ * @return string Error message
+ * @access private
+ */
+ function _setError($error)
+ {
+ if ($error != '')
+ {
+ $this->error = $error;
+ return $error;
+ }
+ }
+}
+
+?>
\ No newline at end of file diff --git a/libgpl/ical/ical_sync.php b/libgpl/ical/ical_sync.php new file mode 100644 index 0000000..b513574 --- /dev/null +++ b/libgpl/ical/ical_sync.php @@ -0,0 +1,144 @@ +<?php +/** + * iCalendar sync for the Calendar plugin + * + * @version @package_version@ + * @author Daniel Morlock <daniel.morlock@awesome-it.de> + * + * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +class ical_sync +{ + const ACTION_NONE = 1; + const ACTION_UPDATE = 2; + const ACTION_CREATE = 4; + + private $cal_id = null; + private $url = null; + private $user = null; + private $pass = null; + private $ical = null; + + public $sync = 0; + + /** + * Default constructor for calendar synchronization adapter. + * + * @param int Calendar id. + * @param array Hash array with ical properties: + * url: Absolute URL to iCAL resource. + */ + public function __construct($cal_id, $props) + { + $this->ical = libcalendaring::get_ical(); + $this->cal_id = $cal_id; + + $this->url = $props["url"]; + $this->user = isset($props["user"]) ? $props["user"] : null; + $this->pass = isset($props["pass"]) ? $props["pass"] : null; + $this->sync = isset($props["sync"]) ? $props["sync"] : 0; + } + + /** + * Determines whether current calendar needs to be synced. + * + * @return True if the current calendar needs to be synced, false otherwise. + */ + public function is_synced() + { + // No change to check that so far. + return false; + } + + /** + * Fetches events from iCAL resource and returns updates. + * + * @param array List of local events. + * @return array Tuple containing the following lists: + * + * Hash list for iCAL events to be created or to be updated with the keys: + * local_event: The local event in case of an update. + * remote_event: The current event retrieved from caldav server. + * + * A list of event ids that are in sync. + */ + public function get_updates($events) + { + $context = null; + if($this->user != null && $this->pass != null) + { + $context = stream_context_create(array( + 'http' => array( + 'header' => "Authorization: Basic " . base64_encode("$this->user:$this->pass") . "\r\n" . + "User-Agent: PHP/" . PHP_VERSION + ) + )); + } + + $vcal = file_get_contents($this->url, false, $context); + $charset = 'UTF-8'; + foreach($http_response_header as $c => $h) + { + if(stristr($h, 'content-type') && stristr($h, 'charset')) + { + preg_match('@Content-Type:\s+([\w/+]+)(;\s+charset=(\S+))?@i', $h, $matches); + if(isset($matches[3])) + { + $charset = strtoupper(trim($matches[3])); + } + } + if(stristr($h, 'content-encoding') && stristr($h, 'gzip')) + { + $vcal = gzinflate(substr($vcal, 10, -8)); + } + } + + $updates = array(); + $synced = array(); + if($vcal !== false) + { + // Hash existing events by uid. + $events_hash = array(); + foreach($events as $event) { + $events_hash[$event['uid']] = $event; + } + foreach ($this->ical->import($vcal, $charset, false, false) as $remote_event) { + // Attach remote event to current calendar + $remote_event["calendar"] = $this->cal_id; + + $local_event = null; + if($events_hash[$remote_event['uid']]) + $local_event = $events_hash[$remote_event['uid']]; + + // Determine whether event don't need an update. + if($local_event && $local_event["changed"] >= $remote_event["changed"]) + { + array_push($synced, $local_event["id"]); + } + else + { + array_push($updates, array('local_event' => $local_event, 'remote_event' => $remote_event)); + } + } + } + + return array($updates, $synced); + } +} + +; +?>
\ No newline at end of file diff --git a/libgpl/jquery_migrate/jquery.migrate.js b/libgpl/jquery_migrate/jquery.migrate.js new file mode 100644 index 0000000..5e73954 --- /dev/null +++ b/libgpl/jquery_migrate/jquery.migrate.js @@ -0,0 +1,521 @@ +/*!
+ * jQuery Migrate - v1.2.1 - 2013-05-08
+ * https://github.com/jquery/jquery-migrate
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ */
+(function( jQuery, window, undefined ) {
+// See http://bugs.jquery.com/ticket/13335
+// "use strict";
+
+
+var warnedAbout = {};
+
+// List of warnings already given; public read only
+jQuery.migrateWarnings = [];
+
+// Set to true to prevent console output; migrateWarnings still maintained
+jQuery.migrateMute = true;
+
+// Show a message on the console so devs know we're active
+if ( !jQuery.migrateMute && window.console && window.console.log ) {
+ window.console.log("JQMIGRATE: Logging is active");
+}
+
+// Set to false to disable traces that appear with warnings
+if ( jQuery.migrateTrace === undefined ) {
+ jQuery.migrateTrace = true;
+}
+
+// Forget any warnings we've already given; public
+jQuery.migrateReset = function() {
+ warnedAbout = {};
+ jQuery.migrateWarnings.length = 0;
+};
+
+function migrateWarn( msg) {
+ var console = window.console;
+ if ( !warnedAbout[ msg ] ) {
+ warnedAbout[ msg ] = true;
+ jQuery.migrateWarnings.push( msg );
+ if ( console && console.warn && !jQuery.migrateMute ) {
+ console.warn( "JQMIGRATE: " + msg );
+ if ( jQuery.migrateTrace && console.trace ) {
+ console.trace();
+ }
+ }
+ }
+}
+
+function migrateWarnProp( obj, prop, value, msg ) {
+ if ( Object.defineProperty ) {
+ // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
+ // allow property to be overwritten in case some other plugin wants it
+ try {
+ Object.defineProperty( obj, prop, {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ migrateWarn( msg );
+ return value;
+ },
+ set: function( newValue ) {
+ migrateWarn( msg );
+ value = newValue;
+ }
+ });
+ return;
+ } catch( err ) {
+ // IE8 is a dope about Object.defineProperty, can't warn there
+ }
+ }
+
+ // Non-ES5 (or broken) browser; just set the property
+ jQuery._definePropertyBroken = true;
+ obj[ prop ] = value;
+}
+
+if ( document.compatMode === "BackCompat" ) {
+ // jQuery has never supported or tested Quirks Mode
+ migrateWarn( "jQuery is not compatible with Quirks Mode" );
+}
+
+
+var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
+ oldAttr = jQuery.attr,
+ valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
+ function() { return null; },
+ valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
+ function() { return undefined; },
+ rnoType = /^(?:input|button)$/i,
+ rnoAttrNodeType = /^[238]$/,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ ruseDefault = /^(?:checked|selected)$/i;
+
+// jQuery.attrFn
+migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
+
+jQuery.attr = function( elem, name, value, pass ) {
+ var lowerName = name.toLowerCase(),
+ nType = elem && elem.nodeType;
+
+ if ( pass ) {
+ // Since pass is used internally, we only warn for new jQuery
+ // versions where there isn't a pass arg in the formal params
+ if ( oldAttr.length < 4 ) {
+ migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
+ }
+ if ( elem && !rnoAttrNodeType.test( nType ) &&
+ (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+ }
+
+ // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
+ // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
+ if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
+ migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
+ }
+
+ // Restore boolHook for boolean property/attribute synchronization
+ if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
+ jQuery.attrHooks[ lowerName ] = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" &&
+ ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+ };
+
+ // Warn only for attributes that can remain distinct from their properties post-1.9
+ if ( ruseDefault.test( lowerName ) ) {
+ migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+ }
+ }
+
+ return oldAttr.call( jQuery, elem, name, value );
+};
+
+// attrHooks: value
+jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrGet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value') no longer gets properties");
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrSet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+};
+
+
+var matched, browser,
+ oldInit = jQuery.fn.init,
+ oldParseJSON = jQuery.parseJSON,
+ // Note: XSS check is done below after string is trimmed
+ rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
+
+// $(html) "looks like html" rule change
+jQuery.fn.init = function( selector, context, rootjQuery ) {
+ var match;
+
+ if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
+ (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+ // This is an HTML string according to the "old" rules; is it still?
+ if ( selector.charAt( 0 ) !== "<" ) {
+ migrateWarn("$(html) HTML strings must start with '<' character");
+ }
+ if ( match[ 3 ] ) {
+ migrateWarn("$(html) HTML text after last tag is ignored");
+ }
+ // Consistently reject any HTML-like string starting with a hash (#9521)
+ // Note that this may break jQuery 1.6.x code that otherwise would work.
+ if ( match[ 0 ].charAt( 0 ) === "#" ) {
+ migrateWarn("HTML string cannot start with a '#' character");
+ jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+ }
+ // Now process using loose rules; let pre-1.8 play too
+ if ( context && context.context ) {
+ // jQuery object as context; parseHTML expects a DOM object
+ context = context.context;
+ }
+ if ( jQuery.parseHTML ) {
+ return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
+ context, rootjQuery );
+ }
+ }
+ return oldInit.apply( this, arguments );
+};
+jQuery.fn.init.prototype = jQuery.fn;
+
+// Let $.parseJSON(falsy_value) return null
+jQuery.parseJSON = function( json ) {
+ if ( !json && json !== null ) {
+ migrateWarn("jQuery.parseJSON requires a valid JSON string");
+ return null;
+ }
+ return oldParseJSON.apply( this, arguments );
+};
+
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+// Don't clobber any existing jQuery.browser in case it's different
+if ( !jQuery.browser ) {
+ matched = jQuery.uaMatch( navigator.userAgent );
+ browser = {};
+
+ if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+ // Chrome is Webkit, but Webkit is also Safari.
+ if ( browser.chrome ) {
+ browser.webkit = true;
+ } else if ( browser.webkit ) {
+ browser.safari = true;
+ }
+
+ jQuery.browser = browser;
+}
+
+// Warn if the code tries to get jQuery.browser
+migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ migrateWarn( "jQuery.sub() is deprecated" );
+ return jQuerySub;
+};
+
+
+// Ensure that $.ajax gets the new parseJSON defined in core.js
+jQuery.ajaxSetup({
+ converters: {
+ "text json": jQuery.parseJSON
+ }
+});
+
+
+var oldFnData = jQuery.fn.data;
+
+jQuery.fn.data = function( name ) {
+ var ret, evt,
+ elem = this[0];
+
+ // Handles 1.7 which has this behavior and 1.8 which doesn't
+ if ( elem && name === "events" && arguments.length === 1 ) {
+ ret = jQuery.data( elem, name );
+ evt = jQuery._data( elem, name );
+ if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
+ migrateWarn("Use of jQuery.fn.data('events') is deprecated");
+ return evt;
+ }
+ }
+ return oldFnData.apply( this, arguments );
+};
+
+
+var rscriptType = /\/(java|ecma)script/i,
+ oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
+
+jQuery.fn.andSelf = function() {
+ migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+ return oldSelf.apply( this, arguments );
+};
+
+// Since jQuery.clean is used internally on older versions, we only shim if it's missing
+if ( !jQuery.clean ) {
+ jQuery.clean = function( elems, context, fragment, scripts ) {
+ // Set context per 1.8 logic
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ migrateWarn("jQuery.clean() is deprecated");
+
+ var i, elem, handleScript, jsTags,
+ ret = [];
+
+ jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
+
+ // Complex logic lifted directly from jQuery 1.8
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var eventAdd = jQuery.event.add,
+ eventRemove = jQuery.event.remove,
+ eventTrigger = jQuery.event.trigger,
+ oldToggle = jQuery.fn.toggle,
+ oldLive = jQuery.fn.live,
+ oldDie = jQuery.fn.die,
+ ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
+ rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ hoverHack = function( events ) {
+ if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
+ return events;
+ }
+ if ( rhoverHack.test( events ) ) {
+ migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
+ }
+ return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+// Event props removed in 1.9, put them back if needed; no practical way to warn them
+if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
+ jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
+}
+
+// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
+if ( jQuery.event.dispatch ) {
+ migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
+}
+
+// Support for 'hover' pseudo-event and ajax event warnings
+jQuery.event.add = function( elem, types, handler, data, selector ){
+ if ( elem !== document && rajaxEvent.test( types ) ) {
+ migrateWarn( "AJAX events should be attached to document: " + types );
+ }
+ eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
+};
+jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
+ eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
+};
+
+jQuery.fn.error = function() {
+ var args = Array.prototype.slice.call( arguments, 0);
+ migrateWarn("jQuery.fn.error() is deprecated");
+ args.splice( 0, 0, "error" );
+ if ( arguments.length ) {
+ return this.bind.apply( this, args );
+ }
+ // error event should not bubble to window, although it does pre-1.7
+ this.triggerHandler.apply( this, args );
+ return this;
+};
+
+jQuery.fn.toggle = function( fn, fn2 ) {
+
+ // Don't mess with animation or css toggles
+ if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
+ return oldToggle.apply( this, arguments );
+ }
+ migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
+
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+};
+
+jQuery.fn.live = function( types, data, fn ) {
+ migrateWarn("jQuery.fn.live() is deprecated");
+ if ( oldLive ) {
+ return oldLive.apply( this, arguments );
+ }
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+};
+
+jQuery.fn.die = function( types, fn ) {
+ migrateWarn("jQuery.fn.die() is deprecated");
+ if ( oldDie ) {
+ return oldDie.apply( this, arguments );
+ }
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+};
+
+// Turn global events into document-triggered events
+jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
+ if ( !elem && !rajaxEvent.test( event ) ) {
+ migrateWarn( "Global events are undocumented and deprecated" );
+ }
+ return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
+};
+jQuery.each( ajaxEvents.split("|"),
+ function( _, name ) {
+ jQuery.event.special[ name ] = {
+ setup: function() {
+ var elem = this;
+
+ // The document needs no shimming; must be !== for oldIE
+ if ( elem !== document ) {
+ jQuery.event.add( document, name + "." + jQuery.guid, function() {
+ jQuery.event.trigger( name, null, elem, true );
+ });
+ jQuery._data( this, name, jQuery.guid++ );
+ }
+ return false;
+ },
+ teardown: function() {
+ if ( this !== document ) {
+ jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
+ }
+ return false;
+ }
+ };
+ }
+);
+
+
+})( jQuery, window );
\ No newline at end of file diff --git a/libgpl/libcalendaring/libcalendaring.js b/libgpl/libcalendaring/libcalendaring.js new file mode 100644 index 0000000..00878be --- /dev/null +++ b/libgpl/libcalendaring/libcalendaring.js @@ -0,0 +1,676 @@ +/** + * Basic Javascript utilities for calendar-related plugins + * + * @version @package_version@ + * @author Thomas Bruederli <bruederli@kolabsys.com> + * + * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +function rcube_libcalendaring(settings) +{ + // member vars + this.settings = settings; + this.alarm_ids = []; + this.alarm_dialog = null; + this.snooze_popup = null; + this.dismiss_link = null; + + // private vars + var me = this; + var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0) - (settings.dst || 0); + var client_timezone = new Date().getTimezoneOffset(); + + // general datepicker settings + var datepicker_settings = { + // translate from fullcalendar format to datepicker format + dateFormat: settings.date_format ? settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y') : 'yy-mm-dd', + firstDay : settings.first_day, + dayNamesMin: settings.days_short, + monthNames: settings.months, + monthNamesShort: settings.months, + changeMonth: false, + showOtherMonths: true, + selectOtherMonths: true + }; + + + /** + * Quote html entities + */ + var Q = this.quote_html = function(str) + { + return String(str).replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); + }; + + /** + * Create a nice human-readable string for the date/time range + */ + this.event_date_text = function(event) + { + if (!event.start) + return ''; + if (!event.end) + event.end = event.start; + + var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000; + if (event.allDay && !event.allDayfake) { + fromto = this.format_datetime(event.start, 1) + + (duration > 86400 || event.start.getDay() != event.end.getDay() ? ' — ' + this.format_datetime(event.end, 1) : ''); + } + else if (duration < 86400 && event.start.getDay() == event.end.getDay()) { + fromto = this.format_datetime(event.start, 0) + + (duration > 0 ? ' — ' + this.format_datetime(event.end, 2) : ''); + } + else { + fromto = this.format_datetime(event.start, 0) + + (duration > 0 ? ' — ' + this.format_datetime(event.end, 0) : ''); + } + + return fromto; + }; + + + /** + * From time and date strings to a real date object + */ + this.parse_datetime = function(time, date) + { + // we use the utility function from datepicker to parse dates + var date = date ? $.datepicker.parseDate(datepicker_settings.dateFormat, date, datepicker_settings) : new Date(); + + var time_arr = time.replace(/\s*[ap][.m]*/i, '').replace(/0([0-9])/g, '$1').split(/[:.]/); + if (!isNaN(time_arr[0])) { + date.setHours(time_arr[0]); + if (time.match(/p[.m]*/i) && date.getHours() < 12) + date.setHours(parseInt(time_arr[0]) + 12); + else if (time.match(/a[.m]*/i) && date.getHours() == 12) + date.setHours(0); + } + if (!isNaN(time_arr[1])) + date.setMinutes(time_arr[1]); + + return date; + } + + /** + * Convert an ISO 8601 formatted date string from the server into a Date object. + * Timezone information will be ignored, the server already provides dates in user's timezone. + */ + this.parseISO8601 = function(s) + { + // force d to be on check's YMD, for daylight savings purposes + var fixDate = function(d, check) { + if (+d) { // prevent infinite looping on invalid dates + while (d.getDate() != check.getDate()) { + d.setTime(+d + (d < check ? 1 : -1) * 3600000); + } + } + } + + // derived from http://delete.me.uk/2005/03/iso8601.html + var m = s && s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/); + if (!m) { + return null; + } + + var date = new Date(m[1], 0, 1), + check = new Date(m[1], 0, 1, 9, 0); + if (m[3]) { + date.setMonth(m[3] - 1); + check.setMonth(m[3] - 1); + } + if (m[5]) { + date.setDate(m[5]); + check.setDate(m[5]); + } + fixDate(date, check); + if (m[7]) { + date.setHours(m[7]); + } + if (m[8]) { + date.setMinutes(m[8]); + } + if (m[10]) { + date.setSeconds(m[10]); + } + if (m[12]) { + date.setMilliseconds(Number("0." + m[12]) * 1000); + } + fixDate(date, check); + + return date; + } + + /** + * Turn the given date into an ISO 8601 date string understandable by PHPs strtotime() + */ + this.date2ISO8601 = function(date) + { + var zeropad = function(num) { return (num < 10 ? '0' : '') + num; }; + + return date.getFullYear() + '-' + zeropad(date.getMonth()+1) + '-' + zeropad(date.getDate()) + + 'T' + zeropad(date.getHours()) + ':' + zeropad(date.getMinutes()) + ':' + zeropad(date.getSeconds()); + }; + + /** + * Format the given date object according to user's prefs + */ + this.format_datetime = function(date, mode) + { + var res = ''; + if (!mode || mode == 1) + res += $.datepicker.formatDate(datepicker_settings.dateFormat, date, datepicker_settings); + if (!mode) + res += ' '; + if (!mode || mode == 2) + res += this.format_time(date); + + return res; + } + + /** + * Clone from fullcalendar.js + */ + this.format_time = function(date) + { + var zeroPad = function(n) { return (n < 10 ? '0' : '') + n; } + var formatters = { + s : function(d) { return d.getSeconds() }, + ss : function(d) { return zeroPad(d.getSeconds()) }, + m : function(d) { return d.getMinutes() }, + mm : function(d) { return zeroPad(d.getMinutes()) }, + h : function(d) { return d.getHours() % 12 || 12 }, + hh : function(d) { return zeroPad(d.getHours() % 12 || 12) }, + H : function(d) { return d.getHours() }, + HH : function(d) { return zeroPad(d.getHours()) }, + t : function(d) { return d.getHours() < 12 ? 'a' : 'p' }, + tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' }, + T : function(d) { return d.getHours() < 12 ? 'A' : 'P' }, + TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' } + }; + + var i, i2, c, formatter, res = '', format = settings['time_format']; + for (i=0; i < format.length; i++) { + c = format.charAt(i); + for (i2=Math.min(i+2, format.length); i2 > i; i2--) { + if (formatter = formatters[format.substring(i, i2)]) { + res += formatter(date); + i = i2 - 1; + break; + } + } + if (i2 == i) { + res += c; + } + } + + return res; + } + + /** + * Convert the given Date object into a unix timestamp respecting browser's and user's timezone settings + */ + this.date2unixtime = function(date) + { + var dst_offset = (client_timezone - date.getTimezoneOffset()) * 60; // adjust DST offset + return Math.round(date.getTime()/1000 + gmt_offset * 3600 + dst_offset); + } + + /** + * Turn a unix timestamp value into a Date object + */ + this.fromunixtime = function(ts) + { + ts -= gmt_offset * 3600; + var date = new Date(ts * 1000), + dst_offset = (client_timezone - date.getTimezoneOffset()) * 60; + if (dst_offset) // adjust DST offset + date.setTime((ts + 3600) * 1000); + return date; + } + + /** + * Simple plaintext to HTML converter, makig URLs clickable + */ + this.text2html = function(str, maxlen, maxlines) + { + var html = Q(String(str)); + + // limit visible text length + if (maxlen) { + var morelink = ' <a href="#more" onclick="$(this).hide().next().show();return false" class="morelink">'+rcmail.gettext('showmore','libcalendaring')+'</a><span style="display:none">', + lines = html.split(/\r?\n/), + words, out = '', len = 0; + + for (var i=0; i < lines.length; i++) { + len += lines[i].length; + if (maxlines && i == maxlines - 1) { + out += lines[i] + '\n' + morelink; + maxlen = html.length * 2; + } + else if (len > maxlen) { + len = out.length; + words = lines[i].split(' '); + for (var j=0; j < words.length; j++) { + len += words[j].length + 1; + out += words[j] + ' '; + if (len > maxlen) { + out += morelink; + maxlen = html.length * 2; + } + } + out += '\n'; + } + else + out += lines[i] + '\n'; + } + + if (maxlen > str.length) + out += '</span>'; + + html = out; + } + + // simple link parser (similar to rcube_string_replacer class in PHP) + var utf_domain = '[^?&@"\'/\\(\\)\\s\\r\\t\\n]+\\.([^\x00-\x2f\x3b-\x40\x5b-\x60\x7b-\x7f]{2,}|xn--[a-z0-9]{2,})'; + var url1 = '.:;,', url2 = 'a-z0-9%=#@+?&/_~\\[\\]-'; + var link_pattern = new RegExp('([hf]t+ps?://)('+utf_domain+'(['+url1+']?['+url2+']+)*)?', 'ig'); + var mailto_pattern = new RegExp('([^\\s\\n\\(\\);]+@'+utf_domain+')', 'ig'); + + return html + .replace(link_pattern, '<a href="$1$2" class="extlink" target="_blank">$1$2</a>') + .replace(mailto_pattern, '<a href="mailto:$1">$1</a>') + .replace(/(mailto:)([^"]+)"/g, '$1$2" onclick="rcmail.command(\'compose\', \'$2\');return false"') + .replace(/\n/g, "<br/>"); + }; + + this.init_alarms_edit = function(prefix) + { + // register events on alarm fields + $(prefix+' select.edit-alarm-type').change(function(){ + $(this).parent().find('span.edit-alarm-values')[(this.selectedIndex>0?'show':'hide')](); + }); + $(prefix+' select.edit-alarm-offset').change(function(){ + var mode = $(this).val() == '@' ? 'show' : 'hide'; + $(this).parent().find('.edit-alarm-date, .edit-alarm-time')[mode](); + $(this).parent().find('.edit-alarm-value').prop('disabled', mode == 'show'); + }); + + $(prefix+' .edit-alarm-date').datepicker(datepicker_settings); + } + + + /***** Alarms handling *****/ + + /** + * Display a notification for the given pending alarms + */ + this.display_alarms = function(alarms) + { + if (parent.tabbed && !self.tabbed) { // Mod by Rosali (tabbed plugin compatibility) + return; + } + + var focused = $(':focus'); + var is_minimized = false; + + // clear old alert first + if (this.alarm_dialog) { + // Begin Mod by Rosali (remove previously added divs) + this.alarm_dialog.dialog('destroy').remove(); + if($('#dialog-extend-fixed-container').get(0)){ + is_minimized = true; + } + $('#dialog-extend-fixed-container').remove(); + // End Mod by Rosali + } + + this.alarm_dialog = $('<div>').attr('id', 'alarm-display'); + + var actions, adismiss, asnooze, alarm, html, event_ids = []; + for (var i=0; i < alarms.length; i++) { + alarm = alarms[i]; + alarm.start = this.parseISO8601(alarm.start); + alarm.end = this.parseISO8601(alarm.end); + event_ids.push(alarm.id); + + html = '<h3 class="event-title">' + Q(alarm.title) + '</h3>'; + html += '<div class="event-section">' + Q(alarm.location || '') + '</div>'; + html += '<div class="event-section">' + Q(this.event_date_text(alarm)) + '</div>'; + + adismiss = $('<a href="#" class="alarm-action-dismiss"></a>').html(rcmail.gettext('dismiss','libcalendaring')).click(function(){ + me.dismiss_link = $(this); + me.dismiss_alarm(me.dismiss_link.data('id'), 0); + }); + asnooze = $('<a href="#" class="alarm-action-snooze"></a>').html(rcmail.gettext('snooze','libcalendaring')).click(function(e){ + me.snooze_dropdown($(this)); + e.stopPropagation(); + return false; + }); + actions = $('<div>').addClass('alarm-actions').append(adismiss.data('id', alarm.id)).append(asnooze.data('id', alarm.id)); + + $('<div>').addClass('alarm-item').html(html).append(actions).appendTo(this.alarm_dialog); + } + + var buttons = {}; + buttons[rcmail.gettext('dismissall','libcalendaring')] = function() { + // submit dismissed event_ids to server + me.dismiss_alarm(me.alarm_ids.join(','), 0); + $(this).dialog('close'); + }; + + // Begin Mod by Rosali + // dialog-extend options + var dialogExtendOptions = { + 'closable' : true, + 'maximizable' : false, + 'minimizable' : true, + 'minimizeLocation' : 'right', + 'collapsable' : false, + 'dblclick' : 'maximize', + 'load' : function(evt, dlg) { + if ((rcmail.task == 'mail' && (rcmail.env.action == 'compose' || rcmail.env.action == 'show')) || is_minimized == true) { + $('#alarm-display').dialogExtend('minimize'); + $('#dialog-extend-fixed-container').children().width(300); + if (focused.is('input') || focused.is('textarea')) { + $(focused).focus(); + } + else if (typeof tinymce == 'object') { + window.setTimeout("tinymce.get(rcmail.env.composebody).getBody().focus();", 100); + } + } + }, + 'minimize' : function (evt, dlg) { + $('#dialog-extend-fixed-container').children().width(300); + }, + }; + // End Mod by Rosali + + this.alarm_dialog.appendTo(document.body).dialog({ + modal: false, + resizable: true, + closeOnEscape: false, + dialogClass: 'alarm', + title: '<span class="ui-icon ui-icon-alarms" style="float:left; margin:0 4px 0 0"></span>' + rcmail.gettext('alarmtitle','libcalendaring'), + buttons: buttons, + close: function() { + $('#alarm-snooze-dropdown').hide(); + $(this).dialog('destroy').remove(); + me.alarm_dialog = null; + me.alarm_ids = null; + }, + drag: function(event, ui) { + $('#alarm-snooze-dropdown').hide(); + } + }).dialogExtend(dialogExtendOptions); // Mod by Rosali + + this.alarm_ids = event_ids; + }; + + /** + * Show a drop-down menu with a selection of snooze times + */ + this.snooze_dropdown = function(link) + { + if (!this.snooze_popup) { + this.snooze_popup = $('#alarm-snooze-dropdown'); + // create popup if not found + if (!this.snooze_popup.length) { + this.snooze_popup = $('<div>').attr('id', 'alarm-snooze-dropdown').addClass('popupmenu').appendTo(document.body); + this.snooze_popup.html(rcmail.env.snooze_select) + } + $('#alarm-snooze-dropdown a').click(function(e){ + var time = String(this.href).replace(/.+#/, ''); + me.dismiss_alarm($('#alarm-snooze-dropdown').data('id'), time); + return false; + }); + } + + // hide visible popup + if (this.snooze_popup.is(':visible') && this.snooze_popup.data('id') == link.data('id')) { + this.snooze_popup.hide(); + this.dismiss_link = null; + } + else { // open popup below the clicked link + var pos = link.offset(); + pos.top += link.height() + 2; + this.snooze_popup.data('id', link.data('id')).css({ top:Math.floor(pos.top)+'px', left:Math.floor(pos.left)+'px' }).show(); + this.dismiss_link = link; + } + }; + + /** + * Dismiss or snooze alarms for the given event + */ + this.dismiss_alarm = function(id, snooze) + { + $('#alarm-snooze-dropdown').hide(); + rcmail.http_post('utils/plugin.alarms', { action:'dismiss', data:{ id:id, snooze:snooze } }); + + // remove dismissed alarm from list + if (this.dismiss_link) { + this.dismiss_link.closest('div.alarm-item').hide(); + var new_ids = jQuery.grep(this.alarm_ids, function(v){ return v != id; }); + if (new_ids.length) + this.alarm_ids = new_ids; + else + this.alarm_dialog.dialog('close'); + } + + this.dismiss_link = null; + }; + + /***** Recurrence form handling *****/ + + /** + * Install event handlers on recurrence form elements + */ + this.init_recurrence_edit = function(prefix) + { + // toggle recurrence frequency forms + $('#edit-recurrence-frequency').change(function(e){ + var freq = $(this).val().toLowerCase(); + $('.recurrence-form').hide(); + if (freq) { + $('#recurrence-form-'+freq).show(); + if (freq != 'rdate') + $('#recurrence-form-until').show(); + } + }); + $('#recurrence-form-rdate input.button.add').click(function(e){ + var dt, dv = $('#edit-recurrence-rdate-input').val(); + if (dv && (dt = me.parse_datetime('12:00', dv))) { + me.add_rdate(dt); + me.sort_rdates(); + $('#edit-recurrence-rdate-input').val('') + } + else { + $('#edit-recurrence-rdate-input').select(); + } + }); + $('#edit-recurrence-rdates').on('click', 'a.delete', function(e){ + $(this).closest('li').remove(); + return false; + }); + + $('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) }); + $('#edit-recurrence-repeat-times').change(function(e){ $('#edit-recurrence-repeat-count').prop('checked', true); }); + $('#edit-recurrence-rdate-input').datepicker(datepicker_settings); + }; + + /** + * Set recurrence form according to the given event/task record + */ + this.set_recurrence_edit = function(rec) + { + var recurrence = $('#edit-recurrence-frequency').val(rec.recurrence ? rec.recurrence.FREQ || (rec.recurrence.RDATE ? 'RDATE' : '') : '').change(), + interval = $('.recurrence-form select.edit-recurrence-interval').val(rec.recurrence ? rec.recurrence.INTERVAL || 1 : 1), + rrtimes = $('#edit-recurrence-repeat-times').val(rec.recurrence ? rec.recurrence.COUNT || 1 : 1), + rrenddate = $('#edit-recurrence-enddate').val(rec.recurrence && rec.recurrence.UNTIL ? this.format_datetime(this.parseISO8601(rec.recurrence.UNTIL), 1) : ''); + $('.recurrence-form input.edit-recurrence-until:checked').prop('checked', false); + $('#edit-recurrence-rdates').html(''); + + var weekdays = ['SU','MO','TU','WE','TH','FR','SA'], + rrepeat_id = '#edit-recurrence-repeat-forever'; + if (rec.recurrence && rec.recurrence.COUNT) rrepeat_id = '#edit-recurrence-repeat-count'; + else if (rec.recurrence && rec.recurrence.UNTIL) rrepeat_id = '#edit-recurrence-repeat-until'; + $(rrepeat_id).prop('checked', true); + + if (rec.recurrence && rec.recurrence.BYDAY && rec.recurrence.FREQ == 'WEEKLY') { + var wdays = rec.recurrence.BYDAY.split(','); + $('input.edit-recurrence-weekly-byday').val(wdays); + } + if (rec.recurrence && rec.recurrence.BYMONTHDAY) { + $('input.edit-recurrence-monthly-bymonthday').val(String(rec.recurrence.BYMONTHDAY).split(',')); + $('input.edit-recurrence-monthly-mode').val(['BYMONTHDAY']); + } + if (rec.recurrence && rec.recurrence.BYDAY && (rec.recurrence.FREQ == 'MONTHLY' || rec.recurrence.FREQ == 'YEARLY')) { + var byday, section = rec.recurrence.FREQ.toLowerCase(); + if ((byday = String(rec.recurrence.BYDAY).match(/(-?[1-4])([A-Z]+)/))) { + $('#edit-recurrence-'+section+'-prefix').val(byday[1]); + $('#edit-recurrence-'+section+'-byday').val(byday[2]); + } + $('input.edit-recurrence-'+section+'-mode').val(['BYDAY']); + } + else if (rec.start) { + $('#edit-recurrence-monthly-byday').val(weekdays[rec.start.getDay()]); + } + if (rec.recurrence && rec.recurrence.BYMONTH) { + $('input.edit-recurrence-yearly-bymonth').val(String(rec.recurrence.BYMONTH).split(',')); + } + else if (rec.start) { + $('input.edit-recurrence-yearly-bymonth').val([String(rec.start.getMonth()+1)]); + } + if (rec.recurrence && rec.recurrence.RDATE) { + $.each(rec.recurrence.RDATE, function(i,rdate){ + me.add_rdate(me.parseISO8601(rdate)); + }); + } + }; + + /** + * Gather recurrence settings from form + */ + this.serialize_recurrence = function(timestr) + { + var recurrence = '', + freq = $('#edit-recurrence-frequency').val(); + + if (freq != '') { + recurrence = { + FREQ: freq, + INTERVAL: $('#edit-recurrence-interval-'+freq.toLowerCase()).val() + }; + + var until = $('input.edit-recurrence-until:checked').val(); + + if (until == 'count') + recurrence.COUNT = $('#edit-recurrence-repeat-times').val(); + else if (until == 'until') + recurrence.UNTIL = me.date2ISO8601(me.parse_datetime(timestr || '00:00', $('#edit-recurrence-enddate').val())); + + if (freq == 'WEEKLY') { + var byday = []; + $('input.edit-recurrence-weekly-byday:checked').each(function(){ byday.push(this.value); }); + if (byday.length) + recurrence.BYDAY = byday.join(','); + } + else if (freq == 'MONTHLY') { + var mode = $('input.edit-recurrence-monthly-mode:checked').val(), bymonday = []; + if (mode == 'BYMONTHDAY') { + $('input.edit-recurrence-monthly-bymonthday:checked').each(function(){ bymonday.push(this.value); }); + if (bymonday.length) + recurrence.BYMONTHDAY = bymonday.join(','); + } + else + recurrence.BYDAY = $('#edit-recurrence-monthly-prefix').val() + $('#edit-recurrence-monthly-byday').val(); + } + else if (freq == 'YEARLY') { + var byday, bymonth = []; + $('input.edit-recurrence-yearly-bymonth:checked').each(function(){ bymonth.push(this.value); }); + if (bymonth.length) + recurrence.BYMONTH = bymonth.join(','); + if ((byday = $('#edit-recurrence-yearly-byday').val())) + recurrence.BYDAY = $('#edit-recurrence-yearly-prefix').val() + byday; + } + else if (freq == 'RDATE') { + recurrence = { RDATE:[] }; + // take selected but not yet added date into account + if ($('#edit-recurrence-rdate-input').val() != '') { + $('#recurrence-form-rdate input.button.add').click(); + } + $('#edit-recurrence-rdates li').each(function(i, li){ + recurrence.RDATE.push($(li).attr('data-value')); + }); + } + } + + return recurrence; + }; + + // add the given date to the RDATE list + this.add_rdate = function(date) + { + var li = $('<li>') + .attr('data-value', this.date2ISO8601(date)) + .html('<span>' + Q(this.format_datetime(date, 1)) + '</span>') + .appendTo('#edit-recurrence-rdates'); + + $('<a>').attr('href', '#del') + .addClass('iconbutton delete') + .html(rcmail.get_label('delete', 'libcalendaring')) + .attr('title', rcmail.get_label('delete', 'libcalendaring')) + .appendTo(li); + }; + + // re-sort the list items by their 'data-value' attribute + this.sort_rdates = function() + { + var mylist = $('#edit-recurrence-rdates'), + listitems = mylist.children('li').get(); + listitems.sort(function(a, b) { + var compA = $(a).attr('data-value'); + var compB = $(b).attr('data-value'); + return (compA < compB) ? -1 : (compA > compB) ? 1 : 0; + }) + $.each(listitems, function(idx, item) { mylist.append(item); }); + }; +} + + +// extend jQuery +(function($){ + $.fn.serializeJSON = function(){ + var json = {}; + jQuery.map($(this).serializeArray(), function(n, i) { + json[n['name']] = n['value']; + }); + return json; + }; +})(jQuery); + + +/* libcalendaring plugin initialization */ +window.rcmail && rcmail.addEventListener('init', function(evt) { + if (rcmail.env.libcal_settings) { + var libcal = new rcube_libcalendaring(rcmail.env.libcal_settings); + rcmail.addEventListener('plugin.display_alarms', function(alarms){ libcal.display_alarms(alarms); }); + if (!rcmail.env.framed && !rcmail.env.extwin && rcmail.env.username) { + window.setTimeout("rcmail.http_post('refresh', '');", 1000); // Mod by Rosali (fetch reminders almost immediately) + } + } +}); diff --git a/libgpl/libgpl.php b/libgpl/libgpl.php new file mode 100644 index 0000000..de9747f --- /dev/null +++ b/libgpl/libgpl.php @@ -0,0 +1,189 @@ +<?php
+#
+# This file is part of MyRoundcube "libgpl" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class libgpl extends rcube_plugin
+{
+ private $labels_merged;
+
+ /* unified plugin properties */
+ static private $plugin = 'libgpl';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?libgpl" target="_blank">Documentation</a>';
+ static private $version = '1.0.38';
+ static private $date = '12-02-2014';
+ static private $licence = 'GPL';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3',
+ 'required_plugins' => array(
+ 'jqueryui' => 'require_plugin',
+ ),
+ );
+ static private $f;
+
+ function init(){
+ self::$f = $this;
+ $this->add_texts('localization/');
+ $this->require_plugin('jqueryui');
+ $this->include_stylesheet('qtip/qtip.css');
+ $this->include_stylesheet($this->local_skin_path() . '/calendar.css');
+ $this->include_script('timepicker2/jquery.timepicker.js');
+ $this->include_stylesheet($this->local_skin_path() . '/timepicker2.css');
+ $this->include_script('dialogextend/jquery.dialogextend.js');
+ $this->include_script('libcalendaring/libcalendaring.js');
+ $this->include_script('jquery_migrate/jquery.migrate.js');
+ $this->include_script('qtip/qtip.js');
+ $this->add_hook('render_page', array($this, 'render_page'));
+ $this->add_hook('send_page', array($this, 'send_page'));
+ $this->add_hook('preferences_list', array($this, 'preferences_list'));
+ if(!class_exists('MyRCHttp')){
+ require_once('http_request/class.http.php');
+ }
+ if(!$this->labels_merged){
+ $this->labels_merged = true;
+ $this->_merge_labels(
+ array(
+ 'tasks' => 'calendar',
+ 'calendar_kolab' => 'calendar',
+ 'calendar_database' => 'calendar',
+ 'calendar_caldav' => 'calendar',
+ 'calendar_ical' => 'calendar',
+ 'calendar_google_xml' => 'calendar',
+ 'errorimportingtask' => 'calendar',
+ 'treat_as_allday' => 'calendar',
+ 'hours' => 'calendar',
+ 'movetotasks' => 'calendar',
+ 'movetocalendar' => 'calendar',
+ 'emailevent' => 'calendar',
+ 'movetonotes' => 'calendar',
+ 'quit' => 'calendar',
+ 'eventaction' => 'calendar',
+ 'gooledisabled' => 'calendar',
+ 'googledisabled_redirect' => 'calendar',
+ 'allowfreebusy' => 'calendar',
+ 'freebusy' => 'calendar',
+ 'sync_interval' => 'calendar',
+ 'minute_s' => 'calendar',
+ 'unabletoadddefaultcalendars' => 'calendar',
+ 'list' => 'tasklist',
+ 'editlist' => 'tasklist',
+ 'tags' => 'tasklist',
+ 'subscribe' => 'tasklist',
+ 'is_subtask' => 'tasklist',
+ 'due' => 'tasklist',
+ 'taskaction' => 'tasklist',
+ 'emailtask' => 'tasklist',
+ 'subscribed' => 'carddav',
+ )
+ );
+ }
+ }
+
+ static public function include_js($js){
+ self::$f->include_script($js);
+ }
+
+ static public function include_php($php){
+ require_once INSTALL_PATH . $php;
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+
+ public function render_page($p){
+ if($this->rc->user->data['username']){
+ $this->rc->output->set_env('username', $this->rc->user->data['username']);
+ }
+ if($p['template'] == 'calendar.calendar' || $p['template'] == 'calendar.print' || $p['template'] == 'tasklist.mainview'){
+ $this->include_script('querystring/querystring.js');
+ $this->include_script('date/date.js');
+ $this->include_stylesheet($this->local_skin_path() . '/jquery.contextMenu.css');
+ $this->include_script('contextmenu/jquery.contextMenu.js');
+ $this->include_script('contextmenu/jquery.ui.position.js');
+ }
+ else if($p['template'] == 'sticky_notes.sticky_notes'){
+ $this->include_stylesheet('fancybox/jquery.fancybox-1.3.4.css');
+ $this->include_script("fancybox/jquery.fancybox-1.3.4.pack.js");
+ $this->include_script('date/date.js');
+ $this->include_stylesheet($this->local_skin_path() . '/jquery.contextMenu.css');
+ $this->include_script('contextmenu/jquery.contextMenu.js');
+ $this->include_script('contextmenu/jquery.ui.position.js');
+ }
+ if(class_exists('password_plus')){
+ $this->include_script('password/password.js');
+ }
+ return $p;
+ }
+
+ public function send_page($args)
+ {
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/libcalendaring\/libcalendaring.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/libcalendaring\/libcalendaring.min.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ if(class_exists('password_plus')){
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/password\/password.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/password\/password.min.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ }
+ return $args;
+ }
+
+ public function preferences_list($args){
+ if($args['section'] == 'calendarsharing'|| $args['section'] == 'addressbooksharing'){
+ $rcmail = rcube::get_instance();
+ if(!$args['current']){
+ $args['blocks']['view']['content'] = true;
+ return $args;
+ }
+ if($dsn = $rcmail->config->get('db_sabredav_dsn')){
+ $this->include_script('flashclipboard/flashclipboard_libgpl.js');
+ }
+ }
+ return $args;
+ }
+
+ private function _merge_labels($labels){
+ foreach($labels as $label => $env){
+ rcube::get_instance()->load_language(null, array(), array($env . '.' . $label => $this->gettext($label)));
+ }
+ }
+
+}
+?>
\ No newline at end of file diff --git a/libgpl/localization/cs_CZ.inc b/libgpl/localization/cs_CZ.inc new file mode 100644 index 0000000..eca44df --- /dev/null +++ b/libgpl/localization/cs_CZ.inc @@ -0,0 +1,48 @@ +<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/22/2015 08:02:38
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV kalendář';
+$labels['calendar_kolab'] = 'Kolab kalendář';
+$labels['calendar_database'] = 'lokální kalendář';
+$labels['calendar_ical'] = 'iCAL kalendář';
+$labels['calendar_google_xml'] = 'Google XML kalendář';
+$labels['sync_interval'] = 'Synchronizovat každých';
+$labels['minute_s'] = 'minut(y)';
+$labels['tasks'] = 'Úkoly';
+$labels['errorimportingtask'] = 'Nepodařilo se naimportovat úkoly';
+$labels['treat_as_allday'] = 'Zobrazit událost jako celodenní pokud trvá déle než';
+$labels['hours'] = 'Hodin';
+$labels['movetotasks'] = 'Přesunout do úkolů';
+$labels['movetocalendar'] = 'Přesunout do kalendáře';
+$labels['emailevent'] = 'Poslat událost';
+$labels['emailnote'] = 'Poslat poznámku';
+$labels['emailtask'] = 'Poslat úkol';
+$labels['movetonotes'] = 'Přesunout do poznámek';
+$labels['quit'] = 'Ukončit';
+$labels['eventaction'] = 'Akce události...';
+$labels['googledisabled'] = 'Povolte prosím přístup k vašemu účtu Google (přejděte na "Nastavení" -> "Správa účtu" -> "Další nastavení účtu" a proveďte patřičná nastavení).';
+$labels['googledisabled_redirect'] = 'Povolte prosím přístup k vašemu účtu Google.';
+$labels['allowfreebusy'] = 'Povolit požadavek na obsazenost';
+$labels['freebusy'] = 'Obsazenost';
+$labels['unabletoadddefaultcalendars'] = 'Nelze přidat výchozí kalendář';
+$labels['taskaction'] = 'Akce úkolu...';
+$labels['due'] = ' ';
+$labels['is_subtask'] = 'Dílčí úkol';
+$labels['subscribe'] = 'Abyste mohli vytvářet úkoly, tak si je prosím povolte ve svém kalendáři.';
+$labels['subscribed'] = 'Přihlášeno';
+$labels['tags'] = 'Kategorie';
+$labels['list'] = 'Kalendář';
+$labels['editlist'] = 'Upravit kalendář';
+
+?>
\ No newline at end of file diff --git a/libgpl/localization/en_US.inc b/libgpl/localization/en_US.inc new file mode 100644 index 0000000..22c7c1b --- /dev/null +++ b/libgpl/localization/en_US.inc @@ -0,0 +1,36 @@ +<?php
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV Calendar';
+$labels['calendar_kolab'] = 'Kolab Calendar';
+$labels['calendar_database'] = 'Local Calendar';
+$labels['calendar_ical'] = 'iCAL Calendar';
+$labels['calendar_google_xml'] = 'Google XML Calendar';
+$labels['sync_interval'] = 'Synchronization every';
+$labels['minute_s'] = 'minute(s)';
+$labels['tasks'] = 'Tasks';
+$labels['errorimportingtask'] = 'Failed to import the task';
+$labels['treat_as_allday'] = 'Show event as all-day if it takes more than';
+$labels['hours'] = 'Hours';
+$labels['movetotasks'] = 'Move to tasks';
+$labels['movetocalendar'] = 'Move to calendar';
+$labels['emailevent'] = 'Email event';
+$labels['emailnote'] = 'Email note';
+$labels['emailtask'] = 'Email task';
+$labels['movetonotes'] = 'Move to notes';
+$labels['quit'] = 'Quit';
+$labels['eventaction'] = 'Event action...';
+$labels['googledisabled'] = 'Please authorize access to your Google account (browse to <i>"Settings"</i> -> <i>"Account Administration" </i> -> <i>"Other account\'s settings"</i> and proceed).';
+$labels['googledisabled_redirect'] = 'Please authorize access to your Google account.';
+$labels['allowfreebusy'] = 'Allow freebusy requests';
+$labels['freebusy'] = 'Freebusy';
+$labels['unabletoadddefaultcalendars'] = 'Unable to add default calendars';
+$labels['taskaction'] = 'Task action...';
+$labels['due'] = 'due';
+$labels['is_subtask'] = 'Subtask';
+$labels['subscribe'] = 'Please subscribe to a calendar in order to create a task.';
+$labels['subscribed'] = 'Subscribed';
+$labels['tags'] = 'Categories';
+$labels['list'] = 'Calendar';
+$labels['editlist'] = 'Edit calendar';
+
+?>
\ No newline at end of file diff --git a/libgpl/localization/es_ES.inc b/libgpl/localization/es_ES.inc new file mode 100644 index 0000000..d84590b --- /dev/null +++ b/libgpl/localization/es_ES.inc @@ -0,0 +1,48 @@ +<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/10/2015 10:46:25
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'Calendario CalDAV';
+$labels['calendar_kolab'] = 'Calendario Kolab';
+$labels['calendar_database'] = 'Calendario Local';
+$labels['calendar_ical'] = 'Calendario iCAL';
+$labels['calendar_google_xml'] = 'Calendario Google XML';
+$labels['sync_interval'] = 'Sincronización cada';
+$labels['minute_s'] = 'minuto(s)';
+$labels['tasks'] = 'Tareas';
+$labels['errorimportingtask'] = 'No se pudo importar la tarea';
+$labels['treat_as_allday'] = 'Mostrar evento como \'todo el día\' si toma más de';
+$labels['hours'] = 'Horas';
+$labels['movetotasks'] = 'Mover a tareas';
+$labels['movetocalendar'] = 'Mover al calendario';
+$labels['emailevent'] = 'Enviar evento por correo';
+$labels['emailnote'] = 'Enviar nota por correo';
+$labels['emailtask'] = 'Enviar tarea por correo';
+$labels['movetonotes'] = 'Mover a notas';
+$labels['quit'] = 'Salir';
+$labels['eventaction'] = 'Acción de evento...';
+$labels['googledisabled'] = 'Please authorize access to your Google account (browse to "Settings" -> "Account Administration" -> "Other account\'s settings" and proceed). Por favor, autorizar el acceso a su cuenta de Google (vaya a "Configuración" -> "Administración de Cuenta" -> "Otros ajustes de cuentas" y proceda).';
+$labels['googledisabled_redirect'] = 'Por favor, autorizar el acceso a su cuenta de Google.';
+$labels['allowfreebusy'] = 'Permitir solicitudes Libre/Ocupado';
+$labels['freebusy'] = 'Libre/Ocupado';
+$labels['unabletoadddefaultcalendars'] = 'No se pudo agregar calendarios predeterminados';
+$labels['taskaction'] = 'Acción de tarea...';
+$labels['due'] = 'debido el';
+$labels['is_subtask'] = 'Subtarea';
+$labels['subscribe'] = 'Por favor, suscribirse a un calendario para poder crear tarea.';
+$labels['subscribed'] = 'Suscrito';
+$labels['tags'] = 'Categorías';
+$labels['list'] = 'Calendario';
+$labels['editlist'] = 'Editar calendario';
+
+?>
\ No newline at end of file diff --git a/libgpl/localization/fi_FI.inc b/libgpl/localization/fi_FI.inc new file mode 100644 index 0000000..021ab3d --- /dev/null +++ b/libgpl/localization/fi_FI.inc @@ -0,0 +1,48 @@ +<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/12/2015 07:37:20
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV kalenteri';
+$labels['calendar_kolab'] = 'Kolab kalenteri';
+$labels['calendar_database'] = 'Paikallinen kalenteri';
+$labels['calendar_ical'] = 'iCal kalenteri';
+$labels['calendar_google_xml'] = 'Google XML kalenteri';
+$labels['sync_interval'] = 'Synkronisointi joka';
+$labels['minute_s'] = 'minuutti(a)';
+$labels['tasks'] = 'Tehtävät';
+$labels['errorimportingtask'] = 'Tehtävän tuonti epäonnistui';
+$labels['treat_as_allday'] = 'Näytä tapahtumat koko päivän tapahtumana jos ne kestävät enemmän kuin';
+$labels['hours'] = 'Tuntia';
+$labels['movetotasks'] = 'Siirrä tehtäviin';
+$labels['movetocalendar'] = 'Siirrä kalenteriin';
+$labels['emailevent'] = 'Lähetä tapahtuma';
+$labels['emailnote'] = 'Lähetä viesti';
+$labels['emailtask'] = 'Lähetä tehtävä';
+$labels['movetonotes'] = 'Siirrä muistioon';
+$labels['quit'] = 'Poistu';
+$labels['eventaction'] = 'Tapahtuman toiminto...';
+$labels['googledisabled'] = 'Anna valtuutus Google tilille ("Asetukset" -> "Tilin hallinta" -> "Muut tilin asetukset")';
+$labels['googledisabled_redirect'] = 'Anna valtuutus Google tilillesi';
+$labels['allowfreebusy'] = 'Salli freebusy pyynnöt';
+$labels['freebusy'] = 'Freebusy';
+$labels['unabletoadddefaultcalendars'] = 'Oletuskalenterien lisäys epäonnistui';
+$labels['taskaction'] = 'Tehtävän toiminto...';
+$labels['due'] = 'valmistuu';
+$labels['is_subtask'] = 'Alatehtävä';
+$labels['subscribe'] = 'Tee tilaus kalenteriin jotta voit luoda tehtäviä.';
+$labels['subscribed'] = 'Tilattu';
+$labels['tags'] = 'Kategoriat';
+$labels['list'] = 'Kalenteri';
+$labels['editlist'] = 'Muokkaa kalenteria';
+
+?>
\ No newline at end of file diff --git a/libgpl/localization/fr_FR.inc b/libgpl/localization/fr_FR.inc new file mode 100644 index 0000000..9344bc3 --- /dev/null +++ b/libgpl/localization/fr_FR.inc @@ -0,0 +1,51 @@ +<?php + +/* ++-----------------------------------------------------------------------+ +| language/fr_FR/labels.inc | +| | +| Language file of the RoundCube Webmail client | +| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland | +| Licensed under the GNU GPL | +| | ++-----------------------------------------------------------------------+ +| Author: Olivier Zolli - 01/11/2015 | ++-----------------------------------------------------------------------+ + +*/ + +$labels = array(); +$labels['calendar_caldav'] = 'Agenda CalDAV'; +$labels['calendar_kolab'] = 'Agenda Kolab'; +$labels['calendar_database'] = 'Agenda local'; +$labels['calendar_ical'] = 'Agenda iCAL'; +$labels['calendar_google_xml'] = 'Agenda Google XML'; +$labels['sync_interval'] = 'Synchronisation chaque'; +$labels['minute_s'] = 'minute(s)'; +$labels['tasks'] = 'Tâches'; +$labels['errorimportingtask'] = 'Echec d\'importation de la tâche'; +$labels['treat_as_allday'] = 'Montrer l\'évènement comme "Toute la journée" s\'il dure plus de'; +$labels['hours'] = 'Heures'; +$labels['movetotasks'] = 'Déplacer vers les tâches'; +$labels['movetocalendar'] = 'Déplacer vers l\'agenda'; +$labels['emailevent'] = 'Evènement courriel'; +$labels['emailnote'] = 'Evènement note'; +$labels['emailtask'] = 'Evènement tâche'; +$labels['movetonotes'] = 'Déplacer vers les notes'; +$labels['quit'] = 'Quitter'; +$labels['eventaction'] = 'Action d\'évènement'; +$labels['googledisabled'] = 'Veuillez autoriser l\'accès à votre compte Google (<i>"Paramètres"</i> -> <i>"Administration du compte"</i> -> <i>"Autres paramètres du compte"</i>'; +$labels['googledisabled_redirect'] = 'Veuillez autoriser l\'accès à votre compte Google'; +$labels['allowfreebusy'] = 'Autoriser les requêtes Libre/Occupé'; +$labels['freebusy'] = 'Libre/Occupé'; +$labels['unabletoadddefaultcalendars'] = 'Impossible d\'ajouter les agendas par défaut'; +$labels['taskaction'] = 'Action de tâche'; +$labels['due'] = 'requis'; +$labels['is_subtask'] = 'Sous-tâche'; +$labels['subscribe'] = 'Veuillez vous inscrire à un agenda pour créer une tâche'; +$labels['subscribed'] = 'Inscrit'; +$labels['tags'] = 'Catégories'; +$labels['list'] = 'Agenda'; +$labels['editlist'] = 'Editer l\'agenda'; + +?>
\ No newline at end of file diff --git a/libgpl/localization/revision.inc.php b/libgpl/localization/revision.inc.php new file mode 100644 index 0000000..e9f587a --- /dev/null +++ b/libgpl/localization/revision.inc.php @@ -0,0 +1,11 @@ +<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'tachec',
+ 'language ' => 'cs_CZ',
+ 'date' => '01/22/2015 08:02:38'
+ )
+);
+
+?>
\ No newline at end of file diff --git a/libgpl/package.xml b/libgpl/package.xml new file mode 100644 index 0000000..f9cc54d --- /dev/null +++ b/libgpl/package.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 + http://pear.php.net/dtd/tasks-1.0.xsd + http://pear.php.net/dtd/package-2.0 + http://pear.php.net/dtd/package-2.0.xsd"> + <name>libgpl</name> + <lead> + <name>Myroundcube Dev Team</name> + <user>rosali</user> + <email>dev-team@myroundcube.com</email> + <active>yes</active> + </lead><date>2014-02-12</date> + <version> + <release>1.0.38</release> + <api>1.0.38</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license> +</package> diff --git a/libgpl/password/password.js b/libgpl/password/password.js new file mode 100644 index 0000000..6b17b64 --- /dev/null +++ b/libgpl/password/password.js @@ -0,0 +1,36 @@ +/** + * Password plugin script + * @version @package_version@ + */ + +if (window.rcmail) { + rcmail.addEventListener('init', function(evt) { + + // register command handler + rcmail.register_command('plugin.password-save', function() { + var input_curpasswd = rcube_find_object('_curpasswd'), + input_newpasswd = rcube_find_object('_newpasswd'), + input_confpasswd = rcube_find_object('_confpasswd'); + input_pwstrength = rcube_find_object('_pwstrength'); + + if (input_curpasswd && input_curpasswd.value == '') { + rcmail.display_message(rcmail.gettext('nocurpassword', 'password'), 'error'); + input_curpasswd.focus(); + } else if (input_newpasswd && input_newpasswd.value == '') { + rcmail.display_message(rcmail.gettext('nopassword', 'password'), 'error'); + input_newpasswd.focus(); + } else if (input_confpasswd && input_confpasswd.value == '') { + rcmail.display_message(rcmail.gettext('nopassword', 'password'), 'error'); + input_confpasswd.focus(); + } else if (input_newpasswd && input_confpasswd && input_newpasswd.value != input_confpasswd.value) { + rcmail.display_message(rcmail.gettext('passwordinconsistency', 'password'), 'error'); + input_newpasswd.focus(); + } else if (input_pwstrength.value == 0) { + rcmail.display_message(rcmail.gettext('passwordweak', 'pwstrength'), 'error'); + input_newpasswd.focus(); + } else { + rcmail.gui_objects.passform.submit(); + } + }, true); + }) +} diff --git a/libgpl/qtip/qtip.css b/libgpl/qtip/qtip.css new file mode 100644 index 0000000..9147bd7 --- /dev/null +++ b/libgpl/qtip/qtip.css @@ -0,0 +1 @@ +.ui-tooltip-fluid{display:block;visibility:hidden;position:static!important;float:left!important;}.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;}.ui-tooltip-content{position:relative;padding:5px 9px;overflow:hidden;border-width:1px;border-style:solid;text-align:left;word-wrap:break-word;overflow:hidden;}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border-width:1px 1px 0;border-style:solid;font-weight:bold;}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0!important;}/*!Default close button class */ .ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;}* html .ui-tooltip-titlebar .ui-state-default{top:16px;}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em;}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em;}/*!Default tooltip style */ .ui-tooltip-titlebar,.ui-tooltip-content{border-color:#F1D031;background-color:#FFFFA3;color:#555;}.ui-tooltip-titlebar{background-color:#FFEF93;}.ui-tooltip-titlebar .ui-tooltip-icon{border-color:#CCC;background:#F1F1F1;color:#777;}.ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111;}/*!Light tooltip style */ .ui-tooltip-light .ui-tooltip-titlebar,.ui-tooltip-light .ui-tooltip-content{border-color:#E2E2E2;color:#454545;}.ui-tooltip-light .ui-tooltip-content{background-color:white;}.ui-tooltip-light .ui-tooltip-titlebar{background-color:#f1f1f1;}/*!Dark tooltip style */ .ui-tooltip-dark .ui-tooltip-titlebar,.ui-tooltip-dark .ui-tooltip-content{border-color:#303030;color:#f3f3f3;}.ui-tooltip-dark .ui-tooltip-content{background-color:#505050;}.ui-tooltip-dark .ui-tooltip-titlebar{background-color:#404040;}.ui-tooltip-dark .ui-tooltip-icon{border-color:#444;}.ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}/*!Cream tooltip style */ .ui-tooltip-cream .ui-tooltip-titlebar,.ui-tooltip-cream .ui-tooltip-content{border-color:#F9E98E;color:#A27D35;}.ui-tooltip-cream .ui-tooltip-content{background-color:#FBF7AA;}.ui-tooltip-cream .ui-tooltip-titlebar{background-color:#F0DE7D;}.ui-tooltip-cream .ui-state-default .ui-tooltip-icon{background-position:-82px 0;}/*!Red tooltip style */ .ui-tooltip-red .ui-tooltip-titlebar,.ui-tooltip-red .ui-tooltip-content{border-color:#D95252;color:#912323;}.ui-tooltip-red .ui-tooltip-content{background-color:#F78B83;}.ui-tooltip-red .ui-tooltip-titlebar{background-color:#F06D65;}.ui-tooltip-red .ui-state-default .ui-tooltip-icon{background-position:-102px 0;}.ui-tooltip-red .ui-tooltip-icon{border-color:#D95252;}.ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{border-color:#D95252;}/*!Green tooltip style */ .ui-tooltip-green .ui-tooltip-titlebar,.ui-tooltip-green .ui-tooltip-content{border-color:#90D93F;color:#3F6219;}.ui-tooltip-green .ui-tooltip-content{background-color:#CAED9E;}.ui-tooltip-green .ui-tooltip-titlebar{background-color:#B0DE78;}.ui-tooltip-green .ui-state-default .ui-tooltip-icon{background-position:-42px 0;}/*!Blue tooltip style */ .ui-tooltip-blue .ui-tooltip-titlebar,.ui-tooltip-blue .ui-tooltip-content{border-color:#ADD9ED;color:#5E99BD;}.ui-tooltip-blue .ui-tooltip-content{background-color:#E5F6FE;}.ui-tooltip-blue .ui-tooltip-titlebar{background-color:#D0E9F5;}.ui-tooltip-blue .ui-state-default .ui-tooltip-icon{background-position:-2px 0;}.ui-tooltip .ui-tooltip-tip{margin:0 auto;overflow:hidden;background:transparent!important;border:0 dashed transparent!important;z-index:10;}.ui-tooltip .ui-tooltip-tip,.ui-tooltip .ui-tooltip-tip *{position:absolute;line-height:.1px!important;font-size:.1px!important;color:#123456;background:transparent;border:0 dashed transparent;}.ui-tooltip .ui-tooltip-tip canvas{position:static;}#qtip-overlay{position:absolute;left:-10000em;top:-10000em;background-color:black;opacity:.7;filter:alpha(opacity=70);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";}/*!Add shadows to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE6+,Safari 2+*/ .ui-tooltip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);}.ui-tooltip-shadow .ui-tooltip-titlebar,.ui-tooltip-shadow .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3);-ms-filter:"progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3)";_margin-bottom:-3px;.margin-bottom:-3px;}/*!Add rounded corners to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE9+,Safari 2+*/ .ui-tooltip-rounded,.ui-tooltip-rounded .ui-tooltip-content,.ui-tooltip-tipsy,.ui-tooltip-tipsy .ui-tooltip-content,.ui-tooltip-youtube,.ui-tooltip-youtube .ui-tooltip-content{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}.ui-tooltip-rounded .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-titlebar{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.ui-tooltip-rounded .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-tipsy .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-youtube .ui-tooltip-titlebar+.ui-tooltip-content{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;}/*!Youtube tooltip style */ .ui-tooltip-youtube{-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;}.ui-tooltip-youtube .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-content{background:transparent;background:rgba(0,0,0,0.85);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border-color:#CCC;}.ui-tooltip-youtube .ui-tooltip-icon{border-color:#222;}.ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-jtools{background:#232323;background:rgba(0,0,0,0.7);background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333;}.ui-tooltip-jtools .ui-tooltip-titlebar{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)";}.ui-tooltip-jtools .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)";}.ui-tooltip-jtools .ui-tooltip-titlebar,.ui-tooltip-jtools .ui-tooltip-content{background:transparent;color:white;border:0 dashed transparent;}.ui-tooltip-jtools .ui-tooltip-icon{border-color:#555;}.ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{border-color:#333;}.ui-tooltip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,0.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,0.4);box-shadow:4px 4px 5px rgba(0,0,0,0.4);}.ui-tooltip-cluetip .ui-tooltip-titlebar{background-color:#87876A;color:white;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-content{background-color:#D9D9C2;color:#111;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-icon{border-color:#808064;}.ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{border-color:#696952;color:#696952;}.ui-tooltip-tipsy{border:0;}.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-content{background:transparent;background:rgba(0,0,0,.87);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border:0 transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:bold;line-height:16px;text-shadow:0 1px black;}.ui-tooltip-tipsy .ui-tooltip-titlebar{padding:6px 35px 0 10;}.ui-tooltip-tipsy .ui-tooltip-content{padding:6px 10;}.ui-tooltip-tipsy .ui-tooltip-icon{border-color:#222;text-shadow:none;}.ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-tipped .ui-tooltip-titlebar,.ui-tooltip-tipped .ui-tooltip-content{border:3px solid #959FA9;}.ui-tooltip-tipped .ui-tooltip-titlebar{background:#3A79B8;background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)";color:white;font-weight:normal;font-family:serif;border-bottom-width:0;-moz-border-radius:3px 3px 0 0;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}.ui-tooltip-tipped .ui-tooltip-content{background-color:#F9F9F9;color:#454545;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.ui-tooltip-tipped .ui-tooltip-icon{border:2px solid #285589;background:#285589;}.ui-tooltip-tipped .ui-tooltip-icon .ui-icon{background-color:#FBFBFB;color:#555;}
\ No newline at end of file diff --git a/libgpl/qtip/qtip.js b/libgpl/qtip/qtip.js new file mode 100644 index 0000000..7f5b9d9 --- /dev/null +++ b/libgpl/qtip/qtip.js @@ -0,0 +1,68 @@ +(function(c,C,N){function X(a){var b=this,f=a.elements,e=f.tooltip,g=".bgiframe-"+a.id;c.extend(b,{init:function(){f.bgiframe=c('<iframe class="ui-tooltip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>');f.bgiframe.appendTo(e);e.bind("tooltipmove"+g,b.adjust)},adjust:function(){var b=a.get("dimensions"),c=a.plugins.tip,h=f.tip,g, +i;i=parseInt(e.css("border-left-width"),10)||0;i={left:-i,top:-i};c&&h&&(g="x"===c.corner.precedance?["width","left"]:["height","top"],i[g[1]]-=h[g[0]]());f.bgiframe.css(i).css(b)},destroy:function(){f.bgiframe.remove();e.unbind(g)}});b.init()}function Y(a){var b=this,f=a.options.show.modal,e=a.elements,r=e.tooltip,o=".qtipmodal"+a.id,m;a.checks.modal={"^show.modal.(on|blur)$":function(){b.init();e.overlay.toggle(r.is(":visible"))}};c.extend(b,{init:function(){if(!f.on)return b;m=b.create();r.attr("is-modal-qtip", +p).unbind(".qtipmodal").unbind(o).bind("tooltipshow.qtipmodal tooltiphide.qtipmodal",function(a,c,f){b[a.type.replace("tooltip","")](a,f)}).bind("tooltipfocus.qtipmodal",function(a,c,b){m[0].style.zIndex=b-1}).bind("tooltipblur.qtipmodal",function(a){c("[is-modal-qtip]:visible").not(r).last().qtip("focus",a)});f.escape&&c(C).unbind(o).bind("keydown"+o,function(c){27===c.keyCode&&r.hasClass(P)&&a.hide(c)});f.blur&&e.overlay.unbind(o).bind("click"+o,function(c){r.hasClass(P)&&a.hide(c)});return b}, +create:function(){var a=c("#qtip-overlay");if(a.length)return e.overlay=a;m=e.overlay=c("<div />",{id:"qtip-overlay",css:{position:"absolute",top:0,left:0,display:"none"},mousedown:function(){return g}}).appendTo(document.body);c(C).unbind(".qtipmodal").bind("resize.qtipmodal",function(){m.css({height:Math.max(c(C).height(),c(document).height()),width:Math.max(c(C).width(),c(document).width())})}).trigger("resize");return m},toggle:function(a,q,i){if(a&&a.isDefaultPrevented())return b;var a=f.effect, +o=q?"show":"hide",t=c("[is-modal-qtip]:visible").not(r);m||(m=b.create());if(m.is(":animated")&&!q||!q&&t.length)return b;q&&e.overlay.css("cursor",f.blur?"pointer":"");m.stop(p,g);c.isFunction(a)?a.call(m,q):a===g?m[o]():m.fadeTo(parseInt(i,10)||90,q?0.7:0,function(){q||c(this).hide()});return b},show:function(a,c){return b.toggle(a,p,c)},hide:function(a,c){return b.toggle(a,g,c)},destroy:function(){var b=m;b&&(b=1>c("[is-modal-qtip]").not(r).length,b?(e.overlay.remove(),c(C).unbind(".qtipmodal")): +e.overlay.unbind(".qtipmodal"+a.id));return r.removeAttr("is-modal-qtip").unbind(".qtipmodal")}});b.init()}function Z(a){function b(a){var c="y"===a.precedance,b=A[c?"width":"height"],d=A[c?"height":"width"],f=-1<a.string().indexOf("center"),k=b*(f?0.5:1),u=Math.pow,a=Math.round,F=Math.sqrt(u(k,2)+u(d,2)),k=[v/k*F,v/d*F];k[2]=Math.sqrt(u(k[0],2)-u(v,2));k[3]=Math.sqrt(u(k[1],2)-u(v,2));f=(F+k[2]+k[3]+(f?0:k[0]))/F;b=[a(f*d),a(f*b)];return{height:b[c?0:1],width:b[c?1:0]}}function f(a,c,b){c=c?c:a[a.precedance]; +c="border-"+c+"-width";a=parseInt((i.titlebar&&"top"===a.y?i.titlebar:i.content).css(c),10);return(b?a||parseInt(n.css(c),10):a)||0}function e(b,d,f){if(i.tip){var b=c.extend({},h.corner),d=f.adjusted,e=a.options.position.adjust.method.split(" "),v=e[0],e=e[1]||e[0],k=g,u=g,F=0,K=0,l,D={},M;h.corner.fixed!==p&&("shift"===v&&"x"===b.precedance&&d.left&&"center"!==b.y?b.precedance="x"===b.precedance?"y":"x":"flip"===v&&d.left&&(b.x="center"===b.x?0<d.left?"left":"right":"left"===b.x?"right":"left"), +"shift"===e&&"y"===b.precedance&&d.top&&"center"!==b.x?b.precedance="y"===b.precedance?"x":"y":"flip"===e&&d.top&&(b.y="center"===b.y?0<d.top?"top":"bottom":"top"===b.y?"bottom":"top"),b.string()!==r&&(o!==d.top||m!==d.left)&&h.update(b,g));l=h.position(b,d);l.right!==N&&(l.left=-l.right);l.bottom!==N&&(l.top=-l.bottom);l.user=Math.max(0,q.offset);if(k="shift"===v&&!!d.left)"center"===b.x?D["margin-left"]=F=l["margin-left"]-d.left:(M=l.right!==N?[d.left,-l.left]:[-d.left,l.left],(F=Math.max(M[0], +M[1]))>M[0]&&(f.left-=d.left,k=g),D[l.right!==N?"right":"left"]=F);if(u="shift"===e&&!!d.top)"center"===b.y?D["margin-top"]=K=l["margin-top"]-d.top:(M=l.bottom!==N?[d.top,-l.top]:[-d.top,l.top],(K=Math.max(M[0],M[1]))>M[0]&&(f.top-=d.top,u=g),D[l.bottom!==N?"bottom":"top"]=K);i.tip.css(D).toggle(!(F&&K||"center"===b.x&&K||"center"===b.y&&F));f.left-=l.left.charAt?l.user:"shift"!==v||u||!k&&!u?l.left:0;f.top-=l.top.charAt?l.user:"shift"!==e||k||!k&&!u?l.top:0;m=d.left;o=d.top;r=b.string()}}var r,o, +m,h=this,q=a.options.style.tip,i=a.elements,n=i.tooltip;m=o=0;r="";var A={width:q.width,height:q.height},y,d,v=q.border||0,G=c("<canvas />")[0].getContext;h.corner=x;h.mimic=x;h.position={};a.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){h.init()||h.destroy();a.reposition()},"^style.tip.(height|width)$":function(){A={width:q.width,height:q.height};h.create();h.update();a.reposition()},"^content.title.text|style.(classes|widget)$":function(){i.tip&&h.update()}};c.extend(h, +{init:function(){var a=h.detectCorner()&&(G||c.browser.msie);a&&(h.create(),h.update(),n.unbind(".qtip-tip").bind("tooltipmove.qtip-tip",e));return a},detectCorner:function(){var b=q.corner,c=a.options.position,d=c.at,c=c.my.string?c.my.string():c.my;if(b===g||c===g&&d===g)return g;b===p?h.corner=new t.Corner(c):b.string||(h.corner=new t.Corner(b),h.corner.fixed=p);return"centercenter"!==h.corner.string()},detectColours:function(){var b,f,j=i.tip.css({backgroundColor:"",border:""});b=h.corner;var e= +b[b.precedance],g="border-"+e+"-color";f="border"+e.charAt(0)+e.substr(1)+"Color";var e=/rgba?\(0, 0, 0(, 0)?\)|transparent/i,k=c(document.body).css("color"),u=a.elements.content.css("color"),F=i.titlebar&&("top"===b.y||"center"===b.y&&j.position().top+A.height/2+q.offset<i.titlebar.outerHeight(1))?i.titlebar:i.content;n.addClass("ui-tooltip-fluid");b=j.css("background-color")||"transparent";f=j[0].style[f];if(!b||e.test(b))y=F.css("background-color"),e.test(y)&&(y=n.css("background-color")||b);if(!f|| +e.test(f))if(d=n.css(g),e.test(d)||d===k)d=F.css(g),d===u&&(d=f);c("*",j).add(j).css("background-color","transparent").css("border","");n.removeClass("ui-tooltip-fluid")},create:function(){var a=A.width,b=A.height;i.tip&&i.tip.remove();i.tip=c("<div />",{"class":"ui-tooltip-tip"}).css({width:a,height:b}).prependTo(n);G?c("<canvas />").appendTo(i.tip)[0].getContext("2d").save():i.tip.html(v?'<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape><vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>': +'<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>')},update:function(a,e){var j=i.tip,r=j.children(),o=A.width,k=A.height,u=q.mimic,F=Math.round,K,l,D,m,n;a||(a=h.corner);u===g?u=a:(u=new t.Corner(u),u.precedance=a.precedance,"inherit"===u.x?u.x=a.x:"inherit"===u.y?u.y=a.y:u.x===u.y&&(u[a.precedance]=a[a.precedance]));K=u.precedance;h.detectColours();v="transparent"===d||"#123456"===d?0:q.border===p?f(a,x,p):q.border;n=u;var B= +o,S=Math.ceil(B/2),W=Math.ceil(k/2),B={bottomright:[[0,0],[B,k],[B,0]],bottomleft:[[0,0],[B,0],[0,k]],topright:[[0,k],[B,0],[B,k]],topleft:[[0,0],[0,k],[B,k]],topcenter:[[0,k],[S,0],[B,k]],bottomcenter:[[0,0],[B,0],[S,k]],rightcenter:[[0,0],[B,W],[0,k]],leftcenter:[[B,0],[B,k],[0,W]]};B.lefttop=B.bottomright;B.righttop=B.bottomleft;B.leftbottom=B.topright;B.rightbottom=B.topleft;D=B[n.string()];n=b(a);j.css(n);"y"===a.precedance?m=[F("left"===u.x?v:"right"===u.x?n.width-o-v:(n.width-o)/2),F("top"=== +u.y?n.height-k:0)]:m=[F("left"===u.x?n.width-o:0),F("top"===u.y?v:"bottom"===u.y?n.height-k-v:(n.height-k)/2)];G?(r.attr(n),l=r[0].getContext("2d"),l.restore(),l.save(),l.clearRect(0,0,3E3,3E3),l.translate(m[0],m[1]),l.beginPath(),l.moveTo(D[0][0],D[0][1]),l.lineTo(D[1][0],D[1][1]),l.lineTo(D[2][0],D[2][1]),l.closePath(),l.fillStyle=y,l.strokeStyle=d,l.lineWidth=2*v,l.lineJoin="miter",l.miterLimit=100,l.stroke(),l.fill()):(D="m"+D[0][0]+","+D[0][1]+" l"+D[1][0]+","+D[1][1]+" "+D[2][0]+","+D[2][1]+ +" xe",m[2]=v&&/^(r|b)/i.test(a.string())?8===parseFloat(c.browser.version,10)?2:1:0,r.css({antialias:""+(-1<u.string().indexOf("center")),left:m[0]-m[2]*Number("x"===K),top:m[1]-m[2]*Number("y"===K),width:o+v,height:k+v}).each(function(a){var b=c(this);b.attr({coordsize:o+v+" "+(k+v),path:D,fillcolor:y,filled:!!a,stroked:!a}).css({display:v||a?"block":"none"});!a&&0<v&&""===b.html()&&b.html('<vml:stroke weight="'+2*v+'px" color="'+d+'" miterlimit="1000" joinstyle="miter" style="behavior:url(#default#VML); display:inline-block;" />')})); +e!==g&&h.position(a)},position:function(a){var d=i.tip,e={},r=Math.max(0,q.offset),m,k,u;if(q.corner===g||!d)return g;a=a||h.corner;m=a.precedance;k=b(a);u=[a.x,a.y];"x"===m&&u.reverse();c.each(u,function(b,d){var u;if("center"===d)u="y"===m?"left":"top",e[u]="50%",e["margin-"+u]=-Math.round(k["y"===m?"width":"height"]/2)+r;else{u=f(a,d,p);var g;g=c.browser.mozilla;var h=a.y+(g?"":"-")+a.x;g=(g?"-moz-":c.browser.webkit?"-webkit-":"")+(g?"border-radius-"+h:"border-"+h+"-radius");g=parseInt((i.titlebar&& +"top"===a.y?i.titlebar:i.content).css(g),10)||parseInt(n.css(g),10)||0;e[d]=b?f(a,d):r+(g>u?g:0)}});e[a[m]]-=k["x"===m?"width":"height"];d.css({top:"",bottom:"",left:"",right:"",margin:""}).css(e);return e},destroy:function(){i.tip&&i.tip.remove();n.unbind(".qtip-tip")}});h.init()}function $(a){var b=this,f=a.elements.tooltip,e=a.options.content.ajax,r=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;a.checks.ajax={"^content.ajax":function(a,c,g){"ajax"===c&&(e=g);"once"===c?b.init():e&&e.url? +b.load():f.unbind(".qtip-ajax")}};c.extend(b,{init:function(){e&&e.url&&f.unbind(".qtip-ajax")[e.once?"one":"bind"]("tooltipshow.qtip-ajax",b.load);return b},load:function(o,m){function h(){p&&(f.css("visibility",""),m=g)}if(o&&o.isDefaultPrevented())return b;var q=e.url.indexOf(" "),i=e.url,n,p=e.once&&!e.loading&&m;p&&f.css("visibility","hidden");-1<q&&(n=i.substr(q),i=i.substr(0,q));c.ajax(c.extend({success:function(b){n&&(b=c("<div/>").append(b.replace(r,"")).find(n));a.set("content.text",b); +h()},error:function(b,c,f){a.set("content.text",c+": "+f);h()},context:a},e,{url:i}));return b}});b.init()}function aa(a,b,f,e){function r(a,u,e,g){var g=0!==parseInt(g,10),l=".qtip-"+f,j=a&&b.show.target[0],u=u&&b.hide.target[0],h=e&&d.rendered&&w.tooltip[0],e=e&&d.rendered&&w.content[0],i=g&&b.position.container[0]===v?document:b.position.container[0],g=g&&C;d.rendered?c([]).pushStack(c.grep([j,u,h,i,e,g],function(a){return"object"===typeof a})).unbind(l):a&&b.show.target.unbind(l+"-create")}function o(k, +u,e,h){function l(a){j.is(":visible")&&d.reposition(a)}function i(a){if(j.hasClass(L))return g;clearTimeout(d.timers.inactive);d.timers.inactive=setTimeout(function(){d.hide(a)},b.hide.inactive)}function r(a){if(j.hasClass(L))return g;var k=c(a.relatedTarget||a.target),f=k.closest(T)[0]===j[0],k=k[0]===q[0];clearTimeout(d.timers.show);clearTimeout(d.timers.hide);if("mouse"===t.target&&f||b.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(f||k))return a.stopPropagation(),a.preventDefault(),g;0<b.hide.delay? +d.timers.hide=setTimeout(function(){d.hide(a)},b.hide.delay):d.hide(a)}function m(a){if(j.hasClass(L))return g;q.trigger("qtip-"+f+"-inactive");clearTimeout(d.timers.show);clearTimeout(d.timers.hide);var c=function(){d.show(a)};0<b.show.delay?d.timers.show=setTimeout(c,b.show.delay):c()}var q,o,p,n=".qtip-"+f,t=b.position;q=b.show.target;o=b.hide.target;t.container[0]===v&&c(document);p=c(document);var y=c.trim(""+b.show.event).split(" "),z=c.trim(""+b.hide.event).split(" "),s=c.browser.msie&&6=== +parseInt(c.browser.version,10);e&&(b.hide.fixed&&(o=o.add(j),j.bind("mouseover"+n,function(){j.hasClass(L)||clearTimeout(d.timers.hide)})),"mouse"===t.target&&t.adjust.mouse&&b.hide.event&&j.bind("mouseleave"+n,function(a){(a.relatedTarget||a.target)!==q[0]&&d.hide(a)}),j.bind("mouseenter"+n,function(a){d["mouseenter"===a.type?"focus":"blur"](a)}),j.bind("mouseenter"+n+" mouseleave"+n,function(a){j.toggleClass(ba,"mouseenter"===a.type)}));u&&("number"===typeof b.hide.inactive&&(q.bind("qtip-"+f+"-inactive", +i),c.each(H.inactiveEvents,function(a,b){o.add(w.tooltip).bind(b+n+"-inactive",i)})),/mouse(over|enter)/i.test(b.show.event)&&!/mouse(out|leave)/i.test(b.hide.event)&&o.bind("mouseleave"+n,function(){clearTimeout(d.timers.show)}),c.each(z,function(a,b){var k=c.inArray(b,y),d=c(o);-1<k&&d.add(q).length===d.length||"unfocus"===b?(q.bind(b+n,function(a){j.is(":visible")?r(a):m(a)}),delete y[k]):o.bind(b+n,r)}));k&&(c.each(y,function(a,b){q.bind(b+n,m)}),"number"===typeof b.hide.distance&&q.bind("mousemove"+ +n,function(a){var c=E.origin||{},k=b.hide.distance,f=Math.abs;c&&(f(a.pageX-c.pageX)>=k||f(a.pageY-c.pageY)>=k)&&d.hide(a)}));h&&((t.adjust.resize||t.viewport)&&c(c.event.special.resize?t.viewport:C).bind("resize"+n,l),(t.viewport||s&&"fixed"===j.css("position"))&&c(t.viewport).bind("scroll"+n,l),/unfocus/i.test(b.hide.event)&&p.bind("mousedown"+n,function(b){var k=c(b.target);0===k.parents(T).length&&1<k.add(a).length&&j.is(":visible")&&!j.hasClass(L)&&d.hide(b)}),b.hide.leave&&/mouseleave|mouseout/i.test(b.hide.event)&& +c(C).bind("blur"+n+" mouse"+(-1<b.hide.leave.indexOf("frame")?"out":"leave")+n,function(a){a.relatedTarget||d.hide(a)}),"mouse"===t.target&&p.bind("mousemove"+n,function(a){t.adjust.mouse&&!j.hasClass(L)&&j.is(":visible")&&d.reposition(a||Q)}))}function m(k){function f(a){function b(){0===(c=c.not(this)).length&&(d.redraw(),d.reposition(E.event),a())}var c;if(0===(c=e.find("img:not([height]):not([width])")).length)return b.call(c);c.each(function(a,c){(function S(){var k=d.timers.img;if(c.height&& +c.width)return clearTimeout(k[a]),b.call(c);k[a]=setTimeout(S,20)})()})}var e=w.content,k=k||b.content.text;if(!d.rendered||!k)return g;c.isFunction(k)&&(k=k.call(a,d)||"");k.jquery&&0<k.length?e.empty().append(k.css({display:"block"})):e.html(k);0>d.rendered?j.queue("fx",f):(J=0,f(c.noop));return d}function h(b){var f=w.title;if(!d.rendered||!b)return g;c.isFunction(b)&&(b=b.call(a,d)||"");b.jquery&&0<b.length?f.empty().append(b.css({display:"block"})):f.html(b);d.redraw();d.rendered&&j.is(":visible")&& +d.reposition(E.event)}function q(){var a=G+"-title";w.titlebar&&n();w.titlebar=c("<div />",{"class":I+"-titlebar "+(b.style.widget?"ui-widget-header":"")}).append(w.title=c("<div />",{id:a,"class":I+"-title","aria-atomic":p})).insertBefore(w.content);b.content.title.button?i():d.rendered&&d.redraw()}function i(){var a=b.content.title.button,f="string"===typeof a?a:"Close tooltip";w.button&&w.button.remove();a.jquery?w.button=a:w.button=c("<a />",{"class":"ui-state-default "+(b.style.widget?"":I+"-icon"), +title:f,"aria-label":f}).prepend(c("<span />",{"class":"ui-icon ui-icon-close",html:"×"}));w.button.appendTo(w.titlebar).attr("role","button").hover(function(a){c(this).toggleClass("ui-state-hover","mouseenter"===a.type)}).click(function(a){j.hasClass(L)||d.hide(a);return g}).bind("mousedown keydown mouseup keyup mouseout",function(a){c(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))});d.redraw()}function n(){w.title&&(w.titlebar.remove(),w.titlebar=w.title=w.button= +x,d.reposition())}function A(){var a=b.style.widget;j.toggleClass(V,a);w.content.toggleClass(V+"-content",a);w.titlebar&&w.titlebar.toggleClass(V+"-header",a);w.button&&w.button.toggleClass(I+"-icon",!a)}function y(a){for(var c=0,d,f=b,a=a.split(".");f=f[a[c++]];)c<a.length&&(d=f);return[d||b,a.pop()]}var d=this,v=document.body,G=I+"-"+f,R=0,J=0,j=c(),w,E;d.id=f;d.rendered=g;d.elements=w={target:a};d.timers={img:[]};d.options=b;d.checks={};d.plugins={};d.cache=E={event:{},target:x,disabled:g,attr:e}; +d.checks.builtin={"^id$":function(a,b,d){a=d===p?H.nextid:d;b=I+"-"+a;a!==g&&0<a.length&&!c("#"+b).length&&(j[0].id=b,w.content[0].id=b+"-content",w.title[0].id=b+"-title")},"^content.text$":function(a,b,c){m(c)},"^content.title.text$":function(a,b,c){if(!c)return n();!w.title&&c&&q();h(c)},"^content.title.button$":function(a,b,c){a=w.button;b=w.title;d.rendered&&(c?(b||q(),i()):a.remove())},"^position.(my|at)$":function(a,b,c){"string"===typeof c&&(a[b]=new t.Corner(c))},"^position.container$":function(a, +b,c){d.rendered&&j.appendTo(c)},"^(show|hide).(event|target|fixed|delay|inactive)$":function(a,b,c,f,e){a=[1,0,0];a["show"===e[1]?"push":"unshift"](0);r.apply(d,a);o.apply(d,[1,1,0,0])},"^show.ready$":function(){d.rendered?d.show():d.render(1)},"^style.classes$":function(a,b,d){c.attr(j[0],"class",I+" qtip ui-helper-reset "+d)},"^style.widget|content.title":A,"^events.(render|show|move|hide|focus|blur)$":function(a,b,d){j[(c.isFunction(d)?"":"un")+"bind"]("tooltip"+b,d)}};c.extend(d,{render:function(k){if(d.rendered)return d; +var f=b.content.title.text,e=c.Event("tooltiprender");c.attr(a[0],"aria-describedby",G);j=w.tooltip=c("<div/>",{id:G,"class":I+" qtip ui-helper-reset "+b.style.classes,width:b.style.width||"",role:"alert","aria-live":"polite","aria-atomic":g,"aria-describedby":G+"-content","aria-hidden":p}).toggleClass(L,E.disabled).data("qtip",d).appendTo(b.position.container).append(w.content=c("<div />",{"class":I+"-content",id:G+"-content","aria-atomic":p}));d.rendered=-1;J=1;f&&(q(),h(f));m();d.rendered=p;A(); +c.each(b.events,function(a,b){c.isFunction(b)&&j.bind("toggle"===a?"tooltipshow tooltiphide":"tooltip"+a,b)});c.each(t,function(){"render"===this.initialize&&this(d)});o(1,1,1,1);j.queue("fx",function(a){e.originalEvent=E.event;j.trigger(e,[d]);J=0;d.redraw();(b.show.ready||k)&&d.show(E.event);a()});return d},get:function(a){switch(a.toLowerCase()){case "dimensions":a={height:j.outerHeight(),width:j.outerWidth()};break;case "offset":a=t.offset(j,b.position.container);break;default:a=y(a.toLowerCase()), +a=a[0][a[1]],a=a.precedance?a.string():a}return a},set:function(a,f){var e=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,l=g,i=g,r=d.checks,q;"string"===typeof a?(q=a,a={},a[q]=f):a=c.extend(p,{},a);c.each(a,function(b,d){var f=y(b.toLowerCase()),g;g=f[0][f[1]];f[0][f[1]]="object"===typeof d&&d.nodeType?c(d):d;a[b]=[f[0],f[1],d,g];l=e.test(b)||l;i=h.test(b)||i});U(b);R=J=1;c.each(a,function(a,b){var c,f,k;for(c in r)for(f in r[c])if(k=RegExp(f, +"i").exec(a))b.push(k),r[c][f].apply(d,b)});R=J=0;j.is(":visible")&&d.rendered&&(l&&d.reposition("mouse"===b.position.target?x:E.event),i&&d.redraw());return d},toggle:function(a,e){function h(){a?(c.browser.msie&&j[0].style.removeAttribute("filter"),j.css("overflow","")):j.css({display:"",visibility:"",width:"",opacity:"",left:"",top:""})}if(!d.rendered)if(a)d.render(1);else return d;var i=a?"show":"hide",l=b[i],r=j.is(":visible");(typeof a).search("boolean|number")&&(a=!r);if(r===a)return d;if(e){if(/over|enter/.test(e.type)&& +/out|leave/.test(E.event.type)&&e.target===b.show.target[0]&&j.has(e.relatedTarget).length)return d;E.event=c.extend({},e)}r=c.Event("tooltip"+i);r.originalEvent=e?E.event:x;j.trigger(r,[d,90]);if(r.isDefaultPrevented())return d;c.attr(j[0],"aria-hidden",!a);a?(E.origin=c.extend({},Q),d.focus(e),c.isFunction(b.content.text)&&m(),d.reposition(e),l.solo&&c(T,l.solo).not(j).qtip("hide",r)):(clearTimeout(d.timers.show),delete E.origin,d.blur(e));j.stop(0,1);c.isFunction(l.effect)?(l.effect.call(j,d), +j.queue("fx",function(a){h();a()})):l.effect===g?(j[i](),h.call(j)):j.fadeTo(90,a?1:0,h);a&&l.target.trigger("qtip-"+f+"-inactive");return d},show:function(a){return d.toggle(p,a)},hide:function(a){return d.toggle(g,a)},focus:function(a){if(!d.rendered)return d;var b=c(T),f=parseInt(j[0].style.zIndex,10),e=H.zindex+b.length,a=c.extend({},a),g;j.hasClass(P)||(g=c.Event("tooltipfocus"),g.originalEvent=a,j.trigger(g,[d,e]),g.isDefaultPrevented()||(f!==e&&(b.each(function(){this.style.zIndex>f&&(this.style.zIndex-= +1)}),b.filter("."+P).qtip("blur",a)),j.addClass(P)[0].style.zIndex=e));return d},blur:function(a){var a=c.extend({},a),b;j.removeClass(P);b=c.Event("tooltipblur");b.originalEvent=a;j.trigger(b,[d]);return d},reposition:function(a,f){if(!d.rendered||R)return d;R=1;var e=b.position.target,h=b.position,l=h.my,i=h.at,r=h.adjust,q=r.method.split(" "),m=j.outerWidth(),n=j.outerHeight(),o=0,p=0,y=c.Event("tooltipmove"),w="fixed"===j.css("position"),z=h.viewport,s={left:0,top:0},A=(d.plugins.tip||{}).corner, +x={horizontal:q[0],vertical:q[1]||q[0],tip:b.style.tip||{},left:function(a){var b="shift"===x.horizontal,c=z.offset.left+z.scrollLeft,d="left"===l.x?m:"right"===l.x?-m:-m/2,f="left"===i.x?o:"right"===i.x?-o:-o/2,e=x.tip.width+2*x.tip.border||0,g=A&&"x"===A.precedance&&!b?e:0,h=c-a-g,k=a+m-z.width-c+g,f=d-("x"===l.precedance||l.x===l.y?f:0),j="center"===l.x;b?(g=A&&"y"===A.precedance?e:0,f=("left"===l.x?1:-1)*d-g,s.left+=0<h?h:0<k?-k:0,s.left=Math.max(z.offset.left+(g&&"center"===A.x?x.tip.offset: +0),a-f,Math.min(Math.max(z.offset.left+z.width,a+f),s.left))):(0<h&&("left"!==l.x||0<k)?s.left-=f+(j?0:2*r.x):0<k&&("right"!==l.x||0<h)&&(s.left-=j?-f:f+2*r.x),s.left!==a&&j&&(s.left-=r.x),s.left<c&&-s.left>k&&(s.left=a));return s.left-a},top:function(a){var b="shift"===x.vertical,c=z.offset.top+z.scrollTop,d="top"===l.y?n:"bottom"===l.y?-n:-n/2,f="top"===i.y?p:"bottom"===i.y?-p:-p/2,e=x.tip.height+2*x.tip.border||0,g=A&&"y"===A.precedance&&!b?e:0,h=c-a-g,c=a+n-z.height-c+g,f=d-("y"===l.precedance|| +l.x===l.y?f:0),k="center"===l.y;b?(g=A&&"x"===A.precedance?e:0,f=("top"===l.y?1:-1)*d-g,s.top+=0<h?h:0<c?-c:0,s.top=Math.max(z.offset.top+(g&&"center"===A.x?x.tip.offset:0),a-f,Math.min(Math.max(z.offset.top+z.height,a+f),s.top))):(0<h&&("top"!==l.y||0<c)?s.top-=f+(k?0:2*r.y):0<c&&("bottom"!==l.y||0<h)&&(s.top-=k?-f:f+2*r.y),s.top!==a&&k&&(s.top-=r.y),0>s.top&&-s.top>c&&(s.top=a));return s.top-a}};if("mouse"===e)i={x:"left",y:"top"},a=a&&("resize"===a.type||"scroll"===a.type)?E.event:!r.mouse&&E.origin? +E.origin:Q&&(r.mouse||!a||!a.pageX)?{pageX:Q.pageX,pageY:Q.pageY}:a,s={top:a.pageY,left:a.pageX};else{"event"===e&&(a&&a.target&&"scroll"!==a.type&&"resize"!==a.type?e=E.target=c(a.target):e=E.target);e=c(e).eq(0);if(0===e.length)return d;e[0]===document||e[0]===C?(o=t.iOS?C.innerWidth:e.width(),p=t.iOS?C.innerHeight:e.height(),e[0]===C&&(s={top:!w||t.iOS?z.scrollTop():0,left:!w||t.iOS?z.scrollLeft():0})):e.is("area")&&t.imagemap?s=t.imagemap(e,i):"http://www.w3.org/2000/svg"===e[0].namespaceURI&& +t.svg?s=t.svg(e,i):(o=e.outerWidth(),p=e.outerHeight(),s=t.offset(e,h.container,w));s.offset&&(o=s.width,p=s.height,s=s.offset);s.left+="right"===i.x?o:"center"===i.x?o/2:0;s.top+="bottom"===i.y?p:"center"===i.y?p/2:0}s.left+=r.x+("right"===l.x?-m:"center"===l.x?-m/2:0);s.top+=r.y+("bottom"===l.y?-n:"center"===l.y?-n/2:0);z.jquery&&e[0]!==C&&e[0]!==v&&"nonenone"!==x.vertical+x.horizontal?(z={elem:z,height:z[(z[0]===C?"h":"outerH")+"eight"](),width:z[(z[0]===C?"w":"outerW")+"idth"](),scrollLeft:z.scrollLeft(), +scrollTop:z.scrollTop(),offset:z.offset()||{left:0,top:0}},s.adjusted={left:"none"!==x.horizontal?x.left(s.left):0,top:"none"!==x.vertical?x.top(s.top):0}):s.adjusted={left:0,top:0};j.attr("class",function(){return c.attr(this,"class").replace(/ui-tooltip-pos-\w+/i,"")}).addClass(I+"-pos-"+l.abbreviation());y.originalEvent=c.extend({},a);j.trigger(y,[d,s,z.elem||z]);if(y.isDefaultPrevented())return d;delete s.adjusted;f===g||isNaN(s.left)||isNaN(s.top)||!c.isFunction(h.effect)?j.css(s):c.isFunction(h.effect)&& +(h.effect.call(j,d,c.extend({},s)),j.queue(function(a){c(this).css({opacity:"",height:""});c.browser.msie&&this.style.removeAttribute("filter");a()}));R=0;return d},redraw:function(){if(1>d.rendered||b.style.width||J)return d;var a=I+"-fluid",f=b.position.container,e,g,h;J=1;j.css("width","").addClass(a);e=j.width()+(c.browser.mozilla?1:0);g=j.css("max-width")||"";h=j.css("min-width")||"";f=-1<(g+h).indexOf("%")?f.width()/100:0;g=(-1<g.indexOf("%")?f:1)*parseInt(g,10)||e;h=(-1<h.indexOf("%")?f:1)* +parseInt(h,10)||0;e=g+h?Math.min(Math.max(e,h),g):e;j.css("width",Math.round(e)).removeClass(a);J=0;return d},disable:function(a){var b=L;"boolean"!==typeof a&&(a=!j.hasClass(b)&&!E.disabled);d.rendered?(j.toggleClass(b,a),c.attr(j[0],"aria-disabled",a)):E.disabled=!!a;return d},enable:function(){return d.disable(g)},destroy:function(){var b=a[0],f=c.attr(b,O);d.rendered&&(j.remove(),c.each(d.plugins,function(){this.destroy&&this.destroy()}));clearTimeout(d.timers.show);clearTimeout(d.timers.hide); +r(1,1,1,1);c.removeData(b,"qtip");f&&(c.attr(b,"title",f),a.removeAttr(O));a.removeAttr("aria-describedby").unbind(".qtip");return a}})}function U(a){var b;if(!a||"object"!==typeof a)return g;"object"!==typeof a.metadata&&(a.metadata={type:a.metadata});if("content"in a){if("object"!==typeof a.content||a.content.jquery)a.content={text:a.content};b=a.content.text||g;!c.isFunction(b)&&(!b&&!b.attr||1>b.length||"object"===typeof b&&!b.jquery)&&(a.content.text=g);"title"in a.content&&("object"!==typeof a.content.title&& +(a.content.title={text:a.content.title}),b=a.content.title.text||g,!c.isFunction(b)&&(!b&&!b.attr||1>b.length||"object"===typeof b&&!b.jquery)&&(a.content.title.text=g))}"position"in a&&"object"!==typeof a.position&&(a.position={my:a.position,at:a.position});"show"in a&&"object"!==typeof a.show&&(a.show.jquery?a.show={target:a.show}:a.show={event:a.show});"hide"in a&&"object"!==typeof a.hide&&(a.hide.jquery?a.hide={target:a.hide}:a.hide={event:a.hide});"style"in a&&"object"!==typeof a.style&&(a.style= +{classes:a.style});c.each(t,function(){this.sanitize&&this.sanitize(a)});return a}function ca(){var a=C.console;return a&&(a.error||a.log||c.noop).apply(a,arguments)}var p=!0,g=!1,x=null,H,t,Q,I="ui-tooltip",V="ui-widget",L="ui-state-disabled",T="div.qtip."+I,P=I+"-focus",ba=I+"-hover",O="oldtitle";H=c.fn.qtip=function(a,b,f){var e=(""+a).toLowerCase(),r=x,o="disable"===e?[p]:c.makeArray(arguments).slice(1,10),m=o[o.length-1],h=this[0]?c.data(this[0],"qtip"):x;if(!arguments.length&&h||"api"===e)return h; +if("string"===typeof a)return this.each(function(){var a=c.data(this,"qtip");if(!a)return p;m&&m.timeStamp&&(a.cache.event=m);if("option"!==e&&"options"!==e||!b)a[e]&&a[e].apply(a[e],o);else if(c.isPlainObject(b)||f!==N)a.set(b,f);else return r=a.get(b),g}),r!==x?r:this;if("object"===typeof a||!arguments.length)return h=U(c.extend(p,{},a)),H.bind.call(this,h,m)};H.bind=function(a,b){return this.each(function(){function f(a){function b(){n.render("object"===typeof a||h.show.ready);o.unbind(e);m.unbind(r)} +if(n.cache.disabled)return g;n.cache.event=c.extend({},a);0<h.show.delay?(clearTimeout(n.timers.show),n.timers.show=setTimeout(b,h.show.delay),e!==r&&m.bind(r,function(){clearTimeout(n.timers.show)})):b()}var e,r,o,m,h,q=!a.id||a.id===g||1>a.id.length||c("#"+I+"-"+a.id).length?H.nextid++:a.id,i=".qtip-"+q+"-create",n;a:{var A,y,d,v,G=c(this),C=c(document.body),J=this===document?C:G;y=G.metadata?G.metadata(a.metadata):x;v="html5"===a.metadata.type&&y?y[a.metadata.name]:x;var j=G.data(a.metadata.name|| +"qtipopts");try{j="string"===typeof j?(new Function("return "+j))():j}catch(w){ca("Unable to parse HTML5 attribute data: "+j)}v=c.extend(p,{},H.defaults,a,"object"===typeof j?U(j):x,U(v||y));y&&c.removeData(this,"metadata");y=v.position;v.id=q;if("boolean"===typeof v.content.text)if(d=G.attr(v.content.attr),v.content.attr!==g&&d)v.content.text=d;else{n=g;break a}y.container===g&&(y.container=C);y.target===g&&(y.target=J);v.show.target===g&&(v.show.target=J);v.show.solo===p&&(v.show.solo=C);v.hide.target=== +g&&(v.hide.target=J);v.position.viewport===p&&(v.position.viewport=y.container);y.at=new t.Corner(y.at);y.my=new t.Corner(y.my);if(c.data(this,"qtip"))if(v.overwrite)G.qtip("destroy");else if(v.overwrite===g){n=g;break a}c.attr(this,"title")&&(c.attr(this,O,c.attr(this,"title")),this.removeAttribute("title"));A=new aa(G,v,q,!!d);c.data(this,"qtip",A);G.bind("remove.qtip",function(){A.destroy()});n=A}if(n===g)return p;h=n.options;c.each(t,function(){"initialize"===this.initialize&&this(n)});o=h.show.target; +m=h.hide.target;e=c.trim(""+h.show.event).replace(/ /g,i+" ")+i;r=c.trim(""+h.hide.event).replace(/ /g,i+" ")+i;/mouse(over|enter)/i.test(e)&&!/mouse(out|leave)/i.test(r)&&(r+=" mouseleave"+i);o.bind(e,f);(h.show.ready||h.prerender)&&f(b)})};t=H.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase();this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase();this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(); +this.precedance=-1<a.charAt(0).search(/^(t|b)/)?"y":"x";this.string=function(){return"y"===this.precedance?this.y+this.x:this.x+this.y};this.abbreviation=function(){var a=this.x.substr(0,1),c=this.y.substr(0,1);return a===c?a:"c"===a||"c"!==a&&"c"!==c?c+a:a+c}},offset:function(a,b,f){var a=a.offset(),e=b,g=0,o=document.body,m;if(e){do{if(e[0]===o)break;"static"!==e.css("position")&&(m=e.position(),a.left-=m.left+(parseInt(e.css("borderLeftWidth"),10)||0),a.top-=m.top+(parseInt(e.css("borderTopWidth"), +10)||0),g++)}while(e=e.offsetParent());if(b[0]!==o||1<g)a.left+=1*b.scrollLeft(),a.top+=1*b.scrollTop();if(4.1>t.iOS&&3.1<t.iOS||!t.iOS&&f)b=c(C),a.left+=-1*b.scrollLeft(),a.top+=-1*b.scrollTop()}return a},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||g,fn:{attr:function(a,b){if(this.length){var f=this[0],e=c.data(f,"qtip");if("title"===a){if(2>arguments.length)return c.attr(f,O);if("object"=== +typeof e)return e&&e.rendered&&"title"===e.options.content.attr&&e.cache.attr&&e.set("content.text",b),c.fn.attr_replacedByqTip.apply(this,arguments),c.attr(f,O,c.attr(f,"title")),this.removeAttr("title")}}},clone:function(a){c([]);return c.fn.clone_replacedByqTip.apply(this,arguments).filter("[oldtitle]").each(function(){c.attr(this,"title",c.attr(this,O));this.removeAttribute(O)}).end()},remove:c.ui?x:function(a,b){c(this).each(function(){b||(!a||c.filter(a,[this]).length)&&c("*",this).add(this).each(function(){c(this).triggerHandler("remove")})})}}}; +c.each(t.fn,function(a,b){if(!b)return p;var f=c.fn[a+"_replacedByqTip"]=c.fn[a];c.fn[a]=function(){return b.apply(this,arguments)||f.apply(this,arguments)}});c(document).bind("mousemove.qtip",function(a){Q={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}});H.version="nightly";H.nextid=0;H.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" ");H.zindex=15E3;H.defaults={prerender:g,id:g,overwrite:p,content:{text:p,attr:"title",title:{text:g,button:g}},position:{my:"top left", +at:"bottom right",target:g,container:g,viewport:g,adjust:{x:0,y:0,mouse:p,resize:p,method:"flip flip"},effect:p},show:{target:g,event:"mouseenter",effect:p,delay:90,solo:g,ready:g},hide:{target:g,event:"mouseleave",effect:p,delay:0,fixed:g,inactive:g,leave:"window",distance:g},style:{classes:"",widget:g,width:g},events:{render:x,move:x,show:x,hide:x,toggle:x,focus:x,blur:x}};t.ajax=function(a){var b=a.plugins.ajax;return"object"===typeof b?b:a.plugins.ajax=new $(a)};t.ajax.initialize="render";t.ajax.sanitize= +function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,"object"!==typeof c&&(c=a.content.ajax={url:c}),"boolean"!==typeof c.once&&c.once&&(c.once=!!c.once))};c.extend(p,H.defaults,{content:{ajax:{loading:p,once:p}}});t.imagemap=function(a,b){var f=a.attr("shape").toLowerCase(),e=a.attr("coords").split(","),g=[],o=c('img[usemap="#'+a.parent("map").attr("name")+'"]'),m=o.offset(),h={width:0,height:0,offset:{top:1E10,right:0,bottom:0,left:1E10}},q=0,i=0;m.left+=Math.ceil((o.outerWidth()-o.width())/2); +m.top+=Math.ceil((o.outerHeight()-o.height())/2);if("poly"===f)for(q=e.length;q--;)i=[parseInt(e[--q],10),parseInt(e[q+1],10)],i[0]>h.offset.right&&(h.offset.right=i[0]),i[0]<h.offset.left&&(h.offset.left=i[0]),i[1]>h.offset.bottom&&(h.offset.bottom=i[1]),i[1]<h.offset.top&&(h.offset.top=i[1]),g.push(i);else g=c.map(e,function(a){return parseInt(a,10)});switch(f){case "rect":h={width:Math.abs(g[2]-g[0]),height:Math.abs(g[3]-g[1]),offset:{left:g[0],top:g[1]}};break;case "circle":h={width:g[2]+2,height:g[2]+ +2,offset:{left:g[0],top:g[1]}};break;case "poly":c.extend(h,{width:Math.abs(h.offset.right-h.offset.left),height:Math.abs(h.offset.bottom-h.offset.top)});if("centercenter"===b.string())h.offset={left:h.offset.left+h.width/2,top:h.offset.top+h.height/2};else{for(var e=f=h,g=g.slice(),o=0,i=q=1,n=0,p=0,t=e.width,d=e.height;0<t&&0<d&&0<q&&0<i;){t=Math.floor(t/2);d=Math.floor(d/2);"left"===b.x?q=t:"right"===b.x?q=e.width-t:q+=Math.floor(t/2);"top"===b.y?i=d:"bottom"===b.y?i=e.height-d:i+=Math.floor(d/ +2);for(o=g.length;o--&&!(2>g.length);)n=g[o][0]-e.offset.left,p=g[o][1]-e.offset.top,("left"===b.x&&n>=q||"right"===b.x&&n<=q||"center"===b.x&&(n<q||n>e.width-q)||"top"===b.y&&p>=i||"bottom"===b.y&&p<=i||"center"===b.y&&(p<i||p>e.height-i))&&g.splice(o,1)}f.offset={left:g[0][0],top:g[0][1]}}h.width=h.height=0}h.offset.left+=m.left;h.offset.top+=m.top;return h};t.tip=function(a){var b=a.plugins.tip;return"object"===typeof b?b:a.plugins.tip=new Z(a)};t.tip.initialize="render";t.tip.sanitize=function(a){var b= +a.style,c;b&&"tip"in b&&(c=a.style.tip,"object"!==typeof c&&(a.style.tip={corner:c}),/string|boolean/i.test(typeof c.corner)||(c.corner=p),"number"!==typeof c.width&&delete c.width,"number"!==typeof c.height&&delete c.height,"number"!==typeof c.border&&c.border!==p&&delete c.border,"number"!==typeof c.offset&&delete c.offset)};c.extend(p,H.defaults,{style:{tip:{corner:p,mimic:g,width:6,height:6,border:p,offset:0}}});t.svg=function(a){var b=c(document),f=a[0],a={width:0,height:0,offset:{top:1E10,left:1E10}}, +e,g,o;if(f.getBBox&&f.parentNode){e=f.getBBox();g=f.getScreenCTM();f=f.farthestViewportElement||f;if(!f.createSVGPoint)return a;f=f.createSVGPoint();f.x=e.x;f.y=e.y;o=f.matrixTransform(g);a.offset.left=o.x;a.offset.top=o.y;f.x+=e.width;f.y+=e.height;o=f.matrixTransform(g);a.width=o.x-a.offset.left;a.height=o.y-a.offset.top;a.offset.left+=b.scrollLeft();a.offset.top+=b.scrollTop()}return a};t.modal=function(a){var b=a.plugins.modal;return"object"===typeof b?b:a.plugins.modal=new Y(a)};t.modal.initialize= +"render";t.modal.sanitize=function(a){a.show&&("object"!==typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"===typeof a.show.modal.on&&(a.show.modal.on=p))};c.extend(p,H.defaults,{show:{modal:{on:g,effect:p,blur:p,escape:p}}});t.bgiframe=function(a){var b=c.browser,f=a.plugins.bgiframe;return 1>c("select, object").length||!b.msie||"6"!==b.version.charAt(0)?g:"object"===typeof f?f:a.plugins.bgiframe=new X(a)};t.bgiframe.initialize="render"})(jQuery,window);
\ No newline at end of file diff --git a/libgpl/querystring/querystring.js b/libgpl/querystring/querystring.js new file mode 100644 index 0000000..c5d5b83 --- /dev/null +++ b/libgpl/querystring/querystring.js @@ -0,0 +1,34 @@ +function PageQuery(q) {
+ if(q.length > 1) this.q = q.substring(1, q.length);
+ else this.q = null;
+ this.keyValuePairs = new Array();
+ if(q) {
+ for(var i=0; i < this.q.split("&").length; i++) {
+ this.keyValuePairs[i] = this.q.split("&")[i];
+ }
+ }
+ this.getKeyValuePairs = function() { return this.keyValuePairs; }
+ this.getValue = function(s) {
+ for(var j=0; j < this.keyValuePairs.length; j++) {
+ if(this.keyValuePairs[j].split("=")[0] == s)
+ return this.keyValuePairs[j].split("=")[1];
+ }
+ return false;
+ }
+ this.getParameters = function() {
+ var a = new Array(this.getLength());
+ for(var j=0; j < this.keyValuePairs.length; j++) {
+ a[j] = this.keyValuePairs[j].split("=")[0];
+ }
+ return a;
+ }
+ this.getLength = function() { return this.keyValuePairs.length; }
+}
+function queryString(key){
+ var page = new PageQuery(window.location.search);
+ var query = page.getValue(key);
+ if(query !== false){
+ query = unescape(query);
+ }
+ return query;
+}
\ No newline at end of file diff --git a/libgpl/skins/classic/calendar.css b/libgpl/skins/classic/calendar.css new file mode 100644 index 0000000..b9c3009 --- /dev/null +++ b/libgpl/skins/classic/calendar.css @@ -0,0 +1,4 @@ +.ui-dialog .ui-dialog-titlebar-close:hover { padding: 1px !important; }
+.ui-dialog .ui-dialog-titlebar-close { border: 1px solid #aaaaaa; background: #e6e6e7 url(images/ui-bg_highlight-hard_75_e6e6e7_1x100.png); height: 16px; width: 16px; }
+.ui-dialog .ui-dialog-title { min-width: 230px; }
+.ui-icon-closethick { background-position: -97px -129px; }
\ No newline at end of file diff --git a/libgpl/skins/classic/images/convert.png b/libgpl/skins/classic/images/convert.png Binary files differnew file mode 100644 index 0000000..d57a19e --- /dev/null +++ b/libgpl/skins/classic/images/convert.png diff --git a/libgpl/skins/classic/images/delete.png b/libgpl/skins/classic/images/delete.png Binary files differnew file mode 100644 index 0000000..af1ecaf --- /dev/null +++ b/libgpl/skins/classic/images/delete.png diff --git a/libgpl/skins/classic/images/door.png b/libgpl/skins/classic/images/door.png Binary files differnew file mode 100644 index 0000000..369fc46 --- /dev/null +++ b/libgpl/skins/classic/images/door.png diff --git a/libgpl/skins/classic/images/edit.png b/libgpl/skins/classic/images/edit.png Binary files differnew file mode 100644 index 0000000..b93e776 --- /dev/null +++ b/libgpl/skins/classic/images/edit.png diff --git a/libgpl/skins/classic/images/message.png b/libgpl/skins/classic/images/message.png Binary files differnew file mode 100644 index 0000000..be1305e --- /dev/null +++ b/libgpl/skins/classic/images/message.png diff --git a/libgpl/skins/classic/images/note.png b/libgpl/skins/classic/images/note.png Binary files differnew file mode 100644 index 0000000..6be00b6 --- /dev/null +++ b/libgpl/skins/classic/images/note.png diff --git a/libgpl/skins/classic/images/task.png b/libgpl/skins/classic/images/task.png Binary files differnew file mode 100644 index 0000000..2d0a5f8 --- /dev/null +++ b/libgpl/skins/classic/images/task.png diff --git a/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png Binary files differnew file mode 100644 index 0000000..e228645 --- /dev/null +++ b/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png diff --git a/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png Binary files differnew file mode 100644 index 0000000..d0a127f --- /dev/null +++ b/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png diff --git a/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png Binary files differnew file mode 100644 index 0000000..675c051 --- /dev/null +++ b/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png diff --git a/libgpl/skins/classic/images/ui-icons_004458_256x240.png b/libgpl/skins/classic/images/ui-icons_004458_256x240.png Binary files differnew file mode 100644 index 0000000..083a564 --- /dev/null +++ b/libgpl/skins/classic/images/ui-icons_004458_256x240.png diff --git a/libgpl/skins/classic/jquery.contextMenu.css b/libgpl/skins/classic/jquery.contextMenu.css new file mode 100644 index 0000000..9512401 --- /dev/null +++ b/libgpl/skins/classic/jquery.contextMenu.css @@ -0,0 +1,141 @@ +/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: git-master + * + * Authors: Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://medialize.github.com/jQuery-contextMenu/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ + +.context-menu-list { + margin:0; + padding:0; + + min-width: 120px; + max-width: 250px; + display: inline-block; + position: absolute; + list-style-type: none; + + border: 1px solid #DDD; + background: #EEE; + + -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +.context-menu-item { + padding: 2px 2px 2px 24px; + background-color: #EEE; + position: relative; + -webkit-user-select: none; + -moz-user-select: -moz-none; + -ms-user-select: none; + user-select: none; +} + +.context-menu-separator { + padding-bottom:0; + border-bottom: 1px solid #DDD; +} + +.context-menu-item > label > input, +.context-menu-item > label > textarea { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.context-menu-item.hover { + cursor: pointer; +} + +.context-menu-item.disabled { + color: #666; +} + +.context-menu-input.hover, +.context-menu-item.disabled.hover { + cursor: default; + background-color: #EEE; +} + +.context-menu-submenu:after { + content: ">"; + color: #666; + position: absolute; + top: 0; + right: 3px; + z-index: 1; +} + +/* icons + #protip: + In case you want to use sprites for icons (which I would suggest you do) have a look at + http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement + .context-menu-item.icon:before {} + */ +.context-menu-item.icon { min-height: 16px; background-repeat: no-repeat; background-position: 4px 2px; } +.context-menu-item.icon-message { background-image: url(images/message.png); } +.context-menu-item.icon-task { background-image: url(../../../tasklist/skins/classic/createfrommail.png); } +.context-menu-item.icon-note { background-image: url(images/note.png); } +.context-menu-item.icon-event { background-image: url(../../../calendar/skins/classic/images/calendars.png); background-position: 3px 0; } +.context-menu-item.icon-edit { background-image: url(images/edit.png); } +.context-menu-item.icon-delete { background-image: url(images/delete.png); } +.context-menu-item.icon-convert { background-image: url(images/actions.png); } + +/* vertically align inside labels */ +.context-menu-input > label > * { vertical-align: top; } + +/* position checkboxes and radios as icons */ +.context-menu-input > label > input[type="checkbox"], +.context-menu-input > label > input[type="radio"] { + margin-left: -17px; +} +.context-menu-input > label > span { + margin-left: 5px; +} + +.context-menu-input > label, +.context-menu-input > label > input[type="text"], +.context-menu-input > label > textarea, +.context-menu-input > label > select { + display: block; + width: 100%; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; +} + +.context-menu-input > label > textarea { + height: 100px; +} +.context-menu-item > .context-menu-list { + display: none; + /* re-positioned by js */ + right: -5px; + top: 5px; +} + +.context-menu-item.hover > .context-menu-list { + display: block; +} + +.context-menu-accesskey { + text-decoration: underline; +} diff --git a/libgpl/skins/classic/timepicker2.css b/libgpl/skins/classic/timepicker2.css new file mode 100644 index 0000000..ee43c69 --- /dev/null +++ b/libgpl/skins/classic/timepicker2.css @@ -0,0 +1,10 @@ +/* css for timepicker */
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
+.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-timepicker-rtl{ direction: rtl; }
+.ui-timepicker-rtl dl { text-align: right; }
+.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; }
\ No newline at end of file diff --git a/libgpl/skins/larry/calendar.css b/libgpl/skins/larry/calendar.css new file mode 100644 index 0000000..65c1ff0 --- /dev/null +++ b/libgpl/skins/larry/calendar.css @@ -0,0 +1,6 @@ +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: 10px; top: 10px; margin: 0; z-index: 99999; width: 18px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 0; background: url(images/ui-icons_004458_256x240.png) -79px -128px no-repeat; width: 18px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close, .ui-dialog .ui-dialog-titlebar-close:focus { border: 1px solid #cccccc; background: #f8f8f8 url(images/ui-bg_highlight-hard_75_f8f8f8_1x100.png) 50% 50% repeat-x; }
+.ui-dialog .ui-dialog-titlebar-close:hover { border: 1px solid #cccccc; background: #e4e4e4 url(images/ui-bg_highlight-soft_90_e4e4e4_1x100.png) 50% 50% repeat-x; }
+.ui-dialog .ui-dialog-title { min-width: 230px; }
+.fc-event { cursor: pointer !important; }
diff --git a/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png b/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png Binary files differnew file mode 100644 index 0000000..e228645 --- /dev/null +++ b/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png diff --git a/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png b/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png Binary files differnew file mode 100644 index 0000000..675c051 --- /dev/null +++ b/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png diff --git a/libgpl/skins/larry/images/ui-icons_004458_256x240.png b/libgpl/skins/larry/images/ui-icons_004458_256x240.png Binary files differnew file mode 100644 index 0000000..083a564 --- /dev/null +++ b/libgpl/skins/larry/images/ui-icons_004458_256x240.png diff --git a/libgpl/skins/larry/jquery.contextMenu.css b/libgpl/skins/larry/jquery.contextMenu.css new file mode 100644 index 0000000..7eeb275 --- /dev/null +++ b/libgpl/skins/larry/jquery.contextMenu.css @@ -0,0 +1,154 @@ +/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: git-master + * + * Authors: Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://medialize.github.com/jQuery-contextMenu/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ + +.context-menu-list { + margin:0; + padding:0; + + min-width: 120px; + max-width: 250px; + display: inline-block; + position: absolute; + list-style-type: none; + + border: 1px solid #999; + border-radius: 4px; + background: #444; + + -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + + font-family: "Lucida Grande",Verdana,Arial,Helvetica,sans-serif; + color: #fff; + /*text-shadow: 0 1px 1px #333;*/ + font-size: 11px; +} + +.context-menu-item { + padding: 6px 6px 6px 30px; + height: 17px; + background-color: #444; + border-bottom: 1px solid #333; + border-top: 1px solid #5a5a5a; + position: relative; + -webkit-user-select: none; + -moz-user-select: -moz-none; + -ms-user-select: none; + user-select: none; +} + +.context-menu-item { + opacity: 0.2; + filter: alpha(opacity=20); +} + +.context-menu-item:hover { + opacity: 0.94; + filter: alpha(opacity=94); + background-color: #008fc7; +} + +.context-menu-separator { + padding-bottom:0; + border-bottom: 1px solid #DDD; +} + +.context-menu-item > label > input, +.context-menu-item > label > textarea { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.context-menu-item.hover { + cursor: pointer; +} + +.context-menu-item.disabled { + color: #666; +} + +.context-menu-input.hover, +.context-menu-item.disabled.hover { + cursor: default; + background-color: #EEE; +} + +.context-menu-submenu:after { + content: ">"; + color: #666; + position: absolute; + top: 0; + right: 3px; + z-index: 1; +} + +.context-menu-root { min-width: 135px; white-space: nowrap; overflow: hidden; } + +.context-menu-item.icon { padding-right: 5px; background-image: url(../../../../skins/larry/images/listicons.png?v=017c.29530); background-repeat: no-repeat; } +.context-menu-item.icon-message { background-position: 5px -1291px; } +.context-menu-item.icon-task { background-position: 5px -2124px; } +.context-menu-item.icon-note { background-position: 5px -2124px; } +.context-menu-item.icon-event { background-position: 5px -2124px; } +.context-menu-item.icon-edit { background-image: url(../../../../skins/larry/images/listicons.png?v=017c.29530); background-repeat: no-repeat; background-position: 5px -1388px; } +.context-menu-item.icon-delete { background-image: url(../../../contextmenu/skins/larry/images/contexticons.png); background-repeat: no-repeat; background-position: 5px -96px; } + + +/* vertically align inside labels */ +.context-menu-input > label > * { vertical-align: top; } + +/* position checkboxes and radios as icons */ +.context-menu-input > label > input[type="checkbox"], +.context-menu-input > label > input[type="radio"] { + margin-left: -17px; +} +.context-menu-input > label > span { + margin-left: 5px; +} + +.context-menu-input > label, +.context-menu-input > label > input[type="text"], +.context-menu-input > label > textarea, +.context-menu-input > label > select { + display: block; + width: 100%; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; +} + +.context-menu-input > label > textarea { + height: 100px; +} +.context-menu-item > .context-menu-list { + display: none; + /* re-positioned by js */ + right: -5px; + top: 5px; +} + +.context-menu-item.hover > .context-menu-list { + display: block; +} + +.context-menu-accesskey { + text-decoration: underline; +} diff --git a/libgpl/skins/larry/timepicker2.css b/libgpl/skins/larry/timepicker2.css new file mode 100644 index 0000000..150c9f3 --- /dev/null +++ b/libgpl/skins/larry/timepicker2.css @@ -0,0 +1,13 @@ +/* css for timepicker */
+
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
+.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-timepicker-rtl{ direction: rtl; }
+.ui-timepicker-rtl dl { text-align: right; }
+.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; }
+.ui-slider { border: 1px solid #AAA; background: white 50% 50% repeat-x; color: black; height: 10px; }
+.ui-timepicker-div dt { margin-left: 5px; }
diff --git a/libgpl/timepicker/jquery.timepicker.css b/libgpl/timepicker/jquery.timepicker.css new file mode 100644 index 0000000..cd75f13 --- /dev/null +++ b/libgpl/timepicker/jquery.timepicker.css @@ -0,0 +1,72 @@ +.ui-timepicker-wrapper { + overflow-y: auto; + height: 150px; + width: 6.5em; + background: #fff; + border: 1px solid #ddd; + -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2); + -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2); + box-shadow:0 5px 10px rgba(0,0,0,0.2); + outline: none; + z-index: 10001; + margin: 0; +} + +.ui-timepicker-wrapper.ui-timepicker-with-duration { + width: 13em; +} + +.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30, +.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 { + width: 11em; +} + +.ui-timepicker-list { + margin: 0; + padding: 0; + list-style: none; +} + +.ui-timepicker-duration { + margin-left: 5px; color: #888; +} + +.ui-timepicker-list:hover .ui-timepicker-duration { + color: #888; +} + +.ui-timepicker-list li { + padding: 3px 0 3px 5px; + cursor: pointer; + white-space: nowrap; + color: #000; + list-style: none; + margin: 0; +} + +.ui-timepicker-list:hover .ui-timepicker-selected { + background: #fff; color: #000; +} + +li.ui-timepicker-selected, +.ui-timepicker-list li:hover, +.ui-timepicker-list .ui-timepicker-selected:hover { + background: #1980EC; color: #fff; +} + +li.ui-timepicker-selected .ui-timepicker-duration, +.ui-timepicker-list li:hover .ui-timepicker-duration { + color: #ccc; +} + +.ui-timepicker-list li.ui-timepicker-disabled, +.ui-timepicker-list li.ui-timepicker-disabled:hover, +.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { + color: #888; + cursor: default; +} + +.ui-timepicker-list li.ui-timepicker-disabled:hover, +.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { + background: #f2f2f2; +} diff --git a/libgpl/timepicker/jquery.timepicker.js b/libgpl/timepicker/jquery.timepicker.js new file mode 100644 index 0000000..462d8fe --- /dev/null +++ b/libgpl/timepicker/jquery.timepicker.js @@ -0,0 +1,1149 @@ +/************************ +jquery-timepicker v1.4.10 +http://jonthornton.github.com/jquery-timepicker/ + +requires jQuery 1.7+ +************************/ + + +(function (factory) { + if (typeof exports === "object" && exports && + typeof module === "object" && module && module.exports === exports) { + // Browserify. Attach to jQuery module. + factory(require("jquery")); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + var _baseDate = _generateBaseDate(); + var _ONE_DAY = 86400; + var _lang = { + am: 'am', + pm: 'pm', + AM: 'AM', + PM: 'PM', + decimal: '.', + mins: 'mins', + hr: 'hr', + hrs: 'hrs' + }; + + var methods = + { + init: function(options) + { + return this.each(function() + { + var self = $(this); + + // pick up settings from data attributes + var attributeOptions = []; + for (var key in $.fn.timepicker.defaults) { + if (self.data(key)) { + attributeOptions[key] = self.data(key); + } + } + + var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options); + + if (settings.lang) { + _lang = $.extend(_lang, settings.lang); + } + + settings = _parseSettings(settings); + self.data('timepicker-settings', settings); + self.addClass('ui-timepicker-input'); + + if (settings.useSelect) { + _render(self); + } else { + self.prop('autocomplete', 'off'); + self.on('click.timepicker focus.timepicker', methods.show); + self.on('change.timepicker', _formatValue); + self.on('keydown.timepicker', _keydownhandler); + self.on('keyup.timepicker', _keyuphandler); + + _formatValue.call(self.get(0)); + } + }); + }, + + show: function(e) + { + var self = $(this); + var settings = self.data('timepicker-settings'); + + if (e) { + if (!settings.showOnFocus) { + return true; + } + + e.preventDefault(); + } + + if (settings.useSelect) { + self.data('timepicker-list').focus(); + return; + } + + if (_hideKeyboard(self)) { + // block the keyboard on mobile devices + self.blur(); + } + + var list = self.data('timepicker-list'); + + // check if input is readonly + if (self.prop('readonly')) { + return; + } + + // check if list needs to be rendered + if (!list || list.length === 0 || typeof settings.durationTime === 'function') { + _render(self); + list = self.data('timepicker-list'); + } + + if (_isVisible(list)) { + return; + } + + // make sure other pickers are hidden + methods.hide(); + + // position the dropdown relative to the input + list.show(); + var listOffset = {}; + + if (settings.orientation == 'rtl') { + // right-align the dropdown + listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10); + } else { + // left-align the dropdown + listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10); + } + + if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) { + // position the dropdown on top + listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10); + } else { + // put it under the input + listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10); + } + + list.offset(listOffset); + + // position scrolling + var selected = list.find('.ui-timepicker-selected'); + + if (!selected.length) { + if (_getTimeValue(self)) { + selected = _findRow(self, list, _time2int(_getTimeValue(self))); + } else if (settings.scrollDefault) { + selected = _findRow(self, list, settings.scrollDefault); + } + } + + if (selected && selected.length) { + var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight(); + list.scrollTop(topOffset); + } else { + list.scrollTop(0); + } + + // attach close handlers + $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler); + if (settings.closeOnWindowScroll) { + $(document).on('scroll.ui-timepicker', _closeHandler); + } + + self.trigger('showTimepicker'); + + return this; + }, + + hide: function(e) + { + var self = $(this); + var settings = self.data('timepicker-settings'); + + if (settings && settings.useSelect) { + self.blur(); + } + + $('.ui-timepicker-wrapper').each(function() { + var list = $(this); + if (!_isVisible(list)) { + return; + } + + var self = list.data('timepicker-input'); + var settings = self.data('timepicker-settings'); + + if (settings && settings.selectOnBlur) { + _selectValue(self); + } + + list.hide(); + self.trigger('hideTimepicker'); + }); + + return this; + }, + + option: function(key, value) + { + return this.each(function(){ + var self = $(this); + var settings = self.data('timepicker-settings'); + var list = self.data('timepicker-list'); + + if (typeof key == 'object') { + settings = $.extend(settings, key); + + } else if (typeof key == 'string' && typeof value != 'undefined') { + settings[key] = value; + + } else if (typeof key == 'string') { + return settings[key]; + } + + settings = _parseSettings(settings); + + self.data('timepicker-settings', settings); + + if (list) { + list.remove(); + self.data('timepicker-list', false); + } + + if (settings.useSelect) { + _render(self); + } + }); + }, + + getSecondsFromMidnight: function() + { + return _time2int(_getTimeValue(this)); + }, + + getTime: function(relative_date) + { + var self = this; + + var time_string = _getTimeValue(self); + if (!time_string) { + return null; + } + + if (!relative_date) { + relative_date = new Date(); + } + var offset = _time2int(time_string); + + // construct a Date with today's date, and offset's time + var time = new Date(relative_date); + time.setHours(offset / 3600); + time.setMinutes(offset % 3600 / 60); + time.setSeconds(offset % 60); + time.setMilliseconds(0); + + return time; + }, + + setTime: function(value) + { + var self = this; + var settings = self.data('timepicker-settings'); + + if (settings.forceRoundTime) { + var prettyTime = _roundAndFormatTime(value, settings) + } else { + var prettyTime = _int2time(_time2int(value), settings.timeFormat); + } + + _setTimeValue(self, prettyTime); + if (self.data('timepicker-list')) { + _setSelected(self, self.data('timepicker-list')); + } + + return this; + }, + + remove: function() + { + var self = this; + + // check if this element is a timepicker + if (!self.hasClass('ui-timepicker-input')) { + return; + } + + var settings = self.data('timepicker-settings'); + self.removeAttr('autocomplete', 'off'); + self.removeClass('ui-timepicker-input'); + self.removeData('timepicker-settings'); + self.off('.timepicker'); + + // timepicker-list won't be present unless the user has interacted with this timepicker + if (self.data('timepicker-list')) { + self.data('timepicker-list').remove(); + } + + if (settings.useSelect) { + self.show(); + } + + self.removeData('timepicker-list'); + + return this; + } + }; + + // private methods + + function _isVisible(elem) + { + var el = elem[0]; + return el.offsetWidth > 0 && el.offsetHeight > 0; + } + + function _parseSettings(settings) + { + if (settings.minTime) { + settings.minTime = _time2int(settings.minTime); + } + + if (settings.maxTime) { + settings.maxTime = _time2int(settings.maxTime); + } + + if (settings.durationTime && typeof settings.durationTime !== 'function') { + settings.durationTime = _time2int(settings.durationTime); + } + + if (settings.scrollDefault == 'now') { + settings.scrollDefault = _time2int(new Date()); + } else if (settings.scrollDefault) { + settings.scrollDefault = _time2int(settings.scrollDefault); + } else if (settings.minTime) { + settings.scrollDefault = settings.minTime; + } + + if (settings.scrollDefault) { + settings.scrollDefault = _roundTime(settings.scrollDefault, settings); + } + + if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) { + settings._twelveHourTime = true; + } + + if (settings.disableTimeRanges.length > 0) { + // convert string times to integers + for (var i in settings.disableTimeRanges) { + settings.disableTimeRanges[i] = [ + _time2int(settings.disableTimeRanges[i][0]), + _time2int(settings.disableTimeRanges[i][1]) + ]; + } + + // sort by starting time + settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){ + return a[0] - b[0]; + }); + + // merge any overlapping ranges + for (var i = settings.disableTimeRanges.length-1; i > 0; i--) { + if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) { + settings.disableTimeRanges[i-1] = [ + Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]), + Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1]) + ]; + settings.disableTimeRanges.splice(i, 1); + } + } + } + + return settings; + } + + function _render(self) + { + var settings = self.data('timepicker-settings'); + var list = self.data('timepicker-list'); + + if (list && list.length) { + list.remove(); + self.data('timepicker-list', false); + } + + if (settings.useSelect) { + list = $('<select />', { 'class': 'ui-timepicker-select' }); + var wrapped_list = list; + } else { + list = $('<ul />', { 'class': 'ui-timepicker-list' }); + + var wrapped_list = $('<div />', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 }); + wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list); + } + + if (settings.noneOption) { + if (settings.noneOption === true) { + settings.noneOption = (settings.useSelect) ? 'Time...' : 'None'; + } + + if ($.isArray(settings.noneOption)) { + for (var i in settings.noneOption) { + if (parseInt(i, 10) == i){ + var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect); + list.append(noneElement); + } + } + } else { + var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect); + list.append(noneElement); + } + } + + if (settings.className) { + wrapped_list.addClass(settings.className); + } + + if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) { + wrapped_list.addClass('ui-timepicker-with-duration'); + wrapped_list.addClass('ui-timepicker-step-'+settings.step); + } + + var durStart = settings.minTime; + if (typeof settings.durationTime === 'function') { + durStart = _time2int(settings.durationTime()); + } else if (settings.durationTime !== null) { + durStart = settings.durationTime; + } + var start = (settings.minTime !== null) ? settings.minTime : 0; + var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1); + + if (end <= start) { + // make sure the end time is greater than start time, otherwise there will be no list to show + end += _ONE_DAY; + } + + if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.timeFormat.indexOf('H') !== -1) { + // show a 24:00 option when using military time + end = _ONE_DAY; + } + + var dr = settings.disableTimeRanges; + var drCur = 0; + var drLen = dr.length; + + for (var i=start; i <= end; i += settings.step*60) { + var timeInt = i; + var timeString = _int2time(timeInt, settings.timeFormat); + + if (settings.useSelect) { + var row = $('<option />', { 'value': timeString }); + row.text(timeString); + } else { + var row = $('<li />'); + row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400)); + row.text(timeString); + } + + if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) { + var durationString = _int2duration(i - durStart, settings.step); + if (settings.useSelect) { + row.text(row.text()+' ('+durationString+')'); + } else { + var duration = $('<span />', { 'class': 'ui-timepicker-duration' }); + duration.text(' ('+durationString+')'); + row.append(duration); + } + } + + if (drCur < drLen) { + if (timeInt >= dr[drCur][1]) { + drCur += 1; + } + + if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) { + if (settings.useSelect) { + row.prop('disabled', true); + } else { + row.addClass('ui-timepicker-disabled'); + } + } + } + + list.append(row); + } + + wrapped_list.data('timepicker-input', self); + self.data('timepicker-list', wrapped_list); + + if (settings.useSelect) { + if (self.val()) { + list.val(_roundAndFormatTime(self.val(), settings)); + } + + list.on('focus', function(){ + $(this).data('timepicker-input').trigger('showTimepicker'); + }); + list.on('blur', function(){ + $(this).data('timepicker-input').trigger('hideTimepicker'); + }); + list.on('change', function(){ + _setTimeValue(self, $(this).val(), 'select'); + }); + + _setTimeValue(self, list.val()); + self.hide().after(list); + } else { + var appendTo = settings.appendTo; + if (typeof appendTo === 'string') { + appendTo = $(appendTo); + } else if (typeof appendTo === 'function') { + appendTo = appendTo(self); + } + appendTo.append(wrapped_list); + _setSelected(self, list); + + list.on('mousedown', 'li', function(e) { + + // hack: temporarily disable the focus handler + // to deal with the fact that IE fires 'focus' + // events asynchronously + self.off('focus.timepicker'); + self.on('focus.timepicker-ie-hack', function(){ + self.off('focus.timepicker-ie-hack'); + self.on('focus.timepicker', methods.show); + }); + + if (!_hideKeyboard(self)) { + self[0].focus(); + } + + // make sure only the clicked row is selected + list.find('li').removeClass('ui-timepicker-selected'); + $(this).addClass('ui-timepicker-selected'); + + if (_selectValue(self)) { + self.trigger('hideTimepicker'); + wrapped_list.hide(); + } + }); + } + } + + function _generateNoneElement(optionValue, useSelect) + { + var label, className, value; + + if (typeof optionValue == 'object') { + label = optionValue.label; + className = optionValue.className; + value = optionValue.value; + } else if (typeof optionValue == 'string') { + label = optionValue; + } else { + $.error('Invalid noneOption value'); + } + + if (useSelect) { + return $('<option />', { + 'value': value, + 'class': className, + 'text': label + }); + } else { + return $('<li />', { + 'class': className, + 'text': label + }).data('time', value); + } + } + + function _roundTime(seconds, settings) + { + if (!$.isNumeric(seconds)) { + seconds = _time2int(seconds); + } + + if (seconds === null) { + return null; + } else { + var offset = seconds % (settings.step*60); // step is in minutes + + if (offset >= settings.step*30) { + // if offset is larger than a half step, round up + seconds += (settings.step*60) - offset; + } else { + // round down + seconds -= offset; + } + + return seconds; + } + } + + function _roundAndFormatTime(seconds, settings) + { + seconds = _roundTime(seconds, settings); + if (seconds !== null) { + return _int2time(seconds, settings.timeFormat); + } + } + + function _generateBaseDate() + { + return new Date(1970, 1, 1, 0, 0, 0); + } + + // event handler to decide whether to close timepicker + function _closeHandler(e) + { + var target = $(e.target); + var input = target.closest('.ui-timepicker-input'); + if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) { + methods.hide(); + $(document).unbind('.ui-timepicker'); + } + } + + function _hideKeyboard(self) + { + var settings = self.data('timepicker-settings'); + return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard); + } + + function _findRow(self, list, value) + { + if (!value && value !== 0) { + return false; + } + + var settings = self.data('timepicker-settings'); + var out = false; + var halfStep = settings.step*30; + + // loop through the menu items + list.find('li').each(function(i, obj) { + var jObj = $(obj); + if (typeof jObj.data('time') != 'number') { + return; + } + + var offset = jObj.data('time') - value; + + // check if the value is less than half a step from each row + if (Math.abs(offset) < halfStep || offset == halfStep) { + out = jObj; + return false; + } + }); + + return out; + } + + function _setSelected(self, list) + { + list.find('li').removeClass('ui-timepicker-selected'); + + var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings')); + if (timeValue === null) { + return; + } + + var selected = _findRow(self, list, timeValue); + if (selected) { + + var topDelta = selected.offset().top - list.offset().top; + + if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) { + list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight()); + } + + selected.addClass('ui-timepicker-selected'); + } + } + + + function _formatValue(e) + { + if (this.value === '') { + return; + } + + var self = $(this); + var list = self.data('timepicker-list'); + + if (self.is(':focus') && (!e || e.type != 'change')) { + return; + } + + var seconds = _time2int(this.value); + + if (seconds === null) { + self.trigger('timeFormatError'); + return; + } + + var settings = self.data('timepicker-settings'); + var rangeError = false; + // check that the time in within bounds + if (settings.minTime !== null && seconds < settings.minTime) { + rangeError = true; + } else if (settings.maxTime !== null && seconds > settings.maxTime) { + rangeError = true; + } + + // check that time isn't within disabled time ranges + $.each(settings.disableTimeRanges, function(){ + if (seconds >= this[0] && seconds < this[1]) { + rangeError = true; + return false; + } + }); + + if (settings.forceRoundTime) { + var offset = seconds % (settings.step*60); // step is in minutes + + if (offset >= settings.step*30) { + // if offset is larger than a half step, round up + seconds += (settings.step*60) - offset; + } else { + // round down + seconds -= offset; + } + } + + var prettyTime = _int2time(seconds, settings.timeFormat); + + if (rangeError) { + if (_setTimeValue(self, prettyTime, 'error')) { + self.trigger('timeRangeError'); + } + } else { + _setTimeValue(self, prettyTime); + } + } + + function _getTimeValue(self) + { + if (self.is('input')) { + return self.val(); + } else { + // use the element's data attributes to store values + return self.data('ui-timepicker-value'); + } + } + + function _setTimeValue(self, value, source) + { + if (self.is('input')) { + self.val(value); + + var settings = self.data('timepicker-settings'); + if (settings.useSelect) { + self.data('timepicker-list').val(_roundAndFormatTime(value, settings)); + } + } + + if (self.data('ui-timepicker-value') != value) { + self.data('ui-timepicker-value', value); + if (source == 'select') { + self.trigger('selectTime').trigger('changeTime').trigger('change'); + } else if (source != 'error') { + self.trigger('changeTime'); + } + + return true; + } else { + self.trigger('selectTime'); + return false; + } + } + + /* + * Keyboard navigation via arrow keys + */ + function _keydownhandler(e) + { + var self = $(this); + var list = self.data('timepicker-list'); + + if (!list || !_isVisible(list)) { + if (e.keyCode == 40) { + // show the list! + methods.show.call(self.get(0)); + list = self.data('timepicker-list'); + if (!_hideKeyboard(self)) { + self.focus(); + } + } else { + return true; + } + } + + switch (e.keyCode) { + + case 13: // return + if (_selectValue(self)) { + methods.hide.apply(this); + } + + e.preventDefault(); + return false; + + case 38: // up + var selected = list.find('.ui-timepicker-selected'); + + if (!selected.length) { + list.find('li').each(function(i, obj) { + if ($(obj).position().top > 0) { + selected = $(obj); + return false; + } + }); + selected.addClass('ui-timepicker-selected'); + + } else if (!selected.is(':first-child')) { + selected.removeClass('ui-timepicker-selected'); + selected.prev().addClass('ui-timepicker-selected'); + + if (selected.prev().position().top < selected.outerHeight()) { + list.scrollTop(list.scrollTop() - selected.outerHeight()); + } + } + + return false; + + case 40: // down + selected = list.find('.ui-timepicker-selected'); + + if (selected.length === 0) { + list.find('li').each(function(i, obj) { + if ($(obj).position().top > 0) { + selected = $(obj); + return false; + } + }); + + selected.addClass('ui-timepicker-selected'); + } else if (!selected.is(':last-child')) { + selected.removeClass('ui-timepicker-selected'); + selected.next().addClass('ui-timepicker-selected'); + + if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) { + list.scrollTop(list.scrollTop() + selected.outerHeight()); + } + } + + return false; + + case 27: // escape + list.find('li').removeClass('ui-timepicker-selected'); + methods.hide(); + break; + + case 9: //tab + methods.hide(); + break; + + default: + return true; + } + } + + /* + * Time typeahead + */ + function _keyuphandler(e) + { + var self = $(this); + var list = self.data('timepicker-list'); + + if (!list || !_isVisible(list)) { + return true; + } + + if (!self.data('timepicker-settings').typeaheadHighlight) { + list.find('li').removeClass('ui-timepicker-selected'); + return true; + } + + switch (e.keyCode) { + + case 96: // numpad numerals + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 48: // numerals + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 65: // a + case 77: // m + case 80: // p + case 186: // colon + case 8: // backspace + case 46: // delete + _setSelected(self, list); + break; + + default: + // list.find('li').removeClass('ui-timepicker-selected'); + return; + } + } + + function _selectValue(self) + { + var settings = self.data('timepicker-settings'); + var list = self.data('timepicker-list'); + var timeValue = null; + + var cursor = list.find('.ui-timepicker-selected'); + + if (cursor.hasClass('ui-timepicker-disabled')) { + return false; + } + + if (cursor.length) { + // selected value found + timeValue = cursor.data('time'); + } + + if (timeValue !== null) { + if (typeof timeValue == 'string') { + self.val(timeValue); + } else { + var timeString = _int2time(timeValue, settings.timeFormat); + _setTimeValue(self, timeString, 'select'); + } + } + + //self.trigger('change').trigger('selectTime'); + return true; + } + + function _int2duration(seconds, step) + { + seconds = Math.abs(seconds); + var minutes = Math.round(seconds/60), + duration = [], + hours, mins; + + if (minutes < 60) { + // Only show (x mins) under 1 hour + duration = [minutes, _lang.mins]; + } else { + hours = Math.floor(minutes/60); + mins = minutes%60; + + // Show decimal notation (eg: 1.5 hrs) for 30 minute steps + if (step == 30 && mins == 30) { + hours += _lang.decimal + 5; + } + + duration.push(hours); + duration.push(hours == 1 ? _lang.hr : _lang.hrs); + + // Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps + // and only if there are remainder minutes to show + if (step != 30 && mins) { + duration.push(mins); + duration.push(_lang.mins); + } + } + + return duration.join(' '); + } + + function _int2time(seconds, format) + { + if (seconds === null) { + return; + } + + var time = new Date(_baseDate.valueOf() + (seconds*1000)); + + if (isNaN(time.getTime())) { + return; + } + + if ($.type(format) === "function") { + return format(time); + } + + var output = ''; + var hour, code; + for (var i=0; i<format.length; i++) { + + code = format.charAt(i); + switch (code) { + + case 'a': + output += (time.getHours() > 11) ? _lang.pm : _lang.am; + break; + + case 'A': + output += (time.getHours() > 11) ? _lang.pm.toUpperCase() : _lang.am.toUpperCase(); + break; + + case 'g': + hour = time.getHours() % 12; + output += (hour === 0) ? '12' : hour; + break; + + case 'G': + output += time.getHours(); + break; + + case 'h': + hour = time.getHours() % 12; + + if (hour !== 0 && hour < 10) { + hour = '0'+hour; + } + + output += (hour === 0) ? '12' : hour; + break; + + case 'H': + hour = time.getHours(); + if (seconds === _ONE_DAY) hour = 24; + output += (hour > 9) ? hour : '0'+hour; + break; + + case 'i': + var minutes = time.getMinutes(); + output += (minutes > 9) ? minutes : '0'+minutes; + break; + + case 's': + seconds = time.getSeconds(); + output += (seconds > 9) ? seconds : '0'+seconds; + break; + + case '\\': + // escape character; add the next character and skip ahead + i++; + output += format.charAt(i); + break; + + default: + output += code; + } + } + + return output; + } + + function _time2int(timeString, settings) + { + if (timeString === '') return null; + if (!timeString || timeString+0 == timeString) return timeString; + + if (typeof(timeString) == 'object') { + return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds(); + } + + timeString = timeString.toLowerCase(); + + // if the last character is an "a" or "p", add the "m" + if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') { + timeString += 'm'; + } + + // try to parse time input + var pattern = new RegExp('^([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*('+_lang.am+'|'+_lang.pm+')?$'); + var time = timeString.match(pattern); + if (!time) { + return null; + } + + var hour = parseInt(time[1]*1, 10); + var ampm = time[4]; + var hours = hour; + + if (hour <= 12 && ampm) { + if (hour == 12) { + hours = (time[4] == _lang.pm) ? 12 : 0; + } else { + hours = (hour + (time[4] == _lang.pm ? 12 : 0)); + } + } + + var minutes = ( time[2]*1 || 0 ); + var seconds = ( time[3]*1 || 0 ); + var timeInt = hours*3600 + minutes*60 + seconds; + + // if no am/pm provided, intelligently guess based on the scrollDefault + if (!ampm && settings && settings._twelveHourTime && settings.scrollDefault) { + var delta = timeInt - settings.scrollDefault; + if (delta < 0 && delta >= _ONE_DAY / -2) { + timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY; + } + } + + return timeInt + } + + function _pad2(n) { + return ("0" + n).slice(-2); + } + + // Plugin entry + $.fn.timepicker = function(method) + { + if (!this.length) return this; + if (methods[method]) { + // check if this element is a timepicker + if (!this.hasClass('ui-timepicker-input')) { + return this; + } + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } + else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); } + else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); } + }; + // Global defaults + $.fn.timepicker.defaults = { + className: null, + minTime: null, + maxTime: null, + durationTime: null, + step: 30, + showDuration: false, + showOnFocus: true, + timeFormat: 'g:ia', + scrollDefault: null, + selectOnBlur: false, + disableTouchKeyboard: false, + forceRoundTime: false, + appendTo: 'body', + orientation: 'ltr', + disableTimeRanges: [], + closeOnWindowScroll: false, + typeaheadHighlight: true, + noneOption: false + }; +})); diff --git a/libgpl/timepicker/jquery.timepicker.min.js b/libgpl/timepicker/jquery.timepicker.min.js new file mode 100644 index 0000000..04daf60 --- /dev/null +++ b/libgpl/timepicker/jquery.timepicker.min.js @@ -0,0 +1,7 @@ +/*! + * jquery-timepicker v1.4.10 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation. + * Copyright (c) 2014 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/ + * License: + */ + +!function(a){"object"==typeof exports&&exports&&"object"==typeof module&&module&&module.exports===exports?a(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=u(b.minTime)),b.maxTime&&(b.maxTime=u(b.maxTime)),b.durationTime&&"function"!=typeof b.durationTime&&(b.durationTime=u(b.durationTime)),"now"==b.scrollDefault?b.scrollDefault=u(new Date):b.scrollDefault?b.scrollDefault=u(b.scrollDefault):b.minTime&&(b.scrollDefault=b.minTime),b.scrollDefault&&(b.scrollDefault=f(b.scrollDefault,b)),"string"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.disableTimeRanges.length>0){for(var c in b.disableTimeRanges)b.disableTimeRanges[c]=[u(b.disableTimeRanges[c][0]),u(b.disableTimeRanges[c][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var c=b.disableTimeRanges.length-1;c>0;c--)b.disableTimeRanges[c][0]<=b.disableTimeRanges[c-1][1]&&(b.disableTimeRanges[c-1]=[Math.min(b.disableTimeRanges[c][0],b.disableTimeRanges[c-1][0]),Math.max(b.disableTimeRanges[c][1],b.disableTimeRanges[c-1][1])],b.disableTimeRanges.splice(c,1))}return b}function d(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");if(d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),c.useSelect){d=a("<select />",{"class":"ui-timepicker-select"});var f=d}else{d=a("<ul />",{"class":"ui-timepicker-list"});var f=a("<div />",{"class":"ui-timepicker-wrapper",tabindex:-1});f.css({display:"none",position:"absolute"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?"Time...":"None"),a.isArray(c.noneOption)){for(var h in c.noneOption)if(parseInt(h,10)==h){var i=e(c.noneOption[h],c.useSelect);d.append(i)}}else{var i=e(c.noneOption,c.useSelect);d.append(i)}c.className&&f.addClass(c.className),null===c.minTime&&null===c.durationTime||!c.showDuration||(f.addClass("ui-timepicker-with-duration"),f.addClass("ui-timepicker-step-"+c.step));var k=c.minTime;"function"==typeof c.durationTime?k=u(c.durationTime()):null!==c.durationTime&&(k=c.durationTime);var m=null!==c.minTime?c.minTime:0,n=null!==c.maxTime?c.maxTime:m+w-1;m>=n&&(n+=w),n===w-1&&"string"===a.type(c.timeFormat)&&-1!==c.timeFormat.indexOf("H")&&(n=w);for(var p=c.disableTimeRanges,q=0,v=p.length,h=m;n>=h;h+=60*c.step){var x=h,z=t(x,c.timeFormat);if(c.useSelect){var A=a("<option />",{value:z});A.text(z)}else{var A=a("<li />");A.data("time",86400>=x?x:x%86400),A.text(z)}if((null!==c.minTime||null!==c.durationTime)&&c.showDuration){var B=s(h-k,c.step);if(c.useSelect)A.text(A.text()+" ("+B+")");else{var C=a("<span />",{"class":"ui-timepicker-duration"});C.text(" ("+B+")"),A.append(C)}}v>q&&(x>=p[q][1]&&(q+=1),p[q]&&x>=p[q][0]&&x<p[q][1]&&(c.useSelect?A.prop("disabled",!0):A.addClass("ui-timepicker-disabled"))),d.append(A)}if(f.data("timepicker-input",b),b.data("timepicker-list",f),c.useSelect)b.val()&&d.val(g(b.val(),c)),d.on("focus",function(){a(this).data("timepicker-input").trigger("showTimepicker")}),d.on("blur",function(){a(this).data("timepicker-input").trigger("hideTimepicker")}),d.on("change",function(){o(b,a(this).val(),"select")}),o(b,d.val()),b.hide().after(d);else{var D=c.appendTo;"string"==typeof D?D=a(D):"function"==typeof D&&(D=D(b)),D.append(f),l(b,d),d.on("mousedown","li",function(){b.off("focus.timepicker"),b.on("focus.timepicker-ie-hack",function(){b.off("focus.timepicker-ie-hack"),b.on("focus.timepicker",y.show)}),j(b)||b[0].focus(),d.find("li").removeClass("ui-timepicker-selected"),a(this).addClass("ui-timepicker-selected"),r(b)&&(b.trigger("hideTimepicker"),f.hide())})}}function e(b,c){var d,e,f;return"object"==typeof b?(d=b.label,e=b.className,f=b.value):"string"==typeof b?d=b:a.error("Invalid noneOption value"),c?a("<option />",{value:f,"class":e,text:d}):a("<li />",{"class":e,text:d}).data("time",f)}function f(b,c){if(a.isNumeric(b)||(b=u(b)),null===b)return null;var d=b%(60*c.step);return d>=30*c.step?b+=60*c.step-d:b-=d,b}function g(a,b){return a=f(a,b),null!==a?t(a,b.timeFormat):void 0}function h(){return new Date(1970,1,1,0,0,0)}function i(b){var c=a(b.target),d=c.closest(".ui-timepicker-input");0===d.length&&0===c.closest(".ui-timepicker-wrapper").length&&(y.hide(),a(document).unbind(".ui-timepicker"))}function j(a){var b=a.data("timepicker-settings");return(window.navigator.msMaxTouchPoints||"ontouchstart"in document)&&b.disableTouchKeyboard}function k(b,c,d){if(!d&&0!==d)return!1;var e=b.data("timepicker-settings"),f=!1,g=30*e.step;return c.find("li").each(function(b,c){var e=a(c);if("number"==typeof e.data("time")){var h=e.data("time")-d;return Math.abs(h)<g||h==g?(f=e,!1):void 0}}),f}function l(a,b){b.find("li").removeClass("ui-timepicker-selected");var c=u(n(a),a.data("timepicker-settings"));if(null!==c){var d=k(a,b,c);if(d){var e=d.offset().top-b.offset().top;(e+d.outerHeight()>b.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass("ui-timepicker-selected")}}}function m(b){if(""!==this.value){var c=a(this);if(c.data("timepicker-list"),!c.is(":focus")||b&&"change"==b.type){var d=u(this.value);if(null===d)return c.trigger("timeFormatError"),void 0;var e=c.data("timepicker-settings"),f=!1;if(null!==e.minTime&&d<e.minTime?f=!0:null!==e.maxTime&&d>e.maxTime&&(f=!0),a.each(e.disableTimeRanges,function(){return d>=this[0]&&d<this[1]?(f=!0,!1):void 0}),e.forceRoundTime){var g=d%(60*e.step);g>=30*e.step?d+=60*e.step-g:d-=g}var h=t(d,e.timeFormat);f?o(c,h,"error")&&c.trigger("timeRangeError"):o(c,h)}}}function n(a){return a.is("input")?a.val():a.data("ui-timepicker-value")}function o(a,b,c){if(a.is("input")){a.val(b);var d=a.data("timepicker-settings");d.useSelect&&a.data("timepicker-list").val(g(b,d))}return a.data("ui-timepicker-value")!=b?(a.data("ui-timepicker-value",b),"select"==c?a.trigger("selectTime").trigger("changeTime").trigger("change"):"error"!=c&&a.trigger("changeTime"),!0):(a.trigger("selectTime"),!1)}function p(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e)){if(40!=c.keyCode)return!0;y.show.call(d.get(0)),e=d.data("timepicker-list"),j(d)||d.focus()}switch(c.keyCode){case 13:return r(d)&&y.hide.apply(this),c.preventDefault(),!1;case 38:var f=e.find(".ui-timepicker-selected");return f.length?f.is(":first-child")||(f.removeClass("ui-timepicker-selected"),f.prev().addClass("ui-timepicker-selected"),f.prev().position().top<f.outerHeight()&&e.scrollTop(e.scrollTop()-f.outerHeight())):(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")),!1;case 40:return f=e.find(".ui-timepicker-selected"),0===f.length?(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")):f.is(":last-child")||(f.removeClass("ui-timepicker-selected"),f.next().addClass("ui-timepicker-selected"),f.next().position().top+2*f.outerHeight()>e.outerHeight()&&e.scrollTop(e.scrollTop()+f.outerHeight())),!1;case 27:e.find("li").removeClass("ui-timepicker-selected"),y.hide();break;case 9:y.hide();break;default:return!0}}function q(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e))return!0;if(!d.data("timepicker-settings").typeaheadHighlight)return e.find("li").removeClass("ui-timepicker-selected"),!0;switch(c.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:l(d,e);break;default:return}}function r(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");if(e.hasClass("ui-timepicker-disabled"))return!1;if(e.length&&(d=e.data("time")),null!==d)if("string"==typeof d)a.val(d);else{var f=t(d,b.timeFormat);o(a,f,"select")}return!0}function s(a,b){a=Math.abs(a);var c,d,e=Math.round(a/60),f=[];return 60>e?f=[e,x.mins]:(c=Math.floor(e/60),d=e%60,30==b&&30==d&&(c+=x.decimal+5),f.push(c),f.push(1==c?x.hr:x.hrs),30!=b&&d&&(f.push(d),f.push(x.mins))),f.join(" ")}function t(b,c){if(null!==b){var d=new Date(v.valueOf()+1e3*b);if(!isNaN(d.getTime())){if("function"===a.type(c))return c(d);for(var e,f,g="",h=0;h<c.length;h++)switch(f=c.charAt(h)){case"a":g+=d.getHours()>11?x.pm:x.am;break;case"A":g+=d.getHours()>11?x.pm.toUpperCase():x.am.toUpperCase();break;case"g":e=d.getHours()%12,g+=0===e?"12":e;break;case"G":g+=d.getHours();break;case"h":e=d.getHours()%12,0!==e&&10>e&&(e="0"+e),g+=0===e?"12":e;break;case"H":e=d.getHours(),b===w&&(e=24),g+=e>9?e:"0"+e;break;case"i":var i=d.getMinutes();g+=i>9?i:"0"+i;break;case"s":b=d.getSeconds(),g+=b>9?b:"0"+b;break;case"\\":h++,g+=c.charAt(h);break;default:g+=f}return g}}}function u(a,b){if(""===a)return null;if(!a||a+0==a)return a;if("object"==typeof a)return 3600*a.getHours()+60*a.getMinutes()+a.getSeconds();a=a.toLowerCase(),("a"==a.slice(-1)||"p"==a.slice(-1))&&(a+="m");var c=new RegExp("^([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*("+x.am+"|"+x.pm+")?$"),d=a.match(c);if(!d)return null;var e=parseInt(1*d[1],10),f=d[4],g=e;12>=e&&f&&(g=12==e?d[4]==x.pm?12:0:e+(d[4]==x.pm?12:0));var h=1*d[2]||0,i=1*d[3]||0,j=3600*g+60*h+i;if(!f&&b&&b._twelveHourTime&&b.scrollDefault){var k=j-b.scrollDefault;0>k&&k>=w/-2&&(j=(j+w/2)%w)}return j}var v=h(),w=86400,x={am:"am",pm:"pm",AM:"AM",PM:"PM",decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},y={init:function(b){return this.each(function(){var e=a(this),f=[];for(var g in a.fn.timepicker.defaults)e.data(g)&&(f[g]=e.data(g));var h=a.extend({},a.fn.timepicker.defaults,f,b);h.lang&&(x=a.extend(x,h.lang)),h=c(h),e.data("timepicker-settings",h),e.addClass("ui-timepicker-input"),h.useSelect?d(e):(e.prop("autocomplete","off"),e.on("click.timepicker focus.timepicker",y.show),e.on("change.timepicker",m),e.on("keydown.timepicker",p),e.on("keyup.timepicker",q),m.call(e.get(0)))})},show:function(c){var e=a(this),f=e.data("timepicker-settings");if(c){if(!f.showOnFocus)return!0;c.preventDefault()}if(f.useSelect)return e.data("timepicker-list").focus(),void 0;j(e)&&e.blur();var g=e.data("timepicker-list");if(!e.prop("readonly")&&(g&&0!==g.length&&"function"!=typeof f.durationTime||(d(e),g=e.data("timepicker-list")),!b(g))){y.hide(),g.show();var h={};h.left="rtl"==f.orientation?e.offset().left+e.outerWidth()-g.outerWidth()+parseInt(g.css("marginLeft").replace("px",""),10):e.offset().left+parseInt(g.css("marginLeft").replace("px",""),10),h.top=e.offset().top+e.outerHeight(!0)+g.outerHeight()>a(window).height()+a(window).scrollTop()?e.offset().top-g.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10):e.offset().top+e.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10),g.offset(h);var l=g.find(".ui-timepicker-selected");if(l.length||(n(e)?l=k(e,g,u(n(e))):f.scrollDefault&&(l=k(e,g,f.scrollDefault))),l&&l.length){var m=g.scrollTop()+l.position().top-l.outerHeight();g.scrollTop(m)}else g.scrollTop(0);return a(document).on("touchstart.ui-timepicker mousedown.ui-timepicker",i),f.closeOnWindowScroll&&a(document).on("scroll.ui-timepicker",i),e.trigger("showTimepicker"),this}},hide:function(){var c=a(this),d=c.data("timepicker-settings");return d&&d.useSelect&&c.blur(),a(".ui-timepicker-wrapper").each(function(){var c=a(this);if(b(c)){var d=c.data("timepicker-input"),e=d.data("timepicker-settings");e&&e.selectOnBlur&&r(d),c.hide(),d.trigger("hideTimepicker")}}),this},option:function(b,e){return this.each(function(){var f=a(this),g=f.data("timepicker-settings"),h=f.data("timepicker-list");if("object"==typeof b)g=a.extend(g,b);else if("string"==typeof b&&"undefined"!=typeof e)g[b]=e;else if("string"==typeof b)return g[b];g=c(g),f.data("timepicker-settings",g),h&&(h.remove(),f.data("timepicker-list",!1)),g.useSelect&&d(f)})},getSecondsFromMidnight:function(){return u(n(this))},getTime:function(a){var b=this,c=n(b);if(!c)return null;a||(a=new Date);var d=u(c),e=new Date(a);return e.setHours(d/3600),e.setMinutes(d%3600/60),e.setSeconds(d%60),e.setMilliseconds(0),e},setTime:function(a){var b=this,c=b.data("timepicker-settings");if(c.forceRoundTime)var d=g(a,c);else var d=t(u(a),c.timeFormat);return o(b,d),b.data("timepicker-list")&&l(b,b.data("timepicker-list")),this},remove:function(){var a=this;if(a.hasClass("ui-timepicker-input")){var b=a.data("timepicker-settings");return a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),b.useSelect&&a.show(),a.removeData("timepicker-list"),this}}};a.fn.timepicker=function(b){return this.length?y[b]?this.hasClass("ui-timepicker-input")?y[b].apply(this,Array.prototype.slice.call(arguments,1)):this:"object"!=typeof b&&b?(a.error("Method "+b+" does not exist on jQuery.timepicker"),void 0):y.init.apply(this,arguments):this},a.fn.timepicker.defaults={className:null,minTime:null,maxTime:null,durationTime:null,step:30,showDuration:!1,showOnFocus:!0,timeFormat:"g:ia",scrollDefault:null,selectOnBlur:!1,disableTouchKeyboard:!1,forceRoundTime:!1,appendTo:"body",orientation:"ltr",disableTimeRanges:[],closeOnWindowScroll:!1,typeaheadHighlight:!0,noneOption:!1}});
\ No newline at end of file diff --git a/libgpl/timepicker2/jquery.timepicker.js b/libgpl/timepicker2/jquery.timepicker.js new file mode 100644 index 0000000..998d2f8 --- /dev/null +++ b/libgpl/timepicker2/jquery.timepicker.js @@ -0,0 +1,2223 @@ +/*! jQuery Timepicker Addon - v1.5.0 - 2014-09-01
+* http://trentrichardson.com/examples/timepicker
+* Copyright (c) 2014 Trent Richardson; Licensed MIT */
+(function ($) {
+
+ /*
+ * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
+ */
+ $.ui.timepicker = $.ui.timepicker || {};
+ if ($.ui.timepicker.version) {
+ return;
+ }
+
+ /*
+ * Extend jQueryUI, get it started with our version number
+ */
+ $.extend($.ui, {
+ timepicker: {
+ version: "1.5.0"
+ }
+ });
+
+ /*
+ * Timepicker manager.
+ * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+ * Settings for (groups of) time pickers are maintained in an instance object,
+ * allowing multiple different settings on the same page.
+ */
+ var Timepicker = function () {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ currentText: 'Now',
+ closeText: 'Done',
+ amNames: ['AM', 'A'],
+ pmNames: ['PM', 'P'],
+ timeFormat: 'HH:mm',
+ timeSuffix: '',
+ timeOnlyTitle: 'Choose Time',
+ timeText: 'Time',
+ hourText: 'Hour',
+ minuteText: 'Minute',
+ secondText: 'Second',
+ millisecText: 'Millisecond',
+ microsecText: 'Microsecond',
+ timezoneText: 'Time Zone',
+ isRTL: false
+ };
+ this._defaults = { // Global defaults for all the datetime picker instances
+ showButtonPanel: true,
+ timeOnly: false,
+ timeOnlyShowDate: false,
+ showHour: null,
+ showMinute: null,
+ showSecond: null,
+ showMillisec: null,
+ showMicrosec: null,
+ showTimezone: null,
+ showTime: true,
+ stepHour: 1,
+ stepMinute: 1,
+ stepSecond: 1,
+ stepMillisec: 1,
+ stepMicrosec: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMin: 0,
+ minuteMin: 0,
+ secondMin: 0,
+ millisecMin: 0,
+ microsecMin: 0,
+ hourMax: 23,
+ minuteMax: 59,
+ secondMax: 59,
+ millisecMax: 999,
+ microsecMax: 999,
+ minDateTime: null,
+ maxDateTime: null,
+ maxTime: null,
+ minTime: null,
+ onSelect: null,
+ hourGrid: 0,
+ minuteGrid: 0,
+ secondGrid: 0,
+ millisecGrid: 0,
+ microsecGrid: 0,
+ alwaysSetTime: true,
+ separator: ' ',
+ altFieldTimeOnly: true,
+ altTimeFormat: null,
+ altSeparator: null,
+ altTimeSuffix: null,
+ altRedirectFocus: true,
+ pickerTimeFormat: null,
+ pickerTimeSuffix: null,
+ showTimepicker: true,
+ timezoneList: null,
+ addSliderAccess: false,
+ sliderAccessArgs: null,
+ controlType: 'slider',
+ defaultValue: null,
+ parse: 'strict'
+ };
+ $.extend(this._defaults, this.regional['']);
+ };
+
+ $.extend(Timepicker.prototype, {
+ $input: null,
+ $altInput: null,
+ $timeObj: null,
+ inst: null,
+ hour_slider: null,
+ minute_slider: null,
+ second_slider: null,
+ millisec_slider: null,
+ microsec_slider: null,
+ timezone_select: null,
+ maxTime: null,
+ minTime: null,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMinOriginal: null,
+ minuteMinOriginal: null,
+ secondMinOriginal: null,
+ millisecMinOriginal: null,
+ microsecMinOriginal: null,
+ hourMaxOriginal: null,
+ minuteMaxOriginal: null,
+ secondMaxOriginal: null,
+ millisecMaxOriginal: null,
+ microsecMaxOriginal: null,
+ ampm: '',
+ formattedDate: '',
+ formattedTime: '',
+ formattedDateTime: '',
+ timezoneList: null,
+ units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
+ support: {},
+ control: null,
+
+ /*
+ * Override the default settings for all instances of the time picker.
+ * @param {Object} settings object - the new settings to use as defaults (anonymous object)
+ * @return {Object} the manager object
+ */
+ setDefaults: function (settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /*
+ * Create a new Timepicker instance
+ */
+ _newInst: function ($input, opts) {
+ var tp_inst = new Timepicker(),
+ inlineSettings = {},
+ fns = {},
+ overrides, i;
+
+ for (var attrName in this._defaults) {
+ if (this._defaults.hasOwnProperty(attrName)) {
+ var attrValue = $input.attr('time:' + attrName);
+ if (attrValue) {
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ }
+
+ overrides = {
+ beforeShow: function (input, dp_inst) {
+ if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
+ return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
+ }
+ },
+ onChangeMonthYear: function (year, month, dp_inst) {
+ // Update the time as well : this prevents the time from disappearing from the $input field.
+ tp_inst._updateDateTime(dp_inst);
+ if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
+ tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
+ }
+ },
+ onClose: function (dateText, dp_inst) {
+ if (tp_inst.timeDefined === true && $input.val() !== '') {
+ tp_inst._updateDateTime(dp_inst);
+ }
+ if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
+ tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
+ }
+ }
+ };
+ for (i in overrides) {
+ if (overrides.hasOwnProperty(i)) {
+ fns[i] = opts[i] || null;
+ }
+ }
+
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
+ evnts: fns,
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+ });
+ tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
+ return val.toUpperCase();
+ });
+ tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
+ return val.toUpperCase();
+ });
+
+ // detect which units are supported
+ tp_inst.support = detectSupport(
+ tp_inst._defaults.timeFormat +
+ (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
+ (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
+
+ // controlType is string - key to our this._controls
+ if (typeof(tp_inst._defaults.controlType) === 'string') {
+ if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
+ tp_inst._defaults.controlType = 'select';
+ }
+ tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
+ }
+ // controlType is an object and must implement create, options, value methods
+ else {
+ tp_inst.control = tp_inst._defaults.controlType;
+ }
+
+ // prep the timezone options
+ var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
+ 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
+ if (tp_inst._defaults.timezoneList !== null) {
+ timezoneList = tp_inst._defaults.timezoneList;
+ }
+ var tzl = timezoneList.length, tzi = 0, tzv = null;
+ if (tzl > 0 && typeof timezoneList[0] !== 'object') {
+ for (; tzi < tzl; tzi++) {
+ tzv = timezoneList[tzi];
+ timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
+ }
+ }
+ tp_inst._defaults.timezoneList = timezoneList;
+
+ // set the default units
+ tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
+ ((new Date()).getTimezoneOffset() * -1);
+ tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
+ tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
+ tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
+ tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
+ tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
+ tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
+ tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
+ tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
+ tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
+ tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
+ tp_inst.ampm = '';
+ tp_inst.$input = $input;
+
+ if (tp_inst._defaults.altField) {
+ tp_inst.$altInput = $(tp_inst._defaults.altField);
+ if (tp_inst._defaults.altRedirectFocus === true) {
+ tp_inst.$altInput.css({
+ cursor: 'pointer'
+ }).focus(function () {
+ $input.trigger("focus");
+ });
+ }
+ }
+
+ if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
+ tp_inst._defaults.minDate = new Date();
+ }
+ if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
+ tp_inst._defaults.maxDate = new Date();
+ }
+
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+ if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+ }
+ if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+ }
+ if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+ }
+ if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+ }
+ tp_inst.$input.bind('focus', function () {
+ tp_inst._onFocus();
+ });
+
+ return tp_inst;
+ },
+
+ /*
+ * add our sliders to the calendar
+ */
+ _addTimePicker: function (dp_inst) {
+ var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
+
+ this.timeDefined = this._parseTime(currDT);
+ this._limitMinMaxDateTime(dp_inst, false);
+ this._injectTimePicker();
+ },
+
+ /*
+ * parse the time string from input value or _setTime
+ */
+ _parseTime: function (timeString, withDate) {
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ if (withDate || !this._defaults.timeOnly) {
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+ try {
+ var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
+ if (!parseRes.timeObj) {
+ return false;
+ }
+ $.extend(this, parseRes.timeObj);
+ } catch (err) {
+ $.timepicker.log("Error parsing the date/time string: " + err +
+ "\ndate/time string = " + timeString +
+ "\ntimeFormat = " + this._defaults.timeFormat +
+ "\ndateFormat = " + dp_dateFormat);
+ return false;
+ }
+ return true;
+ } else {
+ var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
+ if (!timeObj) {
+ return false;
+ }
+ $.extend(this, timeObj);
+ return true;
+ }
+ },
+
+ /*
+ * generate and inject html for timepicker into ui datepicker
+ */
+ _injectTimePicker: function () {
+ var $dp = this.inst.dpDiv,
+ o = this.inst.settings,
+ tp_inst = this,
+ litem = '',
+ uitem = '',
+ show = null,
+ max = {},
+ gridSize = {},
+ size = null,
+ i = 0,
+ l = 0;
+
+ // Prevent displaying twice
+ if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
+ var noDisplay = ' style="display:none;"',
+ html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
+ '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
+
+ // Create the markup
+ for (i = 0, l = this.units.length; i < l; i++) {
+ litem = this.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // Added by Peter Medeiros:
+ // - Figure out what the hour/minute/second max should be based on the step values.
+ // - Example: if stepMinute is 15, then minMax is 45.
+ max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
+ gridSize[litem] = 0;
+
+ html += '<dt class="ui_tpicker_' + litem + '_label"' + (show ? '' : noDisplay) + '>' + o[litem + 'Text'] + '</dt>' +
+ '<dd class="ui_tpicker_' + litem + '"><div class="ui_tpicker_' + litem + '_slider"' + (show ? '' : noDisplay) + '></div>';
+
+ if (show && o[litem + 'Grid'] > 0) {
+ html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
+
+ if (litem === 'hour') {
+ for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
+ html += '<td data-for="' + litem + '">' + tmph + '</td>';
+ }
+ }
+ else {
+ for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
+ }
+ }
+
+ html += '</tr></table></div>';
+ }
+ html += '</dd>';
+ }
+
+ // Timezone
+ var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
+ html += '<dt class="ui_tpicker_timezone_label"' + (showTz ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
+ html += '<dd class="ui_tpicker_timezone" ' + (showTz ? '' : noDisplay) + '></dd>';
+
+ // Create the elements from string
+ html += '</dl></div>';
+ var $tp = $(html);
+
+ // if we only want time picker...
+ if (o.timeOnly === true) {
+ $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
+ $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
+ }
+
+ // add sliders, adjust grids, add events
+ for (i = 0, l = tp_inst.units.length; i < l; i++) {
+ litem = tp_inst.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // add the slider
+ tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
+
+ // adjust the grid and add click event
+ if (show && o[litem + 'Grid'] > 0) {
+ size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
+ $tp.find('.ui_tpicker_' + litem + ' table').css({
+ width: size + "%",
+ marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
+ marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
+ borderCollapse: 'collapse'
+ }).find("td").click(function (e) {
+ var $t = $(this),
+ h = $t.html(),
+ n = parseInt(h.replace(/[^0-9]/g), 10),
+ ap = h.replace(/[^apm]/ig),
+ f = $t.data('for'); // loses scope, so we use data-for
+
+ if (f === 'hour') {
+ if (ap.indexOf('p') !== -1 && n < 12) {
+ n += 12;
+ }
+ else {
+ if (ap.indexOf('a') !== -1 && n === 12) {
+ n = 0;
+ }
+ }
+ }
+
+ tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
+
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / gridSize[litem]) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ } // end if grid > 0
+ } // end for loop
+
+ // Add timezone options
+ this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
+ $.fn.append.apply(this.timezone_select,
+ $.map(o.timezoneList, function (val, idx) {
+ return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
+ }));
+ if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
+ var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
+ if (local_timezone === this.timezone) {
+ selectLocalTimezone(tp_inst);
+ } else {
+ this.timezone_select.val(this.timezone);
+ }
+ } else {
+ if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
+ this.timezone_select.val(o.timezone);
+ } else {
+ selectLocalTimezone(tp_inst);
+ }
+ }
+ this.timezone_select.change(function () {
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+ // End timezone options
+
+ // inject timepicker into datepicker
+ var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
+ if ($buttonPanel.length) {
+ $buttonPanel.before($tp);
+ } else {
+ $dp.append($tp);
+ }
+
+ this.$timeObj = $tp.find('.ui_tpicker_time');
+
+ if (this.inst !== null) {
+ var timeDefined = this.timeDefined;
+ this._onTimeChange();
+ this.timeDefined = timeDefined;
+ }
+
+ // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
+ if (this._defaults.addSliderAccess) {
+ var sliderAccessArgs = this._defaults.sliderAccessArgs,
+ rtl = this._defaults.isRTL;
+ sliderAccessArgs.isRTL = rtl;
+
+ setTimeout(function () { // fix for inline mode
+ if ($tp.find('.ui-slider-access').length === 0) {
+ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
+
+ // fix any grids since sliders are shorter
+ var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
+ if (sliderAccessWidth) {
+ $tp.find('table:visible').each(function () {
+ var $g = $(this),
+ oldWidth = $g.outerWidth(),
+ oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
+ newWidth = oldWidth - sliderAccessWidth,
+ newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
+ css = { width: newWidth, marginRight: 0, marginLeft: 0 };
+ css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
+ $g.css(css);
+ });
+ }
+ }
+ }, 10);
+ }
+ // end slideAccess integration
+
+ tp_inst._limitMinMaxDateTime(this.inst, true);
+ }
+ },
+
+ /*
+ * This function tries to limit the ability to go outside the
+ * min/max date range
+ */
+ _limitMinMaxDateTime: function (dp_inst, adjustSliders) {
+ var o = this._defaults,
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
+
+ if (!this._defaults.showTimepicker) {
+ return;
+ } // No time so nothing to check here
+
+ if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
+ var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
+ minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
+ this.hourMinOriginal = o.hourMin;
+ this.minuteMinOriginal = o.minuteMin;
+ this.secondMinOriginal = o.secondMin;
+ this.millisecMinOriginal = o.millisecMin;
+ this.microsecMinOriginal = o.microsecMin;
+ }
+
+ if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
+ this._defaults.hourMin = minDateTime.getHours();
+ if (this.hour <= this._defaults.hourMin) {
+ this.hour = this._defaults.hourMin;
+ this._defaults.minuteMin = minDateTime.getMinutes();
+ if (this.minute <= this._defaults.minuteMin) {
+ this.minute = this._defaults.minuteMin;
+ this._defaults.secondMin = minDateTime.getSeconds();
+ if (this.second <= this._defaults.secondMin) {
+ this.second = this._defaults.secondMin;
+ this._defaults.millisecMin = minDateTime.getMilliseconds();
+ if (this.millisec <= this._defaults.millisecMin) {
+ this.millisec = this._defaults.millisecMin;
+ this._defaults.microsecMin = minDateTime.getMicroseconds();
+ } else {
+ if (this.microsec < this._defaults.microsecMin) {
+ this.microsec = this._defaults.microsecMin;
+ }
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.hourMin = this.hourMinOriginal;
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ }
+
+ if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
+ var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
+ maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
+ this.hourMaxOriginal = o.hourMax;
+ this.minuteMaxOriginal = o.minuteMax;
+ this.secondMaxOriginal = o.secondMax;
+ this.millisecMaxOriginal = o.millisecMax;
+ this.microsecMaxOriginal = o.microsecMax;
+ }
+
+ if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
+ this._defaults.hourMax = maxDateTime.getHours();
+ if (this.hour >= this._defaults.hourMax) {
+ this.hour = this._defaults.hourMax;
+ this._defaults.minuteMax = maxDateTime.getMinutes();
+ if (this.minute >= this._defaults.minuteMax) {
+ this.minute = this._defaults.minuteMax;
+ this._defaults.secondMax = maxDateTime.getSeconds();
+ if (this.second >= this._defaults.secondMax) {
+ this.second = this._defaults.secondMax;
+ this._defaults.millisecMax = maxDateTime.getMilliseconds();
+ if (this.millisec >= this._defaults.millisecMax) {
+ this.millisec = this._defaults.millisecMax;
+ this._defaults.microsecMax = maxDateTime.getMicroseconds();
+ } else {
+ if (this.microsec > this._defaults.microsecMax) {
+ this.microsec = this._defaults.microsecMax;
+ }
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.hourMax = this.hourMaxOriginal;
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ }
+
+ if (dp_inst.settings.minTime!==null) {
+ var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);
+ if (this.hour<tempMinTime.getHours()) {
+ this.hour=this._defaults.hourMin=tempMinTime.getHours();
+ this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {
+ this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else {
+ if (this._defaults.hourMin<tempMinTime.getHours()) {
+ this._defaults.hourMin=tempMinTime.getHours();
+ this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {
+ this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else {
+ this._defaults.minuteMin=0;
+ }
+ }
+ }
+
+ if (dp_inst.settings.maxTime!==null) {
+ var tempMaxTime=new Date("01/01/1970 " + dp_inst.settings.maxTime);
+ if (this.hour>tempMaxTime.getHours()) {
+ this.hour=this._defaults.hourMax=tempMaxTime.getHours();
+ this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {
+ this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else {
+ if (this._defaults.hourMax>tempMaxTime.getHours()) {
+ this._defaults.hourMax=tempMaxTime.getHours();
+ this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
+ this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else {
+ this._defaults.minuteMax=59;
+ }
+ }
+ }
+
+ if (adjustSliders !== undefined && adjustSliders === true) {
+ var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
+ minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
+ secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
+ millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
+ microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
+
+ if (this.hour_slider) {
+ this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
+ this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
+ }
+ if (this.minute_slider) {
+ this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
+ this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
+ }
+ if (this.second_slider) {
+ this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
+ this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
+ }
+ if (this.millisec_slider) {
+ this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
+ this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
+ }
+ if (this.microsec_slider) {
+ this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
+ this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
+ }
+ }
+
+ },
+
+ /*
+ * when a slider moves, set the internal time...
+ * on time change is also called when the time is updated in the text field
+ */
+ _onTimeChange: function () {
+ if (!this._defaults.showTimepicker) {
+ return;
+ }
+ var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
+ minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
+ second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
+ millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
+ microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
+ timezone = (this.timezone_select) ? this.timezone_select.val() : false,
+ o = this._defaults,
+ pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
+ pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
+
+ if (typeof(hour) === 'object') {
+ hour = false;
+ }
+ if (typeof(minute) === 'object') {
+ minute = false;
+ }
+ if (typeof(second) === 'object') {
+ second = false;
+ }
+ if (typeof(millisec) === 'object') {
+ millisec = false;
+ }
+ if (typeof(microsec) === 'object') {
+ microsec = false;
+ }
+ if (typeof(timezone) === 'object') {
+ timezone = false;
+ }
+
+ if (hour !== false) {
+ hour = parseInt(hour, 10);
+ }
+ if (minute !== false) {
+ minute = parseInt(minute, 10);
+ }
+ if (second !== false) {
+ second = parseInt(second, 10);
+ }
+ if (millisec !== false) {
+ millisec = parseInt(millisec, 10);
+ }
+ if (microsec !== false) {
+ microsec = parseInt(microsec, 10);
+ }
+ if (timezone !== false) {
+ timezone = timezone.toString();
+ }
+
+ var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
+
+ // If the update was done in the input field, the input field should not be updated.
+ // If the update was done using the sliders, update the input field.
+ var hasChanged = (
+ hour !== parseInt(this.hour,10) || // sliders should all be numeric
+ minute !== parseInt(this.minute,10) ||
+ second !== parseInt(this.second,10) ||
+ millisec !== parseInt(this.millisec,10) ||
+ microsec !== parseInt(this.microsec,10) ||
+ (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
+ (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
+ );
+
+ if (hasChanged) {
+
+ if (hour !== false) {
+ this.hour = hour;
+ }
+ if (minute !== false) {
+ this.minute = minute;
+ }
+ if (second !== false) {
+ this.second = second;
+ }
+ if (millisec !== false) {
+ this.millisec = millisec;
+ }
+ if (microsec !== false) {
+ this.microsec = microsec;
+ }
+ if (timezone !== false) {
+ this.timezone = timezone;
+ }
+
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ this._limitMinMaxDateTime(this.inst, true);
+ }
+ if (this.support.ampm) {
+ this.ampm = ampm;
+ }
+
+ // Updates the time within the timepicker
+ this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
+ if (this.$timeObj) {
+ if (pickerTimeFormat === o.timeFormat) {
+ this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
+ }
+ else {
+ this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
+ }
+ }
+
+ this.timeDefined = true;
+ if (hasChanged) {
+ this._updateDateTime();
+ //this.$input.focus(); // may automatically open the picker on setDate
+ }
+ },
+
+ /*
+ * call custom onSelect.
+ * bind to sliders slidestop, and grid click.
+ */
+ _onSelectHandler: function () {
+ var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
+ var inputEl = this.$input ? this.$input[0] : null;
+ if (onSelect && inputEl) {
+ onSelect.apply(inputEl, [this.formattedDateTime, this]);
+ }
+ },
+
+ /*
+ * update our input with the new date time..
+ */
+ _updateDateTime: function (dp_inst) {
+ dp_inst = this.inst || dp_inst;
+ var dtTmp = (dp_inst.currentYear > 0?
+ new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
+ new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ dt = $.datepicker._daylightSavingAdjust(dtTmp),
+ //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
+ dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+ formatCfg = $.datepicker._getFormatConfig(dp_inst),
+ timeAvailable = dt !== null && this.timeDefined;
+ this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
+ var formattedDateTime = this.formattedDate;
+
+ // if a slider was changed but datepicker doesn't have a value yet, set it
+ if (dp_inst.lastVal === "") {
+ dp_inst.currentYear = dp_inst.selectedYear;
+ dp_inst.currentMonth = dp_inst.selectedMonth;
+ dp_inst.currentDay = dp_inst.selectedDay;
+ }
+
+ /*
+ * remove following lines to force every changes in date picker to change the input value
+ * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
+ * If the user manually empty the value in the input field, the date picker will never change selected value.
+ */
+ //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
+ // return;
+ //}
+
+ if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
+ formattedDateTime = this.formattedTime;
+ } else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
+ formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
+ }
+
+ this.formattedDateTime = formattedDateTime;
+
+ if (!this._defaults.showTimepicker) {
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
+ this.$altInput.val(this.formattedTime);
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput) {
+ this.$input.val(formattedDateTime);
+ var altFormattedDateTime = '',
+ altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
+ altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
+
+ if (!this._defaults.timeOnly) {
+ if (this._defaults.altFormat) {
+ altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
+ }
+ else {
+ altFormattedDateTime = this.formattedDate;
+ }
+
+ if (altFormattedDateTime) {
+ altFormattedDateTime += altSeparator;
+ }
+ }
+
+ if (this._defaults.altTimeFormat !== null) {
+ altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
+ }
+ else {
+ altFormattedDateTime += this.formattedTime + altTimeSuffix;
+ }
+ this.$altInput.val(altFormattedDateTime);
+ } else {
+ this.$input.val(formattedDateTime);
+ }
+
+ this.$input.trigger("change");
+ },
+
+ _onFocus: function () {
+ if (!this.$input.val() && this._defaults.defaultValue) {
+ this.$input.val(this._defaults.defaultValue);
+ var inst = $.datepicker._getInst(this.$input.get(0)),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+ }
+ },
+
+ /*
+ * Small abstraction to control types
+ * We can add more, just be sure to follow the pattern: create, options, value
+ */
+ _controls: {
+ // slider methods
+ slider: {
+ create: function (tp_inst, obj, unit, val, min, max, step) {
+ var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
+ return obj.prop('slide', null).slider({
+ orientation: "horizontal",
+ value: rtl ? val * -1 : val,
+ min: rtl ? max * -1 : min,
+ max: rtl ? min * -1 : max,
+ step: step,
+ slide: function (event, ui) {
+ tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
+ tp_inst._onTimeChange();
+ },
+ stop: function (event, ui) {
+ tp_inst._onSelectHandler();
+ }
+ });
+ },
+ options: function (tp_inst, obj, unit, opts, val) {
+ if (tp_inst._defaults.isRTL) {
+ if (typeof(opts) === 'string') {
+ if (opts === 'min' || opts === 'max') {
+ if (val !== undefined) {
+ return obj.slider(opts, val * -1);
+ }
+ return Math.abs(obj.slider(opts));
+ }
+ return obj.slider(opts);
+ }
+ var min = opts.min,
+ max = opts.max;
+ opts.min = opts.max = null;
+ if (min !== undefined) {
+ opts.max = min * -1;
+ }
+ if (max !== undefined) {
+ opts.min = max * -1;
+ }
+ return obj.slider(opts);
+ }
+ if (typeof(opts) === 'string' && val !== undefined) {
+ return obj.slider(opts, val);
+ }
+ return obj.slider(opts);
+ },
+ value: function (tp_inst, obj, unit, val) {
+ if (tp_inst._defaults.isRTL) {
+ if (val !== undefined) {
+ return obj.slider('value', val * -1);
+ }
+ return Math.abs(obj.slider('value'));
+ }
+ if (val !== undefined) {
+ return obj.slider('value', val);
+ }
+ return obj.slider('value');
+ }
+ },
+ // select methods
+ select: {
+ create: function (tp_inst, obj, unit, val, min, max, step) {
+ var sel = '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
+ format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
+
+ for (var i = min; i <= max; i += step) {
+ sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
+ if (unit === 'hour') {
+ sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
+ }
+ else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
+ else {sel += '0' + i.toString(); }
+ sel += '</option>';
+ }
+ sel += '</select>';
+
+ obj.children('select').remove();
+
+ $(sel).appendTo(obj).change(function (e) {
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+
+ return obj;
+ },
+ options: function (tp_inst, obj, unit, opts, val) {
+ var o = {},
+ $t = obj.children('select');
+ if (typeof(opts) === 'string') {
+ if (val === undefined) {
+ return $t.data(opts);
+ }
+ o[opts] = val;
+ }
+ else { o = opts; }
+ return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
+ },
+ value: function (tp_inst, obj, unit, val) {
+ var $t = obj.children('select');
+ if (val !== undefined) {
+ return $t.val(val);
+ }
+ return $t.val();
+ }
+ }
+ } // end _controls
+
+ });
+
+ $.fn.extend({
+ /*
+ * shorthand just to use timepicker.
+ */
+ timepicker: function (o) {
+ o = o || {};
+ var tmp_args = Array.prototype.slice.call(arguments);
+
+ if (typeof o === 'object') {
+ tmp_args[0] = $.extend(o, {
+ timeOnly: true
+ });
+ }
+
+ return $(this).each(function () {
+ $.fn.datetimepicker.apply($(this), tmp_args);
+ });
+ },
+
+ /*
+ * extend timepicker to datepicker
+ */
+ datetimepicker: function (o) {
+ o = o || {};
+ var tmp_args = arguments;
+
+ if (typeof(o) === 'string') {
+ if (o === 'getDate' || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
+ return $.fn.datepicker.apply($(this[0]), tmp_args);
+ } else {
+ return this.each(function () {
+ var $t = $(this);
+ $t.datepicker.apply($t, tmp_args);
+ });
+ }
+ } else {
+ return this.each(function () {
+ var $t = $(this);
+ $t.datepicker($.timepicker._newInst($t, o)._defaults);
+ });
+ }
+ }
+ });
+
+ /*
+ * Public Utility to parse date and time
+ */
+ $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
+ if (parseRes.timeObj) {
+ var t = parseRes.timeObj;
+ parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
+ parseRes.date.setMicroseconds(t.microsec);
+ }
+
+ return parseRes.date;
+ };
+
+ /*
+ * Public utility to parse time
+ */
+ $.datepicker.parseTime = function (timeFormat, timeString, options) {
+ var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
+ iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
+
+ // Strict parse requires the timeString to match the timeFormat exactly
+ var strictParse = function (f, s, o) {
+
+ // pattern for standard and localized AM/PM markers
+ var getPatternAmpm = function (amNames, pmNames) {
+ var markers = [];
+ if (amNames) {
+ $.merge(markers, amNames);
+ }
+ if (pmNames) {
+ $.merge(markers, pmNames);
+ }
+ markers = $.map(markers, function (val) {
+ return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
+ });
+ return '(' + markers.join('|') + ')?';
+ };
+
+ // figure out position of time elements.. cause js cant do named captures
+ var getFormatPositions = function (timeFormat) {
+ var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
+ orders = {
+ h: -1,
+ m: -1,
+ s: -1,
+ l: -1,
+ c: -1,
+ t: -1,
+ z: -1
+ };
+
+ if (finds) {
+ for (var i = 0; i < finds.length; i++) {
+ if (orders[finds[i].toString().charAt(0)] === -1) {
+ orders[finds[i].toString().charAt(0)] = i + 1;
+ }
+ }
+ }
+ return orders;
+ };
+
+ var regstr = '^' + f.toString()
+ .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
+ var ml = match.length;
+ switch (match.charAt(0).toLowerCase()) {
+ case 'h':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 'm':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 's':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 'l':
+ return '(\\d?\\d?\\d)';
+ case 'c':
+ return '(\\d?\\d?\\d)';
+ case 'z':
+ return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
+ case 't':
+ return getPatternAmpm(o.amNames, o.pmNames);
+ default: // literal escaped in quotes
+ return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
+ }
+ })
+ .replace(/\s/g, '\\s?') +
+ o.timeSuffix + '$',
+ order = getFormatPositions(f),
+ ampm = '',
+ treg;
+
+ treg = s.match(new RegExp(regstr, 'i'));
+
+ var resTime = {
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0
+ };
+
+ if (treg) {
+ if (order.t !== -1) {
+ if (treg[order.t] === undefined || treg[order.t].length === 0) {
+ ampm = '';
+ resTime.ampm = '';
+ } else {
+ ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
+ resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
+ }
+ }
+
+ if (order.h !== -1) {
+ if (ampm === 'AM' && treg[order.h] === '12') {
+ resTime.hour = 0; // 12am = 0 hour
+ } else {
+ if (ampm === 'PM' && treg[order.h] !== '12') {
+ resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
+ } else {
+ resTime.hour = Number(treg[order.h]);
+ }
+ }
+ }
+
+ if (order.m !== -1) {
+ resTime.minute = Number(treg[order.m]);
+ }
+ if (order.s !== -1) {
+ resTime.second = Number(treg[order.s]);
+ }
+ if (order.l !== -1) {
+ resTime.millisec = Number(treg[order.l]);
+ }
+ if (order.c !== -1) {
+ resTime.microsec = Number(treg[order.c]);
+ }
+ if (order.z !== -1 && treg[order.z] !== undefined) {
+ resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
+ }
+
+
+ return resTime;
+ }
+ return false;
+ };// end strictParse
+
+ // First try JS Date, if that fails, use strictParse
+ var looseParse = function (f, s, o) {
+ try {
+ var d = new Date('2012-01-01 ' + s);
+ if (isNaN(d.getTime())) {
+ d = new Date('2012-01-01T' + s);
+ if (isNaN(d.getTime())) {
+ d = new Date('01/01/2012 ' + s);
+ if (isNaN(d.getTime())) {
+ throw "Unable to parse time with native Date: " + s;
+ }
+ }
+ }
+
+ return {
+ hour: d.getHours(),
+ minute: d.getMinutes(),
+ second: d.getSeconds(),
+ millisec: d.getMilliseconds(),
+ microsec: d.getMicroseconds(),
+ timezone: d.getTimezoneOffset() * -1
+ };
+ }
+ catch (err) {
+ try {
+ return strictParse(f, s, o);
+ }
+ catch (err2) {
+ $.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
+ }
+ }
+ return false;
+ }; // end looseParse
+
+ if (typeof o.parse === "function") {
+ return o.parse(timeFormat, timeString, o);
+ }
+ if (o.parse === 'loose') {
+ return looseParse(timeFormat, timeString, o);
+ }
+ return strictParse(timeFormat, timeString, o);
+ };
+
+ /**
+ * Public utility to format the time
+ * @param {string} format format of the time
+ * @param {Object} time Object not a Date for timezones
+ * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
+ * @returns {string} the formatted time
+ */
+ $.datepicker.formatTime = function (format, time, options) {
+ options = options || {};
+ options = $.extend({}, $.timepicker._defaults, options);
+ time = $.extend({
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null
+ }, time);
+
+ var tmptime = format,
+ ampmName = options.amNames[0],
+ hour = parseInt(time.hour, 10);
+
+ if (hour > 11) {
+ ampmName = options.pmNames[0];
+ }
+
+ tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
+ switch (match) {
+ case 'HH':
+ return ('0' + hour).slice(-2);
+ case 'H':
+ return hour;
+ case 'hh':
+ return ('0' + convert24to12(hour)).slice(-2);
+ case 'h':
+ return convert24to12(hour);
+ case 'mm':
+ return ('0' + time.minute).slice(-2);
+ case 'm':
+ return time.minute;
+ case 'ss':
+ return ('0' + time.second).slice(-2);
+ case 's':
+ return time.second;
+ case 'l':
+ return ('00' + time.millisec).slice(-3);
+ case 'c':
+ return ('00' + time.microsec).slice(-3);
+ case 'z':
+ return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
+ case 'Z':
+ return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
+ case 'T':
+ return ampmName.charAt(0).toUpperCase();
+ case 'TT':
+ return ampmName.toUpperCase();
+ case 't':
+ return ampmName.charAt(0).toLowerCase();
+ case 'tt':
+ return ampmName.toLowerCase();
+ default:
+ return match.replace(/'/g, "");
+ }
+ });
+
+ return tmptime;
+ };
+
+ /*
+ * the bad hack :/ override datepicker so it doesn't close on select
+ // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
+ */
+ $.datepicker._base_selectDate = $.datepicker._selectDate;
+ $.datepicker._selectDate = function (id, dateStr) {
+ var inst = this._getInst($(id)[0]),
+ tp_inst = this._get(inst, 'timepicker'),
+ was_inline;
+
+ if (tp_inst && inst.settings.showTimepicker) {
+ tp_inst._limitMinMaxDateTime(inst, true);
+ was_inline = inst.inline;
+ inst.inline = inst.stay_open = true;
+ //This way the onSelect handler called from calendarpicker get the full dateTime
+ this._base_selectDate(id, dateStr);
+ inst.inline = was_inline;
+ inst.stay_open = false;
+ this._notifyChange(inst);
+ this._updateDatepicker(inst);
+ } else {
+ this._base_selectDate(id, dateStr);
+ }
+ };
+
+ /*
+ * second bad hack :/ override datepicker so it triggers an event when changing the input field
+ * and does not redraw the datepicker on every selectDate event
+ */
+ $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
+ $.datepicker._updateDatepicker = function (inst) {
+
+ // don't popup the datepicker if there is another instance already opened
+ var input = inst.input[0];
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
+ return;
+ }
+
+ if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
+
+ this._base_updateDatepicker(inst);
+
+ // Reload the time control when changing something in the input text field.
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._addTimePicker(inst);
+ }
+ }
+ };
+
+ /*
+ * third bad hack :/ override datepicker so it allows spaces and colon in the input field
+ */
+ $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
+ $.datepicker._doKeyPress = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if ($.datepicker._get(inst, 'constrainInput')) {
+ var ampm = tp_inst.support.ampm,
+ tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
+ dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+ datetimeChars = tp_inst._defaults.timeFormat.toString()
+ .replace(/[hms]/g, '')
+ .replace(/TT/g, ampm ? 'APM' : '')
+ .replace(/Tt/g, ampm ? 'AaPpMm' : '')
+ .replace(/tT/g, ampm ? 'AaPpMm' : '')
+ .replace(/T/g, ampm ? 'AP' : '')
+ .replace(/tt/g, ampm ? 'apm' : '')
+ .replace(/t/g, ampm ? 'ap' : '') +
+ " " + tp_inst._defaults.separator +
+ tp_inst._defaults.timeSuffix +
+ (tz ? tp_inst._defaults.timezoneList.join('') : '') +
+ (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
+ dateChars,
+ chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
+ return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
+ }
+ }
+
+ return $.datepicker._base_doKeyPress(event);
+ };
+
+ /*
+ * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
+ * Update any alternate field to synchronise with the main field.
+ */
+ $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
+ $.datepicker._updateAlternate = function (inst) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var altField = tp_inst._defaults.altField;
+ if (altField) { // update alternate field too
+ var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
+ date = this._getDate(inst),
+ formatCfg = $.datepicker._getFormatConfig(inst),
+ altFormattedDateTime = '',
+ altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
+ altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
+ altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
+
+ altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
+ if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
+ if (tp_inst._defaults.altFormat) {
+ altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
+ }
+ else {
+ altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
+ }
+ }
+ $(altField).val( inst.input.val() ? altFormattedDateTime : "");
+ }
+ }
+ else {
+ $.datepicker._base_updateAlternate(inst);
+ }
+ };
+
+ /*
+ * Override key up event to sync manual input changes.
+ */
+ $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
+ $.datepicker._doKeyUp = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+
+ return $.datepicker._base_doKeyUp(event);
+ };
+
+ /*
+ * override "Today" button to also grab the time.
+ */
+ $.datepicker._base_gotoToday = $.datepicker._gotoToday;
+ $.datepicker._gotoToday = function (id) {
+ var inst = this._getInst($(id)[0]),
+ $dp = inst.dpDiv;
+ this._base_gotoToday(id);
+ var tp_inst = this._get(inst, 'timepicker');
+ selectLocalTimezone(tp_inst);
+ var now = new Date();
+ this._setTime(inst, now);
+ this._setDate(inst, now);
+ };
+
+ /*
+ * Disable & enable the Time in the datetimepicker
+ */
+ $.datepicker._disableTimepickerDatepicker = function (target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ inst.settings.showTimepicker = false;
+ tp_inst._defaults.showTimepicker = false;
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ $.datepicker._enableTimepickerDatepicker = function (target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ inst.settings.showTimepicker = true;
+ tp_inst._defaults.showTimepicker = true;
+ tp_inst._addTimePicker(inst); // Could be disabled on page load
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create our own set time function
+ */
+ $.datepicker._setTime = function (inst, date) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var defaults = tp_inst._defaults;
+
+ // calling _setTime with no date sets time to defaults
+ tp_inst.hour = date ? date.getHours() : defaults.hour;
+ tp_inst.minute = date ? date.getMinutes() : defaults.minute;
+ tp_inst.second = date ? date.getSeconds() : defaults.second;
+ tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
+ tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
+
+ //check if within min/max times..
+ tp_inst._limitMinMaxDateTime(inst, true);
+
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create new public method to set only time, callable as $().datepicker('setTime', date)
+ */
+ $.datepicker._setTimeDatepicker = function (target, date, withDate) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ this._setDateFromField(inst);
+ var tp_date;
+ if (date) {
+ if (typeof date === "string") {
+ tp_inst._parseTime(date, withDate);
+ tp_date = new Date();
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ tp_date.setMicroseconds(tp_inst.microsec);
+ } else {
+ tp_date = new Date(date.getTime());
+ tp_date.setMicroseconds(date.getMicroseconds());
+ }
+ if (tp_date.toString() === 'Invalid Date') {
+ tp_date = undefined;
+ }
+ this._setTime(inst, tp_date);
+ }
+ }
+
+ };
+
+ /*
+ * override setDate() to allow setting time too within Date object
+ */
+ $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
+ $.datepicker._setDateDatepicker = function (target, _date) {
+ var inst = this._getInst(target);
+ var date = _date;
+ if (!inst) {
+ return;
+ }
+
+ if (typeof(_date) === 'string') {
+ date = new Date(_date);
+ if (!date.getTime()) {
+ this._base_setDateDatepicker.apply(this, arguments);
+ date = $(target).datepicker('getDate');
+ }
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ var tp_date;
+ if (date instanceof Date) {
+ tp_date = new Date(date.getTime());
+ tp_date.setMicroseconds(date.getMicroseconds());
+ } else {
+ tp_date = date;
+ }
+
+ // This is important if you are using the timezone option, javascript's Date
+ // object will only return the timezone offset for the current locale, so we
+ // adjust it accordingly. If not using timezone option this won't matter..
+ // If a timezone is different in tp, keep the timezone as is
+ if (tp_inst && tp_date) {
+ // look out for DST if tz wasn't specified
+ if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
+ tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
+ }
+ date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
+ tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
+ }
+
+ this._updateDatepicker(inst);
+ this._base_setDateDatepicker.apply(this, arguments);
+ this._setTimeDatepicker(target, tp_date, true);
+ };
+
+ /*
+ * override getDate() to allow getting time too within Date object
+ */
+ $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
+ $.datepicker._getDateDatepicker = function (target, noDefault) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ // if it hasn't yet been defined, grab from field
+ if (inst.lastVal === undefined) {
+ this._setDateFromField(inst, noDefault);
+ }
+
+ var date = this._getDate(inst);
+ if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
+ date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ date.setMicroseconds(tp_inst.microsec);
+
+ // This is important if you are using the timezone option, javascript's Date
+ // object will only return the timezone offset for the current locale, so we
+ // adjust it accordingly. If not using timezone option this won't matter..
+ if (tp_inst.timezone != null) {
+ // look out for DST if tz wasn't specified
+ if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
+ tp_inst.timezone = date.getTimezoneOffset() * -1;
+ }
+ date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
+ }
+ }
+ return date;
+ }
+ return this._base_getDateDatepicker(target, noDefault);
+ };
+
+ /*
+ * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
+ * An option in datapicker to ignore extra format characters would be nicer.
+ */
+ $.datepicker._base_parseDate = $.datepicker.parseDate;
+ $.datepicker.parseDate = function (format, value, settings) {
+ var date;
+ try {
+ date = this._base_parseDate(format, value, settings);
+ } catch (err) {
+ // Hack! The error message ends with a colon, a space, and
+ // the "extra" characters. We rely on that instead of
+ // attempting to perfectly reproduce the parsing algorithm.
+ if (err.indexOf(":") >= 0) {
+ date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
+ $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
+ } else {
+ throw err;
+ }
+ }
+ return date;
+ };
+
+ /*
+ * override formatDate to set date with time to the input
+ */
+ $.datepicker._base_formatDate = $.datepicker._formatDate;
+ $.datepicker._formatDate = function (inst, day, month, year) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._updateDateTime(inst);
+ return tp_inst.$input.val();
+ }
+ return this._base_formatDate(inst);
+ };
+
+ /*
+ * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
+ */
+ $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
+ $.datepicker._optionDatepicker = function (target, name, value) {
+ var inst = this._getInst(target),
+ name_clone;
+ if (!inst) {
+ return null;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var min = null,
+ max = null,
+ onselect = null,
+ overrides = tp_inst._defaults.evnts,
+ fns = {},
+ prop,
+ ret,
+ oldVal,
+ $target;
+ if (typeof name === 'string') { // if min/max was set with the string
+ if (name === 'minDate' || name === 'minDateTime') {
+ min = value;
+ } else if (name === 'maxDate' || name === 'maxDateTime') {
+ max = value;
+ } else if (name === 'onSelect') {
+ onselect = value;
+ } else if (overrides.hasOwnProperty(name)) {
+ if (typeof (value) === 'undefined') {
+ return overrides[name];
+ }
+ fns[name] = value;
+ name_clone = {}; //empty results in exiting function after overrides updated
+ }
+ } else if (typeof name === 'object') { //if min/max was set with the JSON
+ if (name.minDate) {
+ min = name.minDate;
+ } else if (name.minDateTime) {
+ min = name.minDateTime;
+ } else if (name.maxDate) {
+ max = name.maxDate;
+ } else if (name.maxDateTime) {
+ max = name.maxDateTime;
+ }
+ for (prop in overrides) {
+ if (overrides.hasOwnProperty(prop) && name[prop]) {
+ fns[prop] = name[prop];
+ }
+ }
+ }
+ for (prop in fns) {
+ if (fns.hasOwnProperty(prop)) {
+ overrides[prop] = fns[prop];
+ if (!name_clone) { name_clone = $.extend({}, name); }
+ delete name_clone[prop];
+ }
+ }
+ if (name_clone && isEmptyObject(name_clone)) { return; }
+ if (min) { //if min was set
+ if (min === 0) {
+ min = new Date();
+ } else {
+ min = new Date(min);
+ }
+ tp_inst._defaults.minDate = min;
+ tp_inst._defaults.minDateTime = min;
+ } else if (max) { //if max was set
+ if (max === 0) {
+ max = new Date();
+ } else {
+ max = new Date(max);
+ }
+ tp_inst._defaults.maxDate = max;
+ tp_inst._defaults.maxDateTime = max;
+ } else if (onselect) {
+ tp_inst._defaults.onSelect = onselect;
+ }
+
+ // Datepicker will override our date when we call _base_optionDatepicker when
+ // calling minDate/maxDate, so we will first grab the value, call
+ // _base_optionDatepicker, then set our value back.
+ if(min || max){
+ $target = $(target);
+ oldVal = $target.datetimepicker('getDate');
+ ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ $target.datetimepicker('setDate', oldVal);
+ return ret;
+ }
+ }
+ if (value === undefined) {
+ return this._base_optionDatepicker.call($.datepicker, target, name);
+ }
+ return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ };
+
+ /*
+ * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
+ * it will return false for all objects
+ */
+ var isEmptyObject = function (obj) {
+ var prop;
+ for (prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /*
+ * jQuery extend now ignores nulls!
+ */
+ var extendRemove = function (target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] === null || props[name] === undefined) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+ };
+
+ /*
+ * Determine by the time format which units are supported
+ * Returns an object of booleans for each unit
+ */
+ var detectSupport = function (timeFormat) {
+ var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
+ isIn = function (f, t) { // does the format contain the token?
+ return f.indexOf(t) !== -1 ? true : false;
+ };
+ return {
+ hour: isIn(tf, 'h'),
+ minute: isIn(tf, 'm'),
+ second: isIn(tf, 's'),
+ millisec: isIn(tf, 'l'),
+ microsec: isIn(tf, 'c'),
+ timezone: isIn(tf, 'z'),
+ ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
+ iso8601: isIn(timeFormat, 'Z')
+ };
+ };
+
+ /*
+ * Converts 24 hour format into 12 hour
+ * Returns 12 hour without leading 0
+ */
+ var convert24to12 = function (hour) {
+ hour %= 12;
+
+ if (hour === 0) {
+ hour = 12;
+ }
+
+ return String(hour);
+ };
+
+ var computeEffectiveSetting = function (settings, property) {
+ return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
+ };
+
+ /*
+ * Splits datetime string into date and time substrings.
+ * Throws exception when date can't be parsed
+ * Returns {dateString: dateString, timeString: timeString}
+ */
+ var splitDateTime = function (dateTimeString, timeSettings) {
+ // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
+ // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
+ var separator = computeEffectiveSetting(timeSettings, 'separator'),
+ format = computeEffectiveSetting(timeSettings, 'timeFormat'),
+ timeParts = format.split(separator), // how many occurrences of separator may be in our format?
+ timePartsLen = timeParts.length,
+ allParts = dateTimeString.split(separator),
+ allPartsLen = allParts.length;
+
+ if (allPartsLen > 1) {
+ return {
+ dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
+ timeString: allParts.splice(0, timePartsLen).join(separator)
+ };
+ }
+
+ return {
+ dateString: dateTimeString,
+ timeString: ''
+ };
+ };
+
+ /*
+ * Internal function to parse datetime interval
+ * Returns: {date: Date, timeObj: Object}, where
+ * date - parsed date without time (type Date)
+ * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
+ */
+ var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var date,
+ parts,
+ parsedTime;
+
+ parts = splitDateTime(dateTimeString, timeSettings);
+ date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
+
+ if (parts.timeString === '') {
+ return {
+ date: date
+ };
+ }
+
+ parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
+
+ if (!parsedTime) {
+ throw 'Wrong time format';
+ }
+
+ return {
+ date: date,
+ timeObj: parsedTime
+ };
+ };
+
+ /*
+ * Internal function to set timezone_select to the local timezone
+ */
+ var selectLocalTimezone = function (tp_inst, date) {
+ if (tp_inst && tp_inst.timezone_select) {
+ var now = date || new Date();
+ tp_inst.timezone_select.val(-now.getTimezoneOffset());
+ }
+ };
+
+ /*
+ * Create a Singleton Instance
+ */
+ $.timepicker = new Timepicker();
+
+ /**
+ * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
+ * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
+ * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
+ * @return {string}
+ */
+ $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
+ if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
+ return tzMinutes;
+ }
+
+ var off = tzMinutes,
+ minutes = off % 60,
+ hours = (off - minutes) / 60,
+ iso = iso8601 ? ':' : '',
+ tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
+
+ if (tz === '+00:00') {
+ return 'Z';
+ }
+ return tz;
+ };
+
+ /**
+ * Get the number in minutes that represents a timezone string
+ * @param {string} tzString formatted like "+0500", "-1245", "Z"
+ * @return {number} the offset minutes or the original string if it doesn't match expectations
+ */
+ $.timepicker.timezoneOffsetNumber = function (tzString) {
+ var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
+
+ if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
+ return 0;
+ }
+
+ if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
+ return tzString;
+ }
+
+ return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
+ ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
+ parseInt(normalized.substr(3, 2), 10))); // minutes
+ };
+
+ /**
+ * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
+ * @param {Date} date
+ * @param {string} toTimezone formatted like "+0500", "-1245"
+ * @return {Date}
+ */
+ $.timepicker.timezoneAdjust = function (date, toTimezone) {
+ var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
+ if (!isNaN(toTz)) {
+ date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
+ }
+ return date;
+ };
+
+ /**
+ * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * n.b. The input value must be correctly formatted (reformatting is not supported)
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the timepicker() call
+ * @return {jQuery}
+ */
+ $.timepicker.timeRange = function (startTime, endTime, options) {
+ return $.timepicker.handleRange('timepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @param {string} method Can be used to specify the type of picker to be added
+ * @return {jQuery}
+ */
+ $.timepicker.datetimeRange = function (startTime, endTime, options) {
+ $.timepicker.handleRange('datetimepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return {jQuery}
+ */
+ $.timepicker.dateRange = function (startTime, endTime, options) {
+ $.timepicker.handleRange('datepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {string} method Can be used to specify the type of picker to be added
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return {jQuery}
+ */
+ $.timepicker.handleRange = function (method, startTime, endTime, options) {
+ options = $.extend({}, {
+ minInterval: 0, // min allowed interval in milliseconds
+ maxInterval: 0, // max allowed interval in milliseconds
+ start: {}, // options for start picker
+ end: {} // options for end picker
+ }, options);
+
+ // for the mean time this fixes an issue with calling getDate with timepicker()
+ var timeOnly = false;
+ if(method === 'timepicker'){
+ timeOnly = true;
+ method = 'datetimepicker';
+ }
+
+ function checkDates(changed, other) {
+ var startdt = startTime[method]('getDate'),
+ enddt = endTime[method]('getDate'),
+ changeddt = changed[method]('getDate');
+
+ if (startdt !== null) {
+ var minDate = new Date(startdt.getTime()),
+ maxDate = new Date(startdt.getTime());
+
+ minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
+ maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
+
+ if (options.minInterval > 0 && minDate > enddt) { // minInterval check
+ endTime[method]('setDate', minDate);
+ }
+ else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
+ endTime[method]('setDate', maxDate);
+ }
+ else if (startdt > enddt) {
+ other[method]('setDate', changeddt);
+ }
+ }
+ }
+
+ function selected(changed, other, option) {
+ if (!changed.val()) {
+ return;
+ }
+ var date = changed[method].call(changed, 'getDate');
+ if (date !== null && options.minInterval > 0) {
+ if (option === 'minDate') {
+ date.setMilliseconds(date.getMilliseconds() + options.minInterval);
+ }
+ if (option === 'maxDate') {
+ date.setMilliseconds(date.getMilliseconds() - options.minInterval);
+ }
+ }
+
+ if (date.getTime) {
+ other[method].call(other, 'option', option, date);
+ }
+ }
+
+ $.fn[method].call(startTime, $.extend({
+ timeOnly: timeOnly,
+ onClose: function (dateText, inst) {
+ checkDates($(this), endTime);
+ },
+ onSelect: function (selectedDateTime) {
+ selected($(this), endTime, 'minDate');
+ }
+ }, options, options.start));
+ $.fn[method].call(endTime, $.extend({
+ timeOnly: timeOnly,
+ onClose: function (dateText, inst) {
+ checkDates($(this), startTime);
+ },
+ onSelect: function (selectedDateTime) {
+ selected($(this), startTime, 'maxDate');
+ }
+ }, options, options.end));
+
+ checkDates(startTime, endTime);
+
+ selected(startTime, endTime, 'minDate');
+ selected(endTime, startTime, 'maxDate');
+
+ return $([startTime.get(0), endTime.get(0)]);
+ };
+
+ /**
+ * Log error or data to the console during error or debugging
+ * @param {Object} err pass any type object to log to the console during error or debugging
+ * @return {void}
+ */
+ $.timepicker.log = function () {
+ if (window.console) {
+ window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
+ }
+ };
+
+ /*
+ * Add util object to allow access to private methods for testability.
+ */
+ $.timepicker._util = {
+ _extendRemove: extendRemove,
+ _isEmptyObject: isEmptyObject,
+ _convert24to12: convert24to12,
+ _detectSupport: detectSupport,
+ _selectLocalTimezone: selectLocalTimezone,
+ _computeEffectiveSetting: computeEffectiveSetting,
+ _splitDateTime: splitDateTime,
+ _parseDateTimeInternal: parseDateTimeInternal
+ };
+
+ /*
+ * Microsecond support
+ */
+ if (!Date.prototype.getMicroseconds) {
+ Date.prototype.microseconds = 0;
+ Date.prototype.getMicroseconds = function () { return this.microseconds; };
+ Date.prototype.setMicroseconds = function (m) {
+ this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
+ this.microseconds = m % 1000;
+ return this;
+ };
+ }
+
+ /*
+ * Keep up with the version
+ */
+ $.timepicker.version = "1.5.0";
+
+})(jQuery);
\ No newline at end of file |