diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ef7e7efc --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 00000000..f5df9bea --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +#Unyson Framework + +[Unyson](http://unyson.themefuse.com/) is a framework for [WordPress](http://wordpress.org/) that facilitates development of a theme. + +This framework was created from the ground up by the team behind [ThemeFuse](http://themefuse.com/) from the desire to empower developers to build outstanding WordPress themes fast and easy. + +To get started, check out http://unyson.themefuse.com/ ! + +##Table of contents + +* [Quick start](#quick-start) +* [Bug reports](#bug-reports) +* [Documentation](#documentation) +* [Copyright and license](#copyright-and-license) + +## Quick start + +Three quick start options are available: + +* [Download the latest release](https://github.com/ThemeFuse/Unyson/releases). +* Clone the repo: `git clone https://github.com/ThemeFuse/Unyson.git`. + +## Bug reports + +We strive to make Unyson Development to be awesome and user friendly, though sometimes it's impossible to avoid bugs. +A bug means "something is broken" or is not working as it should. + +In order to offer you an effective support and fix for an issue, please follow the below guidelines before submitting a bug report: + +#### Explore Known Issues + +Has your issue already been reported? Check the [Issues page](https://github.com/ThemeFuse/Unyson/issues). + +If your issue has already been reported, great! It will be reviewed in an upcoming release. + +#### Submitting a Bug Report + +You can report the issue via [Issues page](https://github.com/ThemeFuse/Unyson/issues). +A good bug report includes full details to easily understand the issue you are having. + +## Documentation + +Unyson's documentation is available on http://unyson-docs.themefuse.com/. + +## Copyright and license + +Code and documentation copyright 2014 ThemeFuse LTD. Code released under [the GPL license](https://github.com/ThemeFuse/Unyson/blob/master/LICENSE). Docs released under [Creative Commons](https://github.com/ThemeFuse/Unyson-Documentation/blob/master/LICENSE). + diff --git a/scratch-child/screenshot.png b/scratch-child/screenshot.png new file mode 100644 index 00000000..100e9d7f Binary files /dev/null and b/scratch-child/screenshot.png differ diff --git a/scratch-child/style.css b/scratch-child/style.css new file mode 100644 index 00000000..a0615a4d --- /dev/null +++ b/scratch-child/style.css @@ -0,0 +1,9 @@ +/* +Theme Name: Scratch Child +Description: Child theme for the Scratch. Child themes are the recommended way of making modifications to a theme. Reade More +Author: ThemeFuse +Author URI: http://themefuse.com/ +Template: scratch-parent +*/ + +@import url("../scratch-parent/style.css"); \ No newline at end of file diff --git a/scratch-parent/404.php b/scratch-parent/404.php new file mode 100644 index 00000000..a373b556 --- /dev/null +++ b/scratch-parent/404.php @@ -0,0 +1,33 @@ + + + +
+
+ + + +
+

+ + +
+ +
+
+ + + +
+
+ + + + + + +
+
+ + + +
+
+ + + +
+

+ +

+ + +
+ +
+ + + +
+
+ + + +
+
+ + + +
+

+ + %s
', $term_description ); + endif; + ?> + + + + +
+ + + +
+ + + +

+ +

+ + 1 && get_option( 'page_comments' ) ) : ?> + + + +
    + 'ol', + 'short_ping' => true, + 'avatar_size'=> 34, + ) ); + ?> +
+ + 1 && get_option( 'page_comments' ) ) : ?> + + + + +

+ + + + + + +
diff --git a/scratch-parent/content-aside.php b/scratch-parent/content-aside.php new file mode 100644 index 00000000..29f61ca7 --- /dev/null +++ b/scratch-parent/content-aside.php @@ -0,0 +1,59 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content-audio.php b/scratch-parent/content-audio.php new file mode 100644 index 00000000..87e57ed1 --- /dev/null +++ b/scratch-parent/content-audio.php @@ -0,0 +1,59 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content-featured-post.php b/scratch-parent/content-featured-post.php new file mode 100644 index 00000000..e494eaf2 --- /dev/null +++ b/scratch-parent/content-featured-post.php @@ -0,0 +1,35 @@ + + +
> + + + + +
+ + + + + ','' ); ?> + +
+
diff --git a/scratch-parent/content-gallery.php b/scratch-parent/content-gallery.php new file mode 100644 index 00000000..346ac671 --- /dev/null +++ b/scratch-parent/content-gallery.php @@ -0,0 +1,58 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content-image.php b/scratch-parent/content-image.php new file mode 100644 index 00000000..5f0aed8c --- /dev/null +++ b/scratch-parent/content-image.php @@ -0,0 +1,58 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content-link.php b/scratch-parent/content-link.php new file mode 100644 index 00000000..76a7f027 --- /dev/null +++ b/scratch-parent/content-link.php @@ -0,0 +1,58 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content-none.php b/scratch-parent/content-none.php new file mode 100644 index 00000000..f061abd1 --- /dev/null +++ b/scratch-parent/content-none.php @@ -0,0 +1,32 @@ + + + + +
+ + +

Get started here.', 'unyson' ), admin_url( 'post-new.php' ) ); ?>

+ + + +

+ + + + +

+ + + +
diff --git a/scratch-parent/content-page.php b/scratch-parent/content-page.php new file mode 100644 index 00000000..38e49691 --- /dev/null +++ b/scratch-parent/content-page.php @@ -0,0 +1,34 @@ + + +
> +
+ ', '' ); + ?> + +
+ +
+ '', + 'link_before' => '', + 'link_after' => '', + ) ); + + edit_post_link( __( 'Edit', 'unyson' ), '', '' ); + ?> +
+
diff --git a/scratch-parent/content-quote.php b/scratch-parent/content-quote.php new file mode 100644 index 00000000..bef7d623 --- /dev/null +++ b/scratch-parent/content-quote.php @@ -0,0 +1,58 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content-video.php b/scratch-parent/content-video.php new file mode 100644 index 00000000..3f6d45f2 --- /dev/null +++ b/scratch-parent/content-video.php @@ -0,0 +1,58 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + ', '', '' ); ?> +
diff --git a/scratch-parent/content.php b/scratch-parent/content.php new file mode 100644 index 00000000..5dc621b9 --- /dev/null +++ b/scratch-parent/content.php @@ -0,0 +1,67 @@ + + +
> + + +
+ + + ', '' ); + else : + the_title( '

', '

' ); + endif; + ?> + + + +
+ + +
+ +
+ +
+ →', 'unyson' ) ); + wp_link_pages( array( + 'before' => '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
+ + + ', '', '' ); ?> +
diff --git a/scratch-parent/css/editor-style.css b/scratch-parent/css/editor-style.css new file mode 100644 index 00000000..ddd9f9ba --- /dev/null +++ b/scratch-parent/css/editor-style.css @@ -0,0 +1,644 @@ +/* +Theme Name: Scratch +Description: Used to style the TinyMCE editor. +*/ + + +/** + * Table of Contents: + * + * 1.0 - Body + * 2.0 - Headings + * 3.0 - Text Elements + * 4.0 - Links + * 5.0 - Alignment + * 6.0 - Tables + * 7.0 - Images + * 8.0 - Galleries + * 9.0 - Audio/Video + * 10.0 - RTL + * ---------------------------------------------------------------------------- + */ + + +/** + * 1.0 Body + * ---------------------------------------------------------------------------- + */ + +html .mceContentBody { + font-size: 100%; + max-width: 474px; +} + +body { + color: #2b2b2b; + font-family: Lato, sans-serif; + font-weight: 400; + line-height: 1.5; + vertical-align: baseline; +} + + +/** + * 2.0 Headings + * ---------------------------------------------------------------------------- + */ + +h1, +h2, +h3, +h4, +h5, +h6 { + clear: both; + font-weight: 700; + margin: 36px 0 12px; +} + +h1 { + font-size: 26px; + line-height: 1.3846153846; +} + +h2 { + font-size: 24px; + line-height: 1; +} + +h3 { + font-size: 22px; + line-height: 1.0909090909; +} + +h4 { + font-size: 20px; + line-height: 1.2; +} + +h5 { + font-size: 18px; + line-height: 1.3333333333; +} + +h6 { + font-size: 16px; + line-height: 1.5; +} + +h1:first-child, +h2:first-child, +h3:first-child, +h4:first-child, +h5:first-child, +h6:first-child { + margin-top: 0; +} + + +/** + * 3.0 Text Elements + * ---------------------------------------------------------------------------- + */ + +address { + font-style: italic; + margin-bottom: 24px; +} + +abbr[title] { + border-bottom: 1px dotted #2b2b2b; + cursor: help; +} + +b, +strong { + font-weight: 700; +} + +cite { + border: 0; +} + +cite, +dfn, +em, +i { + font-style: italic; +} + +mark, +ins { + background: #fff9c0; + border: 0; + color: inherit; + text-decoration: none; +} + +p { + margin: 0 0 24px; +} + +code, +kbd, +tt, +var, +samp, +pre { + font-family: monospace, serif; + font-size: 15px; + line-height: 1.6; +} + +pre { + border: 1px solid rgba(0, 0, 0, 0.1); + margin-bottom: 24px; + max-width: 100%; + overflow: auto; + padding: 12px; + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +blockquote, +q { + quotes: none; +} + +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; +} + +blockquote { + color: #767676; + font-size: 19px; + font-style: italic; + font-weight: 300; + line-height: 1.2631578947; + margin: 0 0 24px; +} + +blockquote cite, +blockquote small { + color: #2b2b2b; + font-size: 16px; + font-weight: 400; + line-height: 1.5; +} + +blockquote em, +blockquote i, +blockquote cite { + font-style: normal; +} + +blockquote strong, +blockquote b { + font-weight: 400; +} + +small { + font-size: smaller; +} + +big { + font-size: 125%; +} + +sup, +sub { + font-size: 75%; + height: 0; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + bottom: 1ex; +} + +sub { + top: .5ex; +} + +dl { + margin: 0 0 24px; +} + +dt { + font-weight: bold; +} + +dd { + margin: 0 0 24px; +} + +ul, +ol { + list-style: none; + margin: 0 0 24px 20px; + padding-left: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li > ul, +li > ol { + margin: 0 0 0 20px; +} + +del { + color: #767676; +} + +hr { + background-color: rgba(0, 0, 0, 0.1); + border: 0; + height: 1px; + margin-bottom: 23px; +} + + +/** + * 4.0 Links + * ---------------------------------------------------------------------------- + */ + +a { + color: #24890d; + text-decoration: none; +} + +a:visited { + color: #24890d; +} + +a:focus { + outline: thin dotted; +} + +a:active, +a:hover { + color: #41a62a; + outline: 0; +} + + +/** + * 5.0 Alignment + * ---------------------------------------------------------------------------- + */ + +.alignleft { + float: left; + margin: 7px 24px 7px 0; +} + +.alignright { + float: right; + margin: 7px 0 7px 24px; +} + +.aligncenter { + clear: both; + display: block; + margin: 7px auto; +} + +blockquote.alignleft, +blockquote.alignright { + border-top: 1px solid rgba(0, 0, 0, 0.1); + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + padding-top: 17px; + width: 50%; +} + +blockquote.alignleft p, +blockquote.alignright p { + margin-bottom: 17px; +} + + +/** + * 6.0 Tables + * ---------------------------------------------------------------------------- + */ + +.mceItemTable { + border: 1px solid rgba(0, 0, 0, 0.1); + border-width: 1px 0 0 1px; + border-collapse: separate; + border-spacing: 0; + font-size: 14px; + line-height: 1.2857142857; + margin-bottom: 24px; + width: 100%; +} + +.mceItemTable th, +.mceItemTable caption { + border: 1px solid rgba(0, 0, 0, 0.1); + border-width: 0 1px 1px 0; + font-weight: 700; + padding: 8px; + text-align: left; + text-transform: uppercase; + vertical-align: baseline; +} + +.mceItemTable td { + border: 1px solid rgba(0, 0, 0, 0.1); + border-width: 0 1px 1px 0; + font-family: Lato, sans-serif; + font-size: 14px; + padding: 8px; + vertical-align: baseline; +} + + +/** + * 7.0 Images + * ---------------------------------------------------------------------------- + */ + +img { + height: auto; + max-width: 474px; + vertical-align: middle; +} + +.wp-caption { + background: transparent; + border: none; + color: #767676; + margin: 0 0 24px 0; + max-width: 474px; + padding: 0; + text-align: left; +} + +.html5-captions .wp-caption { + padding: 0; +} + +.wp-caption.alignleft { + margin: 7px 14px 7px 0; +} + +.html5-captions .wp-caption.alignleft { + margin-right: 24px; +} + +.wp-caption.alignright { + margin: 7px 0 7px 14px; +} + +.wp-caption.alignright img, +.wp-caption.alignright .wp-caption-dd { + padding-left: 10px; +} + +.html5-captions .wp-caption.alignright { + margin-left: 24px; +} + +.html5-captions .wp-caption.alignright img, +.html5-captions .wp-caption.alignright .wp-caption-dd { + padding: 0; +} + +.wp-caption.aligncenter { + margin: 7px 0; +} + +.wp-caption-dt { + margin: 0; +} + +.wp-caption .wp-caption-text, +.wp-caption-dd { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + font-size: 12px; + font-style: italic; + line-height: 1.5; + margin: 9px 0; + padding: 0 10px 0 0; /* Avoid the caption to overflow the width of the image because wp-caption has 10px wider width */ + text-align: left; +} + +.mceTemp + ul, +.mceTemp + ol { + list-style-position: inside; +} + +/** + * 8.0 Gallery + * ----------------------------------------------------------------------------- + */ + +.gallery .gallery-item { + float: left; + margin: 0 4px 4px 0; + overflow: hidden; + padding: 0; + position: relative; +} + +.gallery-columns-1 .gallery-item { + max-width: 100%; + width: auto; +} + +.gallery-columns-2 .gallery-item { + max-width: 48%; + max-width: -webkit-calc(50% - 14px); + max-width: calc(50% - 14px); + width: auto; +} + +.gallery-columns-3 .gallery-item { + max-width: 32%; + max-width: -webkit-calc(33.3% - 11px); + max-width: calc(33.3% - 11px); + width: auto; +} + +.gallery-columns-4 .gallery-item { + max-width: 23%; + max-width: -webkit-calc(25% - 9px); + max-width: calc(25% - 9px); + width: auto; +} + +.gallery-columns-5 .gallery-item { + max-width: 19%; + max-width: -webkit-calc(20% - 8px); + max-width: calc(20% - 8px); + width: auto; +} + +.gallery-columns-6 .gallery-item { + max-width: 15%; + max-width: -webkit-calc(16.7% - 7px); + max-width: calc(16.7% - 7px); + width: auto; +} + +.gallery-columns-7 .gallery-item { + max-width: 13%; + max-width: -webkit-calc(14.28% - 7px); + max-width: calc(14.28% - 7px); + width: auto; +} + +.gallery-columns-8 .gallery-item { + max-width: 11%; + max-width: -webkit-calc(12.5% - 6px); + max-width: calc(12.5% - 6px); + width: auto; +} + +.gallery-columns-9 .gallery-item { + max-width: 9%; + max-width: -webkit-calc(11.1% - 6px); + max-width: calc(11.1% - 6px); + width: auto; +} + +.gallery-columns-1 .gallery-item:nth-of-type(1n), +.gallery-columns-2 .gallery-item:nth-of-type(2n), +.gallery-columns-3 .gallery-item:nth-of-type(3n), +.gallery-columns-4 .gallery-item:nth-of-type(4n), +.gallery-columns-5 .gallery-item:nth-of-type(5n), +.gallery-columns-6 .gallery-item:nth-of-type(6n), +.gallery-columns-7 .gallery-item:nth-of-type(7n), +.gallery-columns-8 .gallery-item:nth-of-type(8n), +.gallery-columns-9 .gallery-item:nth-of-type(9n) { + margin-right: 0; +} + +.gallery-columns-1 .gallery-item:nth-of-type(1n), +.gallery-columns-2 .gallery-item:nth-of-type(2n - 1), +.gallery-columns-3 .gallery-item:nth-of-type(3n - 2), +.gallery-columns-4 .gallery-item:nth-of-type(4n - 3), +.gallery-columns-5 .gallery-item:nth-of-type(5n - 4), +.gallery-columns-6 .gallery-item:nth-of-type(6n - 5), +.gallery-columns-7 .gallery-item:nth-of-type(7n - 6), +.gallery-columns-8 .gallery-item:nth-of-type(8n - 7), +.gallery-columns-9 .gallery-item:nth-of-type(9n - 8) { + margin-left: 12px; /* Compensate for the default negative margin on .gallery, which can't be changed. */ +} + +.gallery .gallery-caption { + background-color: rgba(0, 0, 0, 0.7); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + color: #fff; + font-size: 12px; + line-height: 1.5; + margin: 0; + max-height: 50%; + opacity: 0; + padding: 6px 8px; + position: absolute; + bottom: 0; + left: 0; + text-align: left; + width: 100%; +} + +.gallery .gallery-caption:before { + content: ""; + height: 100%; + min-height: 49px; + position: absolute; + top: 0; + left: 0; + width: 100%; +} + +.gallery-item:hover .gallery-caption { + opacity: 1; +} + +.gallery-columns-7 .gallery-caption, +.gallery-columns-8 .gallery-caption, +.gallery-columns-9 .gallery-caption { + display: none; +} + + +/** + * 9.0 Audio/Video + * ---------------------------------------------------------------------------- + */ + +.mejs-mediaelement, +.mejs-container .mejs-controls { + background: #000; +} + +.mejs-controls .mejs-time-rail .mejs-time-loaded, +.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current { + background: #fff; +} + +.mejs-controls .mejs-time-rail .mejs-time-current { + background: #24890d; +} + +.mejs-controls .mejs-time-rail .mejs-time-total, +.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total { + background: rgba(255, 255, 255, .33); +} + +.mejs-controls .mejs-time-rail span, +.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total, +.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current { + border-radius: 0; +} + +.mejs-overlay-loading { + background: transparent; +} + + +/** + * 10.0 RTL + * ---------------------------------------------------------------------------- + */ + +html .mceContentBody.rtl { + direction: rtl; + unicode-bidi: embed; +} + +.rtl ol, +.rtl ul { + margin-left: 0; + margin-right: 24px; +} + +.rtl .wp-caption, +.rtl tr th { + text-align: right; +} + +.rtl td { + text-align: right; +} diff --git a/scratch-parent/css/font-awesome/css/font-awesome.css b/scratch-parent/css/font-awesome/css/font-awesome.css new file mode 100644 index 00000000..eb4127b7 --- /dev/null +++ b/scratch-parent/css/font-awesome/css/font-awesome.css @@ -0,0 +1,1566 @@ +/*! + * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.1.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper-square:before, +.fa-pied-piper:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} diff --git a/scratch-parent/css/font-awesome/css/font-awesome.min.css b/scratch-parent/css/font-awesome/css/font-awesome.min.css new file mode 100644 index 00000000..3d920fc8 --- /dev/null +++ b/scratch-parent/css/font-awesome/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.1.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-square:before,.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"} \ No newline at end of file diff --git a/scratch-parent/css/font-awesome/fonts/FontAwesome.otf b/scratch-parent/css/font-awesome/fonts/FontAwesome.otf new file mode 100644 index 00000000..3461e3fc Binary files /dev/null and b/scratch-parent/css/font-awesome/fonts/FontAwesome.otf differ diff --git a/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.eot b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.eot new file mode 100755 index 00000000..6cfd5660 Binary files /dev/null and b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.eot differ diff --git a/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.svg b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.svg new file mode 100755 index 00000000..a9f84695 --- /dev/null +++ b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,504 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.ttf b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.ttf new file mode 100755 index 00000000..5cd6cff6 Binary files /dev/null and b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.ttf differ diff --git a/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.woff b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.woff new file mode 100755 index 00000000..9eaecb37 Binary files /dev/null and b/scratch-parent/css/font-awesome/fonts/fontawesome-webfont.woff differ diff --git a/scratch-parent/css/font-awesome/less/bordered-pulled.less b/scratch-parent/css/font-awesome/less/bordered-pulled.less new file mode 100644 index 00000000..0c90eb56 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/bordered-pulled.less @@ -0,0 +1,16 @@ +// Bordered & Pulled +// ------------------------- + +.@{fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em @fa-border-color; + border-radius: .1em; +} + +.pull-right { float: right; } +.pull-left { float: left; } + +.@{fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/scratch-parent/css/font-awesome/less/core.less b/scratch-parent/css/font-awesome/less/core.less new file mode 100644 index 00000000..6d223bc2 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/core.less @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.@{fa-css-prefix} { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/scratch-parent/css/font-awesome/less/fixed-width.less b/scratch-parent/css/font-awesome/less/fixed-width.less new file mode 100644 index 00000000..110289f2 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/fixed-width.less @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.@{fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/scratch-parent/css/font-awesome/less/font-awesome.less b/scratch-parent/css/font-awesome/less/font-awesome.less new file mode 100644 index 00000000..50cbcac4 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/font-awesome.less @@ -0,0 +1,17 @@ +/*! + * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables.less"; +@import "mixins.less"; +@import "path.less"; +@import "core.less"; +@import "larger.less"; +@import "fixed-width.less"; +@import "list.less"; +@import "bordered-pulled.less"; +@import "spinning.less"; +@import "rotated-flipped.less"; +@import "stacked.less"; +@import "icons.less"; diff --git a/scratch-parent/css/font-awesome/less/icons.less b/scratch-parent/css/font-awesome/less/icons.less new file mode 100644 index 00000000..13d8c685 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/icons.less @@ -0,0 +1,506 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.@{fa-css-prefix}-glass:before { content: @fa-var-glass; } +.@{fa-css-prefix}-music:before { content: @fa-var-music; } +.@{fa-css-prefix}-search:before { content: @fa-var-search; } +.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; } +.@{fa-css-prefix}-heart:before { content: @fa-var-heart; } +.@{fa-css-prefix}-star:before { content: @fa-var-star; } +.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; } +.@{fa-css-prefix}-user:before { content: @fa-var-user; } +.@{fa-css-prefix}-film:before { content: @fa-var-film; } +.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; } +.@{fa-css-prefix}-th:before { content: @fa-var-th; } +.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; } +.@{fa-css-prefix}-check:before { content: @fa-var-check; } +.@{fa-css-prefix}-times:before { content: @fa-var-times; } +.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; } +.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; } +.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; } +.@{fa-css-prefix}-signal:before { content: @fa-var-signal; } +.@{fa-css-prefix}-gear:before, +.@{fa-css-prefix}-cog:before { content: @fa-var-cog; } +.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; } +.@{fa-css-prefix}-home:before { content: @fa-var-home; } +.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; } +.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; } +.@{fa-css-prefix}-road:before { content: @fa-var-road; } +.@{fa-css-prefix}-download:before { content: @fa-var-download; } +.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; } +.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; } +.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; } +.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; } +.@{fa-css-prefix}-rotate-right:before, +.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; } +.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; } +.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; } +.@{fa-css-prefix}-lock:before { content: @fa-var-lock; } +.@{fa-css-prefix}-flag:before { content: @fa-var-flag; } +.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; } +.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; } +.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; } +.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; } +.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; } +.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; } +.@{fa-css-prefix}-tag:before { content: @fa-var-tag; } +.@{fa-css-prefix}-tags:before { content: @fa-var-tags; } +.@{fa-css-prefix}-book:before { content: @fa-var-book; } +.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; } +.@{fa-css-prefix}-print:before { content: @fa-var-print; } +.@{fa-css-prefix}-camera:before { content: @fa-var-camera; } +.@{fa-css-prefix}-font:before { content: @fa-var-font; } +.@{fa-css-prefix}-bold:before { content: @fa-var-bold; } +.@{fa-css-prefix}-italic:before { content: @fa-var-italic; } +.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; } +.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; } +.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; } +.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; } +.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; } +.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; } +.@{fa-css-prefix}-list:before { content: @fa-var-list; } +.@{fa-css-prefix}-dedent:before, +.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; } +.@{fa-css-prefix}-indent:before { content: @fa-var-indent; } +.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; } +.@{fa-css-prefix}-photo:before, +.@{fa-css-prefix}-image:before, +.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; } +.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; } +.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; } +.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; } +.@{fa-css-prefix}-tint:before { content: @fa-var-tint; } +.@{fa-css-prefix}-edit:before, +.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; } +.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; } +.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; } +.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; } +.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; } +.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; } +.@{fa-css-prefix}-backward:before { content: @fa-var-backward; } +.@{fa-css-prefix}-play:before { content: @fa-var-play; } +.@{fa-css-prefix}-pause:before { content: @fa-var-pause; } +.@{fa-css-prefix}-stop:before { content: @fa-var-stop; } +.@{fa-css-prefix}-forward:before { content: @fa-var-forward; } +.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; } +.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; } +.@{fa-css-prefix}-eject:before { content: @fa-var-eject; } +.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; } +.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; } +.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; } +.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; } +.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; } +.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; } +.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; } +.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; } +.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; } +.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; } +.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; } +.@{fa-css-prefix}-ban:before { content: @fa-var-ban; } +.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; } +.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; } +.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; } +.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; } +.@{fa-css-prefix}-mail-forward:before, +.@{fa-css-prefix}-share:before { content: @fa-var-share; } +.@{fa-css-prefix}-expand:before { content: @fa-var-expand; } +.@{fa-css-prefix}-compress:before { content: @fa-var-compress; } +.@{fa-css-prefix}-plus:before { content: @fa-var-plus; } +.@{fa-css-prefix}-minus:before { content: @fa-var-minus; } +.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; } +.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; } +.@{fa-css-prefix}-gift:before { content: @fa-var-gift; } +.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; } +.@{fa-css-prefix}-fire:before { content: @fa-var-fire; } +.@{fa-css-prefix}-eye:before { content: @fa-var-eye; } +.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; } +.@{fa-css-prefix}-warning:before, +.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; } +.@{fa-css-prefix}-plane:before { content: @fa-var-plane; } +.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; } +.@{fa-css-prefix}-random:before { content: @fa-var-random; } +.@{fa-css-prefix}-comment:before { content: @fa-var-comment; } +.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; } +.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; } +.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; } +.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; } +.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; } +.@{fa-css-prefix}-folder:before { content: @fa-var-folder; } +.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; } +.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; } +.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; } +.@{fa-css-prefix}-bar-chart-o:before { content: @fa-var-bar-chart-o; } +.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; } +.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; } +.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; } +.@{fa-css-prefix}-key:before { content: @fa-var-key; } +.@{fa-css-prefix}-gears:before, +.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; } +.@{fa-css-prefix}-comments:before { content: @fa-var-comments; } +.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; } +.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; } +.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; } +.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; } +.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; } +.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; } +.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; } +.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; } +.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; } +.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; } +.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; } +.@{fa-css-prefix}-upload:before { content: @fa-var-upload; } +.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; } +.@{fa-css-prefix}-phone:before { content: @fa-var-phone; } +.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; } +.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; } +.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; } +.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; } +.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; } +.@{fa-css-prefix}-github:before { content: @fa-var-github; } +.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } +.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-rss:before { content: @fa-var-rss; } +.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; } +.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } +.@{fa-css-prefix}-bell:before { content: @fa-var-bell; } +.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; } +.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; } +.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; } +.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; } +.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; } +.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; } +.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; } +.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; } +.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; } +.@{fa-css-prefix}-globe:before { content: @fa-var-globe; } +.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; } +.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; } +.@{fa-css-prefix}-filter:before { content: @fa-var-filter; } +.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; } +.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; } +.@{fa-css-prefix}-group:before, +.@{fa-css-prefix}-users:before { content: @fa-var-users; } +.@{fa-css-prefix}-chain:before, +.@{fa-css-prefix}-link:before { content: @fa-var-link; } +.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; } +.@{fa-css-prefix}-flask:before { content: @fa-var-flask; } +.@{fa-css-prefix}-cut:before, +.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; } +.@{fa-css-prefix}-copy:before, +.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; } +.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; } +.@{fa-css-prefix}-save:before, +.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; } +.@{fa-css-prefix}-square:before { content: @fa-var-square; } +.@{fa-css-prefix}-navicon:before, +.@{fa-css-prefix}-reorder:before, +.@{fa-css-prefix}-bars:before { content: @fa-var-bars; } +.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; } +.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; } +.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; } +.@{fa-css-prefix}-underline:before { content: @fa-var-underline; } +.@{fa-css-prefix}-table:before { content: @fa-var-table; } +.@{fa-css-prefix}-magic:before { content: @fa-var-magic; } +.@{fa-css-prefix}-truck:before { content: @fa-var-truck; } +.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; } +.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; } +.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; } +.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; } +.@{fa-css-prefix}-money:before { content: @fa-var-money; } +.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; } +.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; } +.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; } +.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; } +.@{fa-css-prefix}-columns:before { content: @fa-var-columns; } +.@{fa-css-prefix}-unsorted:before, +.@{fa-css-prefix}-sort:before { content: @fa-var-sort; } +.@{fa-css-prefix}-sort-down:before, +.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; } +.@{fa-css-prefix}-sort-up:before, +.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; } +.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; } +.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; } +.@{fa-css-prefix}-rotate-left:before, +.@{fa-css-prefix}-undo:before { content: @fa-var-undo; } +.@{fa-css-prefix}-legal:before, +.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; } +.@{fa-css-prefix}-dashboard:before, +.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; } +.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; } +.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; } +.@{fa-css-prefix}-flash:before, +.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; } +.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; } +.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; } +.@{fa-css-prefix}-paste:before, +.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; } +.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; } +.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; } +.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; } +.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; } +.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; } +.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; } +.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; } +.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; } +.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; } +.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; } +.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; } +.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; } +.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; } +.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; } +.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; } +.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; } +.@{fa-css-prefix}-beer:before { content: @fa-var-beer; } +.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; } +.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; } +.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; } +.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; } +.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; } +.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; } +.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; } +.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; } +.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; } +.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; } +.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; } +.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; } +.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; } +.@{fa-css-prefix}-mobile-phone:before, +.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; } +.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; } +.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; } +.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; } +.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; } +.@{fa-css-prefix}-circle:before { content: @fa-var-circle; } +.@{fa-css-prefix}-mail-reply:before, +.@{fa-css-prefix}-reply:before { content: @fa-var-reply; } +.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; } +.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; } +.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; } +.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; } +.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; } +.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; } +.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; } +.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; } +.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; } +.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; } +.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; } +.@{fa-css-prefix}-code:before { content: @fa-var-code; } +.@{fa-css-prefix}-mail-reply-all:before, +.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; } +.@{fa-css-prefix}-star-half-empty:before, +.@{fa-css-prefix}-star-half-full:before, +.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; } +.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; } +.@{fa-css-prefix}-crop:before { content: @fa-var-crop; } +.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; } +.@{fa-css-prefix}-unlink:before, +.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; } +.@{fa-css-prefix}-question:before { content: @fa-var-question; } +.@{fa-css-prefix}-info:before { content: @fa-var-info; } +.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; } +.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; } +.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; } +.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; } +.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; } +.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; } +.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; } +.@{fa-css-prefix}-shield:before { content: @fa-var-shield; } +.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; } +.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; } +.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; } +.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; } +.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; } +.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; } +.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; } +.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; } +.@{fa-css-prefix}-html5:before { content: @fa-var-html5; } +.@{fa-css-prefix}-css3:before { content: @fa-var-css3; } +.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; } +.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; } +.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; } +.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; } +.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; } +.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; } +.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; } +.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; } +.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; } +.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; } +.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; } +.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; } +.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; } +.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; } +.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; } +.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; } +.@{fa-css-prefix}-compass:before { content: @fa-var-compass; } +.@{fa-css-prefix}-toggle-down:before, +.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; } +.@{fa-css-prefix}-toggle-up:before, +.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; } +.@{fa-css-prefix}-toggle-right:before, +.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; } +.@{fa-css-prefix}-euro:before, +.@{fa-css-prefix}-eur:before { content: @fa-var-eur; } +.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; } +.@{fa-css-prefix}-dollar:before, +.@{fa-css-prefix}-usd:before { content: @fa-var-usd; } +.@{fa-css-prefix}-rupee:before, +.@{fa-css-prefix}-inr:before { content: @fa-var-inr; } +.@{fa-css-prefix}-cny:before, +.@{fa-css-prefix}-rmb:before, +.@{fa-css-prefix}-yen:before, +.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; } +.@{fa-css-prefix}-ruble:before, +.@{fa-css-prefix}-rouble:before, +.@{fa-css-prefix}-rub:before { content: @fa-var-rub; } +.@{fa-css-prefix}-won:before, +.@{fa-css-prefix}-krw:before { content: @fa-var-krw; } +.@{fa-css-prefix}-bitcoin:before, +.@{fa-css-prefix}-btc:before { content: @fa-var-btc; } +.@{fa-css-prefix}-file:before { content: @fa-var-file; } +.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; } +.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; } +.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; } +.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; } +.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; } +.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; } +.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; } +.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; } +.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; } +.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; } +.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; } +.@{fa-css-prefix}-xing:before { content: @fa-var-xing; } +.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; } +.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; } +.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; } +.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; } +.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; } +.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; } +.@{fa-css-prefix}-adn:before { content: @fa-var-adn; } +.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; } +.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; } +.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; } +.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; } +.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; } +.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; } +.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; } +.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; } +.@{fa-css-prefix}-apple:before { content: @fa-var-apple; } +.@{fa-css-prefix}-windows:before { content: @fa-var-windows; } +.@{fa-css-prefix}-android:before { content: @fa-var-android; } +.@{fa-css-prefix}-linux:before { content: @fa-var-linux; } +.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; } +.@{fa-css-prefix}-skype:before { content: @fa-var-skype; } +.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; } +.@{fa-css-prefix}-trello:before { content: @fa-var-trello; } +.@{fa-css-prefix}-female:before { content: @fa-var-female; } +.@{fa-css-prefix}-male:before { content: @fa-var-male; } +.@{fa-css-prefix}-gittip:before { content: @fa-var-gittip; } +.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; } +.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; } +.@{fa-css-prefix}-archive:before { content: @fa-var-archive; } +.@{fa-css-prefix}-bug:before { content: @fa-var-bug; } +.@{fa-css-prefix}-vk:before { content: @fa-var-vk; } +.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; } +.@{fa-css-prefix}-renren:before { content: @fa-var-renren; } +.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; } +.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; } +.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; } +.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; } +.@{fa-css-prefix}-toggle-left:before, +.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; } +.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; } +.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; } +.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; } +.@{fa-css-prefix}-turkish-lira:before, +.@{fa-css-prefix}-try:before { content: @fa-var-try; } +.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; } +.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; } +.@{fa-css-prefix}-slack:before { content: @fa-var-slack; } +.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; } +.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; } +.@{fa-css-prefix}-openid:before { content: @fa-var-openid; } +.@{fa-css-prefix}-institution:before, +.@{fa-css-prefix}-bank:before, +.@{fa-css-prefix}-university:before { content: @fa-var-university; } +.@{fa-css-prefix}-mortar-board:before, +.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; } +.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; } +.@{fa-css-prefix}-google:before { content: @fa-var-google; } +.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; } +.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; } +.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; } +.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; } +.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; } +.@{fa-css-prefix}-digg:before { content: @fa-var-digg; } +.@{fa-css-prefix}-pied-piper-square:before, +.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; } +.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; } +.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; } +.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; } +.@{fa-css-prefix}-language:before { content: @fa-var-language; } +.@{fa-css-prefix}-fax:before { content: @fa-var-fax; } +.@{fa-css-prefix}-building:before { content: @fa-var-building; } +.@{fa-css-prefix}-child:before { content: @fa-var-child; } +.@{fa-css-prefix}-paw:before { content: @fa-var-paw; } +.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; } +.@{fa-css-prefix}-cube:before { content: @fa-var-cube; } +.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; } +.@{fa-css-prefix}-behance:before { content: @fa-var-behance; } +.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; } +.@{fa-css-prefix}-steam:before { content: @fa-var-steam; } +.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; } +.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; } +.@{fa-css-prefix}-automobile:before, +.@{fa-css-prefix}-car:before { content: @fa-var-car; } +.@{fa-css-prefix}-cab:before, +.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; } +.@{fa-css-prefix}-tree:before { content: @fa-var-tree; } +.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; } +.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; } +.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; } +.@{fa-css-prefix}-database:before { content: @fa-var-database; } +.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; } +.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; } +.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; } +.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; } +.@{fa-css-prefix}-file-photo-o:before, +.@{fa-css-prefix}-file-picture-o:before, +.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; } +.@{fa-css-prefix}-file-zip-o:before, +.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; } +.@{fa-css-prefix}-file-sound-o:before, +.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; } +.@{fa-css-prefix}-file-movie-o:before, +.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; } +.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; } +.@{fa-css-prefix}-vine:before { content: @fa-var-vine; } +.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; } +.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; } +.@{fa-css-prefix}-life-bouy:before, +.@{fa-css-prefix}-life-saver:before, +.@{fa-css-prefix}-support:before, +.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; } +.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; } +.@{fa-css-prefix}-ra:before, +.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; } +.@{fa-css-prefix}-ge:before, +.@{fa-css-prefix}-empire:before { content: @fa-var-empire; } +.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; } +.@{fa-css-prefix}-git:before { content: @fa-var-git; } +.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; } +.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; } +.@{fa-css-prefix}-qq:before { content: @fa-var-qq; } +.@{fa-css-prefix}-wechat:before, +.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; } +.@{fa-css-prefix}-send:before, +.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; } +.@{fa-css-prefix}-send-o:before, +.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; } +.@{fa-css-prefix}-history:before { content: @fa-var-history; } +.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; } +.@{fa-css-prefix}-header:before { content: @fa-var-header; } +.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; } +.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; } +.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; } +.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; } +.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; } diff --git a/scratch-parent/css/font-awesome/less/larger.less b/scratch-parent/css/font-awesome/less/larger.less new file mode 100644 index 00000000..c9d64677 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/larger.less @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.@{fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.@{fa-css-prefix}-2x { font-size: 2em; } +.@{fa-css-prefix}-3x { font-size: 3em; } +.@{fa-css-prefix}-4x { font-size: 4em; } +.@{fa-css-prefix}-5x { font-size: 5em; } diff --git a/scratch-parent/css/font-awesome/less/list.less b/scratch-parent/css/font-awesome/less/list.less new file mode 100644 index 00000000..eed93405 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/list.less @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.@{fa-css-prefix}-ul { + padding-left: 0; + margin-left: @fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.@{fa-css-prefix}-li { + position: absolute; + left: -@fa-li-width; + width: @fa-li-width; + top: (2em / 14); + text-align: center; + &.@{fa-css-prefix}-lg { + left: -@fa-li-width + (4em / 14); + } +} diff --git a/scratch-parent/css/font-awesome/less/mixins.less b/scratch-parent/css/font-awesome/less/mixins.less new file mode 100644 index 00000000..19e5a645 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/mixins.less @@ -0,0 +1,20 @@ +// Mixins +// -------------------------- + +.fa-icon-rotate(@degrees, @rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} + +.fa-icon-flip(@horiz, @vert, @rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); + -webkit-transform: scale(@horiz, @vert); + -moz-transform: scale(@horiz, @vert); + -ms-transform: scale(@horiz, @vert); + -o-transform: scale(@horiz, @vert); + transform: scale(@horiz, @vert); +} diff --git a/scratch-parent/css/font-awesome/less/path.less b/scratch-parent/css/font-awesome/less/path.less new file mode 100644 index 00000000..d73bff8b --- /dev/null +++ b/scratch-parent/css/font-awesome/less/path.less @@ -0,0 +1,14 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: ~"url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}')"; + src: ~"url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype')", + ~"url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff')", + ~"url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype')", + ~"url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg')"; +// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/scratch-parent/css/font-awesome/less/rotated-flipped.less b/scratch-parent/css/font-awesome/less/rotated-flipped.less new file mode 100644 index 00000000..8fff3a6c --- /dev/null +++ b/scratch-parent/css/font-awesome/less/rotated-flipped.less @@ -0,0 +1,9 @@ +// Rotated & Flipped Icons +// ------------------------- + +.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } +.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } +.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } + +.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } +.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } diff --git a/scratch-parent/css/font-awesome/less/spinning.less b/scratch-parent/css/font-awesome/less/spinning.less new file mode 100644 index 00000000..06b71ecb --- /dev/null +++ b/scratch-parent/css/font-awesome/less/spinning.less @@ -0,0 +1,32 @@ +// Spinning Icons +// -------------------------- + +.@{fa-css-prefix}-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} diff --git a/scratch-parent/css/font-awesome/less/stacked.less b/scratch-parent/css/font-awesome/less/stacked.less new file mode 100644 index 00000000..fc53fb0e --- /dev/null +++ b/scratch-parent/css/font-awesome/less/stacked.less @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.@{fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.@{fa-css-prefix}-stack-1x { line-height: inherit; } +.@{fa-css-prefix}-stack-2x { font-size: 2em; } +.@{fa-css-prefix}-inverse { color: @fa-inverse; } diff --git a/scratch-parent/css/font-awesome/less/variables.less b/scratch-parent/css/font-awesome/less/variables.less new file mode 100644 index 00000000..d7e8bd72 --- /dev/null +++ b/scratch-parent/css/font-awesome/less/variables.less @@ -0,0 +1,515 @@ +// Variables +// -------------------------- + +@fa-font-path: "../fonts"; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.1.0/fonts"; // for referencing Bootstrap CDN font files directly +@fa-css-prefix: fa; +@fa-version: "4.1.0"; +@fa-border-color: #eee; +@fa-inverse: #fff; +@fa-li-width: (30em / 14); + +@fa-var-adjust: "\f042"; +@fa-var-adn: "\f170"; +@fa-var-align-center: "\f037"; +@fa-var-align-justify: "\f039"; +@fa-var-align-left: "\f036"; +@fa-var-align-right: "\f038"; +@fa-var-ambulance: "\f0f9"; +@fa-var-anchor: "\f13d"; +@fa-var-android: "\f17b"; +@fa-var-angle-double-down: "\f103"; +@fa-var-angle-double-left: "\f100"; +@fa-var-angle-double-right: "\f101"; +@fa-var-angle-double-up: "\f102"; +@fa-var-angle-down: "\f107"; +@fa-var-angle-left: "\f104"; +@fa-var-angle-right: "\f105"; +@fa-var-angle-up: "\f106"; +@fa-var-apple: "\f179"; +@fa-var-archive: "\f187"; +@fa-var-arrow-circle-down: "\f0ab"; +@fa-var-arrow-circle-left: "\f0a8"; +@fa-var-arrow-circle-o-down: "\f01a"; +@fa-var-arrow-circle-o-left: "\f190"; +@fa-var-arrow-circle-o-right: "\f18e"; +@fa-var-arrow-circle-o-up: "\f01b"; +@fa-var-arrow-circle-right: "\f0a9"; +@fa-var-arrow-circle-up: "\f0aa"; +@fa-var-arrow-down: "\f063"; +@fa-var-arrow-left: "\f060"; +@fa-var-arrow-right: "\f061"; +@fa-var-arrow-up: "\f062"; +@fa-var-arrows: "\f047"; +@fa-var-arrows-alt: "\f0b2"; +@fa-var-arrows-h: "\f07e"; +@fa-var-arrows-v: "\f07d"; +@fa-var-asterisk: "\f069"; +@fa-var-automobile: "\f1b9"; +@fa-var-backward: "\f04a"; +@fa-var-ban: "\f05e"; +@fa-var-bank: "\f19c"; +@fa-var-bar-chart-o: "\f080"; +@fa-var-barcode: "\f02a"; +@fa-var-bars: "\f0c9"; +@fa-var-beer: "\f0fc"; +@fa-var-behance: "\f1b4"; +@fa-var-behance-square: "\f1b5"; +@fa-var-bell: "\f0f3"; +@fa-var-bell-o: "\f0a2"; +@fa-var-bitbucket: "\f171"; +@fa-var-bitbucket-square: "\f172"; +@fa-var-bitcoin: "\f15a"; +@fa-var-bold: "\f032"; +@fa-var-bolt: "\f0e7"; +@fa-var-bomb: "\f1e2"; +@fa-var-book: "\f02d"; +@fa-var-bookmark: "\f02e"; +@fa-var-bookmark-o: "\f097"; +@fa-var-briefcase: "\f0b1"; +@fa-var-btc: "\f15a"; +@fa-var-bug: "\f188"; +@fa-var-building: "\f1ad"; +@fa-var-building-o: "\f0f7"; +@fa-var-bullhorn: "\f0a1"; +@fa-var-bullseye: "\f140"; +@fa-var-cab: "\f1ba"; +@fa-var-calendar: "\f073"; +@fa-var-calendar-o: "\f133"; +@fa-var-camera: "\f030"; +@fa-var-camera-retro: "\f083"; +@fa-var-car: "\f1b9"; +@fa-var-caret-down: "\f0d7"; +@fa-var-caret-left: "\f0d9"; +@fa-var-caret-right: "\f0da"; +@fa-var-caret-square-o-down: "\f150"; +@fa-var-caret-square-o-left: "\f191"; +@fa-var-caret-square-o-right: "\f152"; +@fa-var-caret-square-o-up: "\f151"; +@fa-var-caret-up: "\f0d8"; +@fa-var-certificate: "\f0a3"; +@fa-var-chain: "\f0c1"; +@fa-var-chain-broken: "\f127"; +@fa-var-check: "\f00c"; +@fa-var-check-circle: "\f058"; +@fa-var-check-circle-o: "\f05d"; +@fa-var-check-square: "\f14a"; +@fa-var-check-square-o: "\f046"; +@fa-var-chevron-circle-down: "\f13a"; +@fa-var-chevron-circle-left: "\f137"; +@fa-var-chevron-circle-right: "\f138"; +@fa-var-chevron-circle-up: "\f139"; +@fa-var-chevron-down: "\f078"; +@fa-var-chevron-left: "\f053"; +@fa-var-chevron-right: "\f054"; +@fa-var-chevron-up: "\f077"; +@fa-var-child: "\f1ae"; +@fa-var-circle: "\f111"; +@fa-var-circle-o: "\f10c"; +@fa-var-circle-o-notch: "\f1ce"; +@fa-var-circle-thin: "\f1db"; +@fa-var-clipboard: "\f0ea"; +@fa-var-clock-o: "\f017"; +@fa-var-cloud: "\f0c2"; +@fa-var-cloud-download: "\f0ed"; +@fa-var-cloud-upload: "\f0ee"; +@fa-var-cny: "\f157"; +@fa-var-code: "\f121"; +@fa-var-code-fork: "\f126"; +@fa-var-codepen: "\f1cb"; +@fa-var-coffee: "\f0f4"; +@fa-var-cog: "\f013"; +@fa-var-cogs: "\f085"; +@fa-var-columns: "\f0db"; +@fa-var-comment: "\f075"; +@fa-var-comment-o: "\f0e5"; +@fa-var-comments: "\f086"; +@fa-var-comments-o: "\f0e6"; +@fa-var-compass: "\f14e"; +@fa-var-compress: "\f066"; +@fa-var-copy: "\f0c5"; +@fa-var-credit-card: "\f09d"; +@fa-var-crop: "\f125"; +@fa-var-crosshairs: "\f05b"; +@fa-var-css3: "\f13c"; +@fa-var-cube: "\f1b2"; +@fa-var-cubes: "\f1b3"; +@fa-var-cut: "\f0c4"; +@fa-var-cutlery: "\f0f5"; +@fa-var-dashboard: "\f0e4"; +@fa-var-database: "\f1c0"; +@fa-var-dedent: "\f03b"; +@fa-var-delicious: "\f1a5"; +@fa-var-desktop: "\f108"; +@fa-var-deviantart: "\f1bd"; +@fa-var-digg: "\f1a6"; +@fa-var-dollar: "\f155"; +@fa-var-dot-circle-o: "\f192"; +@fa-var-download: "\f019"; +@fa-var-dribbble: "\f17d"; +@fa-var-dropbox: "\f16b"; +@fa-var-drupal: "\f1a9"; +@fa-var-edit: "\f044"; +@fa-var-eject: "\f052"; +@fa-var-ellipsis-h: "\f141"; +@fa-var-ellipsis-v: "\f142"; +@fa-var-empire: "\f1d1"; +@fa-var-envelope: "\f0e0"; +@fa-var-envelope-o: "\f003"; +@fa-var-envelope-square: "\f199"; +@fa-var-eraser: "\f12d"; +@fa-var-eur: "\f153"; +@fa-var-euro: "\f153"; +@fa-var-exchange: "\f0ec"; +@fa-var-exclamation: "\f12a"; +@fa-var-exclamation-circle: "\f06a"; +@fa-var-exclamation-triangle: "\f071"; +@fa-var-expand: "\f065"; +@fa-var-external-link: "\f08e"; +@fa-var-external-link-square: "\f14c"; +@fa-var-eye: "\f06e"; +@fa-var-eye-slash: "\f070"; +@fa-var-facebook: "\f09a"; +@fa-var-facebook-square: "\f082"; +@fa-var-fast-backward: "\f049"; +@fa-var-fast-forward: "\f050"; +@fa-var-fax: "\f1ac"; +@fa-var-female: "\f182"; +@fa-var-fighter-jet: "\f0fb"; +@fa-var-file: "\f15b"; +@fa-var-file-archive-o: "\f1c6"; +@fa-var-file-audio-o: "\f1c7"; +@fa-var-file-code-o: "\f1c9"; +@fa-var-file-excel-o: "\f1c3"; +@fa-var-file-image-o: "\f1c5"; +@fa-var-file-movie-o: "\f1c8"; +@fa-var-file-o: "\f016"; +@fa-var-file-pdf-o: "\f1c1"; +@fa-var-file-photo-o: "\f1c5"; +@fa-var-file-picture-o: "\f1c5"; +@fa-var-file-powerpoint-o: "\f1c4"; +@fa-var-file-sound-o: "\f1c7"; +@fa-var-file-text: "\f15c"; +@fa-var-file-text-o: "\f0f6"; +@fa-var-file-video-o: "\f1c8"; +@fa-var-file-word-o: "\f1c2"; +@fa-var-file-zip-o: "\f1c6"; +@fa-var-files-o: "\f0c5"; +@fa-var-film: "\f008"; +@fa-var-filter: "\f0b0"; +@fa-var-fire: "\f06d"; +@fa-var-fire-extinguisher: "\f134"; +@fa-var-flag: "\f024"; +@fa-var-flag-checkered: "\f11e"; +@fa-var-flag-o: "\f11d"; +@fa-var-flash: "\f0e7"; +@fa-var-flask: "\f0c3"; +@fa-var-flickr: "\f16e"; +@fa-var-floppy-o: "\f0c7"; +@fa-var-folder: "\f07b"; +@fa-var-folder-o: "\f114"; +@fa-var-folder-open: "\f07c"; +@fa-var-folder-open-o: "\f115"; +@fa-var-font: "\f031"; +@fa-var-forward: "\f04e"; +@fa-var-foursquare: "\f180"; +@fa-var-frown-o: "\f119"; +@fa-var-gamepad: "\f11b"; +@fa-var-gavel: "\f0e3"; +@fa-var-gbp: "\f154"; +@fa-var-ge: "\f1d1"; +@fa-var-gear: "\f013"; +@fa-var-gears: "\f085"; +@fa-var-gift: "\f06b"; +@fa-var-git: "\f1d3"; +@fa-var-git-square: "\f1d2"; +@fa-var-github: "\f09b"; +@fa-var-github-alt: "\f113"; +@fa-var-github-square: "\f092"; +@fa-var-gittip: "\f184"; +@fa-var-glass: "\f000"; +@fa-var-globe: "\f0ac"; +@fa-var-google: "\f1a0"; +@fa-var-google-plus: "\f0d5"; +@fa-var-google-plus-square: "\f0d4"; +@fa-var-graduation-cap: "\f19d"; +@fa-var-group: "\f0c0"; +@fa-var-h-square: "\f0fd"; +@fa-var-hacker-news: "\f1d4"; +@fa-var-hand-o-down: "\f0a7"; +@fa-var-hand-o-left: "\f0a5"; +@fa-var-hand-o-right: "\f0a4"; +@fa-var-hand-o-up: "\f0a6"; +@fa-var-hdd-o: "\f0a0"; +@fa-var-header: "\f1dc"; +@fa-var-headphones: "\f025"; +@fa-var-heart: "\f004"; +@fa-var-heart-o: "\f08a"; +@fa-var-history: "\f1da"; +@fa-var-home: "\f015"; +@fa-var-hospital-o: "\f0f8"; +@fa-var-html5: "\f13b"; +@fa-var-image: "\f03e"; +@fa-var-inbox: "\f01c"; +@fa-var-indent: "\f03c"; +@fa-var-info: "\f129"; +@fa-var-info-circle: "\f05a"; +@fa-var-inr: "\f156"; +@fa-var-instagram: "\f16d"; +@fa-var-institution: "\f19c"; +@fa-var-italic: "\f033"; +@fa-var-joomla: "\f1aa"; +@fa-var-jpy: "\f157"; +@fa-var-jsfiddle: "\f1cc"; +@fa-var-key: "\f084"; +@fa-var-keyboard-o: "\f11c"; +@fa-var-krw: "\f159"; +@fa-var-language: "\f1ab"; +@fa-var-laptop: "\f109"; +@fa-var-leaf: "\f06c"; +@fa-var-legal: "\f0e3"; +@fa-var-lemon-o: "\f094"; +@fa-var-level-down: "\f149"; +@fa-var-level-up: "\f148"; +@fa-var-life-bouy: "\f1cd"; +@fa-var-life-ring: "\f1cd"; +@fa-var-life-saver: "\f1cd"; +@fa-var-lightbulb-o: "\f0eb"; +@fa-var-link: "\f0c1"; +@fa-var-linkedin: "\f0e1"; +@fa-var-linkedin-square: "\f08c"; +@fa-var-linux: "\f17c"; +@fa-var-list: "\f03a"; +@fa-var-list-alt: "\f022"; +@fa-var-list-ol: "\f0cb"; +@fa-var-list-ul: "\f0ca"; +@fa-var-location-arrow: "\f124"; +@fa-var-lock: "\f023"; +@fa-var-long-arrow-down: "\f175"; +@fa-var-long-arrow-left: "\f177"; +@fa-var-long-arrow-right: "\f178"; +@fa-var-long-arrow-up: "\f176"; +@fa-var-magic: "\f0d0"; +@fa-var-magnet: "\f076"; +@fa-var-mail-forward: "\f064"; +@fa-var-mail-reply: "\f112"; +@fa-var-mail-reply-all: "\f122"; +@fa-var-male: "\f183"; +@fa-var-map-marker: "\f041"; +@fa-var-maxcdn: "\f136"; +@fa-var-medkit: "\f0fa"; +@fa-var-meh-o: "\f11a"; +@fa-var-microphone: "\f130"; +@fa-var-microphone-slash: "\f131"; +@fa-var-minus: "\f068"; +@fa-var-minus-circle: "\f056"; +@fa-var-minus-square: "\f146"; +@fa-var-minus-square-o: "\f147"; +@fa-var-mobile: "\f10b"; +@fa-var-mobile-phone: "\f10b"; +@fa-var-money: "\f0d6"; +@fa-var-moon-o: "\f186"; +@fa-var-mortar-board: "\f19d"; +@fa-var-music: "\f001"; +@fa-var-navicon: "\f0c9"; +@fa-var-openid: "\f19b"; +@fa-var-outdent: "\f03b"; +@fa-var-pagelines: "\f18c"; +@fa-var-paper-plane: "\f1d8"; +@fa-var-paper-plane-o: "\f1d9"; +@fa-var-paperclip: "\f0c6"; +@fa-var-paragraph: "\f1dd"; +@fa-var-paste: "\f0ea"; +@fa-var-pause: "\f04c"; +@fa-var-paw: "\f1b0"; +@fa-var-pencil: "\f040"; +@fa-var-pencil-square: "\f14b"; +@fa-var-pencil-square-o: "\f044"; +@fa-var-phone: "\f095"; +@fa-var-phone-square: "\f098"; +@fa-var-photo: "\f03e"; +@fa-var-picture-o: "\f03e"; +@fa-var-pied-piper: "\f1a7"; +@fa-var-pied-piper-alt: "\f1a8"; +@fa-var-pied-piper-square: "\f1a7"; +@fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-square: "\f0d3"; +@fa-var-plane: "\f072"; +@fa-var-play: "\f04b"; +@fa-var-play-circle: "\f144"; +@fa-var-play-circle-o: "\f01d"; +@fa-var-plus: "\f067"; +@fa-var-plus-circle: "\f055"; +@fa-var-plus-square: "\f0fe"; +@fa-var-plus-square-o: "\f196"; +@fa-var-power-off: "\f011"; +@fa-var-print: "\f02f"; +@fa-var-puzzle-piece: "\f12e"; +@fa-var-qq: "\f1d6"; +@fa-var-qrcode: "\f029"; +@fa-var-question: "\f128"; +@fa-var-question-circle: "\f059"; +@fa-var-quote-left: "\f10d"; +@fa-var-quote-right: "\f10e"; +@fa-var-ra: "\f1d0"; +@fa-var-random: "\f074"; +@fa-var-rebel: "\f1d0"; +@fa-var-recycle: "\f1b8"; +@fa-var-reddit: "\f1a1"; +@fa-var-reddit-square: "\f1a2"; +@fa-var-refresh: "\f021"; +@fa-var-renren: "\f18b"; +@fa-var-reorder: "\f0c9"; +@fa-var-repeat: "\f01e"; +@fa-var-reply: "\f112"; +@fa-var-reply-all: "\f122"; +@fa-var-retweet: "\f079"; +@fa-var-rmb: "\f157"; +@fa-var-road: "\f018"; +@fa-var-rocket: "\f135"; +@fa-var-rotate-left: "\f0e2"; +@fa-var-rotate-right: "\f01e"; +@fa-var-rouble: "\f158"; +@fa-var-rss: "\f09e"; +@fa-var-rss-square: "\f143"; +@fa-var-rub: "\f158"; +@fa-var-ruble: "\f158"; +@fa-var-rupee: "\f156"; +@fa-var-save: "\f0c7"; +@fa-var-scissors: "\f0c4"; +@fa-var-search: "\f002"; +@fa-var-search-minus: "\f010"; +@fa-var-search-plus: "\f00e"; +@fa-var-send: "\f1d8"; +@fa-var-send-o: "\f1d9"; +@fa-var-share: "\f064"; +@fa-var-share-alt: "\f1e0"; +@fa-var-share-alt-square: "\f1e1"; +@fa-var-share-square: "\f14d"; +@fa-var-share-square-o: "\f045"; +@fa-var-shield: "\f132"; +@fa-var-shopping-cart: "\f07a"; +@fa-var-sign-in: "\f090"; +@fa-var-sign-out: "\f08b"; +@fa-var-signal: "\f012"; +@fa-var-sitemap: "\f0e8"; +@fa-var-skype: "\f17e"; +@fa-var-slack: "\f198"; +@fa-var-sliders: "\f1de"; +@fa-var-smile-o: "\f118"; +@fa-var-sort: "\f0dc"; +@fa-var-sort-alpha-asc: "\f15d"; +@fa-var-sort-alpha-desc: "\f15e"; +@fa-var-sort-amount-asc: "\f160"; +@fa-var-sort-amount-desc: "\f161"; +@fa-var-sort-asc: "\f0de"; +@fa-var-sort-desc: "\f0dd"; +@fa-var-sort-down: "\f0dd"; +@fa-var-sort-numeric-asc: "\f162"; +@fa-var-sort-numeric-desc: "\f163"; +@fa-var-sort-up: "\f0de"; +@fa-var-soundcloud: "\f1be"; +@fa-var-space-shuttle: "\f197"; +@fa-var-spinner: "\f110"; +@fa-var-spoon: "\f1b1"; +@fa-var-spotify: "\f1bc"; +@fa-var-square: "\f0c8"; +@fa-var-square-o: "\f096"; +@fa-var-stack-exchange: "\f18d"; +@fa-var-stack-overflow: "\f16c"; +@fa-var-star: "\f005"; +@fa-var-star-half: "\f089"; +@fa-var-star-half-empty: "\f123"; +@fa-var-star-half-full: "\f123"; +@fa-var-star-half-o: "\f123"; +@fa-var-star-o: "\f006"; +@fa-var-steam: "\f1b6"; +@fa-var-steam-square: "\f1b7"; +@fa-var-step-backward: "\f048"; +@fa-var-step-forward: "\f051"; +@fa-var-stethoscope: "\f0f1"; +@fa-var-stop: "\f04d"; +@fa-var-strikethrough: "\f0cc"; +@fa-var-stumbleupon: "\f1a4"; +@fa-var-stumbleupon-circle: "\f1a3"; +@fa-var-subscript: "\f12c"; +@fa-var-suitcase: "\f0f2"; +@fa-var-sun-o: "\f185"; +@fa-var-superscript: "\f12b"; +@fa-var-support: "\f1cd"; +@fa-var-table: "\f0ce"; +@fa-var-tablet: "\f10a"; +@fa-var-tachometer: "\f0e4"; +@fa-var-tag: "\f02b"; +@fa-var-tags: "\f02c"; +@fa-var-tasks: "\f0ae"; +@fa-var-taxi: "\f1ba"; +@fa-var-tencent-weibo: "\f1d5"; +@fa-var-terminal: "\f120"; +@fa-var-text-height: "\f034"; +@fa-var-text-width: "\f035"; +@fa-var-th: "\f00a"; +@fa-var-th-large: "\f009"; +@fa-var-th-list: "\f00b"; +@fa-var-thumb-tack: "\f08d"; +@fa-var-thumbs-down: "\f165"; +@fa-var-thumbs-o-down: "\f088"; +@fa-var-thumbs-o-up: "\f087"; +@fa-var-thumbs-up: "\f164"; +@fa-var-ticket: "\f145"; +@fa-var-times: "\f00d"; +@fa-var-times-circle: "\f057"; +@fa-var-times-circle-o: "\f05c"; +@fa-var-tint: "\f043"; +@fa-var-toggle-down: "\f150"; +@fa-var-toggle-left: "\f191"; +@fa-var-toggle-right: "\f152"; +@fa-var-toggle-up: "\f151"; +@fa-var-trash-o: "\f014"; +@fa-var-tree: "\f1bb"; +@fa-var-trello: "\f181"; +@fa-var-trophy: "\f091"; +@fa-var-truck: "\f0d1"; +@fa-var-try: "\f195"; +@fa-var-tumblr: "\f173"; +@fa-var-tumblr-square: "\f174"; +@fa-var-turkish-lira: "\f195"; +@fa-var-twitter: "\f099"; +@fa-var-twitter-square: "\f081"; +@fa-var-umbrella: "\f0e9"; +@fa-var-underline: "\f0cd"; +@fa-var-undo: "\f0e2"; +@fa-var-university: "\f19c"; +@fa-var-unlink: "\f127"; +@fa-var-unlock: "\f09c"; +@fa-var-unlock-alt: "\f13e"; +@fa-var-unsorted: "\f0dc"; +@fa-var-upload: "\f093"; +@fa-var-usd: "\f155"; +@fa-var-user: "\f007"; +@fa-var-user-md: "\f0f0"; +@fa-var-users: "\f0c0"; +@fa-var-video-camera: "\f03d"; +@fa-var-vimeo-square: "\f194"; +@fa-var-vine: "\f1ca"; +@fa-var-vk: "\f189"; +@fa-var-volume-down: "\f027"; +@fa-var-volume-off: "\f026"; +@fa-var-volume-up: "\f028"; +@fa-var-warning: "\f071"; +@fa-var-wechat: "\f1d7"; +@fa-var-weibo: "\f18a"; +@fa-var-weixin: "\f1d7"; +@fa-var-wheelchair: "\f193"; +@fa-var-windows: "\f17a"; +@fa-var-won: "\f159"; +@fa-var-wordpress: "\f19a"; +@fa-var-wrench: "\f0ad"; +@fa-var-xing: "\f168"; +@fa-var-xing-square: "\f169"; +@fa-var-yahoo: "\f19e"; +@fa-var-yen: "\f157"; +@fa-var-youtube: "\f167"; +@fa-var-youtube-play: "\f16a"; +@fa-var-youtube-square: "\f166"; + diff --git a/scratch-parent/css/font-awesome/scss/_bordered-pulled.scss b/scratch-parent/css/font-awesome/scss/_bordered-pulled.scss new file mode 100644 index 00000000..9d3fdf3a --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_bordered-pulled.scss @@ -0,0 +1,16 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em $fa-border-color; + border-radius: .1em; +} + +.pull-right { float: right; } +.pull-left { float: left; } + +.#{$fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/scratch-parent/css/font-awesome/scss/_core.scss b/scratch-parent/css/font-awesome/scss/_core.scss new file mode 100644 index 00000000..861ccd9d --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_core.scss @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix} { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/scratch-parent/css/font-awesome/scss/_fixed-width.scss b/scratch-parent/css/font-awesome/scss/_fixed-width.scss new file mode 100644 index 00000000..b221c981 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/scratch-parent/css/font-awesome/scss/_icons.scss b/scratch-parent/css/font-awesome/scss/_icons.scss new file mode 100644 index 00000000..efb44359 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_icons.scss @@ -0,0 +1,506 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } +.#{$fa-css-prefix}-music:before { content: $fa-var-music; } +.#{$fa-css-prefix}-search:before { content: $fa-var-search; } +.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } +.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } +.#{$fa-css-prefix}-star:before { content: $fa-var-star; } +.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } +.#{$fa-css-prefix}-user:before { content: $fa-var-user; } +.#{$fa-css-prefix}-film:before { content: $fa-var-film; } +.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } +.#{$fa-css-prefix}-th:before { content: $fa-var-th; } +.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } +.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-times:before { content: $fa-var-times; } +.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } +.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } +.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } +.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-gear:before, +.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } +.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } +.#{$fa-css-prefix}-home:before { content: $fa-var-home; } +.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } +.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } +.#{$fa-css-prefix}-road:before { content: $fa-var-road; } +.#{$fa-css-prefix}-download:before { content: $fa-var-download; } +.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } +.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } +.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } +.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-rotate-right:before, +.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } +.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } +.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } +.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } +.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } +.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } +.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } +.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } +.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } +.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } +.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } +.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } +.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } +.#{$fa-css-prefix}-book:before { content: $fa-var-book; } +.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } +.#{$fa-css-prefix}-print:before { content: $fa-var-print; } +.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } +.#{$fa-css-prefix}-font:before { content: $fa-var-font; } +.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } +.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } +.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } +.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } +.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } +.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } +.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } +.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } +.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-dedent:before, +.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } +.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } +.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-photo:before, +.#{$fa-css-prefix}-image:before, +.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } +.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } +.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } +.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } +.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-edit:before, +.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } +.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } +.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } +.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } +.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } +.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } +.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } +.#{$fa-css-prefix}-play:before { content: $fa-var-play; } +.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } +.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } +.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } +.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } +.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } +.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } +.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } +.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } +.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } +.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } +.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } +.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } +.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } +.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } +.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } +.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } +.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } +.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } +.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } +.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } +.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } +.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-mail-forward:before, +.#{$fa-css-prefix}-share:before { content: $fa-var-share; } +.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } +.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } +.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } +.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } +.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } +.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } +.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } +.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } +.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } +.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } +.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-warning:before, +.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } +.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } +.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } +.#{$fa-css-prefix}-random:before { content: $fa-var-random; } +.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } +.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } +.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } +.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } +.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } +.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } +.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } +.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } +.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } +.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-bar-chart-o:before { content: $fa-var-bar-chart-o; } +.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } +.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } +.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } +.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-gears:before, +.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } +.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } +.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } +.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } +.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } +.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } +.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } +.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } +.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } +.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } +.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } +.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } +.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } +.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } +.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } +.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } +.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } +.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } +.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } +.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } +.#{$fa-css-prefix}-github:before { content: $fa-var-github; } +.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } +.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } +.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } +.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } +.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } +.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } +.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } +.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } +.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } +.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } +.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } +.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } +.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } +.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } +.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } +.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } +.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } +.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } +.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } +.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-group:before, +.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-chain:before, +.#{$fa-css-prefix}-link:before { content: $fa-var-link; } +.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } +.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-cut:before, +.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-copy:before, +.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } +.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-save:before, +.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } +.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-navicon:before, +.#{$fa-css-prefix}-reorder:before, +.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } +.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } +.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } +.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } +.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } +.#{$fa-css-prefix}-table:before { content: $fa-var-table; } +.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } +.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } +.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } +.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } +.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } +.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } +.#{$fa-css-prefix}-money:before { content: $fa-var-money; } +.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } +.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } +.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } +.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } +.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-unsorted:before, +.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort-down:before, +.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-sort-up:before, +.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } +.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } +.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-rotate-left:before, +.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-legal:before, +.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-dashboard:before, +.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } +.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } +.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-flash:before, +.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } +.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } +.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-paste:before, +.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } +.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } +.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } +.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } +.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } +.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } +.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } +.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } +.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } +.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } +.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } +.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } +.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } +.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } +.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } +.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } +.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } +.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } +.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } +.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } +.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } +.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } +.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } +.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } +.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } +.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } +.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } +.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } +.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } +.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } +.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-mobile-phone:before, +.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } +.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } +.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } +.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } +.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } +.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mail-reply:before, +.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } +.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } +.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } +.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } +.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } +.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } +.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } +.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } +.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } +.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } +.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } +.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } +.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-mail-reply-all:before, +.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-star-half-empty:before, +.#{$fa-css-prefix}-star-half-full:before, +.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } +.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } +.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } +.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-unlink:before, +.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } +.#{$fa-css-prefix}-question:before { content: $fa-var-question; } +.#{$fa-css-prefix}-info:before { content: $fa-var-info; } +.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } +.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } +.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } +.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } +.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } +.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } +.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } +.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } +.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } +.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } +.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } +.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } +.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } +.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } +.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } +.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } +.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } +.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } +.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } +.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } +.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } +.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } +.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } +.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } +.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } +.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } +.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } +.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } +.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } +.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } +.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } +.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } +.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } +.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } +.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-toggle-down:before, +.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-toggle-up:before, +.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-toggle-right:before, +.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-euro:before, +.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } +.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-dollar:before, +.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-rupee:before, +.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-cny:before, +.#{$fa-css-prefix}-rmb:before, +.#{$fa-css-prefix}-yen:before, +.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-ruble:before, +.#{$fa-css-prefix}-rouble:before, +.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-won:before, +.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-bitcoin:before, +.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } +.#{$fa-css-prefix}-file:before { content: $fa-var-file; } +.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } +.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } +.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } +.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } +.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } +.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } +.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } +.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } +.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } +.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } +.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } +.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } +.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } +.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } +.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } +.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } +.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } +.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } +.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } +.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } +.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } +.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } +.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } +.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } +.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } +.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } +.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } +.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } +.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } +.#{$fa-css-prefix}-android:before { content: $fa-var-android; } +.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } +.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } +.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } +.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } +.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } +.#{$fa-css-prefix}-female:before { content: $fa-var-female; } +.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-gittip:before { content: $fa-var-gittip; } +.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } +.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } +.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } +.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } +.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } +.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } +.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } +.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } +.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } +.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } +.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-toggle-left:before, +.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } +.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } +.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } +.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-turkish-lira:before, +.#{$fa-css-prefix}-try:before { content: $fa-var-try; } +.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } +.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; } +.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; } +.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; } +.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; } +.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; } +.#{$fa-css-prefix}-institution:before, +.#{$fa-css-prefix}-bank:before, +.#{$fa-css-prefix}-university:before { content: $fa-var-university; } +.#{$fa-css-prefix}-mortar-board:before, +.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; } +.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; } +.#{$fa-css-prefix}-google:before { content: $fa-var-google; } +.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; } +.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; } +.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; } +.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; } +.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; } +.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; } +.#{$fa-css-prefix}-pied-piper-square:before, +.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } +.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; } +.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; } +.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; } +.#{$fa-css-prefix}-language:before { content: $fa-var-language; } +.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; } +.#{$fa-css-prefix}-building:before { content: $fa-var-building; } +.#{$fa-css-prefix}-child:before { content: $fa-var-child; } +.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; } +.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; } +.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; } +.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; } +.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; } +.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; } +.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; } +.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; } +.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; } +.#{$fa-css-prefix}-automobile:before, +.#{$fa-css-prefix}-car:before { content: $fa-var-car; } +.#{$fa-css-prefix}-cab:before, +.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; } +.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; } +.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; } +.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; } +.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; } +.#{$fa-css-prefix}-database:before { content: $fa-var-database; } +.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; } +.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; } +.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; } +.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; } +.#{$fa-css-prefix}-file-photo-o:before, +.#{$fa-css-prefix}-file-picture-o:before, +.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; } +.#{$fa-css-prefix}-file-zip-o:before, +.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; } +.#{$fa-css-prefix}-file-sound-o:before, +.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; } +.#{$fa-css-prefix}-file-movie-o:before, +.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; } +.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; } +.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; } +.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; } +.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; } +.#{$fa-css-prefix}-life-bouy:before, +.#{$fa-css-prefix}-life-saver:before, +.#{$fa-css-prefix}-support:before, +.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; } +.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; } +.#{$fa-css-prefix}-ra:before, +.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; } +.#{$fa-css-prefix}-ge:before, +.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } +.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } +.#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } +.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } +.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } +.#{$fa-css-prefix}-wechat:before, +.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; } +.#{$fa-css-prefix}-send:before, +.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; } +.#{$fa-css-prefix}-send-o:before, +.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; } +.#{$fa-css-prefix}-history:before { content: $fa-var-history; } +.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; } +.#{$fa-css-prefix}-header:before { content: $fa-var-header; } +.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; } +.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; } +.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; } +.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; } +.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; } diff --git a/scratch-parent/css/font-awesome/scss/_larger.scss b/scratch-parent/css/font-awesome/scss/_larger.scss new file mode 100644 index 00000000..41e9a818 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_larger.scss @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.#{$fa-css-prefix}-2x { font-size: 2em; } +.#{$fa-css-prefix}-3x { font-size: 3em; } +.#{$fa-css-prefix}-4x { font-size: 4em; } +.#{$fa-css-prefix}-5x { font-size: 5em; } diff --git a/scratch-parent/css/font-awesome/scss/_list.scss b/scratch-parent/css/font-awesome/scss/_list.scss new file mode 100644 index 00000000..7d1e4d54 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_list.scss @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + padding-left: 0; + margin-left: $fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.#{$fa-css-prefix}-li { + position: absolute; + left: -$fa-li-width; + width: $fa-li-width; + top: (2em / 14); + text-align: center; + &.#{$fa-css-prefix}-lg { + left: -$fa-li-width + (4em / 14); + } +} diff --git a/scratch-parent/css/font-awesome/scss/_mixins.scss b/scratch-parent/css/font-awesome/scss/_mixins.scss new file mode 100644 index 00000000..3354e695 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_mixins.scss @@ -0,0 +1,20 @@ +// Mixins +// -------------------------- + +@mixin fa-icon-rotate($degrees, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); + -webkit-transform: rotate($degrees); + -moz-transform: rotate($degrees); + -ms-transform: rotate($degrees); + -o-transform: rotate($degrees); + transform: rotate($degrees); +} + +@mixin fa-icon-flip($horiz, $vert, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); + -webkit-transform: scale($horiz, $vert); + -moz-transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + -o-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); +} diff --git a/scratch-parent/css/font-awesome/scss/_path.scss b/scratch-parent/css/font-awesome/scss/_path.scss new file mode 100644 index 00000000..fd21c351 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_path.scss @@ -0,0 +1,14 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); + src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), + url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), + url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); + //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/scratch-parent/css/font-awesome/scss/_rotated-flipped.scss b/scratch-parent/css/font-awesome/scss/_rotated-flipped.scss new file mode 100644 index 00000000..343fa550 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_rotated-flipped.scss @@ -0,0 +1,9 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } +.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } +.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } + +.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } +.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } diff --git a/scratch-parent/css/font-awesome/scss/_spinning.scss b/scratch-parent/css/font-awesome/scss/_spinning.scss new file mode 100644 index 00000000..c3787446 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_spinning.scss @@ -0,0 +1,32 @@ +// Spinning Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} diff --git a/scratch-parent/css/font-awesome/scss/_stacked.scss b/scratch-parent/css/font-awesome/scss/_stacked.scss new file mode 100644 index 00000000..aef74036 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_stacked.scss @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.#{$fa-css-prefix}-stack-1x { line-height: inherit; } +.#{$fa-css-prefix}-stack-2x { font-size: 2em; } +.#{$fa-css-prefix}-inverse { color: $fa-inverse; } diff --git a/scratch-parent/css/font-awesome/scss/_variables.scss b/scratch-parent/css/font-awesome/scss/_variables.scss new file mode 100644 index 00000000..ac2b5051 --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/_variables.scss @@ -0,0 +1,515 @@ +// Variables +// -------------------------- + +$fa-font-path: "../fonts" !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.1.0/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-css-prefix: fa !default; +$fa-version: "4.1.0" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; + +$fa-var-adjust: "\f042"; +$fa-var-adn: "\f170"; +$fa-var-align-center: "\f037"; +$fa-var-align-justify: "\f039"; +$fa-var-align-left: "\f036"; +$fa-var-align-right: "\f038"; +$fa-var-ambulance: "\f0f9"; +$fa-var-anchor: "\f13d"; +$fa-var-android: "\f17b"; +$fa-var-angle-double-down: "\f103"; +$fa-var-angle-double-left: "\f100"; +$fa-var-angle-double-right: "\f101"; +$fa-var-angle-double-up: "\f102"; +$fa-var-angle-down: "\f107"; +$fa-var-angle-left: "\f104"; +$fa-var-angle-right: "\f105"; +$fa-var-angle-up: "\f106"; +$fa-var-apple: "\f179"; +$fa-var-archive: "\f187"; +$fa-var-arrow-circle-down: "\f0ab"; +$fa-var-arrow-circle-left: "\f0a8"; +$fa-var-arrow-circle-o-down: "\f01a"; +$fa-var-arrow-circle-o-left: "\f190"; +$fa-var-arrow-circle-o-right: "\f18e"; +$fa-var-arrow-circle-o-up: "\f01b"; +$fa-var-arrow-circle-right: "\f0a9"; +$fa-var-arrow-circle-up: "\f0aa"; +$fa-var-arrow-down: "\f063"; +$fa-var-arrow-left: "\f060"; +$fa-var-arrow-right: "\f061"; +$fa-var-arrow-up: "\f062"; +$fa-var-arrows: "\f047"; +$fa-var-arrows-alt: "\f0b2"; +$fa-var-arrows-h: "\f07e"; +$fa-var-arrows-v: "\f07d"; +$fa-var-asterisk: "\f069"; +$fa-var-automobile: "\f1b9"; +$fa-var-backward: "\f04a"; +$fa-var-ban: "\f05e"; +$fa-var-bank: "\f19c"; +$fa-var-bar-chart-o: "\f080"; +$fa-var-barcode: "\f02a"; +$fa-var-bars: "\f0c9"; +$fa-var-beer: "\f0fc"; +$fa-var-behance: "\f1b4"; +$fa-var-behance-square: "\f1b5"; +$fa-var-bell: "\f0f3"; +$fa-var-bell-o: "\f0a2"; +$fa-var-bitbucket: "\f171"; +$fa-var-bitbucket-square: "\f172"; +$fa-var-bitcoin: "\f15a"; +$fa-var-bold: "\f032"; +$fa-var-bolt: "\f0e7"; +$fa-var-bomb: "\f1e2"; +$fa-var-book: "\f02d"; +$fa-var-bookmark: "\f02e"; +$fa-var-bookmark-o: "\f097"; +$fa-var-briefcase: "\f0b1"; +$fa-var-btc: "\f15a"; +$fa-var-bug: "\f188"; +$fa-var-building: "\f1ad"; +$fa-var-building-o: "\f0f7"; +$fa-var-bullhorn: "\f0a1"; +$fa-var-bullseye: "\f140"; +$fa-var-cab: "\f1ba"; +$fa-var-calendar: "\f073"; +$fa-var-calendar-o: "\f133"; +$fa-var-camera: "\f030"; +$fa-var-camera-retro: "\f083"; +$fa-var-car: "\f1b9"; +$fa-var-caret-down: "\f0d7"; +$fa-var-caret-left: "\f0d9"; +$fa-var-caret-right: "\f0da"; +$fa-var-caret-square-o-down: "\f150"; +$fa-var-caret-square-o-left: "\f191"; +$fa-var-caret-square-o-right: "\f152"; +$fa-var-caret-square-o-up: "\f151"; +$fa-var-caret-up: "\f0d8"; +$fa-var-certificate: "\f0a3"; +$fa-var-chain: "\f0c1"; +$fa-var-chain-broken: "\f127"; +$fa-var-check: "\f00c"; +$fa-var-check-circle: "\f058"; +$fa-var-check-circle-o: "\f05d"; +$fa-var-check-square: "\f14a"; +$fa-var-check-square-o: "\f046"; +$fa-var-chevron-circle-down: "\f13a"; +$fa-var-chevron-circle-left: "\f137"; +$fa-var-chevron-circle-right: "\f138"; +$fa-var-chevron-circle-up: "\f139"; +$fa-var-chevron-down: "\f078"; +$fa-var-chevron-left: "\f053"; +$fa-var-chevron-right: "\f054"; +$fa-var-chevron-up: "\f077"; +$fa-var-child: "\f1ae"; +$fa-var-circle: "\f111"; +$fa-var-circle-o: "\f10c"; +$fa-var-circle-o-notch: "\f1ce"; +$fa-var-circle-thin: "\f1db"; +$fa-var-clipboard: "\f0ea"; +$fa-var-clock-o: "\f017"; +$fa-var-cloud: "\f0c2"; +$fa-var-cloud-download: "\f0ed"; +$fa-var-cloud-upload: "\f0ee"; +$fa-var-cny: "\f157"; +$fa-var-code: "\f121"; +$fa-var-code-fork: "\f126"; +$fa-var-codepen: "\f1cb"; +$fa-var-coffee: "\f0f4"; +$fa-var-cog: "\f013"; +$fa-var-cogs: "\f085"; +$fa-var-columns: "\f0db"; +$fa-var-comment: "\f075"; +$fa-var-comment-o: "\f0e5"; +$fa-var-comments: "\f086"; +$fa-var-comments-o: "\f0e6"; +$fa-var-compass: "\f14e"; +$fa-var-compress: "\f066"; +$fa-var-copy: "\f0c5"; +$fa-var-credit-card: "\f09d"; +$fa-var-crop: "\f125"; +$fa-var-crosshairs: "\f05b"; +$fa-var-css3: "\f13c"; +$fa-var-cube: "\f1b2"; +$fa-var-cubes: "\f1b3"; +$fa-var-cut: "\f0c4"; +$fa-var-cutlery: "\f0f5"; +$fa-var-dashboard: "\f0e4"; +$fa-var-database: "\f1c0"; +$fa-var-dedent: "\f03b"; +$fa-var-delicious: "\f1a5"; +$fa-var-desktop: "\f108"; +$fa-var-deviantart: "\f1bd"; +$fa-var-digg: "\f1a6"; +$fa-var-dollar: "\f155"; +$fa-var-dot-circle-o: "\f192"; +$fa-var-download: "\f019"; +$fa-var-dribbble: "\f17d"; +$fa-var-dropbox: "\f16b"; +$fa-var-drupal: "\f1a9"; +$fa-var-edit: "\f044"; +$fa-var-eject: "\f052"; +$fa-var-ellipsis-h: "\f141"; +$fa-var-ellipsis-v: "\f142"; +$fa-var-empire: "\f1d1"; +$fa-var-envelope: "\f0e0"; +$fa-var-envelope-o: "\f003"; +$fa-var-envelope-square: "\f199"; +$fa-var-eraser: "\f12d"; +$fa-var-eur: "\f153"; +$fa-var-euro: "\f153"; +$fa-var-exchange: "\f0ec"; +$fa-var-exclamation: "\f12a"; +$fa-var-exclamation-circle: "\f06a"; +$fa-var-exclamation-triangle: "\f071"; +$fa-var-expand: "\f065"; +$fa-var-external-link: "\f08e"; +$fa-var-external-link-square: "\f14c"; +$fa-var-eye: "\f06e"; +$fa-var-eye-slash: "\f070"; +$fa-var-facebook: "\f09a"; +$fa-var-facebook-square: "\f082"; +$fa-var-fast-backward: "\f049"; +$fa-var-fast-forward: "\f050"; +$fa-var-fax: "\f1ac"; +$fa-var-female: "\f182"; +$fa-var-fighter-jet: "\f0fb"; +$fa-var-file: "\f15b"; +$fa-var-file-archive-o: "\f1c6"; +$fa-var-file-audio-o: "\f1c7"; +$fa-var-file-code-o: "\f1c9"; +$fa-var-file-excel-o: "\f1c3"; +$fa-var-file-image-o: "\f1c5"; +$fa-var-file-movie-o: "\f1c8"; +$fa-var-file-o: "\f016"; +$fa-var-file-pdf-o: "\f1c1"; +$fa-var-file-photo-o: "\f1c5"; +$fa-var-file-picture-o: "\f1c5"; +$fa-var-file-powerpoint-o: "\f1c4"; +$fa-var-file-sound-o: "\f1c7"; +$fa-var-file-text: "\f15c"; +$fa-var-file-text-o: "\f0f6"; +$fa-var-file-video-o: "\f1c8"; +$fa-var-file-word-o: "\f1c2"; +$fa-var-file-zip-o: "\f1c6"; +$fa-var-files-o: "\f0c5"; +$fa-var-film: "\f008"; +$fa-var-filter: "\f0b0"; +$fa-var-fire: "\f06d"; +$fa-var-fire-extinguisher: "\f134"; +$fa-var-flag: "\f024"; +$fa-var-flag-checkered: "\f11e"; +$fa-var-flag-o: "\f11d"; +$fa-var-flash: "\f0e7"; +$fa-var-flask: "\f0c3"; +$fa-var-flickr: "\f16e"; +$fa-var-floppy-o: "\f0c7"; +$fa-var-folder: "\f07b"; +$fa-var-folder-o: "\f114"; +$fa-var-folder-open: "\f07c"; +$fa-var-folder-open-o: "\f115"; +$fa-var-font: "\f031"; +$fa-var-forward: "\f04e"; +$fa-var-foursquare: "\f180"; +$fa-var-frown-o: "\f119"; +$fa-var-gamepad: "\f11b"; +$fa-var-gavel: "\f0e3"; +$fa-var-gbp: "\f154"; +$fa-var-ge: "\f1d1"; +$fa-var-gear: "\f013"; +$fa-var-gears: "\f085"; +$fa-var-gift: "\f06b"; +$fa-var-git: "\f1d3"; +$fa-var-git-square: "\f1d2"; +$fa-var-github: "\f09b"; +$fa-var-github-alt: "\f113"; +$fa-var-github-square: "\f092"; +$fa-var-gittip: "\f184"; +$fa-var-glass: "\f000"; +$fa-var-globe: "\f0ac"; +$fa-var-google: "\f1a0"; +$fa-var-google-plus: "\f0d5"; +$fa-var-google-plus-square: "\f0d4"; +$fa-var-graduation-cap: "\f19d"; +$fa-var-group: "\f0c0"; +$fa-var-h-square: "\f0fd"; +$fa-var-hacker-news: "\f1d4"; +$fa-var-hand-o-down: "\f0a7"; +$fa-var-hand-o-left: "\f0a5"; +$fa-var-hand-o-right: "\f0a4"; +$fa-var-hand-o-up: "\f0a6"; +$fa-var-hdd-o: "\f0a0"; +$fa-var-header: "\f1dc"; +$fa-var-headphones: "\f025"; +$fa-var-heart: "\f004"; +$fa-var-heart-o: "\f08a"; +$fa-var-history: "\f1da"; +$fa-var-home: "\f015"; +$fa-var-hospital-o: "\f0f8"; +$fa-var-html5: "\f13b"; +$fa-var-image: "\f03e"; +$fa-var-inbox: "\f01c"; +$fa-var-indent: "\f03c"; +$fa-var-info: "\f129"; +$fa-var-info-circle: "\f05a"; +$fa-var-inr: "\f156"; +$fa-var-instagram: "\f16d"; +$fa-var-institution: "\f19c"; +$fa-var-italic: "\f033"; +$fa-var-joomla: "\f1aa"; +$fa-var-jpy: "\f157"; +$fa-var-jsfiddle: "\f1cc"; +$fa-var-key: "\f084"; +$fa-var-keyboard-o: "\f11c"; +$fa-var-krw: "\f159"; +$fa-var-language: "\f1ab"; +$fa-var-laptop: "\f109"; +$fa-var-leaf: "\f06c"; +$fa-var-legal: "\f0e3"; +$fa-var-lemon-o: "\f094"; +$fa-var-level-down: "\f149"; +$fa-var-level-up: "\f148"; +$fa-var-life-bouy: "\f1cd"; +$fa-var-life-ring: "\f1cd"; +$fa-var-life-saver: "\f1cd"; +$fa-var-lightbulb-o: "\f0eb"; +$fa-var-link: "\f0c1"; +$fa-var-linkedin: "\f0e1"; +$fa-var-linkedin-square: "\f08c"; +$fa-var-linux: "\f17c"; +$fa-var-list: "\f03a"; +$fa-var-list-alt: "\f022"; +$fa-var-list-ol: "\f0cb"; +$fa-var-list-ul: "\f0ca"; +$fa-var-location-arrow: "\f124"; +$fa-var-lock: "\f023"; +$fa-var-long-arrow-down: "\f175"; +$fa-var-long-arrow-left: "\f177"; +$fa-var-long-arrow-right: "\f178"; +$fa-var-long-arrow-up: "\f176"; +$fa-var-magic: "\f0d0"; +$fa-var-magnet: "\f076"; +$fa-var-mail-forward: "\f064"; +$fa-var-mail-reply: "\f112"; +$fa-var-mail-reply-all: "\f122"; +$fa-var-male: "\f183"; +$fa-var-map-marker: "\f041"; +$fa-var-maxcdn: "\f136"; +$fa-var-medkit: "\f0fa"; +$fa-var-meh-o: "\f11a"; +$fa-var-microphone: "\f130"; +$fa-var-microphone-slash: "\f131"; +$fa-var-minus: "\f068"; +$fa-var-minus-circle: "\f056"; +$fa-var-minus-square: "\f146"; +$fa-var-minus-square-o: "\f147"; +$fa-var-mobile: "\f10b"; +$fa-var-mobile-phone: "\f10b"; +$fa-var-money: "\f0d6"; +$fa-var-moon-o: "\f186"; +$fa-var-mortar-board: "\f19d"; +$fa-var-music: "\f001"; +$fa-var-navicon: "\f0c9"; +$fa-var-openid: "\f19b"; +$fa-var-outdent: "\f03b"; +$fa-var-pagelines: "\f18c"; +$fa-var-paper-plane: "\f1d8"; +$fa-var-paper-plane-o: "\f1d9"; +$fa-var-paperclip: "\f0c6"; +$fa-var-paragraph: "\f1dd"; +$fa-var-paste: "\f0ea"; +$fa-var-pause: "\f04c"; +$fa-var-paw: "\f1b0"; +$fa-var-pencil: "\f040"; +$fa-var-pencil-square: "\f14b"; +$fa-var-pencil-square-o: "\f044"; +$fa-var-phone: "\f095"; +$fa-var-phone-square: "\f098"; +$fa-var-photo: "\f03e"; +$fa-var-picture-o: "\f03e"; +$fa-var-pied-piper: "\f1a7"; +$fa-var-pied-piper-alt: "\f1a8"; +$fa-var-pied-piper-square: "\f1a7"; +$fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-square: "\f0d3"; +$fa-var-plane: "\f072"; +$fa-var-play: "\f04b"; +$fa-var-play-circle: "\f144"; +$fa-var-play-circle-o: "\f01d"; +$fa-var-plus: "\f067"; +$fa-var-plus-circle: "\f055"; +$fa-var-plus-square: "\f0fe"; +$fa-var-plus-square-o: "\f196"; +$fa-var-power-off: "\f011"; +$fa-var-print: "\f02f"; +$fa-var-puzzle-piece: "\f12e"; +$fa-var-qq: "\f1d6"; +$fa-var-qrcode: "\f029"; +$fa-var-question: "\f128"; +$fa-var-question-circle: "\f059"; +$fa-var-quote-left: "\f10d"; +$fa-var-quote-right: "\f10e"; +$fa-var-ra: "\f1d0"; +$fa-var-random: "\f074"; +$fa-var-rebel: "\f1d0"; +$fa-var-recycle: "\f1b8"; +$fa-var-reddit: "\f1a1"; +$fa-var-reddit-square: "\f1a2"; +$fa-var-refresh: "\f021"; +$fa-var-renren: "\f18b"; +$fa-var-reorder: "\f0c9"; +$fa-var-repeat: "\f01e"; +$fa-var-reply: "\f112"; +$fa-var-reply-all: "\f122"; +$fa-var-retweet: "\f079"; +$fa-var-rmb: "\f157"; +$fa-var-road: "\f018"; +$fa-var-rocket: "\f135"; +$fa-var-rotate-left: "\f0e2"; +$fa-var-rotate-right: "\f01e"; +$fa-var-rouble: "\f158"; +$fa-var-rss: "\f09e"; +$fa-var-rss-square: "\f143"; +$fa-var-rub: "\f158"; +$fa-var-ruble: "\f158"; +$fa-var-rupee: "\f156"; +$fa-var-save: "\f0c7"; +$fa-var-scissors: "\f0c4"; +$fa-var-search: "\f002"; +$fa-var-search-minus: "\f010"; +$fa-var-search-plus: "\f00e"; +$fa-var-send: "\f1d8"; +$fa-var-send-o: "\f1d9"; +$fa-var-share: "\f064"; +$fa-var-share-alt: "\f1e0"; +$fa-var-share-alt-square: "\f1e1"; +$fa-var-share-square: "\f14d"; +$fa-var-share-square-o: "\f045"; +$fa-var-shield: "\f132"; +$fa-var-shopping-cart: "\f07a"; +$fa-var-sign-in: "\f090"; +$fa-var-sign-out: "\f08b"; +$fa-var-signal: "\f012"; +$fa-var-sitemap: "\f0e8"; +$fa-var-skype: "\f17e"; +$fa-var-slack: "\f198"; +$fa-var-sliders: "\f1de"; +$fa-var-smile-o: "\f118"; +$fa-var-sort: "\f0dc"; +$fa-var-sort-alpha-asc: "\f15d"; +$fa-var-sort-alpha-desc: "\f15e"; +$fa-var-sort-amount-asc: "\f160"; +$fa-var-sort-amount-desc: "\f161"; +$fa-var-sort-asc: "\f0de"; +$fa-var-sort-desc: "\f0dd"; +$fa-var-sort-down: "\f0dd"; +$fa-var-sort-numeric-asc: "\f162"; +$fa-var-sort-numeric-desc: "\f163"; +$fa-var-sort-up: "\f0de"; +$fa-var-soundcloud: "\f1be"; +$fa-var-space-shuttle: "\f197"; +$fa-var-spinner: "\f110"; +$fa-var-spoon: "\f1b1"; +$fa-var-spotify: "\f1bc"; +$fa-var-square: "\f0c8"; +$fa-var-square-o: "\f096"; +$fa-var-stack-exchange: "\f18d"; +$fa-var-stack-overflow: "\f16c"; +$fa-var-star: "\f005"; +$fa-var-star-half: "\f089"; +$fa-var-star-half-empty: "\f123"; +$fa-var-star-half-full: "\f123"; +$fa-var-star-half-o: "\f123"; +$fa-var-star-o: "\f006"; +$fa-var-steam: "\f1b6"; +$fa-var-steam-square: "\f1b7"; +$fa-var-step-backward: "\f048"; +$fa-var-step-forward: "\f051"; +$fa-var-stethoscope: "\f0f1"; +$fa-var-stop: "\f04d"; +$fa-var-strikethrough: "\f0cc"; +$fa-var-stumbleupon: "\f1a4"; +$fa-var-stumbleupon-circle: "\f1a3"; +$fa-var-subscript: "\f12c"; +$fa-var-suitcase: "\f0f2"; +$fa-var-sun-o: "\f185"; +$fa-var-superscript: "\f12b"; +$fa-var-support: "\f1cd"; +$fa-var-table: "\f0ce"; +$fa-var-tablet: "\f10a"; +$fa-var-tachometer: "\f0e4"; +$fa-var-tag: "\f02b"; +$fa-var-tags: "\f02c"; +$fa-var-tasks: "\f0ae"; +$fa-var-taxi: "\f1ba"; +$fa-var-tencent-weibo: "\f1d5"; +$fa-var-terminal: "\f120"; +$fa-var-text-height: "\f034"; +$fa-var-text-width: "\f035"; +$fa-var-th: "\f00a"; +$fa-var-th-large: "\f009"; +$fa-var-th-list: "\f00b"; +$fa-var-thumb-tack: "\f08d"; +$fa-var-thumbs-down: "\f165"; +$fa-var-thumbs-o-down: "\f088"; +$fa-var-thumbs-o-up: "\f087"; +$fa-var-thumbs-up: "\f164"; +$fa-var-ticket: "\f145"; +$fa-var-times: "\f00d"; +$fa-var-times-circle: "\f057"; +$fa-var-times-circle-o: "\f05c"; +$fa-var-tint: "\f043"; +$fa-var-toggle-down: "\f150"; +$fa-var-toggle-left: "\f191"; +$fa-var-toggle-right: "\f152"; +$fa-var-toggle-up: "\f151"; +$fa-var-trash-o: "\f014"; +$fa-var-tree: "\f1bb"; +$fa-var-trello: "\f181"; +$fa-var-trophy: "\f091"; +$fa-var-truck: "\f0d1"; +$fa-var-try: "\f195"; +$fa-var-tumblr: "\f173"; +$fa-var-tumblr-square: "\f174"; +$fa-var-turkish-lira: "\f195"; +$fa-var-twitter: "\f099"; +$fa-var-twitter-square: "\f081"; +$fa-var-umbrella: "\f0e9"; +$fa-var-underline: "\f0cd"; +$fa-var-undo: "\f0e2"; +$fa-var-university: "\f19c"; +$fa-var-unlink: "\f127"; +$fa-var-unlock: "\f09c"; +$fa-var-unlock-alt: "\f13e"; +$fa-var-unsorted: "\f0dc"; +$fa-var-upload: "\f093"; +$fa-var-usd: "\f155"; +$fa-var-user: "\f007"; +$fa-var-user-md: "\f0f0"; +$fa-var-users: "\f0c0"; +$fa-var-video-camera: "\f03d"; +$fa-var-vimeo-square: "\f194"; +$fa-var-vine: "\f1ca"; +$fa-var-vk: "\f189"; +$fa-var-volume-down: "\f027"; +$fa-var-volume-off: "\f026"; +$fa-var-volume-up: "\f028"; +$fa-var-warning: "\f071"; +$fa-var-wechat: "\f1d7"; +$fa-var-weibo: "\f18a"; +$fa-var-weixin: "\f1d7"; +$fa-var-wheelchair: "\f193"; +$fa-var-windows: "\f17a"; +$fa-var-won: "\f159"; +$fa-var-wordpress: "\f19a"; +$fa-var-wrench: "\f0ad"; +$fa-var-xing: "\f168"; +$fa-var-xing-square: "\f169"; +$fa-var-yahoo: "\f19e"; +$fa-var-yen: "\f157"; +$fa-var-youtube: "\f167"; +$fa-var-youtube-play: "\f16a"; +$fa-var-youtube-square: "\f166"; + diff --git a/scratch-parent/css/font-awesome/scss/font-awesome.scss b/scratch-parent/css/font-awesome/scss/font-awesome.scss new file mode 100644 index 00000000..2307dbda --- /dev/null +++ b/scratch-parent/css/font-awesome/scss/font-awesome.scss @@ -0,0 +1,17 @@ +/*! + * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "spinning"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; diff --git a/scratch-parent/css/ie.css b/scratch-parent/css/ie.css new file mode 100644 index 00000000..322451ee --- /dev/null +++ b/scratch-parent/css/ie.css @@ -0,0 +1,1303 @@ +/** + * Global Styles for older IE versions (previous to IE9). + */ + +pre, +fieldset, +table, +th, +td, +input, +textarea { + border: 1px solid #e5e5e5; +} + +hr { + background-color: #e5e5e5; +} + +button, +input, +select, +textarea { + vertical-align: middle; +} + + +input:focus, +textarea:focus { + border: 1px solid #b2b2b2; +} + +.site-content blockquote.alignleft, +.site-content blockquote.alignright { + border-top: 1px solid #e5e5e5; + border-bottom: 1px solid #e5e5e5; +} + +.post-thumbnail, +a.post-thumbnail:hover { + background: transparent; +} + +.list-view .site-content .hentry { + border-top: 1px solid #e5e5e5; + padding-top: 48px; +} + +.gallery-caption { + background: #000; + filter: alpha(opacity=0); +} + +.gallery-item:hover .gallery-caption { + filter: alpha(opacity=70); +} + +.nav-links { + border-top: 1px solid #e5e5e5; +} + +.post-navigation a, +.image-navigation .previous-image, +.image-navigation .next-image, +.contributor { + border-bottom: 1px solid #e5e5e5; +} + +.contributor-avatar, +.comment-author .avatar { + border: 1px solid #e5e5e5; +} + +.comment-list article, +.comment-list .pingback, +.comment-list .trackback { + border-top: 1px solid #e5e5e5; +} + +.comment-list .reply { + margin-top: 0; +} + +#secondary { + color: #b3b3b3; +} + +.widget abbr[title] { + border-color: #b3b3b3; +} + +.widget pre, +.widget fieldset, +.widget table, +.widget th, +.widget td, +.widget input, +.widget textarea { + border-color: #4d4d4d; +} + +.widget blockquote, +.widget .wp-caption { + color: #b3b3b3; +} + +.widget del { + color: #666; +} + +.widget hr { + background-color: #4d4d4d; +} + +.widget input, +.widget textarea { + background-color: #1a1a1a; +} + +.widget input:focus, +.widget textarea:focus { + border-color: #262626; +} + +.widget_calendar thead th { + background-color: #1a1a1a; +} + +.widget_archive li, +.widget_categories li, +.widget_links li, +.widget_meta li, +.widget_nav_menu li, +.widget_pages li, +.widget_recent_comments li, +.widget_recent_entries li, +.widget_categories li ul, +.widget_nav_menu li ul, +.widget_pages li ul { + border-top: 1px solid #4d4d4d; +} + +.content-sidebar .widget pre, +.content-sidebar .widget fieldset, +.content-sidebar .widget table, +.content-sidebar .widget th, +.content-sidebar .widget td, +.content-sidebar .widget input, +.content-sidebar .widget textarea, +.content-sidebar .widget_archive li, +.content-sidebar .widget_categories li, +.content-sidebar .widget_links li, +.content-sidebar .widget_meta li, +.content-sidebar .widget_nav_menu li, +.content-sidebar .widget_pages li, +.content-sidebar .widget_recent_comments li, +.content-sidebar .widget_recent_entries li, +.content-sidebar .widget_categories li ul, +.content-sidebar .widget_nav_menu li ul, +.content-sidebar .widget_pages li ul { + border-color: #e5e5e5; +} + +.content-sidebar .widget hr { + background-color: #e5e5e5; +} + +.content-sidebar .widget input:focus, +.content-sidebar .widget textarea:focus { + border: 1px solid #b2b2b2; +} + +.content-sidebar .widget_calendar thead th { + background-color: #fafafa; +} + +.site-footer, +.site-info, +.site-info a { + color: #b3b3b3; +} + +#supplementary + .site-info { + border-top: 1px solid #4d4d4d; +} + +.featured-content { + background: #000; +} + + +/** + * Internet Explorer 8 + */ + +.ie8 img.size-full, +.ie8 img.size-large, +.ie8 img.header-image, +.ie8 img.wp-post-image, +.ie8 img[class*="align"], +.ie8 img[class*="wp-image-"], +.ie8 img[class*="attachment-"] { + height: auto; + width: auto; /* Prevent stretching of full-size and large-size images with height and width attributes in IE8 */ +} + +.ie8 .full-size-link:before, +.ie8 .parent-post-link:before, +.ie8 .site-content span + .byline:before, +.ie8 .site-content span + .comments-link:before, +.ie8 .site-content span + .edit-link:before, +.ie8 .site-content span + .entry-date:before { + content: ""; +} + +.ie8 .attachment span.entry-date:before, +.ie8 .entry-content .edit-link a:before, +.ie8 .entry-meta .edit-link a:before, +.ie8 .site-content .byline a:before, +.ie8 .site-content .comments-link a:before, +.ie8 .site-content .entry-date a:before, +.ie8 .site-content .featured-post:before, +.ie8 .site-content .full-size-link a:before, +.ie8 .site-content .parent-post-link a:before, +.ie8 .site-content .post-format a:before { + display: inline-block; + font: normal 16px/1 Genericons; + text-decoration: inherit; + vertical-align: text-bottom; +} + +.ie8 .site-content .entry-meta > span { + margin-right: 10px; +} + +.ie8 .site-content .format-video .post-format a:before { + content: "\f104"; +} + +.ie8 .site-content .format-audio .post-format a:before { + content: "\f109"; +} + +.ie8 .site-content .format-image .post-format a:before { + content: "\f473"; + position: relative; + top: 1px; +} + +.ie8 .site-content .format-quote .post-format a:before { + content: "\f106"; + margin-right: 2px; +} + +.ie8 .site-content .format-gallery .post-format a:before { + content: "\f103"; + margin-right: 4px; +} + +.ie8 .site-content .format-aside .post-format a:before { + content: "\f101"; + margin-right: 2px; +} + +.ie8 .site-content .format-link .post-format a:before { + content: "\f107"; + position: relative; + top: 1px; +} + +.ie8 .site-content .featured-post:before { + content: "\f308"; + margin-right: 3px; + position: relative; + top: 1px; +} + +.ie8 .site-content .entry-date a:before, +.ie8 .attachment .site-content span.entry-date:before { + content: "\f303"; + margin-right: 1px; + position: relative; + top: 1px; +} + +.ie8 .site-content .byline a:before { + content: "\f304"; +} + +.ie8 .site-content .comments-link a:before { + content: "\f300"; + margin-right: 2px; +} + +.ie8 .entry-content .edit-link a:before, +.ie8 .entry-meta .edit-link a:before { + content: "\f411"; +} + +.ie8 .site-content .full-size-link a:before { + content: "\f402"; + margin-right: 1px; +} + +.ie8 .site-content .parent-post-link a:before { + content: "\f301"; +} + +.ie8 .main-content { + float: left; +} + +.ie8 .content-area { + float: left; + padding-top: 72px; + width: 100%; +} + +.ie8 .site-content { + margin-right: 29.04761904%; + margin-left: 17.61904761%; +} + +.ie8 .search-box-wrapper, +.ie8 .featured-content { + padding-left: 17.61904761%; +} + +.ie8 .header-main { + padding: 0 0 0 30px; +} + +.ie8 .search-toggle { + margin-right: 0; +} + +.ie8 .search-box .search-field { + width: 324px; +} + +.ie8 .site-navigation li .current_page_item > a, +.ie8 .site-navigation li .current_page_ancestor > a, +.ie8 .site-navigation li .current-menu-item > a, +.ie8 .site-navigation li .current-menu-ancestor > a { + background-color: #000; +} + +.ie8 .primary-navigation { + float: right; + font-size: 11px; + margin: 0 1px 0 -10px; + padding: 0; + text-transform: uppercase; +} + +.ie8 .primary-navigation .menu-toggle { + display: none; + padding: 0; +} + +.ie8 .primary-navigation .nav-menu { + border-bottom: 0; + display: block; +} + +.ie8 .primary-navigation.toggled-on { + border-bottom: 0; + margin: 0; + padding: 0; +} + +.ie8 .primary-navigation li { + border: 0; + display: inline-block; + height: 48px; + line-height: 48px; + position: relative; +} + +.ie8 .primary-navigation a { + display: inline-block; + padding: 0 10px; + white-space: nowrap; +} + +.ie8 .primary-navigation ul ul { + background-color: #24890d; + float: left; + margin: 0; + position: absolute; + top: 48px; + left: -999em; + z-index: 99999; +} + +.ie8 .primary-navigation li li { + border: 0; + display: block; + height: auto; + line-height: 1.0909090909; +} + +.ie8 .primary-navigation ul ul ul { + left: -999em; + top: 0; +} + +.ie8 .primary-navigation ul ul a { + padding: 18px 12px; + white-space: normal; + width: 176px; +} + +.ie8 .primary-navigation li:hover > a, +.ie8 .primary-navigation li.focus > a { + background-color: #24890d; + color: #fff; +} + +.ie8 .primary-navigation ul ul a:hover, +.ie8 .primary-navigation ul ul li.focus > a { + background-color: #41a62a; +} + +.ie8 .primary-navigation ul li:hover > ul, +.ie8 .primary-navigation ul li.focus > ul { + left: auto; +} + +.ie8 .primary-navigation ul ul li:hover > ul, +.ie8 .primary-navigation ul ul li.focus > ul { + left: 100%; +} + +.ie8 .archive-header, +.ie8 .page-header { + margin: 0 auto 60px; + padding: 0 10px; +} + +.ie8 .site-content .has-post-thumbnail .entry-header { + margin-top: -48px; +} + +.ie8 .archive-header, +.ie8 .comments-area, +.ie8 .image-navigation, +.ie8 .page-header, +.ie8 .page-content, +.ie8 .post-navigation, +.ie8 .site-content .entry-header, +.ie8 .site-content .entry-content, +.ie8 .site-content .entry-summary, +.ie8 .site-content footer.entry-meta { + margin-right: 54px; + padding-right: 30px; + padding-left: 30px; +} + +.ie8 .list-view .site-content .hentry:first-child, +.ie8 .list-view .site-content .hentry.has-post-thumbnail { + border-top: 0; + padding-top: 0; +} + +.ie8 .comment-list .trackback, +.ie8 .comment-list .pingback, +.ie8 .comment-list article { + margin-bottom: 36px; + padding-top: 36px; +} + +.ie8 .comment-author .avatar { + height: 34px; + top: 2px; + width: 34px; +} + +.ie8 .comment-author, +.ie8 .comment-awaiting-moderation, +.ie8 .comment-content, +.ie8 .comment-list .reply, +.ie8 .comment-metadata { + padding-left: 50px; +} + +.ie8 .comment-list .children { + margin-left: 20px; +} + +.ie8 .full-width .site-content { + margin-right: 0; +} + +.ie8 .full-width .archive-header, +.ie8 .full-width .comments-area, +.ie8 .full-width .image-navigation, +.ie8 .full-width .page-header, +.ie8 .full-width .page-content, +.ie8 .full-width .post-navigation, +.ie8 .full-width .site-content .entry-header, +.ie8 .full-width .site-content .entry-content, +.ie8 .full-width .site-content .entry-summary, +.ie8 .full-width .site-content footer.entry-meta { + padding-right: 30px; + padding-left: 30px; + margin-right: auto; +} + +.ie8 .full-width.singular .hentry.has-post-thumbnail, +.ie8 .full-width.home .hentry.has-post-thumbnail { + margin-top: -72px; +} + + +.ie8 .singular .hentry.has-post-thumbnail { + margin-top: 0; +} + +.ie8 .error404 .page-header { + margin-bottom: 24px; +} + +.ie8 .contributor-avatar { + margin-left: -168px; +} + +.ie8 .contributor-summary { + float: left; +} + +.ie8 .site:before { + background-color: #000; + content: ""; + display: block; + height: 100%; + min-height: 100%; + position: absolute; + top: 0; + left: 0; + width: 17.61904761%; + z-index: 2; +} + +.ie8 #secondary { + border: 0; + clear: none; + color: #b3b3b3; + float: left; + margin: 0 0 0 -100%; + min-height: 100vh; + padding: 0 30px; + width: 12.85714285%; +} + +.ie8 .site-description { + display: block; + margin: -3px 0 21px; +} + +.ie8 .secondary-navigation { + font-size: 11px; + margin: 0 -30px 48px; + width: calc(100% + 60px); +} + +.ie8 .secondary-navigation li { + border-top: 1px solid #4d4d4d; + position: relative; +} + +.ie8 .secondary-navigation a { + padding: 10px 30px; +} + +.ie8 .secondary-navigation ul ul { + background-color: #24890d; + position: absolute; + top: 0; + left: -999em; + width: 222px; + z-index: 99999; +} + +.ie8 .secondary-navigation li li { + border-top: 0; +} + +.ie8 .secondary-navigation li:hover > a, +.ie8 .secondary-navigation li.focus > a { + background-color: #24890d; + color: #fff; +} + +.ie8 .secondary-navigation ul ul a:hover, +.ie8 .secondary-navigation ul ul li.focus > a { + background-color: #41a62a; +} + +.ie8 .secondary-navigation ul li:hover > ul, +.ie8 .secondary-navigation ul li.focus > ul { + left: 202px; +} + +.ie8 .content-sidebar { + border: 0; + float: right; + margin-left: -29.04761904%; + padding: 72px 30px 24px; + width: 29.04761904%; +} + +.ie8 #supplementary { + padding: 0; +} + +.ie8 .footer-sidebar { + font-size: 12px; + line-height: 1.5; +} + +.ie8 .footer-sidebar .widget, +.ie8 .primary-sidebar .widget { + font-size: 12px; + line-height: 1.5; +} + +.ie8 .footer-sidebar .widget { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + padding: 0 30px; + width: 25%; +} + +.ie8 .footer-sidebar .widget h1, +.ie8 .primary-sidebar .widget h1 { + font-size: 20px; + line-height: 1.2; +} + +.ie8 .footer-sidebar .widget h2, +.ie8 .primary-sidebar .widget h2 { + font-size: 18px; + line-height: 1.3333333333; +} + +.ie8 .footer-sidebar .widget h3, +.ie8 .primary-sidebar .widget h3 { + font-size: 16px; + line-height: 1.5; +} + +.ie8 .footer-sidebar .widget h4, +.ie8 .primary-sidebar .widget h4 { + font-size: 14px; + line-height: 1.7142857142; +} + +.ie8 .footer-sidebar .widget h5, +.ie8 .primary-sidebar .widget h5 { + font-size: 12px; + line-height: 2; +} + +.ie8 .footer-sidebar .widget h6, +.ie8 .primary-sidebar .widget h6 { + font-size: 11px; + line-height: 2.1818181818; +} + +.ie8 .footer-sidebar .widget code, +.ie8 .footer-sidebar .widget kbd, +.ie8 .footer-sidebar .widget tt, +.ie8 .footer-sidebar .widget var, +.ie8 .footer-sidebar .widget samp, +.ie8 .footer-sidebar .widget pre, +.ie8 .primary-sidebar .widget code, +.ie8 .primary-sidebar .widget kbd, +.ie8 .primary-sidebar .widget tt, +.ie8 .primary-sidebar .widget var, +.ie8 .primary-sidebar .widget samp, +.ie8 .primary-sidebar .widget pre { + font-size: 11px; + line-height: 1.6363636363; +} + +.ie8 .footer-sidebar .widget blockquote, +.ie8 .primary-sidebar .widget blockquote { + font-size: 14px; + line-height: 1.2857142857; +} + +.ie8 .footer-sidebar .widget blockquote cite, +.ie8 .primary-sidebar .widget blockquote cite { + font-size: 12px; + line-height: 1.5; +} + +.ie8 .footer-sidebar .widget input, +.ie8 .footer-sidebar .widget textarea, +.ie8 .primary-sidebar .widget input, +.ie8 .primary-sidebar .widget textarea { + font-size: 12px; + padding: 3px 2px 4px 4px; +} + +.ie8 .footer-sidebar .widget input[type="button"], +.ie8 .footer-sidebar .widget input[type="reset"], +.ie8 .footer-sidebar .widget input[type="submit"], +.ie8 .primary-sidebar .widget input[type="button"], +.ie8 .primary-sidebar .widget input[type="reset"], +.ie8 .primary-sidebar .widget input[type="submit"] { + padding: 5px 15px 4px; +} + +.ie8 .footer-sidebar .widget .widget-title, +.ie8 .primary-sidebar .widget .widget-title { + font-size: 11px; + font-weight: 700; + line-height: 1.6363636363; + margin-bottom: 18px; +} + +.ie8 .footer-sidebar .widget_archive li, +.ie8 .footer-sidebar .widget_categories li, +.ie8 .footer-sidebar .widget_links li, +.ie8 .footer-sidebar .widget_meta li, +.ie8 .footer-sidebar .widget_nav_menu li, +.ie8 .footer-sidebar .widget_pages li, +.ie8 .footer-sidebar .widget_recent_comments li, +.ie8 .footer-sidebar .widget_recent_entries li, +.ie8 .primary-sidebar .widget_archive li, +.ie8 .primary-sidebar .widget_categories li, +.ie8 .primary-sidebar .widget_links li, +.ie8 .primary-sidebar .widget_meta li, +.ie8 .primary-sidebar .widget_nav_menu li, +.ie8 .primary-sidebar .widget_pages li, +.ie8 .primary-sidebar .widget_recent_comments li, +.ie8 .primary-sidebar .widget_recent_entries li { + border-top: 0; + padding: 0 0 6px; +} + +.ie8 .footer-sidebar .widget_categories li ul, +.ie8 .footer-sidebar .widget_nav_menu li ul, +.ie8 .footer-sidebar .widget_pages li ul, +.ie8 .primary-sidebar .widget_categories li ul, +.ie8 .primary-sidebar .widget_nav_menu li ul, +.ie8 .primary-sidebar .widget_pages li ul { + border-top: 0; + margin-top: 0; +} + +.ie8 .grid .featured-content .entry-header { + border-color: #000; + border-style: solid; + border-width: 12px 10px; + height: 96px; + padding: 0; +} + +.ie8 .featured-content { + padding-left: 17.61904761%; +} + +.ie8 .grid .featured-content .hentry { + float: left; + width: 33.3333333%; +} + +.ie8 .grid .featured-content .hentry:nth-child( 3n+1 ) { + clear: both; +} + +.ie8 .grid .featured-content .entry-header { + height: 120px; +} + +.ie8 .slider .featured-content .entry-title { + font-size: 33px; + line-height: 1.0909090909; +} + +.ie8 .slider .featured-content .entry-header { + min-height: inherit; + padding: 24px 30px 48px; + position: absolute; + left: 0; + bottom: 0; + width: 50%; + z-index: 3; +} + +.ie8 .slider-control-paging { + background: transparent; + margin-top: -48px; + padding-left: 24px; + width: 50%; +} + +.ie8 .slider-control-paging li { + margin: 12px 12px 12px 0; +} + +.ie8 .slider-control-paging a { + height: 24px; + width: 24px; +} + +.ie8 .slider-control-paging a:before { + top: 6px; + left: 6px; +} + +.ie8 .slider-direction-nav { + clear: none; + float: right; + margin-top: -48px; + width: 98px; +} + +.ie8 .slider-direction-nav li:first-child { + padding: 0 1px 0 0; +} + +.ie8 .slider-direction-nav li { + border: 0; + padding: 0 0 0 1px; +} + +.ie8 .slider-direction-nav a { + height: 48px; +} + +.ie8 .slider-direction-nav a:before { + line-height: 48px; +} + + +/** + * Internet Explorer 7 + */ + +.ie7 audio, +.ie7 canvas, +.ie7 video { + display: inline; + zoom: 1; +} + +.ie7 button, +.ie7 input, +.ie7 select, +.ie7 textarea { + vertical-align: middle; +} + +.ie7 button, +.ie7 input[type="button"], +.ie7 input[type="reset"], +.ie7 input[type="submit"] { + overflow: visible; +} + +.ie7 .screen-reader-text { + clip: rect(1px 1px 1px 1px); +} + +.ie7 .site, +.ie7 .site-header { + max-width: 100%; +} + +.ie7 .search-toggle { + line-height: 45px; + margin-right: 190px; + padding: 0 20px; + text-transform: uppercase; + width: auto; +} + +.ie7 .search-toggle .screen-reader-text { + color: #fff; + position: relative; /* Override inherited `absolute` value set in style.css. */ +} + +.ie7 .search-box { + height: 24px; + padding: 12px 0; +} + +.ie7 .search-box .search-field { + margin: 0 10px; + width: 33%; +} + +.ie7 .site-navigation li { + border-top: 1px solid #4d4d4d; +} + +.ie7 .primary-navigation .nav-menu, +.ie7 .secondary-navigation { + border-bottom: 1px solid #4d4d4d; +} + +.ie7 .secondary-navigation { + margin: 48px auto; + max-width: 474px +} + +.ie7 .content-area { + padding-top: 48px; +} + +.ie7 .hentry { + max-width: 100%; +} + +.ie7 .menu-toggle { + color: #fff; + font-weight: 400; + font-size: 16px; + line-height: 45px; + text-transform: uppercase; + width: 200px; +} + +.ie7 .post-thumbnail img { + display: block; + margin: 0 auto; +} + +.ie7 .entry-meta .tag-links a { + margin-left: 0; +} + +.ie7 .content-sidebar { + padding: 48px 10px; +} + +.ie7 .singular .hentry.has-post-thumbnail { + margin-top: -48px; +} + +.ie7 .entry-meta > span { + margin-right: 20px; +} + +.ie7 #secondary { + border-bottom: 1px solid #4d4d4d; +} + +.ie7 .content-sidebar { + border-top: 1px solid #e5e5e5; + border-bottom: 1px solid #e5e5e5; +} + +.ie7 .widget { + margin: 0 auto 48px; + max-width: 474px; +} + +.ie7 .slider .featured-content .hentry { + display: block; +} + +.ie7 .featured-content .entry-header { + min-height: 0; +} + +.ie7 .slider-control-paging a { + line-height: 40px; + text-indent: 0; +} + +.ie7 .slider-control-paging .slider-active { + color: #41a62a; +} + +.ie7 .slider-direction-nav { + border-top: 2px solid #fff; +} + +.ie7 .slider-direction-nav li { + border: 0; + width: 49%; +} + +.ie7 .slider-direction-nav a { + font-size: 16px; + line-height: 45px; + text-transform: uppercase; +} + +.ie7 .slider-direction-nav a:hover { + background-color: #000; + color: #41a62a; +} + +.ie7 .search-toggle { + line-height: 45px; + margin-right: 190px; +} + +.ie7 .featured-content .post-thumbnail, +.ie7 .slider .featured-content .post-thumbnail { + padding-top: 0; +} + +.ie7 .featured-content .post-thumbnail img { + position: relative; +} + +.ie7 .featured-content .entry-header { + width: auto; +} + +.ie7 .grid .featured-content .hentry { + float: left; + margin: 0 auto; + max-width: 672px; + width: 33.333333%; +} + +.ie7 .slider .featured-content .entry-header { + margin: 0 auto; + max-width: 1038px; +} + +.ie7 .slider-control-paging { + float: none; + margin: -24px auto 0; + max-width: 1038px; + width: auto; +} + + +/** + * RTL for Internet Explorer 8 & 7 + */ + +.rtl .attachment a, +.rtl .gallery a, +.rtl .wp-caption a { + display: inline; +} + + +/** + * RTL overrides for Internet Explorer 8 + */ + +.ie8 .rtl .site-content .entry-meta > span { + margin-right: auto; + margin-left: 10px; +} + +.ie8 .rtl .site-content .format-quote .post-format a:before { + margin-right: auto; + margin-left: 2px; +} + +.ie8 .rtl .site-content .format-gallery .post-format a:before { + margin-right: auto; + margin-left: 4px; +} + +.ie8 .rtl .site-content .format-aside .post-format a:before { + margin-right: auto; + margin-left: 2px; +} + +.ie8 .rtl .site-content .featured-post:before { + margin-right: auto; + margin-left: 3px; +} + +.ie8 .rtl .site-content .entry-date a:before, +.ie8 .rtl .attachment .site-content span.entry-date:before { + margin-right: auto; + margin-left: 1px; +} + +.ie8 .rtl .site-content .comments-link a:before { + margin-right: auto; + margin-left: 2px; +} + +.ie8 .rtl .site-content .full-size-link a:before { + margin-right: auto; + margin-left: 1px; +} + +.ie8 .rtl .main-content { + float: right; +} + +.ie8 .rtl .content-area { + float: right; +} + +.ie8 .rtl .site-content { + margin-right: 17.61904761%; + margin-left: 29.04761904%; +} + +.ie8 .rtl .search-box-wrapper, +.ie8 .rtl .featured-content { + padding-right: 17.61904761%; + padding-left: 0; +} + +.ie8 .rtl .header-main { + padding: 0 30px 0 0; +} + +.ie8 .rtl .search-toggle { + margin-right: auto; + margin-left: 0; +} + +.ie8 .rtl .primary-navigation { + float: left; + margin: 0 -10px 0 1px; +} + +.ie8 .rtl .primary-navigation ul ul { + float: right; + right: -999em; + left: auto; +} + +.ie8 .rtl .primary-navigation ul ul ul { + right: -999em; + left: auto; +} + +.ie8 .rtl .primary-navigation ul li:hover > ul, +.ie8 .rtl .primary-navigation ul li.focus > ul { + right: auto; + left: auto; +} + +.ie8 .rtl .primary-navigation ul ul li:hover > ul, +.ie8 .rtl .primary-navigation ul ul li.focus > ul { + right: 100%; + left: auto; +} + +.ie8 .rtl .entry-meta .tag-links a:before { + right: -8px; +} + +.ie8 .rtl .archive-header, +.ie8 .rtl .comments-area, +.ie8 .rtl .image-navigation, +.ie8 .rtl .page-header, +.ie8 .rtl .page-content, +.ie8 .rtl .post-navigation, +.ie8 .rtl .site-content .entry-header, +.ie8 .rtl .site-content .entry-content, +.ie8 .rtl .site-content .entry-summary, +.ie8 .rtl .site-content footer.entry-meta { + margin-right: auto; + margin-left: 54px; +} + +.ie8 .rtl .comment-author, +.ie8 .rtl .comment-awaiting-moderation, +.ie8 .rtl .comment-content, +.ie8 .rtl .comment-list .reply, +.ie8 .rtl .comment-metadata { + padding-right: 50px; + padding-left: 0; +} + +.ie8 .rtl .comment-list .children { + margin-right: 20px; + margin-left: auto; +} + + +.ie8 .rtl.full-width .site-content { + margin-left: 0; +} + +.ie8 .rtl.full-width .archive-header, +.ie8 .rtl.full-width .comments-area, +.ie8 .rtl.full-width .image-navigation, +.ie8 .rtl.full-width .page-header, +.ie8 .rtl.full-width .page-content, +.ie8 .rtl.full-width .post-navigation, +.ie8 .rtl.full-width .site-content .entry-header, +.ie8 .rtl.full-width .site-content .entry-content, +.ie8 .rtl.full-width .site-content .entry-summary, +.ie8 .rtl.full-width .site-content footer.entry-meta { + margin-left: auto; +} + +.ie8 .rtl .contributor-avatar { + margin-right: -168px; + margin-left: auto; +} + +.ie8 .rtl .contributor-summary { + float: right; +} + +.ie8 .rtl .site:before { + right: 0; + left: auto; +} + +.ie8 .rtl #secondary { + float: right; + margin: 0 -100% 0 0; +} + +.ie8 .rtl .secondary-navigation ul ul { + right: -999em; + left: auto; +} + +.ie8 .rtl .secondary-navigation ul li:hover > ul, +.ie8 .rtl .secondary-navigation ul li.focus > ul { + right: 202px; + left: auto; +} + +.ie8 .rtl .content-sidebar { + float: left; + margin-right: -29.04761904%; + margin-left: auto; +} + +.ie8 .rtl .footer-sidebar .widget { + float: right; +} + +.ie8 .rtl .featured-content { + padding-right: 17.61904761%; + padding-left: 0; +} + +.ie8 .rtl.grid .featured-content .hentry { + float: right; +} + +.ie8 .rtl.slider .featured-content .entry-header { + right: 0; + left: auto; +} + +.ie8 .rtl .slider-control-paging { + padding-right: 24px; + padding-left: 0; +} + +.ie8 .rtl .slider-control-paging li { + margin: 12px 0 12px 12px; +} + +.ie8 .rtl .slider-control-paging a:before { + right: 6px; + left: auto; +} + +.ie8 .rtl .slider-direction-nav { + float: left; +} + +.ie8 .rtl .slider-direction-nav li { + padding: 0 1px 0 0; +} + +.ie8 .rtl .slider-direction-nav li:first-child { + padding: 0 0 0 1px; +} + + +/** + * RTL overrides for Internet Explorer 7 + */ + +.ie7 .rtl.grid .featured-content .hentry { + float: right; +} + +.ie7 .rtl .slider-control-paging { + float: none; + margin: -24px auto 0; +} + +.ie7 .rtl .entry-meta .tag-links a { + margin-right: 0; + margin-left: auto; +} + +.ie7 .rtl .search-toggle { + margin-right: auto; + margin-left: 190px; +} \ No newline at end of file diff --git a/scratch-parent/featured-content.php b/scratch-parent/featured-content.php new file mode 100644 index 00000000..64f97543 --- /dev/null +++ b/scratch-parent/featured-content.php @@ -0,0 +1,25 @@ + + + diff --git a/scratch-parent/footer.php b/scratch-parent/footer.php new file mode 100644 index 00000000..ade950d3 --- /dev/null +++ b/scratch-parent/footer.php @@ -0,0 +1,24 @@ + + + + +
+ + + +
+ + +
+
+ + + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/analytics/class-fw-extension-analytics.php b/scratch-parent/framework-customizations/extensions/analytics/class-fw-extension-analytics.php new file mode 100644 index 00000000..20fb37ca --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/analytics/class-fw-extension-analytics.php @@ -0,0 +1,80 @@ +name = __( 'Analytics', 'fw' ); + $this->admin_actions(); + } + } + + /** + * @internal + */ + private function admin_actions() { + add_action( 'admin_init', array( $this, '_admin_action_add_options' ) ); + add_action( 'admin_init', array( $this, '_admin_action_register_option' ) ); + add_action( 'admin_enqueue_scripts', array( $this, '_admin_action_register_styles' ) ); + } + + /** + * @internal + */ + public function _admin_action_register_styles() { + $current_screen = array( + 'only' => array( + array( 'base' => 'options-general' ) + ) + ); + + if ( fw_current_screen_match( $current_screen ) ) { + wp_enqueue_style( + $this->get_name() . '-styles', + $this->locate_css_URI( 'style' ), + array(), + $this->manifest->get_version() + ); + } + } + + /** + * @internal + */ + public function _admin_action_register_option() { + register_setting( 'general', 'fw-ext-' . $this->get_name() . '-code' ); + } + + /** + * @internal + */ + public function _admin_action_add_options() { + add_settings_field( + 'fw-ext-' . $this->get_name() . '-code', + $this->name, + array( $this, '_get_form' ), + 'general' + ); + } + + /** + * @internal + */ + public function _get_form() { + echo ''; + } + + public function get_analytics_code() { + return get_option( 'fw-ext-' . $this->get_name() . '-code' ); + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/analytics/helpers.php b/scratch-parent/framework-customizations/extensions/analytics/helpers.php new file mode 100644 index 00000000..a9aa40ab --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/analytics/helpers.php @@ -0,0 +1,11 @@ +extensions->get('analytics')->get_analytics_code(); +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/analytics/static/css/style.css b/scratch-parent/framework-customizations/extensions/analytics/static/css/style.css new file mode 100644 index 00000000..e44b2683 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/analytics/static/css/style.css @@ -0,0 +1,3 @@ +textarea#fw-ext-analytics-code { + width: 25em; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/breadcrumbs/index.html b/scratch-parent/framework-customizations/extensions/breadcrumbs/index.html new file mode 100644 index 00000000..71ce6922 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/breadcrumbs/index.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/breadcrumbs/views/breadcrumbs.php b/scratch-parent/framework-customizations/extensions/breadcrumbs/views/breadcrumbs.php new file mode 100644 index 00000000..0f4e186d --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/breadcrumbs/views/breadcrumbs.php @@ -0,0 +1,63 @@ + array( + * 'name' => 'Item name', + * 'url' => 'Item URL' + * ) + * ) + * Each $items array will contain additional information about item, e.g.: + * 'items' => array ( + * 0 => array ( + * 'name' => 'Homepage', + * 'type' => 'front_page', + * 'url' => 'http://yourdomain.com/', + * ), + * 1 => array ( + * 'type' => 'taxonomy', + * 'name' => 'Uncategorized', + * 'id' => 1, + * 'url' => 'http://yourdomain.com/category/uncategorized/', + * 'taxonomy' => 'category', + * ), + * 2 => array ( + * 'name' => 'Post Article', + * 'id' => 4781, + * 'post_type' => 'post', + * 'type' => 'post', + * 'url' => 'http://yourdomain.com/post-article/', + * ), + * ), + * @var string $separator , the separator symbol + */ +?> + + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/breadcrumbs/views/index.html b/scratch-parent/framework-customizations/extensions/breadcrumbs/views/index.html new file mode 100644 index 00000000..71ce6922 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/breadcrumbs/views/index.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/index.html b/scratch-parent/framework-customizations/extensions/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/config.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/config.php new file mode 100644 index 00000000..1aa01f7b --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/config.php @@ -0,0 +1,3 @@ + array( + 'label' => __('Population Method Categories opt 1', 'fw'), + 'desc' => __('Option description', 'fw'), + 'type' => 'text', + 'value' => '', + ), + 'test2' => array( + 'label' => __('Population Method Categories opt 2', 'fw'), + 'desc' => __('Option description', 'fw'), + 'type' => 'text', + 'value' => '', + ), +); + diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/options/custom.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/options/custom.php new file mode 100644 index 00000000..19146128 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/options/custom.php @@ -0,0 +1,10 @@ + array( + 'type' => 'text', + 'label' => __('Subtitle', 'fw'), + 'value' => '', + 'desc' => 'Choose a subtitle for your slide.' + ) +); + diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/options/options.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/options/options.php new file mode 100644 index 00000000..6218bf20 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/options/options.php @@ -0,0 +1,15 @@ + array( + 'label' => __('Type of Transition', 'fw'), + 'desc' => __('Type of transition between slides', 'fw'), + 'type' => 'select', + 'choices' => array( + 'horizontal' => __('Horizontal', 'fw'), + 'vertical' => __('Vertical', 'fw'), + 'fade' => __('Fade', 'fw') + ), + 'value' => 'horizontal', + ) +); diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/images/bx_loader.gif b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/images/bx_loader.gif new file mode 100644 index 00000000..f4ff40ed Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/images/bx_loader.gif differ diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/images/controls.png b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/images/controls.png new file mode 100644 index 00000000..28918dde Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/images/controls.png differ diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/jquery.bxslider.css b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/jquery.bxslider.css new file mode 100644 index 00000000..b19a5ee9 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/css/jquery.bxslider.css @@ -0,0 +1,214 @@ +/** + * BxSlider v4.1.2 - Fully loaded, responsive content slider + * http://bxslider.com + * + * Written by: Steven Wanderski, 2014 + * http://stevenwanderski.com + * (while drinking Belgian ales and listening to jazz) + * + * CEO and founder of bxCreative, LTD + * http://bxcreative.com + */ + + +/** RESET AND LAYOUT +===================================*/ + +.bx-wrapper { + position: relative; + margin: 0 auto 60px; + padding: 0; + *zoom: 1; +} + +.bx-wrapper img { + max-width: 100%; + display: block; +} + +/** THEME +===================================*/ + +.bx-wrapper .bx-viewport { + -moz-box-shadow: 0 0 5px #ccc; + -webkit-box-shadow: 0 0 5px #ccc; + box-shadow: 0 0 5px #ccc; + border: 5px solid #fff; + left: -5px; + background: #fff; + + /*fix other elements on the page moving (on Chrome)*/ + -webkit-transform: translatez(0); + -moz-transform: translatez(0); + -ms-transform: translatez(0); + -o-transform: translatez(0); + transform: translatez(0); +} + +.bx-wrapper .bx-pager, +.bx-wrapper .bx-controls-auto { + position: absolute; + bottom: -30px; + width: 100%; +} + +/* LOADER */ + +.bx-wrapper .bx-loading { + min-height: 50px; + background: url(images/bx_loader.gif) center center no-repeat #fff; + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 2000; +} + +/* PAGER */ + +.bx-wrapper .bx-pager { + text-align: center; + font-size: .85em; + font-family: Arial; + font-weight: bold; + color: #666; + padding-top: 20px; +} + +.bx-wrapper .bx-pager .bx-pager-item, +.bx-wrapper .bx-controls-auto .bx-controls-auto-item { + display: inline-block; + *zoom: 1; + *display: inline; +} + +.bx-wrapper .bx-pager.bx-default-pager a { + background: #666; + text-indent: -9999px; + display: block; + width: 10px; + height: 10px; + margin: 0 5px; + outline: 0; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +.bx-wrapper .bx-pager.bx-default-pager a:hover, +.bx-wrapper .bx-pager.bx-default-pager a.active { + background: #000; +} + +/* DIRECTION CONTROLS (NEXT / PREV) */ + +.bx-wrapper .bx-prev { + left: 10px; + background: url(images/controls.png) no-repeat 0 -32px; +} + +.bx-wrapper .bx-next { + right: 10px; + background: url(images/controls.png) no-repeat -43px -32px; +} + +.bx-wrapper .bx-prev:hover { + background-position: 0 0; +} + +.bx-wrapper .bx-next:hover { + background-position: -43px 0; +} + +.bx-wrapper .bx-controls-direction a { + position: absolute; + top: 50%; + margin-top: -16px; + outline: 0; + width: 32px; + height: 32px; + text-indent: -9999px; + z-index: 9999; +} + +.bx-wrapper .bx-controls-direction a.disabled { + display: none; +} + +/* AUTO CONTROLS (START / STOP) */ + +.bx-wrapper .bx-controls-auto { + text-align: center; +} + +.bx-wrapper .bx-controls-auto .bx-start { + display: block; + text-indent: -9999px; + width: 10px; + height: 11px; + outline: 0; + background: url(images/controls.png) -86px -11px no-repeat; + margin: 0 3px; +} + +.bx-wrapper .bx-controls-auto .bx-start:hover, +.bx-wrapper .bx-controls-auto .bx-start.active { + background-position: -86px 0; +} + +.bx-wrapper .bx-controls-auto .bx-stop { + display: block; + text-indent: -9999px; + width: 9px; + height: 11px; + outline: 0; + background: url(images/controls.png) -86px -44px no-repeat; + margin: 0 3px; +} + +.bx-wrapper .bx-controls-auto .bx-stop:hover, +.bx-wrapper .bx-controls-auto .bx-stop.active { + background-position: -86px -33px; +} + +/* PAGER WITH AUTO-CONTROLS HYBRID LAYOUT */ + +.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager { + text-align: left; + width: 80%; +} + +.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto { + right: 0; + width: 35px; +} + +/* IMAGE CAPTIONS */ + +.bx-wrapper .bx-caption { + position: absolute; + bottom: 0; + left: 0; + background: #666\9; + background: rgba(80, 80, 80, 0.75); + width: 100%; +} + +.bx-wrapper .bx-caption span { + color: #fff; + font-family: Arial; + display: block; + font-size: .85em; + padding: 10px; +} + +.bx-wrapper ul{ + margin: 0px; +} + +.bx-wrapper iframe{ + margin: 0px; + padding: 0px; + float: left; +} diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/images/preview.jpg b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/images/preview.jpg new file mode 100644 index 00000000..7e1ed674 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/images/preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/images/thumb.jpg b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/images/thumb.jpg new file mode 100644 index 00000000..a8222fe9 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/images/thumb.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/bxslider.js b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/bxslider.js new file mode 100644 index 00000000..c0413dff --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/bxslider.js @@ -0,0 +1,1343 @@ +/** + * BxSlider v4.1.2 - Fully loaded, responsive content slider + * http://bxslider.com + * + * Copyright 2014, Steven Wanderski - http://stevenwanderski.com - http://bxcreative.com + * Written while drinking Belgian ales and listening to jazz + * + * Released under the MIT license - http://opensource.org/licenses/MIT + */ + +;(function($){ + + var plugin = {}; + + var defaults = { + + // GENERAL + mode: 'horizontal', + slideSelector: '', + infiniteLoop: true, + hideControlOnEnd: false, + speed: 500, + easing: null, + slideMargin: 0, + startSlide: 0, + randomStart: false, + captions: false, + ticker: false, + tickerHover: false, + adaptiveHeight: false, + adaptiveHeightSpeed: 500, + video: false, + useCSS: true, + preloadImages: 'visible', + responsive: true, + slideZIndex: 50, + wrapperClass: 'bx-wrapper', + + // TOUCH + touchEnabled: true, + swipeThreshold: 50, + oneToOneTouch: true, + preventDefaultSwipeX: true, + preventDefaultSwipeY: false, + + // PAGER + pager: true, + pagerType: 'full', + pagerShortSeparator: ' / ', + pagerSelector: null, + buildPager: null, + pagerCustom: null, + + // CONTROLS + controls: true, + nextText: 'Next', + prevText: 'Prev', + nextSelector: null, + prevSelector: null, + autoControls: false, + startText: 'Start', + stopText: 'Stop', + autoControlsCombine: false, + autoControlsSelector: null, + + // AUTO + auto: false, + pause: 4000, + autoStart: true, + autoDirection: 'next', + autoHover: false, + autoDelay: 0, + autoSlideForOnePage: false, + + // CAROUSEL + minSlides: 1, + maxSlides: 1, + moveSlides: 0, + slideWidth: 0, + + // CALLBACKS + onSliderLoad: function() {}, + onSlideBefore: function() {}, + onSlideAfter: function() {}, + onSlideNext: function() {}, + onSlidePrev: function() {}, + onSliderResize: function() {} + } + + $.fn.bxSlider = function(options){ + + if(this.length == 0) return this; + + // support mutltiple elements + if(this.length > 1){ + this.each(function(){$(this).bxSlider(options)}); + return this; + } + + // create a namespace to be used throughout the plugin + var slider = {}; + // set a reference to our slider element + var el = this; + plugin.el = this; + + /** + * Makes slideshow responsive + */ + // first get the original window dimens (thanks alot IE) + var windowWidth = $(window).width(); + var windowHeight = $(window).height(); + + + + /** + * =================================================================================== + * = PRIVATE FUNCTIONS + * =================================================================================== + */ + + /** + * Initializes namespace settings to be used throughout plugin + */ + var init = function(){ + // merge user-supplied options with the defaults + slider.settings = $.extend({}, defaults, options); + // parse slideWidth setting + slider.settings.slideWidth = parseInt(slider.settings.slideWidth); + // store the original children + slider.children = el.children(slider.settings.slideSelector); + // check if actual number of slides is less than minSlides / maxSlides + if(slider.children.length < slider.settings.minSlides) slider.settings.minSlides = slider.children.length; + if(slider.children.length < slider.settings.maxSlides) slider.settings.maxSlides = slider.children.length; + // if random start, set the startSlide setting to random number + if(slider.settings.randomStart) slider.settings.startSlide = Math.floor(Math.random() * slider.children.length); + // store active slide information + slider.active = { index: slider.settings.startSlide } + // store if the slider is in carousel mode (displaying / moving multiple slides) + slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1; + // if carousel, force preloadImages = 'all' + if(slider.carousel) slider.settings.preloadImages = 'all'; + // calculate the min / max width thresholds based on min / max number of slides + // used to setup and update carousel slides dimensions + slider.minThreshold = (slider.settings.minSlides * slider.settings.slideWidth) + ((slider.settings.minSlides - 1) * slider.settings.slideMargin); + slider.maxThreshold = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin); + // store the current state of the slider (if currently animating, working is true) + slider.working = false; + // initialize the controls object + slider.controls = {}; + // initialize an auto interval + slider.interval = null; + // determine which property to use for transitions + slider.animProp = slider.settings.mode == 'vertical' ? 'top' : 'left'; + // determine if hardware acceleration can be used + slider.usingCSS = slider.settings.useCSS && slider.settings.mode != 'fade' && (function(){ + // create our test div element + var div = document.createElement('div'); + // css transition properties + var props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']; + // test for each property + for(var i in props){ + if(div.style[props[i]] !== undefined){ + slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase(); + slider.animProp = '-' + slider.cssPrefix + '-transform'; + return true; + } + } + return false; + }()); + // if vertical mode always make maxSlides and minSlides equal + if(slider.settings.mode == 'vertical') slider.settings.maxSlides = slider.settings.minSlides; + // save original style data + el.data("origStyle", el.attr("style")); + el.children(slider.settings.slideSelector).each(function() { + $(this).data("origStyle", $(this).attr("style")); + }); + // perform all DOM / CSS modifications + setup(); + } + + /** + * Performs all DOM and CSS modifications + */ + var setup = function(){ + // wrap el in a wrapper + el.wrap('
'); + // store a namspace reference to .bx-viewport + slider.viewport = el.parent(); + // add a loading div to display while images are loading + slider.loader = $('
'); + slider.viewport.prepend(slider.loader); + // set el to a massive width, to hold any needed slides + // also strip any margin and padding from el + el.css({ + width: slider.settings.mode == 'horizontal' ? (slider.children.length * 100 + 215) + '%' : 'auto', + position: 'relative' + }); + // if using CSS, add the easing property + if(slider.usingCSS && slider.settings.easing){ + el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing); + // if not using CSS and no easing value was supplied, use the default JS animation easing (swing) + }else if(!slider.settings.easing){ + slider.settings.easing = 'swing'; + } + var slidesShowing = getNumberSlidesShowing(); + // make modifications to the viewport (.bx-viewport) + slider.viewport.css({ + width: '100%', + overflow: 'hidden', + position: 'relative' + }); + slider.viewport.parent().css({ + maxWidth: getViewportMaxWidth() + }); + // make modification to the wrapper (.bx-wrapper) + if(!slider.settings.pager) { + slider.viewport.parent().css({ + margin: '0 auto 0px' + }); + } + // apply css to all slider children + slider.children.css({ + 'float': slider.settings.mode == 'horizontal' ? 'left' : 'none', + listStyle: 'none', + position: 'relative' + }); + // apply the calculated width after the float is applied to prevent scrollbar interference + slider.children.css('width', getSlideWidth()); + // if slideMargin is supplied, add the css + if(slider.settings.mode == 'horizontal' && slider.settings.slideMargin > 0) slider.children.css('marginRight', slider.settings.slideMargin); + if(slider.settings.mode == 'vertical' && slider.settings.slideMargin > 0) slider.children.css('marginBottom', slider.settings.slideMargin); + // if "fade" mode, add positioning and z-index CSS + if(slider.settings.mode == 'fade'){ + slider.children.css({ + position: 'absolute', + zIndex: 0, + display: 'none' + }); + // prepare the z-index on the showing element + slider.children.eq(slider.settings.startSlide).css({zIndex: slider.settings.slideZIndex, display: 'block'}); + } + // create an element to contain all slider controls (pager, start / stop, etc) + slider.controls.el = $('
'); + // if captions are requested, add them + if(slider.settings.captions) appendCaptions(); + // check if startSlide is last slide + slider.active.last = slider.settings.startSlide == getPagerQty() - 1; + // if video is true, set up the fitVids plugin + if(slider.settings.video) el.fitVids(); + // set the default preload selector (visible) + var preloadSelector = slider.children.eq(slider.settings.startSlide); + if (slider.settings.preloadImages == "all") preloadSelector = slider.children; + // only check for control addition if not in "ticker" mode + if(!slider.settings.ticker){ + // if pager is requested, add it + if(slider.settings.pager) appendPager(); + // if controls are requested, add them + if(slider.settings.controls) appendControls(); + // if auto is true, and auto controls are requested, add them + if(slider.settings.auto && slider.settings.autoControls) appendControlsAuto(); + // if any control option is requested, add the controls wrapper + if(slider.settings.controls || slider.settings.autoControls || slider.settings.pager) slider.viewport.after(slider.controls.el); + // if ticker mode, do not allow a pager + }else{ + slider.settings.pager = false; + } + // preload all images, then perform final DOM / CSS modifications that depend on images being loaded + loadElements(preloadSelector, start); + } + + var loadElements = function(selector, callback){ + var total = selector.find('img, iframe').length; + if (total == 0){ + callback(); + return; + } + var count = 0; + selector.find('img, iframe').each(function(){ + $(this).one('load', function() { + if(++count == total) callback(); + }).each(function() { + if(this.complete) $(this).load(); + }); + }); + } + + /** + * Start the slider + */ + var start = function(){ + // if infinite loop, prepare additional slides + if(slider.settings.infiniteLoop && slider.settings.mode != 'fade' && !slider.settings.ticker){ + var slice = slider.settings.mode == 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides; + var sliceAppend = slider.children.slice(0, slice).clone().addClass('bx-clone'); + var slicePrepend = slider.children.slice(-slice).clone().addClass('bx-clone'); + el.append(sliceAppend).prepend(slicePrepend); + } + // remove the loading DOM element + slider.loader.remove(); + // set the left / top position of "el" + setSlidePosition(); + // if "vertical" mode, always use adaptiveHeight to prevent odd behavior + if (slider.settings.mode == 'vertical') slider.settings.adaptiveHeight = true; + // set the viewport height + slider.viewport.height(getViewportHeight()); + // make sure everything is positioned just right (same as a window resize) + el.redrawSlider(); + // onSliderLoad callback + slider.settings.onSliderLoad(slider.active.index); + // slider has been fully initialized + slider.initialized = true; + // bind the resize call to the window + if (slider.settings.responsive) $(window).bind('resize', resizeWindow); + // if auto is true and has more than 1 page, start the show + if (slider.settings.auto && slider.settings.autoStart && (getPagerQty() > 1 || slider.settings.autoSlideForOnePage)) initAuto(); + // if ticker is true, start the ticker + if (slider.settings.ticker) initTicker(); + // if pager is requested, make the appropriate pager link active + if (slider.settings.pager) updatePagerActive(slider.settings.startSlide); + // check for any updates to the controls (like hideControlOnEnd updates) + if (slider.settings.controls) updateDirectionControls(); + // if touchEnabled is true, setup the touch events + if (slider.settings.touchEnabled && !slider.settings.ticker) initTouch(); + } + + /** + * Returns the calculated height of the viewport, used to determine either adaptiveHeight or the maxHeight value + */ + var getViewportHeight = function(){ + var height = 0; + // first determine which children (slides) should be used in our height calculation + var children = $(); + // if mode is not "vertical" and adaptiveHeight is false, include all children + if(slider.settings.mode != 'vertical' && !slider.settings.adaptiveHeight){ + children = slider.children; + }else{ + // if not carousel, return the single active child + if(!slider.carousel){ + children = slider.children.eq(slider.active.index); + // if carousel, return a slice of children + }else{ + // get the individual slide index + var currentIndex = slider.settings.moveSlides == 1 ? slider.active.index : slider.active.index * getMoveBy(); + // add the current slide to the children + children = slider.children.eq(currentIndex); + // cycle through the remaining "showing" slides + for (i = 1; i <= slider.settings.maxSlides - 1; i++){ + // if looped back to the start + if(currentIndex + i >= slider.children.length){ + children = children.add(slider.children.eq(i - 1)); + }else{ + children = children.add(slider.children.eq(currentIndex + i)); + } + } + } + } + // if "vertical" mode, calculate the sum of the heights of the children + if(slider.settings.mode == 'vertical'){ + children.each(function(index) { + height += $(this).outerHeight(); + }); + // add user-supplied margins + if(slider.settings.slideMargin > 0){ + height += slider.settings.slideMargin * (slider.settings.minSlides - 1); + } + // if not "vertical" mode, calculate the max height of the children + }else{ + height = Math.max.apply(Math, children.map(function(){ + return $(this).outerHeight(false); + }).get()); + } + + if(slider.viewport.css('box-sizing') == 'border-box'){ + height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')) + + parseFloat(slider.viewport.css('border-top-width')) + parseFloat(slider.viewport.css('border-bottom-width')); + }else if(slider.viewport.css('box-sizing') == 'padding-box'){ + height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')); + } + + return height; + } + + /** + * Returns the calculated width to be used for the outer wrapper / viewport + */ + var getViewportMaxWidth = function(){ + var width = '100%'; + if(slider.settings.slideWidth > 0){ + if(slider.settings.mode == 'horizontal'){ + width = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin); + }else{ + width = slider.settings.slideWidth; + } + } + return width; + } + + /** + * Returns the calculated width to be applied to each slide + */ + var getSlideWidth = function(){ + // start with any user-supplied slide width + var newElWidth = slider.settings.slideWidth; + // get the current viewport width + var wrapWidth = slider.viewport.width(); + // if slide width was not supplied, or is larger than the viewport use the viewport width + if(slider.settings.slideWidth == 0 || + (slider.settings.slideWidth > wrapWidth && !slider.carousel) || + slider.settings.mode == 'vertical'){ + newElWidth = wrapWidth; + // if carousel, use the thresholds to determine the width + }else if(slider.settings.maxSlides > 1 && slider.settings.mode == 'horizontal'){ + if(wrapWidth > slider.maxThreshold){ + // newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.maxSlides - 1))) / slider.settings.maxSlides; + }else if(wrapWidth < slider.minThreshold){ + newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.minSlides - 1))) / slider.settings.minSlides; + } + } + return newElWidth; + } + + /** + * Returns the number of slides currently visible in the viewport (includes partially visible slides) + */ + var getNumberSlidesShowing = function(){ + var slidesShowing = 1; + if(slider.settings.mode == 'horizontal' && slider.settings.slideWidth > 0){ + // if viewport is smaller than minThreshold, return minSlides + if(slider.viewport.width() < slider.minThreshold){ + slidesShowing = slider.settings.minSlides; + // if viewport is larger than minThreshold, return maxSlides + }else if(slider.viewport.width() > slider.maxThreshold){ + slidesShowing = slider.settings.maxSlides; + // if viewport is between min / max thresholds, divide viewport width by first child width + }else{ + var childWidth = slider.children.first().width() + slider.settings.slideMargin; + slidesShowing = Math.floor((slider.viewport.width() + + slider.settings.slideMargin) / childWidth); + } + // if "vertical" mode, slides showing will always be minSlides + }else if(slider.settings.mode == 'vertical'){ + slidesShowing = slider.settings.minSlides; + } + return slidesShowing; + } + + /** + * Returns the number of pages (one full viewport of slides is one "page") + */ + var getPagerQty = function(){ + var pagerQty = 0; + // if moveSlides is specified by the user + if(slider.settings.moveSlides > 0){ + if(slider.settings.infiniteLoop){ + pagerQty = Math.ceil(slider.children.length / getMoveBy()); + }else{ + // use a while loop to determine pages + var breakPoint = 0; + var counter = 0 + // when breakpoint goes above children length, counter is the number of pages + while (breakPoint < slider.children.length){ + ++pagerQty; + breakPoint = counter + getNumberSlidesShowing(); + counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing(); + } + } + // if moveSlides is 0 (auto) divide children length by sides showing, then round up + }else{ + pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing()); + } + return pagerQty; + } + + /** + * Returns the number of indivual slides by which to shift the slider + */ + var getMoveBy = function(){ + // if moveSlides was set by the user and moveSlides is less than number of slides showing + if(slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()){ + return slider.settings.moveSlides; + } + // if moveSlides is 0 (auto) + return getNumberSlidesShowing(); + } + + /** + * Sets the slider's (el) left or top position + */ + var setSlidePosition = function(){ + // if last slide, not infinite loop, and number of children is larger than specified maxSlides + if(slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop){ + if (slider.settings.mode == 'horizontal'){ + // get the last child's position + var lastChild = slider.children.last(); + var position = lastChild.position(); + // set the left position + setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.outerWidth())), 'reset', 0); + }else if(slider.settings.mode == 'vertical'){ + // get the last showing index's position + var lastShowingIndex = slider.children.length - slider.settings.minSlides; + var position = slider.children.eq(lastShowingIndex).position(); + // set the top position + setPositionProperty(-position.top, 'reset', 0); + } + // if not last slide + }else{ + // get the position of the first showing slide + var position = slider.children.eq(slider.active.index * getMoveBy()).position(); + // check for last slide + if (slider.active.index == getPagerQty() - 1) slider.active.last = true; + // set the repective position + if (position != undefined){ + if (slider.settings.mode == 'horizontal') setPositionProperty(-position.left, 'reset', 0); + else if (slider.settings.mode == 'vertical') setPositionProperty(-position.top, 'reset', 0); + } + } + } + + /** + * Sets the el's animating property position (which in turn will sometimes animate el). + * If using CSS, sets the transform property. If not using CSS, sets the top / left property. + * + * @param value (int) + * - the animating property's value + * + * @param type (string) 'slider', 'reset', 'ticker' + * - the type of instance for which the function is being + * + * @param duration (int) + * - the amount of time (in ms) the transition should occupy + * + * @param params (array) optional + * - an optional parameter containing any variables that need to be passed in + */ + var setPositionProperty = function(value, type, duration, params){ + // use CSS transform + if(slider.usingCSS){ + // determine the translate3d value + var propValue = slider.settings.mode == 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)'; + // add the CSS transition-duration + el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's'); + if(type == 'slide'){ + // set the property value + el.css(slider.animProp, propValue); + // bind a callback method - executes when CSS transition completes + el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(){ + // unbind the callback + el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'); + updateAfterSlideTransition(); + }); + }else if(type == 'reset'){ + el.css(slider.animProp, propValue); + }else if(type == 'ticker'){ + // make the transition use 'linear' + el.css('-' + slider.cssPrefix + '-transition-timing-function', 'linear'); + el.css(slider.animProp, propValue); + // bind a callback method - executes when CSS transition completes + el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(){ + // unbind the callback + el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'); + // reset the position + setPositionProperty(params['resetValue'], 'reset', 0); + // start the loop again + tickerLoop(); + }); + } + // use JS animate + }else{ + var animateObj = {}; + animateObj[slider.animProp] = value; + if(type == 'slide'){ + el.animate(animateObj, duration, slider.settings.easing, function(){ + updateAfterSlideTransition(); + }); + }else if(type == 'reset'){ + el.css(slider.animProp, value) + }else if(type == 'ticker'){ + el.animate(animateObj, speed, 'linear', function(){ + setPositionProperty(params['resetValue'], 'reset', 0); + // run the recursive loop after animation + tickerLoop(); + }); + } + } + } + + /** + * Populates the pager with proper amount of pages + */ + var populatePager = function(){ + var pagerHtml = ''; + var pagerQty = getPagerQty(); + // loop through each pager item + for(var i=0; i < pagerQty; i++){ + var linkContent = ''; + // if a buildPager function is supplied, use it to get pager link value, else use index + 1 + if(slider.settings.buildPager && $.isFunction(slider.settings.buildPager)){ + linkContent = slider.settings.buildPager(i); + slider.pagerEl.addClass('bx-custom-pager'); + }else{ + linkContent = i + 1; + slider.pagerEl.addClass('bx-default-pager'); + } + // var linkContent = slider.settings.buildPager && $.isFunction(slider.settings.buildPager) ? slider.settings.buildPager(i) : i + 1; + // add the markup to the string + pagerHtml += ''; + }; + // populate the pager element with pager links + slider.pagerEl.html(pagerHtml); + } + + /** + * Appends the pager to the controls element + */ + var appendPager = function(){ + if(!slider.settings.pagerCustom){ + // create the pager DOM element + slider.pagerEl = $('
'); + // if a pager selector was supplied, populate it with the pager + if(slider.settings.pagerSelector){ + $(slider.settings.pagerSelector).html(slider.pagerEl); + // if no pager selector was supplied, add it after the wrapper + }else{ + slider.controls.el.addClass('bx-has-pager').append(slider.pagerEl); + } + // populate the pager + populatePager(); + }else{ + slider.pagerEl = $(slider.settings.pagerCustom); + } + // assign the pager click binding + slider.pagerEl.on('click', 'a', clickPagerBind); + } + + /** + * Appends prev / next controls to the controls element + */ + var appendControls = function(){ + slider.controls.next = $('' + slider.settings.nextText + ''); + slider.controls.prev = $('' + slider.settings.prevText + ''); + // bind click actions to the controls + slider.controls.next.bind('click', clickNextBind); + slider.controls.prev.bind('click', clickPrevBind); + // if nextSlector was supplied, populate it + if(slider.settings.nextSelector){ + $(slider.settings.nextSelector).append(slider.controls.next); + } + // if prevSlector was supplied, populate it + if(slider.settings.prevSelector){ + $(slider.settings.prevSelector).append(slider.controls.prev); + } + // if no custom selectors were supplied + if(!slider.settings.nextSelector && !slider.settings.prevSelector){ + // add the controls to the DOM + slider.controls.directionEl = $('
'); + // add the control elements to the directionEl + slider.controls.directionEl.append(slider.controls.prev).append(slider.controls.next); + // slider.viewport.append(slider.controls.directionEl); + slider.controls.el.addClass('bx-has-controls-direction').append(slider.controls.directionEl); + } + } + + /** + * Appends start / stop auto controls to the controls element + */ + var appendControlsAuto = function(){ + slider.controls.start = $(''); + slider.controls.stop = $(''); + // add the controls to the DOM + slider.controls.autoEl = $('
'); + // bind click actions to the controls + slider.controls.autoEl.on('click', '.bx-start', clickStartBind); + slider.controls.autoEl.on('click', '.bx-stop', clickStopBind); + // if autoControlsCombine, insert only the "start" control + if(slider.settings.autoControlsCombine){ + slider.controls.autoEl.append(slider.controls.start); + // if autoControlsCombine is false, insert both controls + }else{ + slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop); + } + // if auto controls selector was supplied, populate it with the controls + if(slider.settings.autoControlsSelector){ + $(slider.settings.autoControlsSelector).html(slider.controls.autoEl); + // if auto controls selector was not supplied, add it after the wrapper + }else{ + slider.controls.el.addClass('bx-has-controls-auto').append(slider.controls.autoEl); + } + // update the auto controls + updateAutoControls(slider.settings.autoStart ? 'stop' : 'start'); + } + + /** + * Appends image captions to the DOM + */ + var appendCaptions = function(){ + // cycle through each child + slider.children.each(function(index){ + // get the image title attribute + var title = $(this).find('img:first').attr('title'); + // append the caption + if (title != undefined && ('' + title).length) { + $(this).append('
' + title + '
'); + } + }); + } + + /** + * Click next binding + * + * @param e (event) + * - DOM event object + */ + var clickNextBind = function(e){ + // if auto show is running, stop it + if (slider.settings.auto) el.stopAuto(); + el.goToNextSlide(); + e.preventDefault(); + } + + /** + * Click prev binding + * + * @param e (event) + * - DOM event object + */ + var clickPrevBind = function(e){ + // if auto show is running, stop it + if (slider.settings.auto) el.stopAuto(); + el.goToPrevSlide(); + e.preventDefault(); + } + + /** + * Click start binding + * + * @param e (event) + * - DOM event object + */ + var clickStartBind = function(e){ + el.startAuto(); + e.preventDefault(); + } + + /** + * Click stop binding + * + * @param e (event) + * - DOM event object + */ + var clickStopBind = function(e){ + el.stopAuto(); + e.preventDefault(); + } + + /** + * Click pager binding + * + * @param e (event) + * - DOM event object + */ + var clickPagerBind = function(e){ + // if auto show is running, stop it + if (slider.settings.auto) el.stopAuto(); + var pagerLink = $(e.currentTarget); + if(pagerLink.attr('data-slide-index') !== undefined){ + var pagerIndex = parseInt(pagerLink.attr('data-slide-index')); + // if clicked pager link is not active, continue with the goToSlide call + if(pagerIndex != slider.active.index) el.goToSlide(pagerIndex); + e.preventDefault(); + } + } + + /** + * Updates the pager links with an active class + * + * @param slideIndex (int) + * - index of slide to make active + */ + var updatePagerActive = function(slideIndex){ + // if "short" pager type + var len = slider.children.length; // nb of children + if(slider.settings.pagerType == 'short'){ + if(slider.settings.maxSlides > 1) { + len = Math.ceil(slider.children.length/slider.settings.maxSlides); + } + slider.pagerEl.html( (slideIndex + 1) + slider.settings.pagerShortSeparator + len); + return; + } + // remove all pager active classes + slider.pagerEl.find('a').removeClass('active'); + // apply the active class for all pagers + slider.pagerEl.each(function(i, el) { $(el).find('a').eq(slideIndex).addClass('active'); }); + } + + /** + * Performs needed actions after a slide transition + */ + var updateAfterSlideTransition = function(){ + // if infinte loop is true + if(slider.settings.infiniteLoop){ + var position = ''; + // first slide + if(slider.active.index == 0){ + // set the new position + position = slider.children.eq(0).position(); + // carousel, last slide + }else if(slider.active.index == getPagerQty() - 1 && slider.carousel){ + position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position(); + // last slide + }else if(slider.active.index == slider.children.length - 1){ + position = slider.children.eq(slider.children.length - 1).position(); + } + if(position){ + if (slider.settings.mode == 'horizontal') { setPositionProperty(-position.left, 'reset', 0); } + else if (slider.settings.mode == 'vertical') { setPositionProperty(-position.top, 'reset', 0); } + } + } + // declare that the transition is complete + slider.working = false; + // onSlideAfter callback + slider.settings.onSlideAfter(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); + } + + /** + * Updates the auto controls state (either active, or combined switch) + * + * @param state (string) "start", "stop" + * - the new state of the auto show + */ + var updateAutoControls = function(state){ + // if autoControlsCombine is true, replace the current control with the new state + if(slider.settings.autoControlsCombine){ + slider.controls.autoEl.html(slider.controls[state]); + // if autoControlsCombine is false, apply the "active" class to the appropriate control + }else{ + slider.controls.autoEl.find('a').removeClass('active'); + slider.controls.autoEl.find('a:not(.bx-' + state + ')').addClass('active'); + } + } + + /** + * Updates the direction controls (checks if either should be hidden) + */ + var updateDirectionControls = function(){ + if(getPagerQty() == 1){ + slider.controls.prev.addClass('disabled'); + slider.controls.next.addClass('disabled'); + }else if(!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd){ + // if first slide + if (slider.active.index == 0){ + slider.controls.prev.addClass('disabled'); + slider.controls.next.removeClass('disabled'); + // if last slide + }else if(slider.active.index == getPagerQty() - 1){ + slider.controls.next.addClass('disabled'); + slider.controls.prev.removeClass('disabled'); + // if any slide in the middle + }else{ + slider.controls.prev.removeClass('disabled'); + slider.controls.next.removeClass('disabled'); + } + } + } + + /** + * Initialzes the auto process + */ + var initAuto = function(){ + // if autoDelay was supplied, launch the auto show using a setTimeout() call + if(slider.settings.autoDelay > 0){ + var timeout = setTimeout(el.startAuto, slider.settings.autoDelay); + // if autoDelay was not supplied, start the auto show normally + }else{ + el.startAuto(); + } + // if autoHover is requested + if(slider.settings.autoHover){ + // on el hover + el.hover(function(){ + // if the auto show is currently playing (has an active interval) + if(slider.interval){ + // stop the auto show and pass true agument which will prevent control update + el.stopAuto(true); + // create a new autoPaused value which will be used by the relative "mouseout" event + slider.autoPaused = true; + } + }, function(){ + // if the autoPaused value was created be the prior "mouseover" event + if(slider.autoPaused){ + // start the auto show and pass true agument which will prevent control update + el.startAuto(true); + // reset the autoPaused value + slider.autoPaused = null; + } + }); + } + } + + /** + * Initialzes the ticker process + */ + var initTicker = function(){ + var startPosition = 0; + // if autoDirection is "next", append a clone of the entire slider + if(slider.settings.autoDirection == 'next'){ + el.append(slider.children.clone().addClass('bx-clone')); + // if autoDirection is "prev", prepend a clone of the entire slider, and set the left position + }else{ + el.prepend(slider.children.clone().addClass('bx-clone')); + var position = slider.children.first().position(); + startPosition = slider.settings.mode == 'horizontal' ? -position.left : -position.top; + } + setPositionProperty(startPosition, 'reset', 0); + // do not allow controls in ticker mode + slider.settings.pager = false; + slider.settings.controls = false; + slider.settings.autoControls = false; + // if autoHover is requested + if(slider.settings.tickerHover && !slider.usingCSS){ + // on el hover + slider.viewport.hover(function(){ + el.stop(); + }, function(){ + // calculate the total width of children (used to calculate the speed ratio) + var totalDimens = 0; + slider.children.each(function(index){ + totalDimens += slider.settings.mode == 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true); + }); + // calculate the speed ratio (used to determine the new speed to finish the paused animation) + var ratio = slider.settings.speed / totalDimens; + // determine which property to use + var property = slider.settings.mode == 'horizontal' ? 'left' : 'top'; + // calculate the new speed + var newSpeed = ratio * (totalDimens - (Math.abs(parseInt(el.css(property))))); + tickerLoop(newSpeed); + }); + } + // start the ticker loop + tickerLoop(); + } + + /** + * Runs a continuous loop, news ticker-style + */ + var tickerLoop = function(resumeSpeed){ + speed = resumeSpeed ? resumeSpeed : slider.settings.speed; + var position = {left: 0, top: 0}; + var reset = {left: 0, top: 0}; + // if "next" animate left position to last child, then reset left to 0 + if(slider.settings.autoDirection == 'next'){ + position = el.find('.bx-clone').first().position(); + // if "prev" animate left position to 0, then reset left to first non-clone child + }else{ + reset = slider.children.first().position(); + } + var animateProperty = slider.settings.mode == 'horizontal' ? -position.left : -position.top; + var resetValue = slider.settings.mode == 'horizontal' ? -reset.left : -reset.top; + var params = {resetValue: resetValue}; + setPositionProperty(animateProperty, 'ticker', speed, params); + } + + /** + * Initializes touch events + */ + var initTouch = function(){ + // initialize object to contain all touch values + slider.touch = { + start: {x: 0, y: 0}, + end: {x: 0, y: 0} + } + slider.viewport.bind('touchstart', onTouchStart); + } + + /** + * Event handler for "touchstart" + * + * @param e (event) + * - DOM event object + */ + var onTouchStart = function(e){ + if(slider.working){ + e.preventDefault(); + }else{ + // record the original position when touch starts + slider.touch.originalPos = el.position(); + var orig = e.originalEvent; + // record the starting touch x, y coordinates + slider.touch.start.x = orig.changedTouches[0].pageX; + slider.touch.start.y = orig.changedTouches[0].pageY; + // bind a "touchmove" event to the viewport + slider.viewport.bind('touchmove', onTouchMove); + // bind a "touchend" event to the viewport + slider.viewport.bind('touchend', onTouchEnd); + } + } + + /** + * Event handler for "touchmove" + * + * @param e (event) + * - DOM event object + */ + var onTouchMove = function(e){ + var orig = e.originalEvent; + // if scrolling on y axis, do not prevent default + var xMovement = Math.abs(orig.changedTouches[0].pageX - slider.touch.start.x); + var yMovement = Math.abs(orig.changedTouches[0].pageY - slider.touch.start.y); + // x axis swipe + if((xMovement * 3) > yMovement && slider.settings.preventDefaultSwipeX){ + e.preventDefault(); + // y axis swipe + }else if((yMovement * 3) > xMovement && slider.settings.preventDefaultSwipeY){ + e.preventDefault(); + } + if(slider.settings.mode != 'fade' && slider.settings.oneToOneTouch){ + var value = 0; + // if horizontal, drag along x axis + if(slider.settings.mode == 'horizontal'){ + var change = orig.changedTouches[0].pageX - slider.touch.start.x; + value = slider.touch.originalPos.left + change; + // if vertical, drag along y axis + }else{ + var change = orig.changedTouches[0].pageY - slider.touch.start.y; + value = slider.touch.originalPos.top + change; + } + setPositionProperty(value, 'reset', 0); + } + } + + /** + * Event handler for "touchend" + * + * @param e (event) + * - DOM event object + */ + var onTouchEnd = function(e){ + slider.viewport.unbind('touchmove', onTouchMove); + var orig = e.originalEvent; + var value = 0; + // record end x, y positions + slider.touch.end.x = orig.changedTouches[0].pageX; + slider.touch.end.y = orig.changedTouches[0].pageY; + // if fade mode, check if absolute x distance clears the threshold + if(slider.settings.mode == 'fade'){ + var distance = Math.abs(slider.touch.start.x - slider.touch.end.x); + if(distance >= slider.settings.swipeThreshold){ + slider.touch.start.x > slider.touch.end.x ? el.goToNextSlide() : el.goToPrevSlide(); + el.stopAuto(); + } + // not fade mode + }else{ + var distance = 0; + // calculate distance and el's animate property + if(slider.settings.mode == 'horizontal'){ + distance = slider.touch.end.x - slider.touch.start.x; + value = slider.touch.originalPos.left; + }else{ + distance = slider.touch.end.y - slider.touch.start.y; + value = slider.touch.originalPos.top; + } + // if not infinite loop and first / last slide, do not attempt a slide transition + if(!slider.settings.infiniteLoop && ((slider.active.index == 0 && distance > 0) || (slider.active.last && distance < 0))){ + setPositionProperty(value, 'reset', 200); + }else{ + // check if distance clears threshold + if(Math.abs(distance) >= slider.settings.swipeThreshold){ + distance < 0 ? el.goToNextSlide() : el.goToPrevSlide(); + el.stopAuto(); + }else{ + // el.animate(property, 200); + setPositionProperty(value, 'reset', 200); + } + } + } + slider.viewport.unbind('touchend', onTouchEnd); + } + + /** + * Window resize event callback + */ + var resizeWindow = function(e){ + // don't do anything if slider isn't initialized. + if(!slider.initialized) return; + // get the new window dimens (again, thank you IE) + var windowWidthNew = $(window).width(); + var windowHeightNew = $(window).height(); + // make sure that it is a true window resize + // *we must check this because our dinosaur friend IE fires a window resize event when certain DOM elements + // are resized. Can you just die already?* + if(windowWidth != windowWidthNew || windowHeight != windowHeightNew){ + // set the new window dimens + windowWidth = windowWidthNew; + windowHeight = windowHeightNew; + // update all dynamic elements + el.redrawSlider(); + // Call user resize handler + slider.settings.onSliderResize.call(el, slider.active.index); + } + } + + /** + * =================================================================================== + * = PUBLIC FUNCTIONS + * =================================================================================== + */ + + /** + * Performs slide transition to the specified slide + * + * @param slideIndex (int) + * - the destination slide's index (zero-based) + * + * @param direction (string) + * - INTERNAL USE ONLY - the direction of travel ("prev" / "next") + */ + el.goToSlide = function(slideIndex, direction){ + // if plugin is currently in motion, ignore request + if(slider.working || slider.active.index == slideIndex) return; + // declare that plugin is in motion + slider.working = true; + // store the old index + slider.oldIndex = slider.active.index; + // if slideIndex is less than zero, set active index to last child (this happens during infinite loop) + if(slideIndex < 0){ + slider.active.index = getPagerQty() - 1; + // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop) + }else if(slideIndex >= getPagerQty()){ + slider.active.index = 0; + // set active index to requested slide + }else{ + slider.active.index = slideIndex; + } + // onSlideBefore, onSlideNext, onSlidePrev callbacks + slider.settings.onSlideBefore(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); + if(direction == 'next'){ + slider.settings.onSlideNext(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); + }else if(direction == 'prev'){ + slider.settings.onSlidePrev(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); + } + // check if last slide + slider.active.last = slider.active.index >= getPagerQty() - 1; + // update the pager with active class + if(slider.settings.pager) updatePagerActive(slider.active.index); + // // check for direction control update + if(slider.settings.controls) updateDirectionControls(); + // if slider is set to mode: "fade" + if(slider.settings.mode == 'fade'){ + // if adaptiveHeight is true and next height is different from current height, animate to the new height + if(slider.settings.adaptiveHeight && slider.viewport.height() != getViewportHeight()){ + slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed); + } + // fade out the visible child and reset its z-index value + slider.children.filter(':visible').fadeOut(slider.settings.speed).css({zIndex: 0}); + // fade in the newly requested slide + slider.children.eq(slider.active.index).css('zIndex', slider.settings.slideZIndex+1).fadeIn(slider.settings.speed, function(){ + $(this).css('zIndex', slider.settings.slideZIndex); + updateAfterSlideTransition(); + }); + // slider mode is not "fade" + }else{ + // if adaptiveHeight is true and next height is different from current height, animate to the new height + if(slider.settings.adaptiveHeight && slider.viewport.height() != getViewportHeight()){ + slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed); + } + var moveBy = 0; + var position = {left: 0, top: 0}; + // if carousel and not infinite loop + if(!slider.settings.infiniteLoop && slider.carousel && slider.active.last){ + if(slider.settings.mode == 'horizontal'){ + // get the last child position + var lastChild = slider.children.eq(slider.children.length - 1); + position = lastChild.position(); + // calculate the position of the last slide + moveBy = slider.viewport.width() - lastChild.outerWidth(); + }else{ + // get last showing index position + var lastShowingIndex = slider.children.length - slider.settings.minSlides; + position = slider.children.eq(lastShowingIndex).position(); + } + // horizontal carousel, going previous while on first slide (infiniteLoop mode) + }else if(slider.carousel && slider.active.last && direction == 'prev'){ + // get the last child position + var eq = slider.settings.moveSlides == 1 ? slider.settings.maxSlides - getMoveBy() : ((getPagerQty() - 1) * getMoveBy()) - (slider.children.length - slider.settings.maxSlides); + var lastChild = el.children('.bx-clone').eq(eq); + position = lastChild.position(); + // if infinite loop and "Next" is clicked on the last slide + }else if(direction == 'next' && slider.active.index == 0){ + // get the last clone position + position = el.find('> .bx-clone').eq(slider.settings.maxSlides).position(); + slider.active.last = false; + // normal non-zero requests + }else if(slideIndex >= 0){ + var requestEl = slideIndex * getMoveBy(); + position = slider.children.eq(requestEl).position(); + } + + /* If the position doesn't exist + * (e.g. if you destroy the slider on a next click), + * it doesn't throw an error. + */ + if ("undefined" !== typeof(position)) { + var value = slider.settings.mode == 'horizontal' ? -(position.left - moveBy) : -position.top; + // plugin values to be animated + setPositionProperty(value, 'slide', slider.settings.speed); + } + } + } + + /** + * Transitions to the next slide in the show + */ + el.goToNextSlide = function(){ + // if infiniteLoop is false and last page is showing, disregard call + if (!slider.settings.infiniteLoop && slider.active.last) return; + var pagerIndex = parseInt(slider.active.index) + 1; + el.goToSlide(pagerIndex, 'next'); + } + + /** + * Transitions to the prev slide in the show + */ + el.goToPrevSlide = function(){ + // if infiniteLoop is false and last page is showing, disregard call + if (!slider.settings.infiniteLoop && slider.active.index == 0) return; + var pagerIndex = parseInt(slider.active.index) - 1; + el.goToSlide(pagerIndex, 'prev'); + } + + /** + * Starts the auto show + * + * @param preventControlUpdate (boolean) + * - if true, auto controls state will not be updated + */ + el.startAuto = function(preventControlUpdate){ + // if an interval already exists, disregard call + if(slider.interval) return; + // create an interval + slider.interval = setInterval(function(){ + slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide(); + }, slider.settings.pause); + // if auto controls are displayed and preventControlUpdate is not true + if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('stop'); + } + + /** + * Stops the auto show + * + * @param preventControlUpdate (boolean) + * - if true, auto controls state will not be updated + */ + el.stopAuto = function(preventControlUpdate){ + // if no interval exists, disregard call + if(!slider.interval) return; + // clear the interval + clearInterval(slider.interval); + slider.interval = null; + // if auto controls are displayed and preventControlUpdate is not true + if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('start'); + } + + /** + * Returns current slide index (zero-based) + */ + el.getCurrentSlide = function(){ + return slider.active.index; + } + + /** + * Returns current slide element + */ + el.getCurrentSlideElement = function(){ + return slider.children.eq(slider.active.index); + } + + /** + * Returns number of slides in show + */ + el.getSlideCount = function(){ + return slider.children.length; + } + + /** + * Update all dynamic slider elements + */ + el.redrawSlider = function(){ + // resize all children in ratio to new screen size + slider.children.add(el.find('.bx-clone')).width(getSlideWidth()); + // adjust the height + slider.viewport.css('height', getViewportHeight()); + // update the slide position + if(!slider.settings.ticker) setSlidePosition(); + // if active.last was true before the screen resize, we want + // to keep it last no matter what screen size we end on + if (slider.active.last) slider.active.index = getPagerQty() - 1; + // if the active index (page) no longer exists due to the resize, simply set the index as last + if (slider.active.index >= getPagerQty()) slider.active.last = true; + // if a pager is being displayed and a custom pager is not being used, update it + if(slider.settings.pager && !slider.settings.pagerCustom){ + populatePager(); + updatePagerActive(slider.active.index); + } + } + + /** + * Destroy the current instance of the slider (revert everything back to original state) + */ + el.destroySlider = function(){ + // don't do anything if slider has already been destroyed + if(!slider.initialized) return; + slider.initialized = false; + $('.bx-clone', this).remove(); + slider.children.each(function() { + $(this).data("origStyle") != undefined ? $(this).attr("style", $(this).data("origStyle")) : $(this).removeAttr('style'); + }); + $(this).data("origStyle") != undefined ? this.attr("style", $(this).data("origStyle")) : $(this).removeAttr('style'); + $(this).unwrap().unwrap(); + if(slider.controls.el) slider.controls.el.remove(); + if(slider.controls.next) slider.controls.next.remove(); + if(slider.controls.prev) slider.controls.prev.remove(); + if(slider.pagerEl && slider.settings.controls) slider.pagerEl.remove(); + $('.bx-caption', this).remove(); + if(slider.controls.autoEl) slider.controls.autoEl.remove(); + clearInterval(slider.interval); + if(slider.settings.responsive) $(window).unbind('resize', resizeWindow); + } + + /** + * Reload the slider (revert all DOM changes, and re-initialize) + */ + el.reloadSlider = function(settings){ + if (settings != undefined) options = settings; + el.destroySlider(); + init(); + } + + init(); + + // returns the current jQuery object + return this; + } + +})(jQuery); diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/jquery.easing.1.3.js b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/jquery.easing.1.3.js new file mode 100644 index 00000000..ef743210 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/jquery.easing.1.3.js @@ -0,0 +1,205 @@ +/* + * 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 +jQuery.easing['jswing'] = jQuery.easing['swing']; + +jQuery.extend( jQuery.easing, +{ + def: 'easeOutQuad', + swing: function (x, t, b, c, d) { + //alert(jQuery.easing.default); + return jQuery.easing[jQuery.easing.def](x, t, b, c, d); + }, + easeInQuad: function (x, t, b, c, d) { + return c*(t/=d)*t + b; + }, + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + easeInOutQuad: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + easeInCubic: function (x, t, b, c, d) { + return c*(t/=d)*t*t + b; + }, + easeOutCubic: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; + }, + easeInOutCubic: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + easeInQuart: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + easeOutQuart: function (x, t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + easeInOutQuart: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + easeInQuint: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; + }, + easeOutQuint: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + easeInOutQuint: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + easeInSine: function (x, t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + easeOutSine: function (x, t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + easeInOutSine: function (x, t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + easeInExpo: function (x, t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeInOutExpo: function (x, t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + easeInCirc: function (x, t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + easeOutCirc: function (x, t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + easeInOutCirc: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + easeInElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + easeInOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + easeInBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + easeOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + easeInOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + easeInBounce: function (x, t, b, c, d) { + return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; + }, + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + easeInOutBounce: function (x, t, b, c, d) { + if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; + return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}); + +/* + * + * 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. + * + */ \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/jquery.fitvids.js b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/jquery.fitvids.js new file mode 100644 index 00000000..d464f93f --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/static/js/jquery.fitvids.js @@ -0,0 +1,80 @@ +/*global jQuery */ +/*jshint multistr:true browser:true */ +/*! +* FitVids 1.0 +* +* Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com +* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ +* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ +* +* Date: Thu Sept 01 18:00:00 2011 -0500 +*/ + +(function( $ ){ + + "use strict"; + + $.fn.fitVids = function( options ) { + var settings = { + customSelector: null + }; + + var div = document.createElement('div'), + ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0]; + + div.className = 'fit-vids-style'; + div.innerHTML = '­'; + + ref.parentNode.insertBefore(div,ref); + + if ( options ) { + $.extend( settings, options ); + } + + return this.each(function(){ + var selectors = [ + "iframe[src*='player.vimeo.com']", + "iframe[src*='www.youtube.com']", + "iframe[src*='www.kickstarter.com']", + "object", + "embed" + ]; + + if (settings.customSelector) { + selectors.push(settings.customSelector); + } + + var $allVideos = $(this).find(selectors.join(',')); + + $allVideos.each(function(){ + var $this = $(this); + if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } + var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), + width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), + aspectRatio = height / width; + if(!$this.attr('id')){ + var videoID = 'fitvid' + Math.floor(Math.random()*999999); + $this.attr('id', videoID); + } + $this.wrap('
').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); + $this.removeAttr('height').removeAttr('width'); + }); + }); + }; +})( jQuery ); diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/views/bx-slider.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/views/bx-slider.php new file mode 100644 index 00000000..404e5fb6 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/bx-slider/views/bx-slider.php @@ -0,0 +1,21 @@ + + + +
    + +
  • + + + + <?php echo $slide['title'] ?> + +
  • + +
+ diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/nivo-slider/config.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/nivo-slider/config.php new file mode 100644 index 00000000..4c175af7 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/nivo-slider/config.php @@ -0,0 +1,3 @@ + 0){ + if(settings.startSlide >= vars.totalSlides) { settings.startSlide = vars.totalSlides - 1; } + vars.currentSlide = settings.startSlide; + } + + // Get initial image + if($(kids[vars.currentSlide]).is('img')){ + vars.currentImage = $(kids[vars.currentSlide]); + } else { + vars.currentImage = $(kids[vars.currentSlide]).find('img:first'); + } + + // Show initial link + if($(kids[vars.currentSlide]).is('a')){ + $(kids[vars.currentSlide]).css('display','block'); + } + + // Set first background + var sliderImg = $('').addClass('nivo-main-image'); + sliderImg.attr('src', vars.currentImage.attr('src')).show(); + slider.append(sliderImg); + + // Detect Window Resize + $(window).resize(function() { + slider.children('img').width(slider.width()); + sliderImg.attr('src', vars.currentImage.attr('src')); + sliderImg.stop().height('auto'); + $('.nivo-slice').remove(); + $('.nivo-box').remove(); + }); + + //Create caption + slider.append($('
')); + + // Process caption function + var processCaption = function(settings){ + var nivoCaption = $('.nivo-caption', slider); + if(vars.currentImage.attr('title') != '' && vars.currentImage.attr('title') != undefined){ + var title = vars.currentImage.attr('title'); + if(title.substr(0,1) == '#') title = $(title).html(); + + if(nivoCaption.css('display') == 'block'){ + setTimeout(function(){ + nivoCaption.html(title); + }, settings.animSpeed); + } else { + nivoCaption.html(title); + nivoCaption.stop().fadeIn(settings.animSpeed); + } + } else { + nivoCaption.stop().fadeOut(settings.animSpeed); + } + } + + //Process initial caption + processCaption(settings); + + // In the words of Super Mario "let's a go!" + var timer = 0; + if(!settings.manualAdvance && kids.length > 1){ + timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime); + } + + // Add Direction nav + if(settings.directionNav){ + slider.append(''); + + $(slider).on('click', 'a.nivo-prevNav', function(){ + if(vars.running) { return false; } + clearInterval(timer); + timer = ''; + vars.currentSlide -= 2; + nivoRun(slider, kids, settings, 'prev'); + }); + + $(slider).on('click', 'a.nivo-nextNav', function(){ + if(vars.running) { return false; } + clearInterval(timer); + timer = ''; + nivoRun(slider, kids, settings, 'next'); + }); + } + + // Add Control nav + if(settings.controlNav){ + vars.controlNavEl = $('
'); + slider.after(vars.controlNavEl); + for(var i = 0; i < kids.length; i++){ + if(settings.controlNavThumbs){ + vars.controlNavEl.addClass('nivo-thumbs-enabled'); + var child = kids.eq(i); + if(!child.is('img')){ + child = child.find('img:first'); + } + if(child.attr('data-thumb')) vars.controlNavEl.append(''); + } else { + vars.controlNavEl.append(''+ (i + 1) +''); + } + } + + //Set initial active link + $('a:eq('+ vars.currentSlide +')', vars.controlNavEl).addClass('active'); + + $('a', vars.controlNavEl).bind('click', function(){ + if(vars.running) return false; + if($(this).hasClass('active')) return false; + clearInterval(timer); + timer = ''; + sliderImg.attr('src', vars.currentImage.attr('src')); + vars.currentSlide = $(this).attr('rel') - 1; + nivoRun(slider, kids, settings, 'control'); + }); + } + + //For pauseOnHover setting + if(settings.pauseOnHover){ + slider.hover(function(){ + vars.paused = true; + clearInterval(timer); + timer = ''; + }, function(){ + vars.paused = false; + // Restart the timer + if(timer === '' && !settings.manualAdvance){ + timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime); + } + }); + } + + // Event when Animation finishes + slider.bind('nivo:animFinished', function(){ + sliderImg.attr('src', vars.currentImage.attr('src')); + vars.running = false; + // Hide child links + $(kids).each(function(){ + if($(this).is('a')){ + $(this).css('display','none'); + } + }); + // Show current link + if($(kids[vars.currentSlide]).is('a')){ + $(kids[vars.currentSlide]).css('display','block'); + } + // Restart the timer + if(timer === '' && !vars.paused && !settings.manualAdvance){ + timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime); + } + // Trigger the afterChange callback + settings.afterChange.call(this); + }); + + // Add slices for slice animations + var createSlices = function(slider, settings, vars) { + if($(vars.currentImage).parent().is('a')) $(vars.currentImage).parent().css('display','block'); + $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').width(slider.width()).css('visibility', 'hidden').show(); + var sliceHeight = ($('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').parent().is('a')) ? $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').parent().height() : $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').height(); + + for(var i = 0; i < settings.slices; i++){ + var sliceWidth = Math.round(slider.width()/settings.slices); + + if(i === settings.slices-1){ + slider.append( + $('
').css({ + left:(sliceWidth*i)+'px', + width:(slider.width()-(sliceWidth*i))+'px', + height:sliceHeight+'px', + opacity:'0', + overflow:'hidden' + }) + ); + } else { + slider.append( + $('
').css({ + left:(sliceWidth*i)+'px', + width:sliceWidth+'px', + height:sliceHeight+'px', + opacity:'0', + overflow:'hidden' + }) + ); + } + } + + $('.nivo-slice', slider).height(sliceHeight); + sliderImg.stop().animate({ + height: $(vars.currentImage).height() + }, settings.animSpeed); + }; + + // Add boxes for box animations + var createBoxes = function(slider, settings, vars){ + if($(vars.currentImage).parent().is('a')) $(vars.currentImage).parent().css('display','block'); + $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').width(slider.width()).css('visibility', 'hidden').show(); + var boxWidth = Math.round(slider.width()/settings.boxCols), + boxHeight = Math.round($('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').height() / settings.boxRows); + + + for(var rows = 0; rows < settings.boxRows; rows++){ + for(var cols = 0; cols < settings.boxCols; cols++){ + if(cols === settings.boxCols-1){ + slider.append( + $('
').css({ + opacity:0, + left:(boxWidth*cols)+'px', + top:(boxHeight*rows)+'px', + width:(slider.width()-(boxWidth*cols))+'px' + + }) + ); + $('.nivo-box[name="'+ cols +'"]', slider).height($('.nivo-box[name="'+ cols +'"] img', slider).height()+'px'); + } else { + slider.append( + $('
').css({ + opacity:0, + left:(boxWidth*cols)+'px', + top:(boxHeight*rows)+'px', + width:boxWidth+'px' + }) + ); + $('.nivo-box[name="'+ cols +'"]', slider).height($('.nivo-box[name="'+ cols +'"] img', slider).height()+'px'); + } + } + } + + sliderImg.stop().animate({ + height: $(vars.currentImage).height() + }, settings.animSpeed); + }; + + // Private run method + var nivoRun = function(slider, kids, settings, nudge){ + // Get our vars + var vars = slider.data('nivo:vars'); + + // Trigger the lastSlide callback + if(vars && (vars.currentSlide === vars.totalSlides - 1)){ + settings.lastSlide.call(this); + } + + // Stop + if((!vars || vars.stop) && !nudge) { return false; } + + // Trigger the beforeChange callback + settings.beforeChange.call(this); + + // Set current background before change + if(!nudge){ + sliderImg.attr('src', vars.currentImage.attr('src')); + } else { + if(nudge === 'prev'){ + sliderImg.attr('src', vars.currentImage.attr('src')); + } + if(nudge === 'next'){ + sliderImg.attr('src', vars.currentImage.attr('src')); + } + } + + vars.currentSlide++; + // Trigger the slideshowEnd callback + if(vars.currentSlide === vars.totalSlides){ + vars.currentSlide = 0; + settings.slideshowEnd.call(this); + } + if(vars.currentSlide < 0) { vars.currentSlide = (vars.totalSlides - 1); } + // Set vars.currentImage + if($(kids[vars.currentSlide]).is('img')){ + vars.currentImage = $(kids[vars.currentSlide]); + } else { + vars.currentImage = $(kids[vars.currentSlide]).find('img:first'); + } + + // Set active links + if(settings.controlNav){ + $('a', vars.controlNavEl).removeClass('active'); + $('a:eq('+ vars.currentSlide +')', vars.controlNavEl).addClass('active'); + } + + // Process caption + processCaption(settings); + + // Remove any slices from last transition + $('.nivo-slice', slider).remove(); + + // Remove any boxes from last transition + $('.nivo-box', slider).remove(); + + var currentEffect = settings.effect, + anims = ''; + + // Generate random effect + if(settings.effect === 'random'){ + anims = new Array('sliceDownRight','sliceDownLeft','sliceUpRight','sliceUpLeft','sliceUpDown','sliceUpDownLeft','fold','fade', + 'boxRandom','boxRain','boxRainReverse','boxRainGrow','boxRainGrowReverse'); + currentEffect = anims[Math.floor(Math.random()*(anims.length + 1))]; + if(currentEffect === undefined) { currentEffect = 'fade'; } + } + + // Run random effect from specified set (eg: effect:'fold,fade') + if(settings.effect.indexOf(',') !== -1){ + anims = settings.effect.split(','); + currentEffect = anims[Math.floor(Math.random()*(anims.length))]; + if(currentEffect === undefined) { currentEffect = 'fade'; } + } + + // Custom transition as defined by "data-transition" attribute + if(vars.currentImage.attr('data-transition')){ + currentEffect = vars.currentImage.attr('data-transition'); + } + + // Run effects + vars.running = true; + var timeBuff = 0, + i = 0, + slices = '', + firstSlice = '', + totalBoxes = '', + boxes = ''; + + if(currentEffect === 'sliceDown' || currentEffect === 'sliceDownRight' || currentEffect === 'sliceDownLeft'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + slices = $('.nivo-slice', slider); + if(currentEffect === 'sliceDownLeft') { slices = $('.nivo-slice', slider)._reverse(); } + + slices.each(function(){ + var slice = $(this); + slice.css({ 'top': '0px' }); + if(i === settings.slices-1){ + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + i++; + }); + } else if(currentEffect === 'sliceUp' || currentEffect === 'sliceUpRight' || currentEffect === 'sliceUpLeft'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + slices = $('.nivo-slice', slider); + if(currentEffect === 'sliceUpLeft') { slices = $('.nivo-slice', slider)._reverse(); } + + slices.each(function(){ + var slice = $(this); + slice.css({ 'bottom': '0px' }); + if(i === settings.slices-1){ + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + i++; + }); + } else if(currentEffect === 'sliceUpDown' || currentEffect === 'sliceUpDownRight' || currentEffect === 'sliceUpDownLeft'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + var v = 0; + slices = $('.nivo-slice', slider); + if(currentEffect === 'sliceUpDownLeft') { slices = $('.nivo-slice', slider)._reverse(); } + + slices.each(function(){ + var slice = $(this); + if(i === 0){ + slice.css('top','0px'); + i++; + } else { + slice.css('bottom','0px'); + i = 0; + } + + if(v === settings.slices-1){ + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + v++; + }); + } else if(currentEffect === 'fold'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + + $('.nivo-slice', slider).each(function(){ + var slice = $(this); + var origWidth = slice.width(); + slice.css({ top:'0px', width:'0px' }); + if(i === settings.slices-1){ + setTimeout(function(){ + slice.animate({ width:origWidth, opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({ width:origWidth, opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + i++; + }); + } else if(currentEffect === 'fade'){ + createSlices(slider, settings, vars); + + firstSlice = $('.nivo-slice:first', slider); + firstSlice.css({ + 'width': slider.width() + 'px' + }); + + firstSlice.animate({ opacity:'1.0' }, (settings.animSpeed*2), '', function(){ slider.trigger('nivo:animFinished'); }); + } else if(currentEffect === 'slideInRight'){ + createSlices(slider, settings, vars); + + firstSlice = $('.nivo-slice:first', slider); + firstSlice.css({ + 'width': '0px', + 'opacity': '1' + }); + + firstSlice.animate({ width: slider.width() + 'px' }, (settings.animSpeed*2), '', function(){ slider.trigger('nivo:animFinished'); }); + } else if(currentEffect === 'slideInLeft'){ + createSlices(slider, settings, vars); + + firstSlice = $('.nivo-slice:first', slider); + firstSlice.css({ + 'width': '0px', + 'opacity': '1', + 'left': '', + 'right': '0px' + }); + + firstSlice.animate({ width: slider.width() + 'px' }, (settings.animSpeed*2), '', function(){ + // Reset positioning + firstSlice.css({ + 'left': '0px', + 'right': '' + }); + slider.trigger('nivo:animFinished'); + }); + } else if(currentEffect === 'boxRandom'){ + createBoxes(slider, settings, vars); + + totalBoxes = settings.boxCols * settings.boxRows; + i = 0; + timeBuff = 0; + + boxes = shuffle($('.nivo-box', slider)); + boxes.each(function(){ + var box = $(this); + if(i === totalBoxes-1){ + setTimeout(function(){ + box.animate({ opacity:'1' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + box.animate({ opacity:'1' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 20; + i++; + }); + } else if(currentEffect === 'boxRain' || currentEffect === 'boxRainReverse' || currentEffect === 'boxRainGrow' || currentEffect === 'boxRainGrowReverse'){ + createBoxes(slider, settings, vars); + + totalBoxes = settings.boxCols * settings.boxRows; + i = 0; + timeBuff = 0; + + // Split boxes into 2D array + var rowIndex = 0; + var colIndex = 0; + var box2Darr = []; + box2Darr[rowIndex] = []; + boxes = $('.nivo-box', slider); + if(currentEffect === 'boxRainReverse' || currentEffect === 'boxRainGrowReverse'){ + boxes = $('.nivo-box', slider)._reverse(); + } + boxes.each(function(){ + box2Darr[rowIndex][colIndex] = $(this); + colIndex++; + if(colIndex === settings.boxCols){ + rowIndex++; + colIndex = 0; + box2Darr[rowIndex] = []; + } + }); + + // Run animation + for(var cols = 0; cols < (settings.boxCols * 2); cols++){ + var prevCol = cols; + for(var rows = 0; rows < settings.boxRows; rows++){ + if(prevCol >= 0 && prevCol < settings.boxCols){ + /* Due to some weird JS bug with loop vars + being used in setTimeout, this is wrapped + with an anonymous function call */ + (function(row, col, time, i, totalBoxes) { + var box = $(box2Darr[row][col]); + var w = box.width(); + var h = box.height(); + if(currentEffect === 'boxRainGrow' || currentEffect === 'boxRainGrowReverse'){ + box.width(0).height(0); + } + if(i === totalBoxes-1){ + setTimeout(function(){ + box.animate({ opacity:'1', width:w, height:h }, settings.animSpeed/1.3, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + time)); + } else { + setTimeout(function(){ + box.animate({ opacity:'1', width:w, height:h }, settings.animSpeed/1.3); + }, (100 + time)); + } + })(rows, prevCol, timeBuff, i, totalBoxes); + i++; + } + prevCol--; + } + timeBuff += 100; + } + } + }; + + // Shuffle an array + var shuffle = function(arr){ + for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i, 10), x = arr[--i], arr[i] = arr[j], arr[j] = x); + return arr; + }; + + // For debugging + var trace = function(msg){ + if(this.console && typeof console.log !== 'undefined') { console.log(msg); } + }; + + // Start / Stop + this.stop = function(){ + if(!$(element).data('nivo:vars').stop){ + $(element).data('nivo:vars').stop = true; + trace('Stop Slider'); + } + }; + + this.start = function(){ + if($(element).data('nivo:vars').stop){ + $(element).data('nivo:vars').stop = false; + trace('Start Slider'); + } + }; + + // Trigger the afterLoad callback + settings.afterLoad.call(this); + + return this; + }; + + $.fn.nivoSlider = function(options) { + return this.each(function(key, value){ + var element = $(this); + // Return early if this element already has a plugin instance + if (element.data('nivoslider')) { return element.data('nivoslider'); } + // Pass options to plugin constructor + var nivoslider = new NivoSlider(this, options); + // Store plugin object in this element's data + element.data('nivoslider', nivoslider); + }); + }; + + //Default settings + $.fn.nivoSlider.defaults = { + effect: 'random', + slices: 15, + boxCols: 8, + boxRows: 4, + animSpeed: 500, + pauseTime: 3000, + startSlide: 0, + directionNav: true, + controlNav: true, + controlNavThumbs: false, + pauseOnHover: true, + manualAdvance: false, + prevText: 'Prev', + nextText: 'Next', + randomStart: false, + beforeChange: function(){}, + afterChange: function(){}, + slideshowEnd: function(){}, + lastSlide: function(){}, + afterLoad: function(){} + }; + + $.fn._reverse = [].reverse; + +})(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/nivo-slider/views/nivo-slider.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/nivo-slider/views/nivo-slider.php new file mode 100644 index 00000000..89b0caaa --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/nivo-slider/views/nivo-slider.php @@ -0,0 +1,23 @@ + + + + + +
+
+ $slide): ?> + ' height="" src="" alt="" title="#nivo-"/> + +
+ $slide): ?> +
+ +
+ +
+ + diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/owl-carousel/config.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/owl-carousel/config.php new file mode 100644 index 00000000..1d3a8a87 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/owl-carousel/config.php @@ -0,0 +1,2 @@ +0)&&(this.$stage.children(".cloned").remove(),this._clones=[])}},{filter:["items","settings"],run:function(){var a,b,c=this._clones,d=this._items,e=this.settings.loop?c.length-Math.max(2*this.settings.items,4):0;for(a=0,b=Math.abs(e/2);b>a;a++)e>0?(this.$stage.children().eq(d.length+c.length-1).remove(),c.pop(),this.$stage.children().eq(0).remove(),c.pop()):(c.push(c.length/2),this.$stage.append(d[c[c.length-1]].clone().addClass("cloned")),c.push(d.length-1-(c.length-1)/2),this.$stage.prepend(d[c[c.length-1]].clone().addClass("cloned")))}},{filter:["width","items","settings"],run:function(){var a,b,c,d=this.settings.rtl?1:-1,e=(this.width()/this.settings.items).toFixed(3),f=0;for(this._coordinates=[],b=0,c=this._clones.length+this._items.length;c>b;b++)a=this._mergers[this.relative(b)],a=this.settings.mergeFit&&Math.min(a,this.settings.items)||a,f+=(this.settings.autoWidth?this._items[this.relative(b)].width()+this.settings.margin:e*a)*d,this._coordinates.push(f)}},{filter:["width","items","settings"],run:function(){var b,c,d=(this.width()/this.settings.items).toFixed(3),e={width:Math.abs(this._coordinates[this._coordinates.length-1])+2*this.settings.stagePadding,"padding-left":this.settings.stagePadding||"","padding-right":this.settings.stagePadding||""};if(this.$stage.css(e),e={width:this.settings.autoWidth?"auto":d-this.settings.margin},e[this.settings.rtl?"margin-left":"margin-right"]=this.settings.margin,!this.settings.autoWidth&&a.grep(this._mergers,function(a){return a>1}).length>0)for(b=0,c=this._coordinates.length;c>b;b++)e.width=Math.abs(this._coordinates[b])-Math.abs(this._coordinates[b-1]||0)-this.settings.margin,this.$stage.children().eq(b).css(e);else this.$stage.children().css(e)}},{filter:["width","items","settings"],run:function(a){a.current&&this.reset(this.$stage.children().index(a.current))}},{filter:["position"],run:function(){this.animate(this.coordinates(this._current))}},{filter:["width","position","items","settings"],run:function(){var a,b,c,d,e=this.settings.rtl?1:-1,f=2*this.settings.stagePadding,g=this.coordinates(this.current())+f,h=g+this.width()*e,i=[];for(c=0,d=this._coordinates.length;d>c;c++)a=this._coordinates[c-1]||0,b=Math.abs(this._coordinates[c])+f*e,(this.op(a,"<=",g)&&this.op(a,">",h)||this.op(b,"<",g)&&this.op(b,">",h))&&i.push(c);this.$stage.children("."+this.settings.activeClass).removeClass(this.settings.activeClass),this.$stage.children(":eq("+i.join("), :eq(")+")").addClass(this.settings.activeClass),this.settings.center&&(this.$stage.children("."+this.settings.centerClass).removeClass(this.settings.centerClass),this.$stage.children().eq(this.current()).addClass(this.settings.centerClass))}}],e.prototype.initialize=function(){if(this.trigger("initialize"),this.$element.addClass(this.settings.baseClass).addClass(this.settings.themeClass).toggleClass("owl-rtl",this.settings.rtl),this.browserSupport(),this.settings.autoWidth&&this.state.imagesLoaded!==!0){var b,c,e;if(b=this.$element.find("img"),c=this.settings.nestedItemSelector?"."+this.settings.nestedItemSelector:d,e=this.$element.children(c).width(),b.length&&0>=e)return this.preloadAutoWidthImages(b),!1}this.$element.addClass("owl-loading"),this.$stage=a("<"+this.settings.stageElement+' class="owl-stage"/>').wrap('
'),this.$element.append(this.$stage.parent()),this.replace(this.$element.children().not(this.$stage.parent())),this._width=this.$element.width(),this.refresh(),this.$element.removeClass("owl-loading").addClass("owl-loaded"),this.eventsCall(),this.internalEvents(),this.addTriggerableEvents(),this.trigger("initialized")},e.prototype.setup=function(){var b=this.viewport(),c=this.options.responsive,d=-1,e=null;c?(a.each(c,function(a){b>=a&&a>d&&(d=Number(a))}),e=a.extend({},this.options,c[d]),delete e.responsive,e.responsiveClass&&this.$element.attr("class",function(a,b){return b.replace(/\b owl-responsive-\S+/g,"")}).addClass("owl-responsive-"+d)):e=a.extend({},this.options),(null===this.settings||this._breakpoint!==d)&&(this.trigger("change",{property:{name:"settings",value:e}}),this._breakpoint=d,this.settings=e,this.invalidate("settings"),this.trigger("changed",{property:{name:"settings",value:this.settings}}))},e.prototype.optionsLogic=function(){this.$element.toggleClass("owl-center",this.settings.center),this.settings.loop&&this._items.length").addClass(this.settings.itemClass).append(b)),this.trigger("prepared",{content:c.data}),c.data},e.prototype.update=function(){for(var b=0,c=this._pipe.length,d=a.proxy(function(a){return this[a]},this._invalidated),e={};c>b;)(this._invalidated.all||a.grep(this._pipe[b].filter,d).length>0)&&this._pipe[b].run(e),b++;this._invalidated={}},e.prototype.width=function(a){switch(a=a||e.Width.Default){case e.Width.Inner:case e.Width.Outer:return this._width;default:return this._width-2*this.settings.stagePadding+this.settings.margin}},e.prototype.refresh=function(){if(0===this._items.length)return!1;(new Date).getTime();this.trigger("refresh"),this.setup(),this.optionsLogic(),this.$stage.addClass("owl-refresh"),this.update(),this.$stage.removeClass("owl-refresh"),this.state.orientation=b.orientation,this.watchVisibility(),this.trigger("refreshed")},e.prototype.eventsCall=function(){this.e._onDragStart=a.proxy(function(a){this.onDragStart(a)},this),this.e._onDragMove=a.proxy(function(a){this.onDragMove(a)},this),this.e._onDragEnd=a.proxy(function(a){this.onDragEnd(a)},this),this.e._onResize=a.proxy(function(a){this.onResize(a)},this),this.e._transitionEnd=a.proxy(function(a){this.transitionEnd(a)},this),this.e._preventClick=a.proxy(function(a){this.preventClick(a)},this)},e.prototype.onThrottledResize=function(){b.clearTimeout(this.resizeTimer),this.resizeTimer=b.setTimeout(this.e._onResize,this.settings.responsiveRefreshRate)},e.prototype.onResize=function(){return this._items.length?this._width===this.$element.width()?!1:this.trigger("resize").isDefaultPrevented()?!1:(this._width=this.$element.width(),this.invalidate("width"),this.refresh(),void this.trigger("resized")):!1},e.prototype.eventsRouter=function(a){var b=a.type;"mousedown"===b||"touchstart"===b?this.onDragStart(a):"mousemove"===b||"touchmove"===b?this.onDragMove(a):"mouseup"===b||"touchend"===b?this.onDragEnd(a):"touchcancel"===b&&this.onDragEnd(a)},e.prototype.internalEvents=function(){var c=(k(),l());this.settings.mouseDrag?(this.$stage.on("mousedown",a.proxy(function(a){this.eventsRouter(a)},this)),this.$stage.on("dragstart",function(){return!1}),this.$stage.get(0).onselectstart=function(){return!1}):this.$element.addClass("owl-text-select-on"),this.settings.touchDrag&&!c&&this.$stage.on("touchstart touchcancel",a.proxy(function(a){this.eventsRouter(a)},this)),this.transitionEndVendor&&this.on(this.$stage.get(0),this.transitionEndVendor,this.e._transitionEnd,!1),this.settings.responsive!==!1&&this.on(b,"resize",a.proxy(this.onThrottledResize,this))},e.prototype.onDragStart=function(d){var e,g,h,i;if(e=d.originalEvent||d||b.event,3===e.which||this.state.isTouch)return!1;if("mousedown"===e.type&&this.$stage.addClass("owl-grab"),this.trigger("drag"),this.drag.startTime=(new Date).getTime(),this.speed(0),this.state.isTouch=!0,this.state.isScrolling=!1,this.state.isSwiping=!1,this.drag.distance=0,g=f(e).x,h=f(e).y,this.drag.offsetX=this.$stage.position().left,this.drag.offsetY=this.$stage.position().top,this.settings.rtl&&(this.drag.offsetX=this.$stage.position().left+this.$stage.width()-this.width()+this.settings.margin),this.state.inMotion&&this.support3d)i=this.getTransformProperty(),this.drag.offsetX=i,this.animate(i),this.state.inMotion=!0;else if(this.state.inMotion&&!this.support3d)return this.state.inMotion=!1,!1;this.drag.startX=g-this.drag.offsetX,this.drag.startY=h-this.drag.offsetY,this.drag.start=g-this.drag.startX,this.drag.targetEl=e.target||e.srcElement,this.drag.updatedX=this.drag.start,("IMG"===this.drag.targetEl.tagName||"A"===this.drag.targetEl.tagName)&&(this.drag.targetEl.draggable=!1),a(c).on("mousemove.owl.dragEvents mouseup.owl.dragEvents touchmove.owl.dragEvents touchend.owl.dragEvents",a.proxy(function(a){this.eventsRouter(a)},this))},e.prototype.onDragMove=function(a){var c,e,g,h,i,j;this.state.isTouch&&(this.state.isScrolling||(c=a.originalEvent||a||b.event,e=f(c).x,g=f(c).y,this.drag.currentX=e-this.drag.startX,this.drag.currentY=g-this.drag.startY,this.drag.distance=this.drag.currentX-this.drag.offsetX,this.drag.distance<0?this.state.direction=this.settings.rtl?"right":"left":this.drag.distance>0&&(this.state.direction=this.settings.rtl?"left":"right"),this.settings.loop?this.op(this.drag.currentX,">",this.coordinates(this.minimum()))&&"right"===this.state.direction?this.drag.currentX-=(this.settings.center&&this.coordinates(0))-this.coordinates(this._items.length):this.op(this.drag.currentX,"<",this.coordinates(this.maximum()))&&"left"===this.state.direction&&(this.drag.currentX+=(this.settings.center&&this.coordinates(0))-this.coordinates(this._items.length)):(h=this.coordinates(this.settings.rtl?this.maximum():this.minimum()),i=this.coordinates(this.settings.rtl?this.minimum():this.maximum()),j=this.settings.pullDrag?this.drag.distance/5:0,this.drag.currentX=Math.max(Math.min(this.drag.currentX,h+j),i+j)),(this.drag.distance>8||this.drag.distance<-8)&&(c.preventDefault!==d?c.preventDefault():c.returnValue=!1,this.state.isSwiping=!0),this.drag.updatedX=this.drag.currentX,(this.drag.currentY>16||this.drag.currentY<-16)&&this.state.isSwiping===!1&&(this.state.isScrolling=!0,this.drag.updatedX=this.drag.start),this.animate(this.drag.updatedX)))},e.prototype.onDragEnd=function(b){var d,e,f;if(this.state.isTouch){if("mouseup"===b.type&&this.$stage.removeClass("owl-grab"),this.trigger("dragged"),this.drag.targetEl.removeAttribute("draggable"),this.state.isTouch=!1,this.state.isScrolling=!1,this.state.isSwiping=!1,0===this.drag.distance&&this.state.inMotion!==!0)return this.state.inMotion=!1,!1;this.drag.endTime=(new Date).getTime(),d=this.drag.endTime-this.drag.startTime,e=Math.abs(this.drag.distance),(e>3||d>300)&&this.removeClick(this.drag.targetEl),f=this.closest(this.drag.updatedX),this.speed(this.settings.dragEndSpeed||this.settings.smartSpeed),this.current(f),this.invalidate("position"),this.update(),this.settings.pullDrag||this.drag.updatedX!==this.coordinates(f)||this.transitionEnd(),this.drag.distance=0,a(c).off(".owl.dragEvents")}},e.prototype.removeClick=function(c){this.drag.targetEl=c,a(c).on("click.preventClick",this.e._preventClick),b.setTimeout(function(){a(c).off("click.preventClick")},300)},e.prototype.preventClick=function(b){b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation&&b.stopPropagation(),a(b.target).off("click.preventClick")},e.prototype.getTransformProperty=function(){var a,c;return a=b.getComputedStyle(this.$stage.get(0),null).getPropertyValue(this.vendorName+"transform"),a=a.replace(/matrix(3d)?\(|\)/g,"").split(","),c=16===a.length,c!==!0?a[4]:a[12]},e.prototype.closest=function(b){var c=-1,d=30,e=this.width(),f=this.coordinates();return this.settings.freeDrag||a.each(f,a.proxy(function(a,g){return b>g-d&&g+d>b?c=a:this.op(b,"<",g)&&this.op(b,">",f[a+1]||g-e)&&(c="left"===this.state.direction?a+1:a),-1===c},this)),this.settings.loop||(this.op(b,">",f[this.minimum()])?c=b=this.minimum():this.op(b,"<",f[this.maximum()])&&(c=b=this.maximum())),c},e.prototype.animate=function(b){this.trigger("translate"),this.state.inMotion=this.speed()>0,this.support3d?this.$stage.css({transform:"translate3d("+b+"px,0px, 0px)",transition:this.speed()/1e3+"s"}):this.state.isTouch?this.$stage.css({left:b+"px"}):this.$stage.animate({left:b},this.speed()/1e3,this.settings.fallbackEasing,a.proxy(function(){this.state.inMotion&&this.transitionEnd()},this))},e.prototype.current=function(a){if(a===d)return this._current;if(0===this._items.length)return d;if(a=this.normalize(a),this._current!==a){var b=this.trigger("change",{property:{name:"position",value:a}});b.data!==d&&(a=this.normalize(b.data)),this._current=a,this.invalidate("position"),this.trigger("changed",{property:{name:"position",value:this._current}})}return this._current},e.prototype.invalidate=function(a){this._invalidated[a]=!0},e.prototype.reset=function(a){a=this.normalize(a),a!==d&&(this._speed=0,this._current=a,this.suppress(["translate","translated"]),this.animate(this.coordinates(a)),this.release(["translate","translated"]))},e.prototype.normalize=function(b,c){var e=c?this._items.length:this._items.length+this._clones.length;return!a.isNumeric(b)||1>e?d:b=this._clones.length?(b%e+e)%e:Math.max(this.minimum(c),Math.min(this.maximum(c),b))},e.prototype.relative=function(a){return a=this.normalize(a),a-=this._clones.length/2,this.normalize(a,!0)},e.prototype.maximum=function(a){var b,c,d,e=0,f=this.settings;if(a)return this._items.length-1;if(!f.loop&&f.center)b=this._items.length-1;else if(f.loop||f.center)if(f.loop||f.center)b=this._items.length+f.items;else{if(!f.autoWidth&&!f.merge)throw"Can not detect maximum absolute position.";for(revert=f.rtl?1:-1,c=this.$stage.width()-this.$element.width();(d=this.coordinates(e))&&!(d*revert>=c);)b=++e}else b=this._items.length-f.items;return b},e.prototype.minimum=function(a){return a?0:this._clones.length/2},e.prototype.items=function(a){return a===d?this._items.slice():(a=this.normalize(a,!0),this._items[a])},e.prototype.mergers=function(a){return a===d?this._mergers.slice():(a=this.normalize(a,!0),this._mergers[a])},e.prototype.clones=function(b){var c=this._clones.length/2,e=c+this._items.length,f=function(a){return a%2===0?e+a/2:c-(a+1)/2};return b===d?a.map(this._clones,function(a,b){return f(b)}):a.map(this._clones,function(a,c){return a===b?f(c):null})},e.prototype.speed=function(a){return a!==d&&(this._speed=a),this._speed},e.prototype.coordinates=function(b){var c=null;return b===d?a.map(this._coordinates,a.proxy(function(a,b){return this.coordinates(b)},this)):(this.settings.center?(c=this._coordinates[b],c+=(this.width()-c+(this._coordinates[b-1]||0))/2*(this.settings.rtl?-1:1)):c=this._coordinates[b-1]||0,c)},e.prototype.duration=function(a,b,c){return Math.min(Math.max(Math.abs(b-a),1),6)*Math.abs(c||this.settings.smartSpeed)},e.prototype.to=function(c,d){if(this.settings.loop){var e=c-this.relative(this.current()),f=this.current(),g=this.current(),h=this.current()+e,i=0>g-h?!0:!1,j=this._clones.length+this._items.length;h=j-this.settings.items&&i===!0&&(f=g-this._items.length,this.reset(f)),b.clearTimeout(this.e._goToLoop),this.e._goToLoop=b.setTimeout(a.proxy(function(){this.speed(this.duration(this.current(),f+e,d)),this.current(f+e),this.update()},this),30)}else this.speed(this.duration(this.current(),c,d)),this.current(c),this.update()},e.prototype.next=function(a){a=a||!1,this.to(this.relative(this.current())+1,a)},e.prototype.prev=function(a){a=a||!1,this.to(this.relative(this.current())-1,a)},e.prototype.transitionEnd=function(a){return a!==d&&(a.stopPropagation(),(a.target||a.srcElement||a.originalTarget)!==this.$stage.get(0))?!1:(this.state.inMotion=!1,void this.trigger("translated"))},e.prototype.viewport=function(){var d;if(this.options.responsiveBaseElement!==b)d=a(this.options.responsiveBaseElement).width();else if(b.innerWidth)d=b.innerWidth;else{if(!c.documentElement||!c.documentElement.clientWidth)throw"Can not detect viewport width.";d=c.documentElement.clientWidth}return d},e.prototype.replace=function(b){this.$stage.empty(),this._items=[],b&&(b=b instanceof jQuery?b:a(b)),this.settings.nestedItemSelector&&(b=b.find("."+this.settings.nestedItemSelector)),b.filter(function(){return 1===this.nodeType}).each(a.proxy(function(a,b){b=this.prepare(b),this.$stage.append(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").andSelf("[data-merge]").attr("data-merge")||1)},this)),this.reset(a.isNumeric(this.settings.startPosition)?this.settings.startPosition:0),this.invalidate("items")},e.prototype.add=function(a,b){b=b===d?this._items.length:this.normalize(b,!0),this.trigger("add",{content:a,position:b}),0===this._items.length||b===this._items.length?(this.$stage.append(a),this._items.push(a),this._mergers.push(1*a.find("[data-merge]").andSelf("[data-merge]").attr("data-merge")||1)):(this._items[b].before(a),this._items.splice(b,0,a),this._mergers.splice(b,0,1*a.find("[data-merge]").andSelf("[data-merge]").attr("data-merge")||1)),this.invalidate("items"),this.trigger("added",{content:a,position:b})},e.prototype.remove=function(a){a=this.normalize(a,!0),a!==d&&(this.trigger("remove",{content:this._items[a],position:a}),this._items[a].remove(),this._items.splice(a,1),this._mergers.splice(a,1),this.invalidate("items"),this.trigger("removed",{content:null,position:a}))},e.prototype.addTriggerableEvents=function(){var b=a.proxy(function(b,c){return a.proxy(function(a){a.relatedTarget!==this&&(this.suppress([c]),b.apply(this,[].slice.call(arguments,1)),this.release([c]))},this)},this);a.each({next:this.next,prev:this.prev,to:this.to,destroy:this.destroy,refresh:this.refresh,replace:this.replace,add:this.add,remove:this.remove},a.proxy(function(a,c){this.$element.on(a+".owl.carousel",b(c,a+".owl.carousel"))},this))},e.prototype.watchVisibility=function(){function c(a){return a.offsetWidth>0&&a.offsetHeight>0}function d(){c(this.$element.get(0))&&(this.$element.removeClass("owl-hidden"),this.refresh(),b.clearInterval(this.e._checkVisibile))}c(this.$element.get(0))||(this.$element.addClass("owl-hidden"),b.clearInterval(this.e._checkVisibile),this.e._checkVisibile=b.setInterval(a.proxy(d,this),500))},e.prototype.preloadAutoWidthImages=function(b){var c,d,e,f;c=0,d=this,b.each(function(g,h){e=a(h),f=new Image,f.onload=function(){c++,e.attr("src",f.src),e.css("opacity",1),c>=b.length&&(d.state.imagesLoaded=!0,d.initialize())},f.src=e.attr("src")||e.attr("data-src")||e.attr("data-src-retina")})},e.prototype.destroy=function(){this.$element.hasClass(this.settings.themeClass)&&this.$element.removeClass(this.settings.themeClass),this.settings.responsive!==!1&&a(b).off("resize.owl.carousel"),this.transitionEndVendor&&this.off(this.$stage.get(0),this.transitionEndVendor,this.e._transitionEnd);for(var d in this._plugins)this._plugins[d].destroy();(this.settings.mouseDrag||this.settings.touchDrag)&&(this.$stage.off("mousedown touchstart touchcancel"),a(c).off(".owl.dragEvents"),this.$stage.get(0).onselectstart=function(){},this.$stage.off("dragstart",function(){return!1})),this.$element.off(".owl"),this.$stage.children(".cloned").remove(),this.e=null,this.$element.removeData("owlCarousel"),this.$stage.children().contents().unwrap(),this.$stage.children().unwrap(),this.$stage.unwrap()},e.prototype.op=function(a,b,c){var d=this.settings.rtl;switch(b){case"<":return d?a>c:c>a;case">":return d?c>a:a>c;case">=":return d?c>=a:a>=c;case"<=":return d?a>=c:c>=a}},e.prototype.on=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},e.prototype.off=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d):a.detachEvent&&a.detachEvent("on"+b,c)},e.prototype.trigger=function(b,c,d){var e={item:{count:this._items.length,index:this.current()}},f=a.camelCase(a.grep(["on",b,d],function(a){return a}).join("-").toLowerCase()),g=a.Event([b,"owl",d||"carousel"].join(".").toLowerCase(),a.extend({relatedTarget:this},e,c));return this._supress[b]||(a.each(this._plugins,function(a,b){b.onTrigger&&b.onTrigger(g)}),this.$element.trigger(g),this.settings&&"function"==typeof this.settings[f]&&this.settings[f].apply(this,g)),g},e.prototype.suppress=function(b){a.each(b,a.proxy(function(a,b){this._supress[b]=!0},this))},e.prototype.release=function(b){a.each(b,a.proxy(function(a,b){delete this._supress[b]},this))},e.prototype.browserSupport=function(){if(this.support3d=j(),this.support3d){this.transformVendor=i();var a=["transitionend","webkitTransitionEnd","transitionend","oTransitionEnd"];this.transitionEndVendor=a[h()],this.vendorName=this.transformVendor.replace(/Transform/i,""),this.vendorName=""!==this.vendorName?"-"+this.vendorName.toLowerCase()+"-":""}this.state.orientation=b.orientation},a.fn.owlCarousel=function(b){return this.each(function(){a(this).data("owlCarousel")||a(this).data("owlCarousel",new e(this,b))})},a.fn.owlCarousel.Constructor=e}(window.Zepto||window.jQuery,window,document),function(a,b){var c=function(b){this._core=b,this._loaded=[],this._handlers={"initialized.owl.carousel change.owl.carousel":a.proxy(function(b){if(b.namespace&&this._core.settings&&this._core.settings.lazyLoad&&(b.property&&"position"==b.property.name||"initialized"==b.type))for(var c=this._core.settings,d=c.center&&Math.ceil(c.items/2)||c.items,e=c.center&&-1*d||0,f=(b.property&&b.property.value||this._core.current())+e,g=this._core.clones().length,h=a.proxy(function(a,b){this.load(b)},this);e++-1||(e.each(a.proxy(function(c,d){var e,f=a(d),g=b.devicePixelRatio>1&&f.attr("data-src-retina")||f.attr("data-src");this._core.trigger("load",{element:f,url:g},"lazy"),f.is("img")?f.one("load.owl.lazy",a.proxy(function(){f.css("opacity",1),this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("src",g):(e=new Image,e.onload=a.proxy(function(){f.css({"background-image":"url("+g+")",opacity:"1"}),this._core.trigger("loaded",{element:f,url:g},"lazy")},this),e.src=g)},this)),this._loaded.push(d.get(0)))},c.prototype.destroy=function(){var a,b;for(a in this.handlers)this._core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Lazy=c}(window.Zepto||window.jQuery,window,document),function(a){var b=function(c){this._core=c,this._handlers={"initialized.owl.carousel":a.proxy(function(){this._core.settings.autoHeight&&this.update()},this),"changed.owl.carousel":a.proxy(function(a){this._core.settings.autoHeight&&"position"==a.property.name&&this.update()},this),"loaded.owl.lazy":a.proxy(function(a){this._core.settings.autoHeight&&a.element.closest("."+this._core.settings.itemClass)===this._core.$stage.children().eq(this._core.current())&&this.update()},this)},this._core.options=a.extend({},b.Defaults,this._core.options),this._core.$element.on(this._handlers)};b.Defaults={autoHeight:!1,autoHeightClass:"owl-height"},b.prototype.update=function(){this._core.$stage.parent().height(this._core.$stage.children().eq(this._core.current()).height()).addClass(this._core.settings.autoHeightClass)},b.prototype.destroy=function(){var a,b;for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoHeight=b}(window.Zepto||window.jQuery,window,document),function(a,b,c){var d=function(b){this._core=b,this._videos={},this._playing=null,this._fullscreen=!1,this._handlers={"resize.owl.carousel":a.proxy(function(a){this._core.settings.video&&!this.isInFullScreen()&&a.preventDefault()},this),"refresh.owl.carousel changed.owl.carousel":a.proxy(function(){this._playing&&this.stop()},this),"prepared.owl.carousel":a.proxy(function(b){var c=a(b.content).find(".owl-video");c.length&&(c.css("display","none"),this.fetch(c,a(b.content)))},this)},this._core.options=a.extend({},d.Defaults,this._core.options),this._core.$element.on(this._handlers),this._core.$element.on("click.owl.video",".owl-video-play-icon",a.proxy(function(a){this.play(a)},this))};d.Defaults={video:!1,videoHeight:!1,videoWidth:!1},d.prototype.fetch=function(a,b){var c=a.attr("data-vimeo-id")?"vimeo":"youtube",d=a.attr("data-vimeo-id")||a.attr("data-youtube-id"),e=a.attr("data-width")||this._core.settings.videoWidth,f=a.attr("data-height")||this._core.settings.videoHeight,g=a.attr("href");if(!g)throw new Error("Missing video URL.");if(d=g.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/),d[3].indexOf("youtu")>-1)c="youtube";else{if(!(d[3].indexOf("vimeo")>-1))throw new Error("Video URL not supported.");c="vimeo"}d=d[6],this._videos[g]={type:c,id:d,width:e,height:f},b.attr("data-video",g),this.thumbnail(a,this._videos[g])},d.prototype.thumbnail=function(b,c){var d,e,f,g=c.width&&c.height?'style="width:'+c.width+"px;height:"+c.height+'px;"':"",h=b.find("img"),i="src",j="",k=this._core.settings,l=function(a){e='
',d=k.lazyLoad?'
':'
',b.after(d),b.after(e)};return b.wrap('
"),this._core.settings.lazyLoad&&(i="data-src",j="owl-lazy"),h.length?(l(h.attr(i)),h.remove(),!1):void("youtube"===c.type?(f="http://img.youtube.com/vi/"+c.id+"/hqdefault.jpg",l(f)):"vimeo"===c.type&&a.ajax({type:"GET",url:"http://vimeo.com/api/v2/video/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a[0].thumbnail_large,l(f)}}))},d.prototype.stop=function(){this._core.trigger("stop",null,"video"),this._playing.find(".owl-video-frame").remove(),this._playing.removeClass("owl-video-playing"),this._playing=null},d.prototype.play=function(b){this._core.trigger("play",null,"video"),this._playing&&this.stop();var c,d,e=a(b.target||b.srcElement),f=e.closest("."+this._core.settings.itemClass),g=this._videos[f.attr("data-video")],h=g.width||"100%",i=g.height||this._core.$stage.height();"youtube"===g.type?c='':"vimeo"===g.type&&(c=''),f.addClass("owl-video-playing"),this._playing=f,d=a('
'+c+"
"),e.after(d)},d.prototype.isInFullScreen=function(){var d=c.fullscreenElement||c.mozFullScreenElement||c.webkitFullscreenElement;return d&&a(d).parent().hasClass("owl-video-frame")&&(this._core.speed(0),this._fullscreen=!0),d&&this._fullscreen&&this._playing?!1:this._fullscreen?(this._fullscreen=!1,!1):this._playing&&this._core.state.orientation!==b.orientation?(this._core.state.orientation=b.orientation,!1):!0},d.prototype.destroy=function(){var a,b;this._core.$element.off("click.owl.video");for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Video=d}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this.core=b,this.core.options=a.extend({},e.Defaults,this.core.options),this.swapping=!0,this.previous=d,this.next=d,this.handlers={"change.owl.carousel":a.proxy(function(a){"position"==a.property.name&&(this.previous=this.core.current(),this.next=a.property.value)},this),"drag.owl.carousel dragged.owl.carousel translated.owl.carousel":a.proxy(function(a){this.swapping="translated"==a.type},this),"translate.owl.carousel":a.proxy(function(){this.swapping&&(this.core.options.animateOut||this.core.options.animateIn)&&this.swap()},this)},this.core.$element.on(this.handlers)};e.Defaults={animateOut:!1,animateIn:!1},e.prototype.swap=function(){if(1===this.core.settings.items&&this.core.support3d){this.core.speed(0);var b,c=a.proxy(this.clear,this),d=this.core.$stage.children().eq(this.previous),e=this.core.$stage.children().eq(this.next),f=this.core.settings.animateIn,g=this.core.settings.animateOut;this.core.current()!==this.previous&&(g&&(b=this.core.coordinates(this.previous)-this.core.coordinates(this.next),d.css({left:b+"px"}).addClass("animated owl-animated-out").addClass(g).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",c)),f&&e.addClass("animated owl-animated-in").addClass(f).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",c))}},e.prototype.clear=function(b){a(b.target).css({left:""}).removeClass("animated owl-animated-out owl-animated-in").removeClass(this.core.settings.animateIn).removeClass(this.core.settings.animateOut),this.core.transitionEnd()},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this.core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Animate=e}(window.Zepto||window.jQuery,window,document),function(a,b,c){var d=function(b){this.core=b,this.core.options=a.extend({},d.Defaults,this.core.options),this.handlers={"translated.owl.carousel refreshed.owl.carousel":a.proxy(function(){this.autoplay() +},this),"play.owl.autoplay":a.proxy(function(a,b,c){this.play(b,c)},this),"stop.owl.autoplay":a.proxy(function(){this.stop()},this),"mouseover.owl.autoplay":a.proxy(function(){this.core.settings.autoplayHoverPause&&this.pause()},this),"mouseleave.owl.autoplay":a.proxy(function(){this.core.settings.autoplayHoverPause&&this.autoplay()},this)},this.core.$element.on(this.handlers)};d.Defaults={autoplay:!1,autoplayTimeout:5e3,autoplayHoverPause:!1,autoplaySpeed:!1},d.prototype.autoplay=function(){this.core.settings.autoplay&&!this.core.state.videoPlay?(b.clearInterval(this.interval),this.interval=b.setInterval(a.proxy(function(){this.play()},this),this.core.settings.autoplayTimeout)):b.clearInterval(this.interval)},d.prototype.play=function(){return c.hidden===!0||this.core.state.isTouch||this.core.state.isScrolling||this.core.state.isSwiping||this.core.state.inMotion?void 0:this.core.settings.autoplay===!1?void b.clearInterval(this.interval):void this.core.next(this.core.settings.autoplaySpeed)},d.prototype.stop=function(){b.clearInterval(this.interval)},d.prototype.pause=function(){b.clearInterval(this.interval)},d.prototype.destroy=function(){var a,c;b.clearInterval(this.interval);for(a in this.handlers)this.core.$element.off(a,this.handlers[a]);for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},a.fn.owlCarousel.Constructor.Plugins.autoplay=d}(window.Zepto||window.jQuery,window,document),function(a){"use strict";var b=function(c){this._core=c,this._initialized=!1,this._pages=[],this._controls={},this._templates=[],this.$element=this._core.$element,this._overrides={next:this._core.next,prev:this._core.prev,to:this._core.to},this._handlers={"prepared.owl.carousel":a.proxy(function(b){this._core.settings.dotsData&&this._templates.push(a(b.content).find("[data-dot]").andSelf("[data-dot]").attr("data-dot"))},this),"add.owl.carousel":a.proxy(function(b){this._core.settings.dotsData&&this._templates.splice(b.position,0,a(b.content).find("[data-dot]").andSelf("[data-dot]").attr("data-dot"))},this),"remove.owl.carousel prepared.owl.carousel":a.proxy(function(a){this._core.settings.dotsData&&this._templates.splice(a.position,1)},this),"change.owl.carousel":a.proxy(function(a){if("position"==a.property.name&&!this._core.state.revert&&!this._core.settings.loop&&this._core.settings.navRewind){var b=this._core.current(),c=this._core.maximum(),d=this._core.minimum();a.data=a.property.value>c?b>=c?d:c:a.property.value").addClass(d.dotClass).append(a("")).prop("outerHTML")]),d.navContainer&&d.dotsContainer||(this._controls.$container=a("
").addClass(d.controlsClass).appendTo(this.$element)),this._controls.$indicators=d.dotsContainer?a(d.dotsContainer):a("
").hide().addClass(d.dotsClass).appendTo(this._controls.$container),this._controls.$indicators.on("click","div",a.proxy(function(b){var c=a(b.target).parent().is(this._controls.$indicators)?a(b.target).index():a(b.target).parent().index();b.preventDefault(),this.to(c,d.dotsSpeed)},this)),b=d.navContainer?a(d.navContainer):a("
").addClass(d.navContainerClass).prependTo(this._controls.$container),this._controls.$next=a("<"+d.navElement+">"),this._controls.$previous=this._controls.$next.clone(),this._controls.$previous.addClass(d.navClass[0]).html(d.navText[0]).hide().prependTo(b).on("click",a.proxy(function(){this.prev(d.navSpeed)},this)),this._controls.$next.addClass(d.navClass[1]).html(d.navText[1]).hide().appendTo(b).on("click",a.proxy(function(){this.next(d.navSpeed)},this));for(c in this._overrides)this._core[c]=a.proxy(this[c],this)},b.prototype.destroy=function(){var a,b,c,d;for(a in this._handlers)this.$element.off(a,this._handlers[a]);for(b in this._controls)this._controls[b].remove();for(d in this.overides)this._core[d]=this._overrides[d];for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},b.prototype.update=function(){var a,b,c,d=this._core.settings,e=this._core.clones().length/2,f=e+this._core.items().length,g=d.center||d.autoWidth||d.dotData?1:d.dotsEach||d.items;if("page"!==d.slideBy&&(d.slideBy=Math.min(d.slideBy,d.items)),d.dots||"page"==d.slideBy)for(this._pages=[],a=e,b=0,c=0;f>a;a++)(b>=g||0===b)&&(this._pages.push({start:a-e,end:a-e+g-1}),b=0,++c),b+=this._core.mergers(this._core.relative(a))},b.prototype.draw=function(){var b,c,d="",e=this._core.settings,f=(this._core.$stage.children(),this._core.relative(this._core.current()));if(!e.nav||e.loop||e.navRewind||(this._controls.$previous.toggleClass("disabled",0>=f),this._controls.$next.toggleClass("disabled",f>=this._core.maximum())),this._controls.$previous.toggle(e.nav),this._controls.$next.toggle(e.nav),e.dots){if(b=this._pages.length-this._controls.$indicators.children().length,e.dotData&&0!==b){for(c=0;c0?(d=new Array(b+1).join(this._templates[0]),this._controls.$indicators.append(d)):0>b&&this._controls.$indicators.children().slice(b).remove();this._controls.$indicators.find(".active").removeClass("active"),this._controls.$indicators.children().eq(a.inArray(this.current(),this._pages)).addClass("active")}this._controls.$indicators.toggle(e.dots)},b.prototype.onTrigger=function(b){var c=this._core.settings;b.page={index:a.inArray(this.current(),this._pages),count:this._pages.length,size:c&&(c.center||c.autoWidth||c.dotData?1:c.dotsEach||c.items)}},b.prototype.current=function(){var b=this._core.relative(this._core.current());return a.grep(this._pages,function(a){return a.start<=b&&a.end>=b}).pop()},b.prototype.getPosition=function(b){var c,d,e=this._core.settings;return"page"==e.slideBy?(c=a.inArray(this.current(),this._pages),d=this._pages.length,b?++c:--c,c=this._pages[(c%d+d)%d].start):(c=this._core.relative(this._core.current()),d=this._core.items().length,b?c+=e.slideBy:c-=e.slideBy),c},b.prototype.next=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!0),b)},b.prototype.prev=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!1),b)},b.prototype.to=function(b,c,d){var e;d?a.proxy(this._overrides.to,this._core)(b,c):(e=this._pages.length,a.proxy(this._overrides.to,this._core)(this._pages[(b%e+e)%e].start,c))},a.fn.owlCarousel.Constructor.Plugins.Navigation=b}(window.Zepto||window.jQuery,window,document),function(a,b){"use strict";var c=function(d){this._core=d,this._hashes={},this.$element=this._core.$element,this._handlers={"initialized.owl.carousel":a.proxy(function(){"URLHash"==this._core.settings.startPosition&&a(b).trigger("hashchange.owl.navigation")},this),"prepared.owl.carousel":a.proxy(function(b){var c=a(b.content).find("[data-hash]").andSelf("[data-hash]").attr("data-hash");this._hashes[c]=b.content},this)},this._core.options=a.extend({},c.Defaults,this._core.options),this.$element.on(this._handlers),a(b).on("hashchange.owl.navigation",a.proxy(function(){var a=b.location.hash.substring(1),c=this._core.$stage.children(),d=this._hashes[a]&&c.index(this._hashes[a])||0;return a?void this._core.to(d,!1,!0):!1},this))};c.Defaults={URLhashListener:!1},c.prototype.destroy=function(){var c,d;a(b).off("hashchange.owl.navigation");for(c in this._handlers)this._core.$element.off(c,this._handlers[c]);for(d in Object.getOwnPropertyNames(this))"function"!=typeof this[d]&&(this[d]=null)},a.fn.owlCarousel.Constructor.Plugins.Hash=c}(window.Zepto||window.jQuery,window,document); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/owl-carousel/views/owl-carousel.php b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/owl-carousel/views/owl-carousel.php new file mode 100644 index 00000000..69409b30 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/media/extensions/slider/extensions/owl-carousel/views/owl-carousel.php @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/scratch-parent/framework-customizations/extensions/portfolio/config.php b/scratch-parent/framework-customizations/extensions/portfolio/config.php new file mode 100644 index 00000000..b60c5e52 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/config.php @@ -0,0 +1,18 @@ + array( + 'width' => 223, + 'height' => 139, + 'crop' => true + ), + 'gallery-image' => array( + 'width' => 700, + 'height' => 455, + 'crop' => true + ) +); diff --git a/scratch-parent/framework-customizations/extensions/portfolio/helpers.php b/scratch-parent/framework-customizations/extensions/portfolio/helpers.php new file mode 100644 index 00000000..323a9322 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/helpers.php @@ -0,0 +1,93 @@ + false + ); + + if ( is_numeric( $term_ids ) ) { + $args['parent'] = $term_ids; + } elseif ( is_array( $term_ids ) ) { + $args['include'] = $term_ids; + } + + $categories = get_terms( $taxonomy, $args ); + + if ( ! is_wp_error( $categories ) && ! empty( $categories ) ) { + + if ( count( $categories ) === 1 ) { + $categories = array_values( $categories ); + $categories = get_terms( $taxonomy, array( 'parent' => $categories[0]->term_id, 'hide_empty' => false ) ); + } + + foreach ( $categories as $key => $category ) { + $children = get_term_children( $category->term_id, $taxonomy ); + $categories[ $key ]->children = $children; + + //remove empty categories + if(($category->count == 0) && (is_wp_error($children) || empty($children))) { + unset($categories[$key]); + } + } + + return $categories; + } + + return array(); +} + +function fw_ext_portfolio_get_sort_classes( $items, $taxonomy, $categories, $prefix = 'category_' ) { + + $classes = array(); + $categories_classes = array(); + foreach ( $items as $key => $item ) { + $class_name = ''; + $terms = wp_get_post_terms( $item->ID, $taxonomy ); + + foreach ( $terms as $term ) { + foreach ( $categories as $category ) { + if ( $term->term_id == $category->term_id ) { + $class_name .= $prefix . $category->term_id . ' '; + $categories_classes[ $term->term_id ] = true; + } else { + if ( in_array( $term->term_id, $category->children, true ) ) { + $class_name .= $prefix . $category->term_id . ' '; + $categories_classes[ $term->term_id ] = true; + } + } + $classes[ $item->ID ] = $class_name; + } + } + } + + return $classes; +} + +function _fw_ext_portfolio_theme_action_set_posts_per_page( $query ) { + if( !$query->is_main_query() ) { + return; + } + + if( isset( $query->query['post_type'] ) && $query->query['post_type'] != fw()->extensions->get('portfolio')->get_post_type_name()){ + return; + } + + $query->set( 'posts_per_page', -1 ); +} +add_action( 'pre_get_posts', '_fw_ext_portfolio_theme_action_set_posts_per_page' ); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static.php b/scratch-parent/framework-customizations/extensions/portfolio/static.php new file mode 100644 index 00000000..231b3bab --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static.php @@ -0,0 +1,83 @@ +extensions->get( 'portfolio' ); + $settings = $ext_instance->get_settings(); + + if ( is_singular( $settings['post_type'] ) ) { + + wp_enqueue_style( + 'fw-extension-'. $ext_instance->get_name() .'-nivo-default', + $ext_instance->locate_css_URI( 'NivoSlider/themes/default/default' ), + array(), + $ext_instance->manifest->get_version() + ); + wp_enqueue_style( + 'fw-extension-'. $ext_instance->get_name() .'-nivo-bar', + $ext_instance->locate_css_URI( 'NivoSlider/themes/bar/bar' ), + array(), + $ext_instance->manifest->get_version() + ); + wp_enqueue_style( + 'fw-extension-'. $ext_instance->get_name() .'-nivo-dark', + $ext_instance->locate_css_URI( 'NivoSlider/themes/dark/dark' ), + array(), + $ext_instance->manifest->get_version() + ); + wp_enqueue_style( + 'fw-extension-'. $ext_instance->get_name() .'-nivo-light', + $ext_instance->locate_css_URI( 'NivoSlider/themes/light/light' ), + array(), + $ext_instance->manifest->get_version() + ); + wp_enqueue_style( + 'fw-extension-'. $ext_instance->get_name() .'-nivo-slider', + $ext_instance->locate_css_URI( 'nivo-slider' ), + array(), + $ext_instance->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-extension-'. $ext_instance->get_name() .'-nivoslider', + $ext_instance->locate_js_URI( 'jquery.nivo.slider' ), + array( 'jquery' ), + $ext_instance->manifest->get_version(), + true + ); + wp_enqueue_script( + 'fw-extension-'. $ext_instance->get_name() .'-script', + $ext_instance->locate_js_URI( 'projects-script' ), + array( 'fw-extension-'. $ext_instance->get_name() .'-nivoslider' ), + $ext_instance->manifest->get_version(), + true + ); + + } elseif ( is_tax( $settings['taxonomy_name'] ) || is_post_type_archive( $settings['post_type'] ) ) { + wp_enqueue_style( + 'fw-extension-'. $ext_instance->get_name() .'-style', + $ext_instance->locate_css_URI( 'style' ), + array(), + $ext_instance->manifest->get_version() + ); + wp_enqueue_script( + 'fw-extension-'. $ext_instance->get_name() .'-mixitup', + $ext_instance->locate_js_URI( 'jquery.mixitup.min' ), + array( 'jquery' ), + $ext_instance->manifest->get_version(), + true + ); + wp_enqueue_script( + 'fw-extension-'. $ext_instance->get_name() .'-script', + $ext_instance->locate_js_URI( 'portfolio-script' ), + array( 'fw-extension-'. $ext_instance->get_name() .'-mixitup' ), + $ext_instance->manifest->get_version(), + true + ); + + } +} + + + diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/arrows.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/arrows.png new file mode 100644 index 00000000..8f562bd8 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/arrows.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/bar.css b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/bar.css new file mode 100644 index 00000000..668bc55f --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/bar.css @@ -0,0 +1,132 @@ +/* +Skin Name: Nivo Slider Bar Theme +Skin URI: http://nivo.dev7studios.com +Description: The bottom bar skin for the Nivo Slider. +Version: 1.0 +Author: Gilbert Pellegrom +Author URI: http://dev7studios.com +Supports Thumbs: false +*/ + +.theme-bar.slider-wrapper { + position: relative; + border: 1px solid #333; + overflow: hidden; +} +.theme-bar .nivoSlider { + position:relative; + background:#fff url(loading.gif) no-repeat 50% 50%; +} +.theme-bar .nivoSlider img { + position:absolute; + top:0px; + left:0px; + display:none; +} +.theme-bar .nivoSlider a { + border:0; + display:block; +} + +.theme-bar .nivo-controlNav { + position: absolute; + left: 0; + bottom: -41px; + z-index: 10; + width: 100%; + height: 30px; + text-align: center; + padding: 5px 0; + border-top: 1px solid #333; + background: #333; + background: -moz-linear-gradient(top, #565656 0%, #333333 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#565656), color-stop(100%,#333333)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #565656 0%,#333333 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #565656 0%,#333333 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #565656 0%,#333333 100%); /* IE10+ */ + background: linear-gradient(to bottom, #565656 0%,#333333 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#565656', endColorstr='#333333',GradientType=0 ); /* IE6-9 */ + opacity: 0.5; + -webkit-transition: all 200ms ease-in-out; + -moz-transition: all 200ms ease-in-out; + -o-transition: all 200ms ease-in-out; + transition: all 200ms ease-in-out; +} +.theme-bar:hover .nivo-controlNav { + bottom: 0; + opacity: 1; +} +.theme-bar .nivo-controlNav a { + display:inline-block; + width:22px; + height:22px; + background:url(bullets.png) no-repeat; + text-indent:-9999px; + border:0; + margin: 5px 2px 0 2px; +} +.theme-bar .nivo-controlNav a.active { + background-position:0 -22px; +} + +.theme-bar .nivo-directionNav a { + display:block; + border:0; + color: #fff; + text-transform: uppercase; + top: auto; + bottom: 10px; + z-index: 11; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 20px; + opacity: 0.5; + -webkit-transition: all 200ms ease-in-out; + -moz-transition: all 200ms ease-in-out; + -o-transition: all 200ms ease-in-out; + transition: all 200ms ease-in-out; +} +.theme-bar a.nivo-nextNav { right: -50px; } +.theme-bar a.nivo-prevNav { left: -50px; } +.theme-bar:hover a.nivo-nextNav { + right: 15px; + opacity: 1; +} +.theme-bar:hover a.nivo-prevNav { + left: 15px; + opacity: 1; +} +.theme-bar .nivo-directionNav a:hover { color: #ddd; } + +.theme-bar .nivo-caption { + font-family: Helvetica, Arial, sans-serif; + -webkit-transition: all 200ms ease-in-out; + -moz-transition: all 200ms ease-in-out; + -o-transition: all 200ms ease-in-out; + transition: all 200ms ease-in-out; +} +.theme-bar:hover .nivo-caption { + bottom: 41px; +} +.theme-bar .nivo-caption a { + color:#fff; + border-bottom:1px dotted #fff; +} +.theme-bar .nivo-caption a:hover { + color:#fff; +} + +.theme-bar .nivo-controlNav.nivo-thumbs-enabled { + width: 100%; +} +.theme-bar .nivo-controlNav.nivo-thumbs-enabled a { + width: auto; + height: auto; + background: none; + margin-bottom: 5px; +} +.theme-bar .nivo-controlNav.nivo-thumbs-enabled img { + display: block; + width: 120px; + height: auto; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/bullets.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/bullets.png new file mode 100644 index 00000000..a84c9c0b Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/bullets.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/loading.gif b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/loading.gif new file mode 100644 index 00000000..1560b646 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/bar/loading.gif differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/arrows.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/arrows.png new file mode 100644 index 00000000..fe7f378c Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/arrows.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/bullets.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/bullets.png new file mode 100644 index 00000000..92b2124a Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/bullets.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/dark.css b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/dark.css new file mode 100644 index 00000000..5b2a3ac7 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/dark.css @@ -0,0 +1,102 @@ +/* +Skin Name: Nivo Slider Dark Theme +Skin URI: http://nivo.dev7studios.com +Description: A dark skin for the Nivo Slider. +Version: 1.0 +Author: Gilbert Pellegrom +Author URI: http://dev7studios.com +Supports Thumbs: true +*/ + +.theme-dark.slider-wrapper { + background: #222; + padding: 10px; +} +.theme-dark .nivoSlider { + position:relative; + background:#fff url(loading.gif) no-repeat 50% 50%; + margin-bottom:10px; + overflow: visible; +} +.theme-dark .nivoSlider img { + position:absolute; + top:0px; + left:0px; + display:none; +} +.theme-dark .nivoSlider a { + border:0; + display:block; +} + +.theme-dark .nivo-controlNav { + text-align: left; + padding: 0; + position: relative; + z-index: 10; +} +.theme-dark .nivo-controlNav a { + display:inline-block; + width:10px; + height:10px; + background:url(bullets.png) no-repeat 0 2px; + text-indent:-9999px; + border:0; + margin: 0 2px; +} +.theme-dark .nivo-controlNav a.active { + background-position:0 100%; +} + +.theme-dark .nivo-directionNav a { + display:block; + width:30px; + height:30px; + background: url(arrows.png) no-repeat; + text-indent:-9999px; + border:0; + top: auto; + bottom: -36px; + z-index: 11; +} +.theme-dark .nivo-directionNav a:hover { + background-color: #333; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.theme-dark a.nivo-nextNav { + background-position:-16px 50%; + right:0px; +} +.theme-dark a.nivo-prevNav { + background-position:11px 50%; + left: auto; + right: 35px; +} + +.theme-dark .nivo-caption { + font-family: Helvetica, Arial, sans-serif; +} +.theme-dark .nivo-caption a { + color:#fff; + border-bottom:1px dotted #fff; +} +.theme-dark .nivo-caption a:hover { + color:#fff; +} + +.theme-dark .nivo-controlNav.nivo-thumbs-enabled { + width: 80%; +} +.theme-dark .nivo-controlNav.nivo-thumbs-enabled a { + width: auto; + height: auto; + background: none; + margin-bottom: 5px; +} +.theme-dark .nivo-controlNav.nivo-thumbs-enabled img { + display: block; + width: 120px; + height: auto; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/loading.gif b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/loading.gif new file mode 100644 index 00000000..1560b646 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/dark/loading.gif differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/arrows.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/arrows.png new file mode 100644 index 00000000..8f562bd8 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/arrows.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/arrows2.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/arrows2.png new file mode 100644 index 00000000..7a88c35c Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/arrows2.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/bullets.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/bullets.png new file mode 100644 index 00000000..a84c9c0b Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/bullets.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/default.css b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/default.css new file mode 100644 index 00000000..c877a1d8 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/default.css @@ -0,0 +1,93 @@ +/* +Skin Name: Nivo Slider Default Theme +Skin URI: http://nivo.dev7studios.com +Description: The default skin for the Nivo Slider. +Version: 1.3 +Author: Gilbert Pellegrom +Author URI: http://dev7studios.com +Supports Thumbs: true +*/ + +.theme-default .nivoSlider { + position:relative; + background:#fff url(loading.gif) no-repeat 50% 50%; + margin-bottom:10px; + -webkit-box-shadow: 0px 1px 5px 0px #4a4a4a; + -moz-box-shadow: 0px 1px 5px 0px #4a4a4a; + box-shadow: 0px 1px 5px 0px #4a4a4a; +} +.theme-default .nivoSlider img { + position:absolute; + top:0px; + left:0px; + display:none; +} +.theme-default .nivoSlider a { + border:0; + display:block; +} + +.theme-default .nivo-controlNav { + text-align: center; + padding: 20px 0; +} +.theme-default .nivo-controlNav a { + display:inline-block; + width:22px; + height:22px; + background:url(bullets.png) no-repeat; + text-indent:-9999px; + border:0; + margin: 0 2px; +} +.theme-default .nivo-controlNav a.active { + background-position:0 -22px; +} + +.theme-default .nivo-directionNav a { + display:block; + width:30px; + height:30px; + background:url(arrows.png) no-repeat; + text-indent:-9999px; + border:0; + opacity: 0; + -webkit-transition: all 200ms ease-in-out; + -moz-transition: all 200ms ease-in-out; + -o-transition: all 200ms ease-in-out; + transition: all 200ms ease-in-out; +} +.theme-default:hover .nivo-directionNav a { opacity: 1; } +.theme-default a.nivo-nextNav { + background-position:-30px 0; + right:15px; +} +.theme-default a.nivo-prevNav { + left:15px; +} + +.theme-default .nivo-caption { + font-family: Helvetica, Arial, sans-serif; +} +.theme-default .nivo-caption a { + color:#fff; + border-bottom:1px dotted #fff; +} +.theme-default .nivo-caption a:hover { + color:#fff; +} + +.theme-default .nivo-controlNav.nivo-thumbs-enabled { + width: 100%; +} +.theme-default .nivo-controlNav.nivo-thumbs-enabled a { + width: auto; + height: auto; + background: none; + margin-bottom: 5px; +} +.theme-default .nivo-controlNav.nivo-thumbs-enabled img { + display: block; + width: 120px; + height: auto; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/loading.gif b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/loading.gif new file mode 100644 index 00000000..1560b646 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/default/loading.gif differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/arrows.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/arrows.png new file mode 100644 index 00000000..1c5d881f Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/arrows.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/bullets.png b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/bullets.png new file mode 100644 index 00000000..54d1a7bf Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/bullets.png differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/light.css b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/light.css new file mode 100644 index 00000000..3146c057 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/light.css @@ -0,0 +1,102 @@ +/* +Skin Name: Nivo Slider Light Theme +Skin URI: http://nivo.dev7studios.com +Description: A light skin for the Nivo Slider. +Version: 1.0 +Author: Gilbert Pellegrom +Author URI: http://dev7studios.com +Supports Thumbs: true +*/ + +.theme-light.slider-wrapper { + background: #fff; + padding: 10px; +} +.theme-light .nivoSlider { + position:relative; + background:#fff url(loading.gif) no-repeat 50% 50%; + margin-bottom:10px; + overflow: visible; +} +.theme-light .nivoSlider img { + position:absolute; + top:0px; + left:0px; + display:none; +} +.theme-light .nivoSlider a { + border:0; + display:block; +} + +.theme-light .nivo-controlNav { + text-align: left; + padding: 0; + position: relative; + z-index: 10; +} +.theme-light .nivo-controlNav a { + display:inline-block; + width:10px; + height:10px; + background:url(bullets.png) no-repeat; + text-indent:-9999px; + border:0; + margin: 0 2px; +} +.theme-light .nivo-controlNav a.active { + background-position:0 100%; +} + +.theme-light .nivo-directionNav a { + display:block; + width:30px; + height:30px; + background: url(arrows.png) no-repeat; + text-indent:-9999px; + border:0; + top: auto; + bottom: -36px; + z-index: 11; +} +.theme-light .nivo-directionNav a:hover { + background-color: #eee; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.theme-light a.nivo-nextNav { + background-position:160% 50%; + right:0px; +} +.theme-light a.nivo-prevNav { + background-position:-60% 50%; + left: auto; + right: 35px; +} + +.theme-light .nivo-caption { + font-family: Helvetica, Arial, sans-serif; +} +.theme-light .nivo-caption a { + color:#fff; + border-bottom:1px dotted #fff; +} +.theme-light .nivo-caption a:hover { + color:#fff; +} + +.theme-light .nivo-controlNav.nivo-thumbs-enabled { + width: 80%; +} +.theme-light .nivo-controlNav.nivo-thumbs-enabled a { + width: auto; + height: auto; + background: none; + margin-bottom: 5px; +} +.theme-light .nivo-controlNav.nivo-thumbs-enabled img { + display: block; + width: 120px; + height: auto; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/loading.gif b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/loading.gif new file mode 100644 index 00000000..1560b646 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/css/NivoSlider/themes/light/loading.gif differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/nivo-slider.css b/scratch-parent/framework-customizations/extensions/portfolio/static/css/nivo-slider.css new file mode 100644 index 00000000..5bd1b5d2 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/css/nivo-slider.css @@ -0,0 +1,113 @@ +/* + * jQuery Nivo Slider v3.2 + * http://nivo.dev7studios.com + * + * Copyright 2012, Dev7studios + * Free to use and abuse under the MIT license. + * http://www.opensource.org/licenses/mit-license.php + */ + +/* The Nivo Slider styles */ +.nivoSlider { + position:relative; + width:100%; + height:auto; + overflow: hidden; +} +.nivoSlider img { + position:absolute; + top:0px; + left:0px; + max-width: none; +} +.nivo-main-image { + display: block !important; + position: relative !important; + width: 100% !important; +} + +/* If an image is wrapped in a link */ +.nivoSlider a.nivo-imageLink { + position:absolute; + top:0px; + left:0px; + width:100%; + height:100%; + border:0; + padding:0; + margin:0; + z-index:6; + display:none; + background:white; + filter:alpha(opacity=0); + opacity:0; +} +/* The slices and boxes in the Slider */ +.nivo-slice { + display:block; + position:absolute; + z-index:5; + height:100%; + top:0; +} +.nivo-box { + display:block; + position:absolute; + z-index:5; + overflow:hidden; +} +.nivo-box img { display:block; } + +/* Caption styles */ +.nivo-caption { + position:absolute; + left:0px; + bottom:0px; + background:#000; + color:#fff; + width:100%; + z-index:8; + padding: 5px 10px; + opacity: 0.8; + overflow: hidden; + display: none; + -moz-opacity: 0.8; + filter:alpha(opacity=8); + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ +} +.nivo-caption p { + padding:5px; + margin:0; +} +.nivo-caption a { + display:inline !important; +} +.nivo-html-caption { + display:none; +} +/* Direction nav styles (e.g. Next & Prev) */ +.nivo-directionNav a { + position:absolute; + top:45%; + z-index:9; + cursor:pointer; +} +.nivo-prevNav { + left:0px; +} +.nivo-nextNav { + right:0px; +} +/* Control nav styles (e.g. 1,2,3...) */ +.nivo-controlNav { + text-align:center; + padding: 15px 0; +} +.nivo-controlNav a { + cursor:pointer; +} +.nivo-controlNav a.active { + font-weight:bold; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/css/style.css b/scratch-parent/framework-customizations/extensions/portfolio/static/css/style.css new file mode 100644 index 00000000..dac8bbb0 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/css/style.css @@ -0,0 +1,3 @@ +#Container .portfolio-list .portfolio-item{ + display: none; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/img/no-photo.jpg b/scratch-parent/framework-customizations/extensions/portfolio/static/img/no-photo.jpg new file mode 100644 index 00000000..4d082e1d Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/portfolio/static/img/no-photo.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/js/jquery.mixitup.min.js b/scratch-parent/framework-customizations/extensions/portfolio/static/js/jquery.mixitup.min.js new file mode 100644 index 00000000..a4fa70ab --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/js/jquery.mixitup.min.js @@ -0,0 +1,14 @@ +/**! + * MixItUp v2.1.5 + * + * @copyright Copyright 2014 KunkaLabs Limited. + * @author KunkaLabs Limited. + * @link https://mixitup.kunkalabs.com + * + * @license Commercial use requires a commercial license. + * https://mixitup.kunkalabs.com/licenses/ + * + * Non-commercial use permitted under terms of CC-BY-NC license. + * http://creativecommons.org/licenses/by-nc/3.0/ + */ +!function(a,b){a.MixItUp=function(){var b=this;b._execAction("_constructor",0),a.extend(b,{selectors:{target:".mix",filter:".filter",sort:".sort"},animation:{enable:!0,effects:"fade scale",duration:600,easing:"ease",perspectiveDistance:"3000",perspectiveOrigin:"50% 50%",queue:!0,queueLimit:1,animateChangeLayout:!1,animateResizeContainer:!0,animateResizeTargets:!1,staggerSequence:!1,reverseOut:!1},callbacks:{onMixLoad:!1,onMixStart:!1,onMixBusy:!1,onMixEnd:!1,onMixFail:!1,_user:!1},controls:{enable:!0,live:!1,toggleFilterButtons:!1,toggleLogic:"or",activeClass:"active"},layout:{display:"inline-block",containerClass:"",containerClassFail:"fail"},load:{filter:"all",sort:!1},_$body:null,_$container:null,_$targets:null,_$parent:null,_$sortButtons:null,_$filterButtons:null,_suckMode:!1,_mixing:!1,_sorting:!1,_clicking:!1,_loading:!0,_changingLayout:!1,_changingClass:!1,_changingDisplay:!1,_origOrder:[],_startOrder:[],_newOrder:[],_activeFilter:null,_toggleArray:[],_toggleString:"",_activeSort:"default:asc",_newSort:null,_startHeight:null,_newHeight:null,_incPadding:!0,_newDisplay:null,_newClass:null,_targetsBound:0,_targetsDone:0,_queue:[],_$show:a(),_$hide:a()}),b._execAction("_constructor",1)},a.MixItUp.prototype={constructor:a.MixItUp,_instances:{},_handled:{_filter:{},_sort:{}},_bound:{_filter:{},_sort:{}},_actions:{},_filters:{},extend:function(b){for(var c in b)a.MixItUp.prototype[c]=b[c]},addAction:function(b,c,d,e){a.MixItUp.prototype._addHook("_actions",b,c,d,e)},addFilter:function(b,c,d,e){a.MixItUp.prototype._addHook("_filters",b,c,d,e)},_addHook:function(b,c,d,e,f){var g=a.MixItUp.prototype[b],h={};f=1===f||"post"===f?"post":"pre",h[c]={},h[c][f]={},h[c][f][d]=e,a.extend(!0,g,h)},_init:function(b,c){var d=this;if(d._execAction("_init",0,arguments),c&&a.extend(!0,d,c),d._$body=a("body"),d._domNode=b,d._$container=a(b),d._$container.addClass(d.layout.containerClass),d._id=b.id,d._platformDetect(),d._brake=d._getPrefixedCSS("transition","none"),d._refresh(!0),d._$parent=d._$targets.parent().length?d._$targets.parent():d._$container,d.load.sort&&(d._newSort=d._parseSort(d.load.sort),d._newSortString=d.load.sort,d._activeSort=d.load.sort,d._sort(),d._printSort()),d._activeFilter="all"===d.load.filter?d.selectors.target:"none"===d.load.filter?"":d.load.filter,d.controls.enable&&d._bindHandlers(),d.controls.toggleFilterButtons){d._buildToggleArray();for(var e=0;e-1){var k=d._helpers._camelCase(i.substring(5,i.length));f.dataset[k]=j}}}f.mixParent===b&&(f.mixParent=d._id)}if(d._$targets.length&&a||!d._origOrder.length&&d._$targets.length){d._origOrder=[];for(var e=0;e-1)&&(a(e.selectors.sort).removeClass(e.controls.activeClass),f(c,d),e.sort(g))}if("filter"===d){var h,i=c.attr("data-filter"),j="or"===e.controls.toggleLogic?",":"";e.controls.toggleFilterButtons?(e._buildToggleArray(),c.hasClass(e.controls.activeClass)?(f(c,d,!0),h=e._toggleArray.indexOf(i),e._toggleArray.splice(h,1)):(f(c,d),e._toggleArray.push(i)),e._toggleArray=a.grep(e._toggleArray,function(a){return a}),e._toggleString=e._toggleArray.join(j),e.filter(e._toggleString)):c.hasClass(e.controls.activeClass)||(a(e.selectors.filter).removeClass(e.controls.activeClass),f(c,d),e.filter(i))}e._execAction("_processClick",1,arguments)}else"function"==typeof e.callbacks.onMixBusy&&e.callbacks.onMixBusy.call(e._domNode,e._state,e),e._execAction("_processClickBusy",1,arguments)},_buildToggleArray:function(){var a=this,b=a._activeFilter.replace(/\s/g,"");if(a._execAction("_buildToggleArray",0,arguments),"or"===a.controls.toggleLogic)a._toggleArray=b.split(",");else{a._toggleArray=b.split("."),!a._toggleArray[0]&&a._toggleArray.shift();for(var c,d=0;c=a._toggleArray[d];d++)a._toggleArray[d]="."+c}a._execAction("_buildToggleArray",1,arguments)},_updateControls:function(c,d){var e=this,f={filter:c.filter,sort:c.sort},g=function(a,b){d&&"filter"==h&&"none"!==f.filter&&""!==f.filter?a.filter(b).addClass(e.controls.activeClass):a.removeClass(e.controls.activeClass).filter(b).addClass(e.controls.activeClass)},h="filter",i=null;e._execAction("_updateControls",0,arguments),c.filter===b&&(f.filter=e._activeFilter),c.sort===b&&(f.sort=e._activeSort),f.filter===e.selectors.target&&(f.filter="all");for(var j=0;2>j;j++)i=e.controls.live?a(e.selectors[h]):e["_$"+h+"Buttons"],i&&g(i,"[data-"+h+'="'+f[h]+'"]'),h="sort";e._execAction("_updateControls",1,arguments)},_filter:function(){var b=this;b._execAction("_filter",0);for(var c=0;cg?"asc"==e?-1:1:g>h?"asc"==e?1:-1:g==h&&d._newSort.length>c+1?d._compare(a,b,c+1):0},_printSort:function(a){var b=this,c=a?b._startOrder:b._newOrder,d=b._$parent[0].querySelectorAll(b.selectors.target),e=d[d.length-1].nextElementSibling,f=document.createDocumentFragment();b._execAction("_printSort",0,arguments);for(var g=0;g-1){if(c){var d=a.animation.effects.indexOf(b+"(");if(d>-1){var e=a.animation.effects.substring(d),f=/\(([^)]+)\)/.exec(e),g=f[1];return{val:g}}}return!0}return!1},d=function(a,b){return b?"-"===a.charAt(0)?a.substr(1,a.length):"-"+a:a},e=function(a,e){for(var f=[["scale",".01"],["translateX","20px"],["translateY","20px"],["translateZ","20px"],["rotateX","90deg"],["rotateY","90deg"],["rotateZ","180deg"]],g=0;gi;i++){var j=0===i?j=b._prefix:"";b._ff&&b._ff<=20&&(h[j+"transition-property"]="all",h[j+"transition-timing-function"]=b.animation.easing+"ms",h[j+"transition-duration"]=b.animation.duration+"ms"),h[j+"transition-delay"]=g+"ms",h[j+"transform"]="translate("+f.x+"px,"+f.y+"px)"}(b.effects.transform||b.effects.opacity)&&b._bindTargetDone(e),b._ff&&b._ff<=20?e.css(h):e.css(b.effects.transition).css(h)}for(var c=0;ci;i++){var j=0===i?j=b._prefix:"";k[j+"transition-delay"]=g+"ms",k[j+"transform"]=b.effects.transformOut,k.opacity=b.effects.opacity}e.css(b.effects.transition).css(k),(b.effects.transform||b.effects.opacity)&&b._bindTargetDone(e)}b._execAction("_animateTargets",1)},_bindTargetDone:function(b){var c=this,d=b[0];c._execAction("_bindTargetDone",0,arguments),d.dataset.bound||(d.dataset.bound=!0,c._targetsBound++,b.on("webkitTransitionEnd.mixItUp transitionend.mixItUp",function(e){(e.originalEvent.propertyName.indexOf("transform")>-1||e.originalEvent.propertyName.indexOf("opacity")>-1)&&a(e.originalEvent.target).is(c.selectors.target)&&(b.off(".mixItUp"),delete d.dataset.bound,c._targetDone())})),c._execAction("_bindTargetDone",1,arguments)},_targetDone:function(){var a=this;a._execAction("_targetDone",0),a._targetsDone++,a._targetsDone===a._targetsBound&&a._cleanUp(),a._execAction("_targetDone",1)},_cleanUp:function(){var b=this,c=b.animation.animateResizeTargets?"transform opacity width height margin-bottom margin-right":"transform opacity";unBrake=function(){b._$targets.removeStyle("transition",b._prefix)},b._execAction("_cleanUp",0),b._changingLayout?b._$show.css("display",b._newDisplay):b._$show.css("display",b.layout.display),b._$targets.css(b._brake),b._$targets.removeStyle(c,b._prefix).removeAttr("data-inter-pos-x data-inter-pos-y data-final-pos-x data-final-pos-y data-orig-pos-x data-orig-pos-y data-orig-height data-orig-width data-final-height data-final-width data-inter-width data-inter-height data-orig-margin-right data-orig-margin-bottom data-inter-margin-right data-inter-margin-bottom data-final-margin-right data-final-margin-bottom"),b._$hide.removeStyle("display"),b._$parent.removeStyle("height transition perspective-distance perspective perspective-origin-x perspective-origin-y perspective-origin perspectiveOrigin",b._prefix),b._sorting&&(b._printSort(),b._activeSort=b._newSortString,b._sorting=!1),b._changingLayout&&(b._changingDisplay&&(b.layout.display=b._newDisplay,b._changingDisplay=!1),b._changingClass&&(b._$parent.removeClass(b.layout.containerClass).addClass(b._newClass),b.layout.containerClass=b._newClass,b._changingClass=!1),b._changingLayout=!1),b._refresh(),b._buildState(),b._state.fail&&b._$container.addClass(b.layout.containerClassFail),b._$show=a(),b._$hide=a(),window.requestAnimationFrame&&requestAnimationFrame(unBrake),b._mixing=!1,"function"==typeof b.callbacks._user&&b.callbacks._user.call(b._domNode,b._state,b),"function"==typeof b.callbacks.onMixEnd&&b.callbacks.onMixEnd.call(b._domNode,b._state,b),b._$container.trigger("mixEnd",[b._state,b]),b._state.fail&&("function"==typeof b.callbacks.onMixFail&&b.callbacks.onMixFail.call(b._domNode,b._state,b),b._$container.trigger("mixFail",[b._state,b])),b._loading&&("function"==typeof b.callbacks.onMixLoad&&b.callbacks.onMixLoad.call(b._domNode,b._state,b),b._$container.trigger("mixLoad",[b._state,b])),b._queue.length&&(b._execAction("_queue",0),b.multiMix(b._queue[0][0],b._queue[0][1],b._queue[0][2]),b._queue.splice(0,1)),b._execAction("_cleanUp",1),b._loading=!1},_getPrefixedCSS:function(a,b,c){var d=this,e={};for(i=0;2>i;i++){var f=0===i?d._prefix:"";e[f+a]=c?f+b:b}return d._execFilter("_getPrefixedCSS",e,arguments)},_getDelay:function(a){var b=this,c="function"==typeof b.animation.staggerSequence?b.animation.staggerSequence.call(b._domNode,a,b._state):a,d=b.animation.stagger?c*b.animation.staggerDuration:0;return b._execFilter("_getDelay",d,arguments)},_parseMultiMixArgs:function(a){for(var b=this,c={command:null,animate:b.animation.enable,callback:null},d=0;dg;)h=d[g],g++;return a!==b?a[e]!==b?a[e]:a:void 0};return a?c._execFilter("getOption",d(c,a),arguments):c},setOptions:function(b){var c=this;c._execAction("setOptions",0,arguments),"object"==typeof b&&a.extend(!0,c,b),c._execAction("setOptions",1,arguments)},getState:function(){var a=this;return a._execFilter("getState",a._state,a)},forceRefresh:function(){var a=this;a._refresh(!1,!0)},destroy:function(b){var c=this;c._execAction("destroy",0,arguments),c._$body.add(a(c.selectors.sort)).add(a(c.selectors.filter)).off(".mixItUp");for(var d=0;d1?e:e[0]:c},a.fn.removeStyle=function(a,c){return c=c?c:"",this.each(function(){for(var d=this,e=a.split(" "),f=0;fg;g++){var h=g?e[f]:c+e[f];if(d.style[h]!==b&&"unknown"!=typeof d.style[h]&&d.style[h].length>0&&(d.style[h]=""),!c)break}d.attributes&&d.attributes.style&&d.attributes.style!==b&&""===d.attributes.style.nodeValue&&d.attributes.removeNamedItem("style")})}}(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/js/jquery.nivo.slider.js b/scratch-parent/framework-customizations/extensions/portfolio/static/js/jquery.nivo.slider.js new file mode 100644 index 00000000..b7ed530f --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/js/jquery.nivo.slider.js @@ -0,0 +1,662 @@ +/* + * jQuery Nivo Slider v3.2 + * http://nivo.dev7studios.com + * + * Copyright 2012, Dev7studios + * Free to use and abuse under the MIT license. + * http://www.opensource.org/licenses/mit-license.php + */ + +(function($) { + var NivoSlider = function(element, options){ + // Defaults are below + var settings = $.extend({}, $.fn.nivoSlider.defaults, options); + + // Useful variables. Play carefully. + var vars = { + currentSlide: 0, + currentImage: '', + totalSlides: 0, + running: false, + paused: false, + stop: false, + controlNavEl: false + }; + + // Get this slider + var slider = $(element); + slider.data('nivo:vars', vars).addClass('nivoSlider'); + + // Find our slider children + var kids = slider.children(); + kids.each(function() { + var child = $(this); + var link = ''; + if(!child.is('img')){ + if(child.is('a')){ + child.addClass('nivo-imageLink'); + link = child; + } + child = child.find('img:first'); + } + // Get img width & height + var childWidth = (childWidth === 0) ? child.attr('width') : child.width(), + childHeight = (childHeight === 0) ? child.attr('height') : child.height(); + + if(link !== ''){ + link.css('display','none'); + } + child.css('display','none'); + vars.totalSlides++; + }); + + // If randomStart + if(settings.randomStart){ + settings.startSlide = Math.floor(Math.random() * vars.totalSlides); + } + + // Set startSlide + if(settings.startSlide > 0){ + if(settings.startSlide >= vars.totalSlides) { settings.startSlide = vars.totalSlides - 1; } + vars.currentSlide = settings.startSlide; + } + + // Get initial image + if($(kids[vars.currentSlide]).is('img')){ + vars.currentImage = $(kids[vars.currentSlide]); + } else { + vars.currentImage = $(kids[vars.currentSlide]).find('img:first'); + } + + // Show initial link + if($(kids[vars.currentSlide]).is('a')){ + $(kids[vars.currentSlide]).css('display','block'); + } + + // Set first background + var sliderImg = $('').addClass('nivo-main-image'); + sliderImg.attr('src', vars.currentImage.attr('src')).show(); + slider.append(sliderImg); + + // Detect Window Resize + $(window).resize(function() { + slider.children('img').width(slider.width()); + sliderImg.attr('src', vars.currentImage.attr('src')); + sliderImg.stop().height('auto'); + $('.nivo-slice').remove(); + $('.nivo-box').remove(); + }); + + //Create caption + slider.append($('
')); + + // Process caption function + var processCaption = function(settings){ + var nivoCaption = $('.nivo-caption', slider); + if(vars.currentImage.attr('title') != '' && vars.currentImage.attr('title') != undefined){ + var title = vars.currentImage.attr('title'); + if(title.substr(0,1) == '#') title = $(title).html(); + + if(nivoCaption.css('display') == 'block'){ + setTimeout(function(){ + nivoCaption.html(title); + }, settings.animSpeed); + } else { + nivoCaption.html(title); + nivoCaption.stop().fadeIn(settings.animSpeed); + } + } else { + nivoCaption.stop().fadeOut(settings.animSpeed); + } + } + + //Process initial caption + processCaption(settings); + + // In the words of Super Mario "let's a go!" + var timer = 0; + if(!settings.manualAdvance && kids.length > 1){ + timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime); + } + + // Add Direction nav + if(settings.directionNav){ + slider.append(''); + + $(slider).on('click', 'a.nivo-prevNav', function(){ + if(vars.running) { return false; } + clearInterval(timer); + timer = ''; + vars.currentSlide -= 2; + nivoRun(slider, kids, settings, 'prev'); + }); + + $(slider).on('click', 'a.nivo-nextNav', function(){ + if(vars.running) { return false; } + clearInterval(timer); + timer = ''; + nivoRun(slider, kids, settings, 'next'); + }); + } + + // Add Control nav + if(settings.controlNav){ + vars.controlNavEl = $('
'); + slider.after(vars.controlNavEl); + for(var i = 0; i < kids.length; i++){ + if(settings.controlNavThumbs){ + vars.controlNavEl.addClass('nivo-thumbs-enabled'); + var child = kids.eq(i); + if(!child.is('img')){ + child = child.find('img:first'); + } + if(child.attr('data-thumb')) vars.controlNavEl.append(''); + } else { + vars.controlNavEl.append(''+ (i + 1) +''); + } + } + + //Set initial active link + $('a:eq('+ vars.currentSlide +')', vars.controlNavEl).addClass('active'); + + $('a', vars.controlNavEl).bind('click', function(){ + if(vars.running) return false; + if($(this).hasClass('active')) return false; + clearInterval(timer); + timer = ''; + sliderImg.attr('src', vars.currentImage.attr('src')); + vars.currentSlide = $(this).attr('rel') - 1; + nivoRun(slider, kids, settings, 'control'); + }); + } + + //For pauseOnHover setting + if(settings.pauseOnHover){ + slider.hover(function(){ + vars.paused = true; + clearInterval(timer); + timer = ''; + }, function(){ + vars.paused = false; + // Restart the timer + if(timer === '' && !settings.manualAdvance){ + timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime); + } + }); + } + + // Event when Animation finishes + slider.bind('nivo:animFinished', function(){ + sliderImg.attr('src', vars.currentImage.attr('src')); + vars.running = false; + // Hide child links + $(kids).each(function(){ + if($(this).is('a')){ + $(this).css('display','none'); + } + }); + // Show current link + if($(kids[vars.currentSlide]).is('a')){ + $(kids[vars.currentSlide]).css('display','block'); + } + // Restart the timer + if(timer === '' && !vars.paused && !settings.manualAdvance){ + timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime); + } + // Trigger the afterChange callback + settings.afterChange.call(this); + }); + + // Add slices for slice animations + var createSlices = function(slider, settings, vars) { + if($(vars.currentImage).parent().is('a')) $(vars.currentImage).parent().css('display','block'); + $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').width(slider.width()).css('visibility', 'hidden').show(); + var sliceHeight = ($('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').parent().is('a')) ? $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').parent().height() : $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').height(); + + for(var i = 0; i < settings.slices; i++){ + var sliceWidth = Math.round(slider.width()/settings.slices); + + if(i === settings.slices-1){ + slider.append( + $('
').css({ + left:(sliceWidth*i)+'px', + width:(slider.width()-(sliceWidth*i))+'px', + height:sliceHeight+'px', + opacity:'0', + overflow:'hidden' + }) + ); + } else { + slider.append( + $('
').css({ + left:(sliceWidth*i)+'px', + width:sliceWidth+'px', + height:sliceHeight+'px', + opacity:'0', + overflow:'hidden' + }) + ); + } + } + + $('.nivo-slice', slider).height(sliceHeight); + sliderImg.stop().animate({ + height: $(vars.currentImage).height() + }, settings.animSpeed); + }; + + // Add boxes for box animations + var createBoxes = function(slider, settings, vars){ + if($(vars.currentImage).parent().is('a')) $(vars.currentImage).parent().css('display','block'); + $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').width(slider.width()).css('visibility', 'hidden').show(); + var boxWidth = Math.round(slider.width()/settings.boxCols), + boxHeight = Math.round($('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').height() / settings.boxRows); + + + for(var rows = 0; rows < settings.boxRows; rows++){ + for(var cols = 0; cols < settings.boxCols; cols++){ + if(cols === settings.boxCols-1){ + slider.append( + $('
').css({ + opacity:0, + left:(boxWidth*cols)+'px', + top:(boxHeight*rows)+'px', + width:(slider.width()-(boxWidth*cols))+'px' + + }) + ); + $('.nivo-box[name="'+ cols +'"]', slider).height($('.nivo-box[name="'+ cols +'"] img', slider).height()+'px'); + } else { + slider.append( + $('
').css({ + opacity:0, + left:(boxWidth*cols)+'px', + top:(boxHeight*rows)+'px', + width:boxWidth+'px' + }) + ); + $('.nivo-box[name="'+ cols +'"]', slider).height($('.nivo-box[name="'+ cols +'"] img', slider).height()+'px'); + } + } + } + + sliderImg.stop().animate({ + height: $(vars.currentImage).height() + }, settings.animSpeed); + }; + + // Private run method + var nivoRun = function(slider, kids, settings, nudge){ + // Get our vars + var vars = slider.data('nivo:vars'); + + // Trigger the lastSlide callback + if(vars && (vars.currentSlide === vars.totalSlides - 1)){ + settings.lastSlide.call(this); + } + + // Stop + if((!vars || vars.stop) && !nudge) { return false; } + + // Trigger the beforeChange callback + settings.beforeChange.call(this); + + // Set current background before change + if(!nudge){ + sliderImg.attr('src', vars.currentImage.attr('src')); + } else { + if(nudge === 'prev'){ + sliderImg.attr('src', vars.currentImage.attr('src')); + } + if(nudge === 'next'){ + sliderImg.attr('src', vars.currentImage.attr('src')); + } + } + + vars.currentSlide++; + // Trigger the slideshowEnd callback + if(vars.currentSlide === vars.totalSlides){ + vars.currentSlide = 0; + settings.slideshowEnd.call(this); + } + if(vars.currentSlide < 0) { vars.currentSlide = (vars.totalSlides - 1); } + // Set vars.currentImage + if($(kids[vars.currentSlide]).is('img')){ + vars.currentImage = $(kids[vars.currentSlide]); + } else { + vars.currentImage = $(kids[vars.currentSlide]).find('img:first'); + } + + // Set active links + if(settings.controlNav){ + $('a', vars.controlNavEl).removeClass('active'); + $('a:eq('+ vars.currentSlide +')', vars.controlNavEl).addClass('active'); + } + + // Process caption + processCaption(settings); + + // Remove any slices from last transition + $('.nivo-slice', slider).remove(); + + // Remove any boxes from last transition + $('.nivo-box', slider).remove(); + + var currentEffect = settings.effect, + anims = ''; + + // Generate random effect + if(settings.effect === 'random'){ + anims = new Array('sliceDownRight','sliceDownLeft','sliceUpRight','sliceUpLeft','sliceUpDown','sliceUpDownLeft','fold','fade', + 'boxRandom','boxRain','boxRainReverse','boxRainGrow','boxRainGrowReverse'); + currentEffect = anims[Math.floor(Math.random()*(anims.length + 1))]; + if(currentEffect === undefined) { currentEffect = 'fade'; } + } + + // Run random effect from specified set (eg: effect:'fold,fade') + if(settings.effect.indexOf(',') !== -1){ + anims = settings.effect.split(','); + currentEffect = anims[Math.floor(Math.random()*(anims.length))]; + if(currentEffect === undefined) { currentEffect = 'fade'; } + } + + // Custom transition as defined by "data-transition" attribute + if(vars.currentImage.attr('data-transition')){ + currentEffect = vars.currentImage.attr('data-transition'); + } + + // Run effects + vars.running = true; + var timeBuff = 0, + i = 0, + slices = '', + firstSlice = '', + totalBoxes = '', + boxes = ''; + + if(currentEffect === 'sliceDown' || currentEffect === 'sliceDownRight' || currentEffect === 'sliceDownLeft'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + slices = $('.nivo-slice', slider); + if(currentEffect === 'sliceDownLeft') { slices = $('.nivo-slice', slider)._reverse(); } + + slices.each(function(){ + var slice = $(this); + slice.css({ 'top': '0px' }); + if(i === settings.slices-1){ + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + i++; + }); + } else if(currentEffect === 'sliceUp' || currentEffect === 'sliceUpRight' || currentEffect === 'sliceUpLeft'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + slices = $('.nivo-slice', slider); + if(currentEffect === 'sliceUpLeft') { slices = $('.nivo-slice', slider)._reverse(); } + + slices.each(function(){ + var slice = $(this); + slice.css({ 'bottom': '0px' }); + if(i === settings.slices-1){ + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + i++; + }); + } else if(currentEffect === 'sliceUpDown' || currentEffect === 'sliceUpDownRight' || currentEffect === 'sliceUpDownLeft'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + var v = 0; + slices = $('.nivo-slice', slider); + if(currentEffect === 'sliceUpDownLeft') { slices = $('.nivo-slice', slider)._reverse(); } + + slices.each(function(){ + var slice = $(this); + if(i === 0){ + slice.css('top','0px'); + i++; + } else { + slice.css('bottom','0px'); + i = 0; + } + + if(v === settings.slices-1){ + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + v++; + }); + } else if(currentEffect === 'fold'){ + createSlices(slider, settings, vars); + timeBuff = 0; + i = 0; + + $('.nivo-slice', slider).each(function(){ + var slice = $(this); + var origWidth = slice.width(); + slice.css({ top:'0px', width:'0px' }); + if(i === settings.slices-1){ + setTimeout(function(){ + slice.animate({ width:origWidth, opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + slice.animate({ width:origWidth, opacity:'1.0' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 50; + i++; + }); + } else if(currentEffect === 'fade'){ + createSlices(slider, settings, vars); + + firstSlice = $('.nivo-slice:first', slider); + firstSlice.css({ + 'width': slider.width() + 'px' + }); + + firstSlice.animate({ opacity:'1.0' }, (settings.animSpeed*2), '', function(){ slider.trigger('nivo:animFinished'); }); + } else if(currentEffect === 'slideInRight'){ + createSlices(slider, settings, vars); + + firstSlice = $('.nivo-slice:first', slider); + firstSlice.css({ + 'width': '0px', + 'opacity': '1' + }); + + firstSlice.animate({ width: slider.width() + 'px' }, (settings.animSpeed*2), '', function(){ slider.trigger('nivo:animFinished'); }); + } else if(currentEffect === 'slideInLeft'){ + createSlices(slider, settings, vars); + + firstSlice = $('.nivo-slice:first', slider); + firstSlice.css({ + 'width': '0px', + 'opacity': '1', + 'left': '', + 'right': '0px' + }); + + firstSlice.animate({ width: slider.width() + 'px' }, (settings.animSpeed*2), '', function(){ + // Reset positioning + firstSlice.css({ + 'left': '0px', + 'right': '' + }); + slider.trigger('nivo:animFinished'); + }); + } else if(currentEffect === 'boxRandom'){ + createBoxes(slider, settings, vars); + + totalBoxes = settings.boxCols * settings.boxRows; + i = 0; + timeBuff = 0; + + boxes = shuffle($('.nivo-box', slider)); + boxes.each(function(){ + var box = $(this); + if(i === totalBoxes-1){ + setTimeout(function(){ + box.animate({ opacity:'1' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + timeBuff)); + } else { + setTimeout(function(){ + box.animate({ opacity:'1' }, settings.animSpeed); + }, (100 + timeBuff)); + } + timeBuff += 20; + i++; + }); + } else if(currentEffect === 'boxRain' || currentEffect === 'boxRainReverse' || currentEffect === 'boxRainGrow' || currentEffect === 'boxRainGrowReverse'){ + createBoxes(slider, settings, vars); + + totalBoxes = settings.boxCols * settings.boxRows; + i = 0; + timeBuff = 0; + + // Split boxes into 2D array + var rowIndex = 0; + var colIndex = 0; + var box2Darr = []; + box2Darr[rowIndex] = []; + boxes = $('.nivo-box', slider); + if(currentEffect === 'boxRainReverse' || currentEffect === 'boxRainGrowReverse'){ + boxes = $('.nivo-box', slider)._reverse(); + } + boxes.each(function(){ + box2Darr[rowIndex][colIndex] = $(this); + colIndex++; + if(colIndex === settings.boxCols){ + rowIndex++; + colIndex = 0; + box2Darr[rowIndex] = []; + } + }); + + // Run animation + for(var cols = 0; cols < (settings.boxCols * 2); cols++){ + var prevCol = cols; + for(var rows = 0; rows < settings.boxRows; rows++){ + if(prevCol >= 0 && prevCol < settings.boxCols){ + /* Due to some weird JS bug with loop vars + being used in setTimeout, this is wrapped + with an anonymous function call */ + (function(row, col, time, i, totalBoxes) { + var box = $(box2Darr[row][col]); + var w = box.width(); + var h = box.height(); + if(currentEffect === 'boxRainGrow' || currentEffect === 'boxRainGrowReverse'){ + box.width(0).height(0); + } + if(i === totalBoxes-1){ + setTimeout(function(){ + box.animate({ opacity:'1', width:w, height:h }, settings.animSpeed/1.3, '', function(){ slider.trigger('nivo:animFinished'); }); + }, (100 + time)); + } else { + setTimeout(function(){ + box.animate({ opacity:'1', width:w, height:h }, settings.animSpeed/1.3); + }, (100 + time)); + } + })(rows, prevCol, timeBuff, i, totalBoxes); + i++; + } + prevCol--; + } + timeBuff += 100; + } + } + }; + + // Shuffle an array + var shuffle = function(arr){ + for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i, 10), x = arr[--i], arr[i] = arr[j], arr[j] = x); + return arr; + }; + + // For debugging + var trace = function(msg){ + if(this.console && typeof console.log !== 'undefined') { console.log(msg); } + }; + + // Start / Stop + this.stop = function(){ + if(!$(element).data('nivo:vars').stop){ + $(element).data('nivo:vars').stop = true; + trace('Stop Slider'); + } + }; + + this.start = function(){ + if($(element).data('nivo:vars').stop){ + $(element).data('nivo:vars').stop = false; + trace('Start Slider'); + } + }; + + // Trigger the afterLoad callback + settings.afterLoad.call(this); + + return this; + }; + + $.fn.nivoSlider = function(options) { + return this.each(function(key, value){ + var element = $(this); + // Return early if this element already has a plugin instance + if (element.data('nivoslider')) { return element.data('nivoslider'); } + // Pass options to plugin constructor + var nivoslider = new NivoSlider(this, options); + // Store plugin object in this element's data + element.data('nivoslider', nivoslider); + }); + }; + + //Default settings + $.fn.nivoSlider.defaults = { + effect: 'random', + slices: 15, + boxCols: 8, + boxRows: 4, + animSpeed: 500, + pauseTime: 3000, + startSlide: 0, + directionNav: true, + controlNav: true, + controlNavThumbs: false, + pauseOnHover: true, + manualAdvance: false, + prevText: 'Prev', + nextText: 'Next', + randomStart: false, + beforeChange: function(){}, + afterChange: function(){}, + slideshowEnd: function(){}, + lastSlide: function(){}, + afterLoad: function(){} + }; + + $.fn._reverse = [].reverse; + +})(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/js/portfolio-script.js b/scratch-parent/framework-customizations/extensions/portfolio/static/js/portfolio-script.js new file mode 100644 index 00000000..0f9973ea --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/js/portfolio-script.js @@ -0,0 +1,5 @@ +jQuery(document).ready(function ( $ ) { + $(document).ready(function(){ + $('#Container').mixItUp(); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/static/js/projects-script.js b/scratch-parent/framework-customizations/extensions/portfolio/static/js/projects-script.js new file mode 100644 index 00000000..f58709d1 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/static/js/projects-script.js @@ -0,0 +1,30 @@ +jQuery(document).ready(function($) { + //NivoSlider + var slider = $('#slider'); + if(slider.length>0){ + slider.nivoSlider({ + effect: 'fade', // Specify sets like: 'fold,fade,sliceDown' + slices: 15, // For slice animations + boxCols: 8, // For box animations + boxRows: 4, // For box animations + animSpeed: 500, // Slide transition speed + pauseTime: 3000, // How long each slide will show + startSlide: 0, // Set starting Slide (0 index) + directionNav: true, // Next & Prev navigation + controlNav: true, // 1,2,3... navigation + controlNavThumbs: false, // Use thumbnails for Control Nav + pauseOnHover: true, // Stop animation while hovering + manualAdvance: false, // Force manual transitions + prevText: 'next', // Prev directionNav text + nextText: 'prev', // Next directionNav text + randomStart: false, // Start on a random slide + beforeChange: function(){}, // Triggers before a slide transition + afterChange: function(){}, // Triggers after a slide transition + slideshowEnd: function(){}, // Triggers after all slides have been shown + lastSlide: function(){}, // Triggers when last slide is shown + afterLoad: function(){} + + }); + } +}); + diff --git a/scratch-parent/framework-customizations/extensions/portfolio/views/archive.php b/scratch-parent/framework-customizations/extensions/portfolio/views/archive.php new file mode 100644 index 00000000..9e5b9139 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/views/archive.php @@ -0,0 +1,80 @@ +extensions->get( 'portfolio' ); +$ext_portfolio_settings = $ext_portfolio_instance->get_settings(); + +$taxonomy = $ext_portfolio_settings['taxonomy_name']; +$term = get_term_by( 'slug', get_query_var( 'term' ), $taxonomy ); +$term_id = ( ! empty( $term->term_id ) ) ? $term->term_id : 0; +$categories = fw_ext_portfolio_get_listing_categories( $term_id, $taxonomy ); + +$listing_classes = fw_ext_portfolio_get_sort_classes( $wp_query->posts, $ext_portfolio_settings['taxonomy_name'], $categories ); +$loop_data = array( + 'settings' => $ext_portfolio_instance->get_settings(), + 'categories' => $categories, + 'image_sizes' => $ext_portfolio_instance->get_image_sizes(), + 'listing_classes' => $listing_classes +); +set_query_var( 'fw_portfolio_loop_data', $loop_data ); +?> +
+
+
+
+ ' . $term->name . ''; + } else { + echo '

' . __( 'Portfolios', 'fw' ) . '

'; + } + + if ( function_exists( 'fw_ext_breadcrumbs_render' ) ) { + echo fw_ext_breadcrumbs_render(); + } + ?> + + +
+ +
+ +
+
+
+ +
    + get_rel_path() . '/views/loop', 'item' ); //fixme hardcoded 'framework-customizations/extensions' + endwhile; + fw_theme_paging_nav(); + ?> +
+ + + +
+
+
+
+
+
+ +
  • + +
  • \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/portfolio/views/single.php b/scratch-parent/framework-customizations/extensions/portfolio/views/single.php new file mode 100644 index 00000000..a2ceb293 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/portfolio/views/single.php @@ -0,0 +1,96 @@ +extensions->get( 'portfolio' )->get_config( 'image_sizes' ); +$fw_ext_projects_gallery_image = $fw_ext_projects_gallery_image['gallery-image']; + +get_header(); ?> + +
    + + +
    +
    + + + +
    > + +
    + ', '' ); ?> + +
    + + +
    + +
    +
    + post_title; + + $image = fw_resize( $thumbnail['attachment_id'], $fw_ext_projects_gallery_image['width'], $fw_ext_projects_gallery_image['height'], $fw_ext_projects_gallery_image['crop'] ); + ?> + <?php echo $attachment->post_title ?> + +
    +
    + $post_title ) : ?> +
    + +
    +
    + +
    + +
    + +
    + +
    + + + +
    + +
    + + +
    + +extensions->get( 'portfolio' )->get_rel_path() . '/views/archive' ); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/README.md b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/README.md new file mode 100644 index 00000000..666e299a --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/README.md @@ -0,0 +1,134 @@ +# Sitemap + +Generates `sitemap.xml` file for search engines. + +## Configuration + +```php +/** + * Search engines where to report about the sitemap existence. + * By default the extension supports only Google and Bing. + */ +$cfg['search_engines'] = array('google', 'bing'); + +/** + * The frequently of the sitemap refresh (measured in days). + */ +$cfg['sitemap_refresh_rate'] = 2; + +/** + * Exclude post types from sitemap indexing. + */ +$cfg['excluded_post_types'] = array('attachment'); + +/** + * Exclude taxonomies from sitemap indexing. + */ +$cfg['excluded_taxonomies'] = array('post_tag'); + +/** + * Setup the URL frequency and priority for each post_type, taxonomy and the homepage + */ +$cfg['url_settings'] = array( + 'home' => array( + 'priority' => 1, + 'frequency' => 'daily', + ), + 'posts' => array( + 'priority' => 0.6, + 'frequency' => 'daily', + /** + * In case you have specific posts type that you want to set different settings + */ + 'type' => array( + 'page' => array( + 'priority' => 0.5, + 'frequency' => 'weekly', + ) + ) + ), + 'taxonomies' => array( + 'priority' => 0.4, + 'frequency' => 'weekly', + /** + * In case you have specific taxonomy that you want to set different settings + */ + 'type' => array( + 'post_tag' => array( + 'priority' => 0.3, + 'frequency' => 'weekly', + ) + ) + ) +); +``` + +## Views + +There are 3 views you can customize: + +* `sitemap-header.php` - Header content for the `sitemap.xml` file. +* `sitemap.php` - Content for the `sitemap.xml` file. You can edit this file in case you want to exclude some items from sitemap. +* `sitemap-style.php` - Gives sitemap a user friendly view when it's accessed in the browser. + +## Hooks + +* `fw_ext_seo_sitemap_date_format` - Filter to change the date format of the last modified date in sitemap. + + ```php + /** + * @internal + */ + function _filter_modify_sitemap_date_format( $format ) { + return 'Y M, d'; + } + add_filter('fw_ext_seo_sitemap_date_format', '_filter_modify_sitemap_date_format'); + ``` + +* `fw_ext_seo_sitemap_pre_update` - Action fired when the sitemap prepares to be updated. + + ```php + /** + * @internal + */ + function _action_pre_update_sitemap() { + // ... + } + add_action('fw_ext_seo_sitemap_pre_update', '_action_pre_update_sitemap'); + ``` + +* `fw_ext_seo_sitemap_updated` - Action fired after the sitemap was updated. + + ```php + /** + * @internal + */ + function _action_sitemap_updated() { + // ... + } + add_action('fw_ext_seo_sitemap_updated', '_action_sitemap_updated'); + ``` + +* `fw_ext_seo_sitemap_pre_delete` - Action fired when the sitemap prepares to be deleted. + + ```php + /** + * @internal + */ + function _action_pre_delete_sitemap() { + // ... + } + add_action('fw_ext_seo_sitemap_pre_delete', '_action_pre_delete_sitemap'); + ``` + +* `fw_ext_seo_sitemap_deleted` - Action fired after the sitemap was deleted. + + ```php + /** + * @internal + */ + function _action_sitemap_deleted() { + // ... + } + add_action('fw_ext_seo_sitemap_deleted', '_action_sitemap_deleted'); + ``` \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/class-fw-extension-seo-sitemap.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/class-fw-extension-seo-sitemap.php new file mode 100644 index 00000000..47ee0339 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/class-fw-extension-seo-sitemap.php @@ -0,0 +1,480 @@ +add_actions(); + $this->add_filters(); + if ( is_admin() ) { + $this->add_admin_actions(); + $this->add_admin_filters(); + } + } + + /** + * Init the necessary action hooks for the extension functionality + */ + private function add_actions() { + add_action( 'init', array( $this, '_action_init' ), 9999 ); + + add_action( 'fw_deleted_sitemap', array( $this, '_action_delete_xsl_file' ), 9999 ); + + add_action( 'fw_sitemap_updated', array( $this, '_action_ping_to_search_engines' ), 9999 ); + add_action( 'fw_sitemap_updated', array( $this, '_action_create_xsl_file' ), 9999 ); + } + + /** + * Init the necessary filter hooks for the extension functionality + */ + private function add_filters() { + add_filter( 'set_sitemap_xml_header', array( $this, '_filter_xsl_header' ) ); + } + + private function add_admin_actions() { + add_action( 'wp_ajax_fw_update_sitemap', array( $this, '_action_ajax_update_sitemap' ), 9999 ); + add_action( 'wp_ajax_fw_delete_sitemap', array( $this, '_action_ajax_delete_sitemap' ), 9999 ); + + add_action( 'admin_enqueue_scripts', array( $this, '_admin_action_css' ) ); + add_action( 'admin_enqueue_scripts', array( $this, '_admin_action_js' ) ); + } + + private function add_admin_filters() { + add_filter( 'fw_ext_seo_admin_options', array( $this, '_filter_set_framework_sitemap_tab' ) ); + } + + /** + * Returns an array with allowed custom post types for this extension + * @return array + */ + public function get_allowed_post_types() { + return $this->allowed_post_types; + } + + /** + * Retuns an array with allows taxonomies for this extension + * @return array + */ + public function get_allowed_taxonomies() { + return $this->allowed_taxonomies; + } + + public function get_search_engines() { + return $this->serach_engies; + } + + /** + * Necessary to build the extension after wordpress init action + * @internal + */ + public function _action_init() { + $this->check_for_sitemap_auto_build(); + } + + /** + * Check when the sitemap was updated last time and if the time is logner then the sitemap refresh rate time, + * updates it + */ + private function check_for_sitemap_auto_build() { + $last_modif = fw_get_db_extension_data( $this->get_name(), 'last_modif' ); + $refresh_rate = $this->get_config( 'sitemap_refresh_rate' ); + if ( empty( $refresh_rate ) ) { + $refresh_rate = 2; + } + + if ( ! isset( $last_modif['last_sitemap_update'] ) || empty( $last_modif['last_sitemap_update'] ) ) { + $this->set_parameters(); + $this->update_sitemap(); + + return; + } + + $prev_date = strtotime( date( 'Y-m-d', $last_modif['last_sitemap_update'] ) ); + $current_date = strtotime( date( 'Y-m-d' ) ); + + $interval = intval( ( $current_date - $prev_date ) / 86400 ); + + if ( $interval >= $refresh_rate ) { + $this->update_sitemap(); + } + } + + private function set_parameters() { + if ( self::$set_parameters ) { + return; + } + + $this->define_search_engines(); + $this->set_custom_posts(); + $this->set_taxonomies(); + $this->create_sitemap_object(); + + self::$set_parameters = true; + } + + private function get_admin_options() { + if ( is_null( $this->settings_options ) ) { + $this->settings_options = fw_get_db_extension_data( $this->get_parent()->get_name(), 'options' ); + } + + return $this->settings_options; + } + + private function define_search_engines() { + $this->serach_engies = array( + 'google' => array( + 'name' => __( 'Google', 'fw' ), + 'url' => 'http://www.google.com/webmasters/tools/ping?sitemap=' + ), + 'bing' => array( + 'name' => __( 'Bing', 'fw' ), + 'url' => 'http://www.bing.com/webmaster/ping.aspx?sitemap=' + ) + ); + } + + /** + * Defines the allowed custom post types for this extension + */ + private function set_custom_posts() { + $custom_posts = get_post_types( array( 'public' => true ) ); + $excluded_types = $this->get_config( 'excluded_post_types' ); + + unset( $custom_posts['nav_menu_item'] ); + unset( $custom_posts['revision'] ); + + foreach ( $excluded_types as $type ) { + if ( isset( $custom_posts[ $type ] ) ) { + unset( $custom_posts[ $type ] ); + } + } + $this->allowed_post_types = $custom_posts; + } + + /** + * Defines the allowed taxonomies for this extension + */ + private function set_taxonomies() { + $taxonomies = get_taxonomies(); + + $excluded_types = $this->get_config( 'excluded_taxonomies' ); + + unset( $taxonomies['nav_menu'] ); + unset( $taxonomies['link_category'] ); + unset( $taxonomies['post_format'] ); + + foreach ( $excluded_types as $type ) { + if ( isset( $taxonomies[ $type ] ) ) { + unset( $taxonomies[ $type ] ); + } + } + + $this->allowed_taxonomies = $taxonomies; + } + + private function create_sitemap_object() { + $settings = array( + 'posts' => $this->get_workable_custom_post_types(), + 'taxonomies' => $this->get_workable_taxonomies(), + 'views-path' => $this->get_declared_path() . '/views/', + 'url_settings' => $this->get_config( 'url_settings' ) + ); + + $this->sitemap = new _FW_Ext_Seo_Sitemap_Builder( $settings ); + } + + /** + * Returns an array with allowed custom post types for this extension, this doesn't include post types that was disabled from admin area + * @return array + */ + public function get_workable_custom_post_types() { + $custom_post_types = array(); + $custom_posts = $this->allowed_post_types; + + foreach ( $custom_posts as $custom_post ) { + $allowed = $this->get_admin_options(); + $id = $this->get_name() . '-exclude-custom-post-' . $custom_post; + if ( isset( $allowed[ $id ] ) && $allowed[ $id ] === true ) { + continue; + } + + array_push( $custom_post_types, $custom_post ); + } + + return $custom_post_types; + } + + /** + * Returns an array with allowed taxonomies for this extension, this doesn't include post types that was disabled from admin area + * @return array + */ + public function get_workable_taxonomies() { + $taxonomies_types = array(); + $taxonomies = $this->allowed_taxonomies; + + foreach ( $taxonomies as $taxonomy ) { + $allowed = $this->get_admin_options(); + $id = $this->get_name() . '-exclude-taxonomy-' . $taxonomy; + + if ( isset( $allowed[ $id ] ) && $allowed[ $id ] === true ) { + continue; + } + + array_push( $taxonomies_types, $taxonomy ); + } + + return $taxonomies_types; + } + + /** + * Update sitemap.xml file + */ + public function update_sitemap() { + if ( empty( $this->sitemap ) ) { + return false; + } + do_action( 'fw_ext_seo_sitemap_pre_update' ); + + $response = $this->sitemap->update_sitemap(); + $options = array( + 'last_sitemap_update' => time() + ); + fw_set_db_extension_data( $this->get_name(), 'last_modif', $options ); + do_action( 'fw_ext_seo_sitemap_updated' ); + + return $response; + } + + /** + * Load scripts for the admin area + * @internal + */ + public function _admin_action_js() { + wp_enqueue_script( + 'fw-ext-'. $this->get_name() . '-admin-scripts', + $this->locate_js_URI( 'admin-scripts' ), + array( 'jquery' ), + $this->manifest->get_version(), + true + ); + } + + /** + * Load styles for the admin area + * @internal + */ + public function _admin_action_css() { + wp_enqueue_style( + 'fw-ext-'. $this->get_name() . '-admin-style', + $this->locate_css_URI( 'admin-style' ), + array(), + $this->manifest->get_version() + ); + } + + /** + * Triggers the sitemap update method, made for ajax calls + * @internal + */ + public function _action_ajax_update_sitemap() { + if (!current_user_can('edit_files')) { + wp_send_json_error(); + } + + $this->set_parameters(); + die( $this->update_sitemap() ); + } + + /** + * Triggers the sitemap delete method + * @internal + */ + public function _action_delete_sitemap() { + $this->delete_sitemap(); + } + + /** + * Deletes the xml sitemap + * Returns true if the sitemap was deleted successfully + * @return bool + */ + public function delete_sitemap() { + do_action( 'fw_ext_seo_sitemap_pre_delete' ); + $response = $this->sitemap->delete_xml_sitemap(); + + if ( $response ) { + do_action( 'fw_ext_seo_sitemap_deleted' ); + } + + return $response; + } + + /** + * Triggers the sitemap delete method, made for ajax calls + * @internal + */ + public function _action_ajax_delete_sitemap() { + if (!current_user_can('edit_files')) { + wp_send_json_error(); + } + + $this->set_parameters(); + die( $this->delete_sitemap() ); + } + + /** + * Pings to the search engines the presence of the sitemap + * @internal + */ + public function _action_ping_to_search_engines() { + $search_engines = $this->get_config( 'search_engines' ); + + if ( empty( $search_engines ) ) { + return; + } + + foreach ( $search_engines as $search_engine ) { + if ( ! isset( $this->serach_engies[ $search_engine ] ) ) { + continue; + } + + wp_remote_post( $this->serach_engies[ $search_engine ]['url'] . $this->get_sitemap_uri() ); + } + } + + /** + * Get sitemap.xml file URI + * @return string + */ + public function get_sitemap_uri() { + if ( empty( $this->sitemap ) ) { + return ''; + } + + return $this->sitemap->get_sitemap_uri(); + } + + /** + * Deletes the XSL file + * @internal + */ + public function _action_delete_xsl_file() { + $this->delete_xsl(); + } + + /** + * Deletes the sitemap XSL style file + * @return bool + */ + private function delete_xsl() { + $file_path = fw_ext_seo_sitemap_get_home_path() . 'sitemap-xsl.xsl'; + if ( ! file_exists( $file_path ) ) { + return true; + } + + if ( ! fw_ext_seo_sitemap_try_make_file_writable( $file_path ) ) { + if ( is_admin() ) { + FW_Flash_Messages::add( 'fw-ext-seo-sitemap-delete-file', sprintf( __( 'Could not delete the %s. File is not writable', 'fw' ), $file_path ), 'warning' ); + } + + return false; + } + + return ( unlink( $file_path ) ); + } + + /** + * Creates the XSL file + * @internal + */ + public function _action_create_xsl_file() { + $this->create_xsl(); + } + + /** + * Create the simep XSL style file + */ + private function create_xsl() { + $file_path = fw_ext_seo_sitemap_get_home_path() . 'sitemap-xsl.xsl'; + + if ( ! fw_ext_seo_sitemap_try_make_file_writable( $file_path ) ) { + if ( is_admin() ) { + FW_Flash_Messages::add( 'fw-ext-seo-sitemap-try-modify-file', sprintf( __( 'Could not create/write the %s. File is not writable', 'fw' ), $file_path ), 'warning' ); + } + + return; + } + + $file = fopen( $file_path, 'w' ); + fwrite( $file, fw_render_view( $this->locate_view_path( 'sitemap-style' ) ) ); + } + + /** + * Adds the extension settings tab in Framework in SEO extension + * + * @param $seo_options , holds the general options from extension config file + * + * @return array + * @internal + */ + public function _filter_set_framework_sitemap_tab( $seo_options ) { + $this->set_parameters(); + $sitemap_options = fw_ext_seo_sitemap_get_settings_options(); + if ( is_array( $sitemap_options ) && ! empty( $sitemap_options ) ) { + return array_merge( $seo_options, $sitemap_options ); + } + + return $seo_options; + } + + /** + * Adds the in the sitemap XML header the link to the XSL styling file + * @return string + * @internal + */ + public function _filter_xsl_header() { + return ''; + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/config.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/config.php new file mode 100644 index 00000000..819fbc41 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/config.php @@ -0,0 +1,40 @@ + array( 'google', 'bing' ), + 'sitemap_refresh_rate' => 2, + 'excluded_post_types' => array( 'attachment' ), + 'excluded_taxonomies' => array( 'post_tag' ), + 'url_settings' => array( + 'home' => array( + 'priority' => 1, + 'frequency' => 'daily', + ), + 'posts' => array( + 'priority' => 0.6, + 'frequency' => 'daily', + 'type' => array( + 'page' => array( + 'priority' => 0.5, + 'frequency' => 'weekly', + ) + ) + ), + 'taxonomies' => array( + 'priority' => 0.4, + 'frequency' => 'weekly', + 'type' => array( + 'post_tag' => array( + 'priority' => 0.3, + 'frequency' => 'weekly', + ) + ) + ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/helpers.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/helpers.php new file mode 100644 index 00000000..685cf189 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/helpers.php @@ -0,0 +1,111 @@ +extensions->get( 'seo-sitemap' )->get_search_engines(); + $available_engines = fw()->extensions->get( 'seo-sitemap' )->get_config( 'search_engines' ); + + if ( empty( $search_engines ) ) { + if ( $array ) { + array(); + } else { + ''; + } + } + + $names = array(); + + foreach ( $search_engines as $id => $search_engine ) { + if ( in_array( $id, $available_engines ) ) { + array_push( $names, $search_engine['name'] ); + } + } + + if ( $array ) { + return $names; + } + + $names = implode( $divider . ' ', $names ); + + return $names; +} + +/** + * Return the home path + * @return string + */ +function fw_ext_seo_sitemap_get_home_path() { + if ( function_exists( "get_home_path" ) ) { + $res = get_home_path(); + } else { + $home = home_url(); + if ( $home != '' && $home != get_option( 'url' ) ) { + $home_path = parse_url( $home ); + if ( isset( $home_path['path'] ) ) { + $home_path = $home_path['path']; + $root = str_replace( $_SERVER["PHP_SELF"], '', $_SERVER["SCRIPT_FILENAME"] ); + $home_path = trailingslashit( $root . $home_path ); + } else { + $home_path = ABSPATH; + } + + } else { + $home_path = ABSPATH; + } + + $res = $home_path; + } + + return $res; +} + +/** + * Returns sitemap URI address + * @return string + */ +function fw_ext_seo_sitemap_get_stiemap_link() { + return fw()->extensions->get( 'seo-sitemap' )->get_sitemap_uri(); +} + +/** + * Updates sitemap + */ +function fw_ext_seo_sitemap_update() { + fw()->extensions->get( 'seo-sitemap' )->update_sitemap(); +} + +/** + * Checks if the file is writable and if is not tries to make it writable + * + * @param string $filename , the name of the file with the entire path + * + * @return bool + */ +function fw_ext_seo_sitemap_try_make_file_writable( $filename ) { + if ( ! is_writable( $filename ) ) { + if ( ! @chmod( $filename, 0666 ) ) { + $pathtofilename = dirname( $filename ); + if ( ! is_writable( $pathtofilename ) ) { + if ( ! @chmod( $pathtofilename, 0666 ) ) { + return false; + } + } + } + } + + return true; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/includes/class-sitemap-builder.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/includes/class-sitemap-builder.php new file mode 100644 index 00000000..a2d53fce --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/includes/class-sitemap-builder.php @@ -0,0 +1,392 @@ + array( + 'priority' => 1, + 'frequency' => 'daily', + ), + 'posts' => array( + 'priority' => 0.6, + 'frequency' => 'daily', + 'type' => array( + 'attachment' => array( + 'priority' => 0.3, + 'frequency' => 'daily', + ) + ) + ), + 'taxonomies' => array( + 'priority' => 0.4, + 'frequency' => 'weekly', + 'type' => array( + 'post_tag' => array( + 'priority' => 0.3, + 'frequency' => 'weekly', + ) + ) + ) + ); + private $xml_file = null; + + /** + * @param array $settings , array of the sitemap settings + */ + public function __construct( $settings = array() ) { + //Check if the class wasn't initialized already + if ( self::$active === true ) { + return; + } + self::$active = true; + + $this->set_up_defaults( $settings ); + } + + private function set_up_defaults( $settings = array() ) { + + if ( isset( $settings['posts'] ) ) { + $this->custom_posts = $settings['posts']; + } + + if ( isset( $settings['taxonomies'] ) ) { + $this->taxonomies = $settings['taxonomies']; + } + + if ( isset( $settings['file-name'] ) ) { + $this->file_name = $settings['file-name']; + } + + if ( isset( $settings['views-path'] ) ) { + $this->views_path = $settings['views-path']; + } + + if ( isset( $settings['url_settings'] ) ) { + $url_settings = $settings['url_settings']; + + if ( isset( $url_settings['home'] ) ) { + if ( isset( $url_settings['home']['priority'] ) ) { + $this->url_settings['home']['priority'] = $url_settings['home']['priority']; + } + + if ( isset( $url_settings['home']['frequency'] ) ) { + $this->url_settings['home']['frequency'] = $url_settings['home']['frequency']; + } + } + + if ( isset( $url_settings['posts'] ) ) { + if ( isset( $url_settings['posts']['priority'] ) ) { + $this->url_settings['posts']['priority'] = $url_settings['posts']['priority']; + } + + if ( isset( $url_settings['posts']['frequency'] ) ) { + $this->url_settings['posts']['frequency'] = $url_settings['posts']['frequency']; + } + + if ( isset( $url_settings['posts']['type'] ) ) { + $types = $url_settings['posts']['type']; + $this->url_settings['posts']['type'] + = array_merge( $this->url_settings['posts']['type'], $types ); + } + } + + if ( isset( $url_settings['taxonomies'] ) ) { + if ( isset( $url_settings['taxonomies']['priority'] ) ) { + $this->url_settings['taxonomies']['priority'] = $url_settings['taxonomies']['priority']; + } + + if ( isset( $url_settings['taxonomies']['frequency'] ) ) { + $this->url_settings['taxonomies']['frequency'] = $url_settings['taxonomies']['frequency']; + } + + if ( isset( $url_settings['taxonomies']['type'] ) ) { + $types = $url_settings['taxonomies']['type']; + $this->url_settings['taxonomies']['type'] + = array_merge( $this->url_settings['taxonomies']['type'], $types ); + } + } + } + } + + /** + * Public function to create the sitemap + */ + public function create_sitemap() { + $this->sitemap_build_prepare(); + } + + /** + * Preparing XML file to be written + * @return bool + */ + private function sitemap_build_prepare() { + $file_path = $this->get_path(); + + if ( ! $this->check_path() ) { + return false; + } + $this->xml_file = fopen( $file_path, 'w' ); + $this->build_sitemap(); + + return true; + } + + /** + * Get the sitemap XML file path + * @return string + */ + private function get_path() { + return fw_ext_seo_sitemap_get_home_path() . $this->file_name; + } + + private function check_path() { + if ( ! fw_ext_seo_sitemap_try_make_file_writable( $this->get_path() ) ) { + if ( is_admin() ) { + FW_Flash_Messages::add( 'fw-ext-seo-sitemap-try-edit-file', sprintf( __( 'Could not create/write the %s. File is not writable', 'fw' ), $this->get_path() ), 'warning' ); + } + + return false; + } + + return true; + } + + /** + * Main function that builds the sitemap.xml file + */ + private function build_sitemap() { + $this->add_element( $this->get_header() ); + + $this->add_home_page(); + $this->add_custom_posts(); + $this->add_taxonomies(); + + $this->add_element( $this->get_footer() ); + fclose( $this->xml_file ); + } + + /** + * Adds new element in XML file + * + * @param string $element - element needs to be added + */ + private function add_element( $element = '' ) { + fwrite( $this->xml_file, $element ); + } + + /** + * Returns the XML file header + * @return string + */ + private function get_header() { + $data['content'] = apply_filters( 'set_sitemap_xml_header', '' ); + + return fw_render_view( $this->views_path . '/sitemap-header.php', $data ); + } + + /** + * Adds all custom posts in the sitemap.xml + */ + private function add_home_page() { + $items = array(); + + $item['url'] = home_url( '/' ); + $item['priority'] = $this->get_homepage_url_details( 'priority' ); + $item['frequency'] = $this->get_homepage_url_details( 'frequency' ); + + $id = get_option( 'page_on_front' ); + + if ( intval( $id ) == 0 ) { + global $wpdb; + + $post = $wpdb->get_row( 'SELECT post_modified_gmt modified FROM ' . $wpdb->posts . ' WHERE post_type = \'post\' ORDER BY post_modified_gmt DESC LIMIT 1', ARRAY_A ); + $date = $post['modified']; + } else { + $post = get_post( $id ); + $date = $post->post_modified_gmt; + } + + $item['modified'] = date( apply_filters( 'fw_ext_seo_sitemap_date_format', 'Y-m-d' ), strtotime( $date ) ); + + $items[] = $item; + + $this->add_element( fw_render_view( $this->views_path . 'sitemap.php', array( 'items' => $items ) ) ); + } + + /** + * Returns the homepage details: priority or change frequency + * + * @param string $need the index you need: priority or frequency + * + * @return array + */ + private function get_homepage_url_details( $need = 'priority' ) { + $details = $this->url_settings['home']; + + return $details[ $need ]; + } + + /** + * Adds all custom posts in the sitemap.xml + */ + private function add_custom_posts() { + global $wpdb; + + if( empty( $this->custom_posts ) ) { + return; + } + + foreach ( $this->custom_posts as $post_type ) { + $items = $wpdb->get_results( $wpdb->prepare( + "SELECT id, post_type, post_modified_gmt modified + FROM $wpdb->posts + WHERE post_type = '%s' AND post_status IN ('publish', 'inherit')", + $post_type ), + ARRAY_A ); + + foreach ( $items as $key => $item ) { + $items[ $key ]['url'] = get_permalink( $item['id'] ); + $items[ $key ]['modified'] = date( apply_filters( 'fw_ext_seo_sitemap_date_format', 'Y-m-d' ), strtotime( $items[ $key ]['modified'] ) ); + $items[ $key ]['priority'] = $this->get_post_type_url_details( $item['post_type'] ); + $items[ $key ]['frequency'] = $this->get_post_type_url_details( $item['post_type'], 'frequency' ); + + unset( $items[ $key ]['id'] ); + unset( $items[ $key ]['post_type'] ); + } + + $this->add_element( fw_render_view( $this->views_path . 'sitemap.php', array( 'items' => $items ) ) ); + } + } + + /** + * Adds all custom posts in the sitemap.xml + */ + private function add_taxonomies() { + global $wpdb; + + if( empty( $this->taxonomies ) ) { + return; + } + + foreach ( $this->taxonomies as $taxonomy ) { + $items = array(); + $terms = get_terms( $taxonomy, array( 'hide_empty' => true, 'hierarchical' => false ) ); + + foreach ( $terms as $term ) { + $item = array(); + $sql = $wpdb->prepare( "SELECT MAX(p.post_modified_gmt) AS modified + FROM $wpdb->posts AS p + INNER JOIN $wpdb->term_relationships AS term_rel + ON term_rel.object_id = p.ID + INNER JOIN $wpdb->term_taxonomy AS term_tax + ON term_tax.term_taxonomy_id = term_rel.term_taxonomy_id + AND term_tax.taxonomy = '%s' + AND term_tax.term_id = %d + WHERE p.post_status IN ('publish','inherit')", $taxonomy, $term->term_id ); + $item['modified'] = date( apply_filters( 'fw_ext_seo_sitemap_date_format', 'Y-m-d' ), strtotime( $wpdb->get_var( $sql ) ) ); + $item['url'] = get_term_link( $term, $taxonomy ); + $item['priority'] = $this->get_taxonomy_url_details( $taxonomy ); + $item['frequency'] = $this->get_taxonomy_url_details( $taxonomy, 'frequency' ); + + unset( $item['id'] ); + + $items[] = $item; + } + $this->add_element( fw_render_view( $this->views_path . 'sitemap.php', array( 'items' => $items ) ) ); + } + + } + + /** + * Returns the posts details: priority or change frequency + * + * @param string $post_type , the custom post type name + * @param string $need the index you need: priority or frequency + * + * @return array + */ + private function get_post_type_url_details( $post_type, $need = 'priority' ) { + $details = $this->url_settings['posts']; + if ( in_array( $post_type, $details['type'] ) ) { + return $details['type'][ $need ]; + } + + return $details[ $need ]; + } + + /** + * Returns the taxonomy details: priority or change frequency + * + * @param string $taxonomy , the taxonomy name + * @param string $need the index you need: priority or frequency + * + * @return array + */ + private function get_taxonomy_url_details( $taxonomy, $need = 'priority' ) { + $details = $this->url_settings['taxonomies']; + if ( in_array( $taxonomy, $details['type'] ) ) { + return $details['type'][ $need ]; + } + + return $details[ $need ]; + } + + /** + * Returns the XML file footer + * @return string + */ + private function get_footer() { + return ''; + } + + /** + * Public function to update the sitemap + * @return bool + */ + public function update_sitemap() { + return $this->sitemap_build_prepare(); + } + + public function delete_xml_sitemap() { + return $this->delete_sitemap(); + } + + /** + * Deletes the XML sitemap + * TRUE if the sitemap was deleted + * @return bool + */ + private function delete_sitemap() { + if ( ! file_exists( $this->get_path() ) ) { + return true; + } + + if ( ! $this->check_path() ) { + return false; + } + + return ( unlink( $this->get_path() ) ); + } + + /** + * Returns the sitemap file uri + * @return string + */ + public function get_sitemap_uri() { + return home_url( '/' ) . $this->file_name; + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/includes/fw-sitemap-options.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/includes/fw-sitemap-options.php new file mode 100644 index 00000000..a3f1dc82 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/includes/fw-sitemap-options.php @@ -0,0 +1,127 @@ +extensions->get( 'seo-sitemap' )->get_allowed_post_types(); + $prefix = fw()->extensions->get( 'seo-sitemap' )->get_name() . '-'; + $options = array(); + + foreach ( $post_types as $post_type ) { + $post = get_post_type_object( $post_type ); + + $option = array( + 'label' => $post->labels->name, + 'text' => __( 'Check if you want to exclude this page', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ); + + $options[ $prefix . 'exclude-custom-post-' . $post_type ] = $option; + } + + return $options; +} + +function fw_ext_seo_sitemap_get_taxonomies_options() { + $taxonomies = fw()->extensions->get( 'seo-sitemap' )->get_allowed_taxonomies(); + $prefix = fw()->extensions->get( 'seo-sitemap' )->get_name() . '-'; + $options = array(); + + foreach ( $taxonomies as $taxonomy ) { + $tax = get_taxonomy( $taxonomy ); + + $option = array( + 'label' => $tax->labels->name, + 'text' => __( 'Check if you want to exclude this category', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ); + + $options[ $prefix . 'exclude-taxonomy-' . $taxonomy ] = $option; + } + + return $options; +} + +function fw_ext_seo_sitemap_get_settings_options() { + $ext_name = fw()->extensions->get( 'seo-sitemap' )->get_name(); + $prefix = $ext_name . '-'; + + return array( + $ext_name => array( + 'title' => __( 'Sitemap', 'fw' ), + 'type' => 'tab', + 'options' => array( + $prefix . 'box' => array( + 'title' => __('Sitemap Settings', 'fw'), + 'type' => 'box', + 'options' => array( + $prefix . 'group-sitemap-button' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'sitemap-button' => array( + 'label' => __( 'View Sitemap', 'fw' ), + 'desc' => __( 'Press button to view sitemap file', 'fw' ), + 'type' => 'html', + 'html' => '' . __( 'XML Sitemap', 'fw' ) . '', + 'value' => '' + ) + ) + ), + $prefix . 'group-search-engines' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'search-engies-pings' => array( + 'label' => __( 'Search Engines', 'fw' ), + 'type' => 'html', + 'html' => __( 'After adding contnet the extension will automatically ping to:', 'fw' ) . ' ' . fw_ext_seo_sitemap_get_search_engines_names( false ) . '', + 'value' => '' + ) + ) + ), + $prefix . 'group-custom-posts' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'exclude-custom-posts-html' => array( + 'label' => __( 'Exclude Pages', 'fw' ), + 'type' => 'html', + 'html' => __( 'Please check the pages you do not want to include in sitemap', 'fw' ), + 'value' => '' + ), + fw_ext_seo_sitemap_get_posts_types_options() + ) + ), + $prefix . 'group-taxonomies' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'exclude-taxonomies-html' => array( + 'label' => __( 'Exclude Categories', 'fw' ), + 'type' => 'html', + 'html' => __( 'Please check the categories you do not want to include in sitemap', 'fw' ), + 'value' => '' + ), + fw_ext_seo_sitemap_get_taxonomies_options() + ) + ), + $prefix . 'update-sitemap' => array( + 'label' => __( 'Update Sitemap', 'fw' ), + 'desc' => __( 'Update sitemap XML file', 'fw' ), + 'type' => 'html', + 'html' => '' . __( 'Update XML Sitemap', 'fw' ) . ' + ' . __( 'The sitemap was updated successfully' ) . ' + ' . __( 'Unable to update the sitemap' ) . ' + ', + 'value' => '' + ), + ) + ), + + ) + ) + ); +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/manifest.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/manifest.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/manifest.php @@ -0,0 +1 @@ +'; +echo $content; +?> + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/views/sitemap-style.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/views/sitemap-style.php new file mode 100644 index 00000000..0b945408 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/views/sitemap-style.php @@ -0,0 +1,130 @@ +' ?> + + + + + + + + +
    +

    XML Sitemap

    + +

    This is a XML file generated by via Wordpress and is supposed to be processed by search engines.
    + You can find more information about XML sitemaps on sitemaps.org + and Google's list of sitemap programs. +

    + + + + + + + + + + + + + + + +
    URLPriorityCh. FreqLas Mod.
    + + + + + _blank + + + + + % + + + + +
    +
    + + + +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/views/sitemap.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/views/sitemap.php new file mode 100644 index 00000000..496dddf0 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-sitemap/views/sitemap.php @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/README.md b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/README.md new file mode 100644 index 00000000..fbed08ac --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/README.md @@ -0,0 +1,58 @@ +# Titles and Meta + +A sub-extension of SEO extension, used to setup the theme SEO titles and meta keywords for search engines. + +## Configuration + +```php +// Custom posts types that you want to exclude from titles and meta settings +$cfg['excluded_post_types'] = array('attachment'); + +// Custom taxonomies that you want to exclude from titles and meta settings. +$cfg['excluded_taxonomies'] = array('post_tag'); +``` + +## Views + +* `meta.php` - Template to render the meta keywords and description. + +## Hooks + + +* `fw_ext_seo_titles_metas_load_metas` - Filter that allows you to modify some meta properties before it will be rendered in front-end. + + ```php + /** + * @internal + * @param array $data All metas that needs to be rendered on the current page + * @param array $location Current page location details + */ + function _filter_modify_seo_meta($data, $location) { + /** + * The view to display current meta. + * If the view key is not set, then will be loaded meta.php. + */ + $data['view'] = 'my-view'; + + return $data; + } + add_filter('fw_ext_seo_titles_metas_load_metas', '_filter_modify_seo_meta'); + ``` + +* `fw_ext_seo_titles_metas_load_title` - Filter that allows you to make some modifications in page title before it will be rendered. + + ```php + /** + * @internal + * @param string $title The current title + * @param string $separator Separator symbol + * @param string $sepdirection Separator position + * @param array $location Current page location details + */ + function _filter_modify_seo_title($title, $separator, $sepdirection, $location) { + // ... + + return $title; + } + add_filter('fw_ext_seo_titles_metas_load_title', '_filter_modify_seo_title'); + ``` diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/class-fw-extension-seo-titles-metas.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/class-fw-extension-seo-titles-metas.php new file mode 100644 index 00000000..662ee3d3 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/class-fw-extension-seo-titles-metas.php @@ -0,0 +1,725 @@ +add_admin_filters(); + } else { + $this->add_theme_actions(); + $this->add_theme_filters(); + } + add_action( 'init', array( $this, '_action_set_allowed_items' ) ); + } + + /** + * Init the admin area filters + */ + private function add_admin_filters() { + add_filter( 'fw_ext_seo_admin_options', array( $this, '_filter_set_framework_titles_metas_tab' ) ); + add_filter( 'fw_ext_seo_general_setting_admin_options', array( + $this, + '_filter_set_framework_titles_metas_options' + ) ); + add_filter( 'fw_ext_seo_post_type_options', array( + $this, + '_filter_set_custom_posts_titles_metas_metabox' + ), 10, 2 ); + add_filter( 'fw_ext_seo_taxonomy_options', array( + $this, + '_filter_set_taxonomies_titles_metas_options' + ), 10, 2 ); + } + + /** + * Init the frontend area actions + */ + private function add_theme_actions() { + add_action( 'wp_head', array( $this, '_action_add_meta' ) ); + } + + /** + * Init the frontend area filters + */ + private function add_theme_filters() { + add_filter( 'wp_title', array( $this, '_action_add_title' ), 999, 3 ); + } + + /** + * @internal + * + * @param null|string $index + * + * @return mixed|null + */ + private function get_admin_options( $index = null ) { + if ( is_null( $this->settings_options ) ) { + $this->settings_options = fw_get_db_extension_data( $this->get_parent()->get_name(), 'options' ); + } + + if ( is_null( $index ) ) { + return $this->settings_options; + } + + if ( ! isset( $this->settings_options[ $index ] ) ) { + return null; + } + + return $this->settings_options[ $index ]; + } + + /** + * Parses the options array and adds necessary prefixes and labels names for each post type + * + * @param $posts_options , options array + * + * @return array + */ + public function get_custom_pots_options( $posts_options = array() ) { + if ( ! is_array( $posts_options ) || empty( $posts_options ) ) { + return array(); + } + + $custom_posts_options = array(); + + foreach ( $this->allowed_post_types as $post_type ) { + $options = $posts_options; + $return = array(); + $prefix = $this->get_name() . '-' . $post_type . '-'; + + $post = get_post_type_object( $post_type ); + $post_name = $post->labels->name; + + foreach ( $options as $key => $option ) { + if ( is_int( $key ) && is_array( $option ) ) { + foreach ( $option as $op_key => $op ) { + if ( is_array( $op ) && ! isset( $options[ $prefix . $op_key ] ) ) { + if ( isset( $op['label'] ) ) { + $op['label'] = $post_name . ' ' . $op['label']; + } + + $return[ $prefix . $op_key ] = $op; + } + } + continue; + } + + if ( isset( $option['label'] ) ) { + $option['label'] = $post_name . ' ' . $option['label']; + } + $return[ $prefix . $key ] = $option; + } + $custom_posts_options[ $this->get_name() . '-' . $post_type . '-group' ] = array( + 'type' => 'group', + 'options' => $return + ); + } + + return $custom_posts_options; + } + + /** + * Parses the options array and adds necessary prefixes and labels names for each taxonomy + * This functions is used to generate general options for each taxonomy in Taxonomies metabox + * in extension editor from Framework. + * + * @param $taxonomies_options , options array + * + * @return array + */ + public function get_taxonomies_options( $taxonomies_options = array() ) { + if ( ! is_array( $taxonomies_options ) || empty( $taxonomies_options ) ) { + return array(); + } + + $custom_posts_options = array(); + + foreach ( $this->allowed_taxonomies as $taxonomy ) { + $options = $taxonomies_options; + $return = array(); + $prefix = $this->get_name() . '-' . $taxonomy . '-'; + + $tax = get_taxonomy( $taxonomy ); + $taxonomy_name = $tax->labels->name; + + foreach ( $options as $key => $option ) { + if ( is_int( $key ) && is_array( $option ) ) { + foreach ( $option as $op_key => $op ) { + if ( is_array( $op ) && ! isset( $options[ $prefix . $op_key ] ) ) { + if ( isset( $op['label'] ) ) { + $op['label'] = $taxonomy_name . ' ' . $op['label']; + } + + $return[ $prefix . $op_key ] = $op; + } + } + continue; + } + + if ( isset( $option['label'] ) ) { + $option['label'] = $taxonomy_name . ' ' . $option['label']; + } + $return[ $prefix . $key ] = $option; + } + + $custom_posts_options[ $this->get_name() . '-' . $taxonomy . '-group' ] = array( + 'type' => 'group', + 'options' => $return + ); + } + + return $custom_posts_options; + } + + /** + * @param array $value , meta keywords option array + * + * @return array + */ + public function use_meta_keywords( $value ) { + if ( fw_get_db_settings_option( 'seo-titles-metas-metakeywords' ) === true ) { + return $value; + } + + return array(); + } + + /** + * Init the titles-metas extension in frontend + * This method get the location ( posts, pages, archives, taxonomies ) SEO metas and renders them in frontend + * @internal + */ + public function _action_add_meta() { + $location = $this->get_parent()->get_location(); + $prefix = $this->get_name() . '-'; + + $data = array(); + + switch ( $location['type'] ) { + case 'front_page' : + $description = fw_ext_seo_parse_meta_tags( fw_get_db_settings_option( $prefix . 'homepage-description' ) ); + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } elseif ( isset( $location['id'] ) ) { + $description = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'description' ) ); + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + } + + if ( $this->get_admin_options( 'seo-titles-metas-metakeywords' ) === true ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'homepage-metakeywords' ) ); + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } elseif ( isset( $location['id'] ) ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'metakeywords' ) ); + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'description' + ); + } + } + } + + break; + case 'blog_page' : + $description = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'description' ) ); + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + $meta_keywords = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'metakeywords' ) ); + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'description' + ); + } + + break; + case 'author_archive' : + $description = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'author-archive-description' ) ); + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + if ( $this->get_admin_options( 'seo-titles-metas-metakeywords' ) === true ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'author-archive-metakeywords' ) ); + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } + } + + break; + case 'date_archive' : + $description = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'date-archive-description' ) ); + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + if ( $this->get_admin_options( 'seo-titles-metas-metakeywords' ) === true ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'date-archive-metakeywords' ) ); + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } + } + + break; + case 'singular' : + if ( ! in_array( $location['post_type'], $this->allowed_post_types ) ) { + break; + } + + $data = array(); + + $description = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'description' ) ); + if ( empty( $description ) ) { + $description = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['post_type'] . '-description' ) ); + } + + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + $meta_keywords = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'metakeywords' ) ); + if ( empty( $meta_keywords ) ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['post_type'] . '-metakeywords' ) ); + } + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } + + $robots = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['post_type'] . '-noindex' ) ); + if ( ! is_null( $robots ) && $robots == true ) { + $data['robots'] = array( + 'content' => 'noindex,follow', + 'name' => 'robots' + ); + } + break; + case 'category' : + if ( ! in_array( 'post_tag', $this->allowed_taxonomies ) ) { + break; + } + + $data = array(); + + $description = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], 'category', $prefix . 'description' ) ); + if ( empty( $description ) ) { + $description = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'category-description' ) ); + } + + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + $meta_keywords = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], 'category', $prefix . 'metakeywords' ) ); + if ( empty( $meta_keywords ) ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'category-metakeywords' ) ); + } + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } + + $robots = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'category-noindex' ) ); + if ( ! is_null( $robots ) && $robots == true ) { + $data['robots'] = array( + 'content' => 'noindex,follow', + 'name' => 'robots' + ); + } + break; + case 'tag' : + if ( ! in_array( 'post_tag', $this->allowed_taxonomies ) ) { + break; + } + + $data = array(); + + $description = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], 'post_tag', $prefix . 'description' ) ); + if ( empty( $description ) ) { + $description = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'post_tag-description' ) ); + } + + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + $meta_keywords = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], 'post_tag', $prefix . 'metakeywords' ) ); + if ( empty( $meta_keywords ) ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'post_tag-metakeywords' ) ); + } + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } + + $robots = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'post_tag-noindex' ) ); + if ( ! is_null( $robots ) && $robots == true ) { + $data['robots'] = array( + 'content' => 'noindex,follow', + 'name' => 'robots' + ); + } + break; + case 'taxonomy' : + if ( ! in_array( $location['taxonomy_type'], $this->allowed_taxonomies ) ) { + break; + } + + $data = array(); + + $description = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], $location['taxonomy_type'], $prefix . 'description' ) ); + if ( empty( $description ) ) { + $description = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['taxonomy_type'] . '-description' ) ); + } + + if ( ! empty( $description ) ) { + $data['description'] = array( + 'content' => $description, + 'name' => 'description' + ); + } + + + $meta_keywords = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], $location['taxonomy_type'], $prefix . 'metakeywords' ) ); + if ( empty( $meta_keywords ) ) { + $meta_keywords = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['taxonomy_type'] . '-metakeywords' ) ); + } + + if ( ! empty( $meta_keywords ) ) { + $data['keywords'] = array( + 'content' => $meta_keywords, + 'name' => 'keywords' + ); + } + + $robots = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['taxonomy_type'] . '-noindex' ) ); + if ( ! is_null( $robots ) && $robots == true ) { + $data['robots'] = array( + 'content' => 'noindex,follow', + 'name' => 'robots' + ); + } + break; + } + + $data = apply_filters( 'fw_ext_seo_titles_metas_load_metas', $data, $location ); + + foreach ( $data as $meta ) { + if ( isset( $meta['view'] ) ) { + echo $this->render_view( $meta['view'], $meta ); + } else { + echo $this->render_view( 'meta', $meta ); + } + } + } + + /** + * Init the titles-metas extension in frontend + * This method get the location ( posts, pages, archives, taxonomies ) SEO titles and returns to the wp_title + * + * @param $title , current wordpress title, before being processed + * @param $sep , worpdress title separator + * @param $sepdirection , wordpress separator direction + * + * @return string + * @internal + */ + public function _action_add_title( $title, $sep, $sepdirection ) { + $location = $this->get_parent()->get_location(); + $prefix = $this->get_name() . '-'; + + switch ( $location['type'] ) { + case '404' : + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'not-found-title' ) ); + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + case 'search' : + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'search-page-title' ) ); + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + case 'author_archive' : + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'author-archive-title' ) ); + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + case 'date_archive' : + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'date-archive-title' ) ); + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + case 'front_page' : + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'homepage-title' ) ); + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } elseif ( isset( $location['id'] ) ) { + $fw_title = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'title' ) ); + + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + } + break; + case 'blog_page' : + $fw_title = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'title' ) ); + + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + case 'singular' : + if ( ! in_array( $location['post_type'], $this->allowed_post_types ) ) { + break; + } + + $fw_title = fw_ext_seo_parse_meta_tags( fw_get_db_post_option( $location['id'], $prefix . 'title' ) ); + if ( empty( $fw_title ) ) { + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['post_type'] . '-title' ) ); + } + + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + case 'category' : + if ( ! in_array( 'post_tag', $this->allowed_taxonomies ) ) { + break; + } + + $fw_title = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], 'category', $prefix . 'title' ) ); + + if ( empty( $fw_title ) ) { + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'category-title' ) ); + } + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + + break; + case 'tag' : + if ( ! in_array( 'post_tag', $this->allowed_taxonomies ) ) { + break; + } + + + $fw_title = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], 'post_tag', $prefix . 'title' ) ); + if ( empty( $fw_title ) ) { + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . 'post_tag-title' ) ); + } + + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + + break; + case 'taxonomy' : + if ( ! in_array( $location['taxonomy_type'], $this->allowed_taxonomies ) ) { + break; + } + + $fw_title = fw_ext_seo_parse_meta_tags( fw_get_db_term_option( $location['id'], $location['taxonomy_type'], $prefix . 'title' ) ); + if ( empty( $fw_title ) ) { + $fw_title = fw_ext_seo_parse_meta_tags( $this->get_admin_options( $prefix . $location['taxonomy_type'] . '-title' ) ); + } + + if ( ! empty( $fw_title ) ) { + $title = $fw_title; + } + break; + } + + $title = apply_filters( 'fw_ext_seo_titles_metas_load_title', $title, $sep, $sepdirection, $location ); + + return $title; + } + + /** + * Defines the custom posts and taxonomies allowed to be used by this extension + * @internal + */ + public function _action_set_allowed_items() { + + $post_types = get_post_types( array( 'public' => true ) ); + $excluded_posts = $this->get_config( 'excluded_post_types' ); + unset( $post_types['nav_menu_item'] ); + unset( $post_types['revision'] ); + + foreach ( $excluded_posts as $type ) { + if ( isset( $post_types[ $type ] ) ) { + unset( $post_types[ $type ] ); + } + } + $this->allowed_post_types = $post_types; + + $taxonomies = get_taxonomies(); + $excluded_taxonomies = $this->get_config( 'excluded_taxonomies' ); + + unset( $taxonomies['nav_menu'] ); + unset( $taxonomies['link_category'] ); + unset( $taxonomies['post_format'] ); + + foreach ( $excluded_taxonomies as $type ) { + if ( isset( $post_types[ $type ] ) ) { + unset( $post_types[ $type ] ); + } + } + $this->allowed_taxonomies = $taxonomies; + } + + /** + * Adds the extension settings tab in Framework in SEO extension + * + * @param $seo_options , holds the general options from extension config file + * + * @return array + * @internal + */ + public function _filter_set_framework_titles_metas_tab( $seo_options ) { + $titles_metas_options = fw_ext_seo_titles_meta_get_settings_options(); + + if ( is_array( $titles_metas_options ) && ! empty( $titles_metas_options ) ) { + return array_merge( $seo_options, $titles_metas_options ); + } + + return $seo_options; + } + + /** + * Adds the extension settings metabox in custom posts editor page + * + * @param $seo_options , contains the custom post options + * @param $post_type , contains the custom post type + * + * @return array + * @internal + */ + public function _filter_set_custom_posts_titles_metas_metabox( $seo_options, $post_type ) { + if ( ! in_array( $post_type, $this->allowed_post_types ) ) { + return $seo_options; + } + + $titles_metas_options = fw_ext_seo_titles_meta_get_post_types_options(); + + if ( is_array( $titles_metas_options ) && ! empty( $titles_metas_options ) ) { + return array_merge( $seo_options, $titles_metas_options ); + } + + return $seo_options; + } + + /** + * Adds the extension settings metabox in taxonomies editor page + * + * @param $seo_options , contains the taxonomy options + * @param $taxonomy , contains the taxonomy type + * + * @return array + * @internal + */ + public function _filter_set_taxonomies_titles_metas_options( $seo_options, $taxonomy ) { + if ( ! in_array( $taxonomy, $this->allowed_taxonomies ) ) { + return $seo_options; + } + + $titles_metas_options = fw_ext_seo_titles_meta_get_taxonomies_options(); + + if ( is_array( $titles_metas_options ) && ! empty( $titles_metas_options ) ) { + return array_merge( $seo_options, $titles_metas_options ); + } + + return $seo_options; + } + + /** + * Adds the extension general option in SEO extension General Settings tab + * + * @param $options , holds the general options from extension config file + * + * @return array + * @internal + */ + public function _filter_set_framework_titles_metas_options( $options ) { + $general_options = fw_ext_seo_titles_meta_get_general_settings_options(); + + if ( is_array( $general_options ) && ! empty( $general_options ) ) { + return array_merge( $options, $general_options ); + } + + return $options; + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/config.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/config.php new file mode 100644 index 00000000..1ca2a336 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/config.php @@ -0,0 +1,8 @@ + array( 'attachment' ), + 'excluded_taxonomies' => array( 'post_tag' ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/includes/fw-title-meta-options.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/includes/fw-title-meta-options.php new file mode 100644 index 00000000..f3ca21e3 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/includes/fw-title-meta-options.php @@ -0,0 +1,371 @@ +extensions->get( 'seo-titles-metas' )->get_name(); + $prefix = $ext_name . '-'; + + return array( + $ext_name => array( + 'title' => __( 'Titles & Meta', 'fw' ), + 'type' => 'tab', + 'options' => array( + 'homepage' => array( + 'title' => __( 'Homepage', 'fw' ), + 'type' => 'box', + 'options' => array( + $prefix . 'homepage-title' => array( + 'label' => __( 'Homepage Title', 'fw' ), + 'desc' => __( 'Set homepage title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '%%sitename%% | %%sitedesc%%' + ), + $prefix . 'homepage-description' => array( + 'label' => __( 'Homepage Description', 'fw' ), + 'desc' => __( 'Set homepage description', 'fw' ), + 'type' => 'textarea', + 'value' => '' + ), + fw()->extensions->get( 'seo-titles-metas' )->use_meta_keywords( + array( + $prefix . 'homepage-metakeywords' => array( + 'label' => __( 'Homepage Meta Keywords', 'fw' ), + 'desc' => __( 'Set homepage meta keywords', 'fw' ), + 'type' => 'seo-tags', + 'value' => '' + ), + ) + ), + ) + ), + 'custom_posts_options' => array( + 'title' => __( 'Pages', 'fw' ), + 'type' => 'box', + 'options' => fw()->extensions->get( $ext_name )->get_custom_pots_options( + array( + 'title' => array( + 'label' => __( 'Title', 'fw' ), + 'desc' => __( 'Set title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '%%title%% | %%sitename%%', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ), + 'description' => array( + 'label' => __( 'Description', 'fw' ), + 'desc' => __( 'Set description format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ), + fw()->extensions->get( 'seo-titles-metas' )->use_meta_keywords( + array( + 'metakeywords' => array( + 'label' => __( 'Meta Keywords', 'fw' ), + 'desc' => __( 'Set meta keywords', 'fw' ), + 'type' => 'seo-tags', + 'value' => '', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ) + ) + ), + 'noindex' => array( + 'label' => __( 'Meta Robots', 'fw' ), + 'desc' => __( 'noindex, follow', 'fw' ), + 'type' => 'checkbox', + 'value' => false, + ), + ) + ), + ), + 'custom_taxonomies_options' => array( + 'title' => __( 'Taxonomies', 'fw' ), + 'type' => 'box', + 'options' => fw()->extensions->get( $ext_name )->get_taxonomies_options( + array_merge( + array( + 'title' => array( + 'label' => __( 'Title', 'fw' ), + 'desc' => __( 'Set title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '%%title%% | %%description%%', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ), + 'description' => array( + 'label' => __( 'Description', 'fw' ), + 'desc' => __( 'Set description format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ), + fw()->extensions->get( 'seo-titles-metas' )->use_meta_keywords( + array( + 'metakeywords' => array( + 'label' => __( 'Meta Keywords', 'fw' ), + 'desc' => __( 'Set meta keywords', 'fw' ), + 'type' => 'seo-tags', + 'value' => '', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ) + ) + ), + 'noindex' => array( + 'label' => __( 'Meta Robots', 'fw' ), + 'desc' => __( 'noindex, follow', 'fw' ), + 'type' => 'checkbox', + 'value' => false, + ), + ) + ) + ) + ), + 'other_pages_options' => array( + 'title' => __( 'Other', 'fw' ), + 'type' => 'box', + 'options' => array( + $prefix . 'author-archive-group' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'author-archive-title' => array( + 'label' => __( 'Author Page Title', 'fw' ), + 'desc' => __( 'Set author page title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '%%author_name%% | %%sitename%%' + ), + $prefix . 'author-archive-description' => array( + 'label' => __( 'Author Page Description', 'fw' ), + 'desc' => __( 'Set author page description', 'fw' ), + 'type' => 'textarea', + 'value' => '' + ), + fw()->extensions->get( 'seo-titles-metas' )->use_meta_keywords( + array( + $prefix . 'author-archive-metakeywords' => array( + 'label' => __( 'Author Meta Keywords', 'fw' ), + 'desc' => __( 'Set author page meta keywords', 'fw' ), + 'type' => 'seo-tags', + 'value' => '' + ), + ) + ), + $prefix . 'author-archive-noindex' => array( + 'label' => __( 'Metarobots', 'fw' ), + 'desc' => __( 'noindex, follow', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ), + $prefix . 'author-archive-disable' => array( + 'label' => __( 'Disable Author Archives', 'fw' ), + 'desc' => __( 'Disable Author archives SEO settings', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ) + ) + ), + $prefix . 'date-archive-group' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'date-archive-title' => array( + 'label' => __( 'Date Achieves Title', 'fw' ), + 'desc' => __( 'Set date achieves title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '%%date%% | %%sitename%%' + ), + $prefix . 'date-archive-description' => array( + 'label' => __( 'Date Achieves Description', 'fw' ), + 'desc' => __( 'Set date achieves description', 'fw' ), + 'type' => 'textarea', + 'value' => '' + ), + fw()->extensions->get( 'seo-titles-metas' )->use_meta_keywords( + array( + $prefix . 'date-archive-metakeywords' => array( + 'label' => __( 'Date achieves Meta Keywords', 'fw' ), + 'desc' => __( 'Set date achieves meta keywords', 'fw' ), + 'type' => 'seo-tags', + 'value' => '' + ), + ) + ), + $prefix . 'date-archive-noindex' => array( + 'label' => __( 'Metarobots', 'fw' ), + 'desc' => __( 'noindex, follow', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ), + $prefix . 'date-archive-disable' => array( + 'label' => __( 'Disable Date Archives', 'fw' ), + 'desc' => __( 'Disable date archives SEO settings', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ) + ) + ), + $prefix . 'search-page-group' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'search-page-title' => array( + 'label' => __( 'Search Page Title', 'fw' ), + 'desc' => __( 'Set search page title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '%%searchphrase%%', + 'help' => sprintf( "%s%s", + __( 'Here are some tags examples:
    ', 'fw' ), + __( '%%sitename%%
    + %%currentdate%%
    + %%title%%', 'fw' ) + ), + ) + ) + ), + $prefix . 'not-found-group' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'not-found-title' => array( + 'label' => __( '404 Page Title', 'fw' ), + 'desc' => __( 'Set 404 page title format', 'fw' ), + 'type' => 'seo-tags', + 'value' => '404 Not Found' + ) + ) + ), + ) + ) + ) + ) + ); +} + +/** + * Array of options that will appear in taxonomies editor + * + * @internal + * + * @return array + */ +function fw_ext_seo_titles_meta_get_taxonomies_options() { + $ext_name = fw()->extensions->get( 'seo-titles-metas' )->get_name(); + $prefix = $ext_name . '-'; + + return array( + $prefix . 'title' => array( + 'label' => __( 'Page Title', 'fw' ), + 'desc' => __( 'Set title format', 'fw' ), + 'type' => 'text', + 'value' => '' + ), + $prefix . 'description' => array( + 'label' => __( 'SEO Description', 'fw' ), + 'desc' => __( 'Set description format', 'fw' ), + 'type' => 'textarea', + 'value' => '' + ) + ); +} + +/** + * Array of options that will appear in custom posts editor + * @return array + */ +function fw_ext_seo_titles_meta_get_post_types_options() { + $ext_name = fw()->extensions->get( 'seo-titles-metas' )->get_name(); + $prefix = $ext_name . '-'; + + return array( + $ext_name . 'tab' => array( + 'title' => __( 'Titles & Meta', 'fw' ), + 'type' => 'tab', + 'options' => array( + $prefix . 'title' => array( + 'label' => __( 'Page Title', 'fw' ), + 'desc' => __( 'Set title format', 'fw' ), + 'type' => 'text', + 'value' => '' + ), + $prefix . 'description' => array( + 'label' => __( 'Description', 'fw' ), + 'desc' => __( 'Set description format', 'fw' ), + 'type' => 'textarea', + 'value' => '' + ), + fw()->extensions->get( 'seo-titles-metas' )->use_meta_keywords( + array( + $prefix . 'metakeywords' => array( + 'label' => __( 'Metakeywords', 'fw' ), + 'desc' => __( 'Set meta keywords', 'fw' ), + 'type' => 'text', + 'value' => '' + ), + ) + ), + ) + ) + ); +} + +/** + * Array of options that will appear in framework SEO General settings + * + * @internal + * + * @return array + */ +function fw_ext_seo_titles_meta_get_general_settings_options() { + $ext_name = fw()->extensions->get( 'seo-titles-metas' )->get_name(); + $prefix = $ext_name . '-'; + + return array( + $prefix . 'general-options' => array( + 'type' => 'group', + 'options' => array( + $prefix . 'metakeywords' => array( + 'label' => __( 'Use Meta Keywords', 'fw' ), + 'desc' => __( 'Allow to use mata keywords in posts and taxonomies', 'fw' ), + 'type' => 'checkbox', + 'value' => false + ) + ), + ), + ); +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/manifest.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/manifest.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-titles-metas/manifest.php @@ -0,0 +1 @@ + tag view + * + * View supports 2 parameters: $name, $content + * + * @var $name , meta tag name attribute value + * @var $content , meta tag content attribute value + */ + +?> + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/README.md b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/README.md new file mode 100644 index 00000000..f6af3200 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/README.md @@ -0,0 +1,19 @@ +# Webmasters + +A sub-extension of the SEO extension, used to setup your Webmasters providers. + +At the moment is supported only Google and Bing. + +## Configuration + +```php +// Webmasters you want o use +$cfg['webmasters'] = array( + 'google', + 'bing' +); +``` + +## Views + +* `meta.php` - Template for meta keywords and description. \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/class-fw-extension-seo-webmasters.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/class-fw-extension-seo-webmasters.php new file mode 100644 index 00000000..9820fc4f --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/class-fw-extension-seo-webmasters.php @@ -0,0 +1,159 @@ +define_webmasters(); + + if ( is_admin() ) { + $this->add_admin_filters(); + } else { + $this->add_theme_actions(); + } + } + + /** + * @internal + * + * Defines the array with the available webmasters + */ + private function define_webmasters() { + $this->webmasters = array( + 'google' => array( + 'id' => 'google', + 'name' => __( 'Google Webmasters', 'fw' ), + 'desc' => __( 'Insert Google Webmasters verification code', 'fw' ), + 'settings' => array( + 'meta-name' => 'google-site-verification' + ) + ), + 'bing' => array( + 'id' => 'bing', + 'name' => __( 'Bing Webmasters', 'fw' ), + 'desc' => __( 'Insert Bing Webmasters verification code', 'fw' ), + 'settings' => array( + 'meta-name' => 'msvalidate.01' + ) + ), + ); + } + + /** + * Init admin area filters + */ + private function add_admin_filters() { + add_filter( 'fw_ext_seo_general_tab_admin_options', array( $this, '_admin_filter_set_framework_options' ) ); + } + + /** + * Init frontend are actions + */ + private function add_theme_actions() { + add_action( 'wp_head', array( $this, '_theme_action_add_webmasters_meta' ) ); + } + + /** + * @internal + * + * @param null|string $index + * + * @return mixed|null + */ + private function get_admin_options( $index = null ) { + if ( is_null( $this->settings_options ) ) { + $this->settings_options = fw_get_db_extension_data( $this->get_parent()->get_name(), 'options' ); + } + + if ( is_null( $index ) ) { + return $this->settings_options; + } + + if ( ! isset( $this->settings_options[ $index ] ) ) { + return null; + } + + return $this->settings_options[ $index ]; + } + + /** + * Adds the extension settings box in Framework in SEO extension + * + * @param $options , holds the general options from extension config file + * + * @return array + * @internal + */ + public function _admin_filter_set_framework_options( $options ) { + $webmasters = $this->get_config( 'webmasters' ); + if ( empty( $webmasters ) ) { + return $options; + } + + $general_options = array( + $this->get_name() => array( + 'title' => __( 'Webmasters', 'fw' ), + 'type' => 'box', + 'options' => array() + ) + ); + + foreach ( $webmasters as $webmaster ) { + if ( ! isset( $this->webmasters[ $webmaster ] ) ) { + FW_Flash_Messages::add( 'fw-ext-seo-add-tabs', sprintf( __( 'Webmaster %s already exists', 'fw' ), $webmaster ), 'warning' ); + continue; + } + + $prefix = $this->get_name() . '-' . $webmaster; + $general_options[ $this->get_name() ]['options'][ $prefix ] = array( + 'label' => $this->webmasters[ $webmaster ]['name'], + 'desc' => $this->webmasters[ $webmaster ]['desc'], + 'type' => 'text', + 'value' => '' + ); + } + + if ( empty( $general_options[ $this->get_name() ]['options'] ) ) { + return $options; + } + + $options = array_merge( $options, $general_options ); + + return $options; + } + + /** + * Adds webmasters meta tags in front-end + * @internal + */ + public function _theme_action_add_webmasters_meta() { + $webmasters = $this->get_config( 'webmasters' ); + + foreach ( $webmasters as $webmaster ) { + + if ( ! isset( $this->webmasters[ $webmaster ] ) ) { + continue; + } + + $data = array(); + $value = $this->get_admin_options( $this->get_name() . '-' . $webmaster ); + + if ( empty( $value ) ) { + continue; + } + + $data['name'] = $this->webmasters[ $webmaster ]['settings']['meta-name']; + $data['content'] = $value; + + echo $this->render_view( 'meta', $data ); + } + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/config.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/config.php new file mode 100644 index 00000000..793a5408 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/config.php @@ -0,0 +1,11 @@ + array( 'google', 'bing' ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/manifest.php b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/manifest.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/extensions/seo-webmasters/manifest.php @@ -0,0 +1 @@ + tag view + * + * View supports 2 parameters: $name, $content + * + * @var $name , meta tag name attribute value + * @var $content , meta tag name attribute value + */ + +?> + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/seo/index.html b/scratch-parent/framework-customizations/extensions/seo/index.html new file mode 100644 index 00000000..71ce6922 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/seo/index.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/sidebars/config.php b/scratch-parent/framework-customizations/extensions/sidebars/config.php new file mode 100644 index 00000000..87ccc469 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/sidebars/config.php @@ -0,0 +1,31 @@ + array( + 'full' => array( + 'icon_url' => 'full.png', + 'sidebars_number' => 0 + + ), + 'left' => array( + 'icon_url' => 'left.png', + 'sidebars_number' => 1 + + ), + 'right' => array( + 'icon_url' => 'right.png', + 'sidebars_number' => 1 + ), + 'left_right' => array( + 'icon_url' => 'left_right.png', + 'sidebars_number' => 2 + ), + ), + + 'dynamic_sidebar_args' => array( + 'before_widget' => '', + 'before_title' => '

    ', + 'after_title' => '

    ', + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/sidebars/static/images/full.png b/scratch-parent/framework-customizations/extensions/sidebars/static/images/full.png new file mode 100644 index 00000000..d6a09fe1 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/sidebars/static/images/full.png differ diff --git a/scratch-parent/framework-customizations/extensions/sidebars/static/images/index.html b/scratch-parent/framework-customizations/extensions/sidebars/static/images/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/extensions/sidebars/static/images/left.png b/scratch-parent/framework-customizations/extensions/sidebars/static/images/left.png new file mode 100644 index 00000000..df721eb2 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/sidebars/static/images/left.png differ diff --git a/scratch-parent/framework-customizations/extensions/sidebars/static/images/left_right.png b/scratch-parent/framework-customizations/extensions/sidebars/static/images/left_right.png new file mode 100644 index 00000000..8c8158f4 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/sidebars/static/images/left_right.png differ diff --git a/scratch-parent/framework-customizations/extensions/sidebars/static/images/right.png b/scratch-parent/framework-customizations/extensions/sidebars/static/images/right.png new file mode 100644 index 00000000..316f9f64 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/sidebars/static/images/right.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/README.md b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/README.md new file mode 100644 index 00000000..019b1e02 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/README.md @@ -0,0 +1,18 @@ +# Switch Style Panel + +Show on the front-end a panel that allows the user to make the switch between predefined styles. + +## Configuration + +```php +$cfg = array( + // enable or disable panel + 'display' => true, + // the text that will be displayed at the top of the panel + 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' +); +``` + +## Views + +* `panel.php` - contains the html of the panel. \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/class-fw-extension-switch-style-panel.php b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/class-fw-extension-switch-style-panel.php new file mode 100644 index 00000000..3a689490 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/class-fw-extension-switch-style-panel.php @@ -0,0 +1,96 @@ +check_settings(); + } + } + + protected function check_settings() { + if ( ! $this->get_config( 'display' ) ) { + return; + } + $theme_options = fw_extract_only_options( $this->get_parent()->get_settings_options() ); + $options = false; + + foreach ( $theme_options as $option_name => $option_settings ) { + if ( $option_settings['type'] !== 'style' ) { + unset ( $theme_options[ $option_name ] ); + continue; + } + $options = $option_settings; + break; + } + + if ( ! empty( $options['predefined'] ) ) { + $this->options = $options; + $this->add_theme_actions(); + } + } + + protected function add_theme_actions() { + add_action( 'wp_head', array( $this, '_theme_action_print_saved_css' ), 99 ); + add_action( 'wp_footer', array( $this, '_theme_action_print_styling_switcher' ), 10 ); + } + + /** + * @internal + */ + public function _theme_action_print_saved_css() { + $stored_style = FW_Request::COOKIE( $this->cache_key ); + if ( ! empty( $this->options['predefined'][ $stored_style ] ) ) { + echo $this->generate_initial_css( $this->options['blocks'], $this->options['predefined'][ $stored_style ] ); + }; + } + + private function generate_initial_css( $blocks, $style_options ) { + $data = FW_Switch_Style_Panel_Css_Generator::get_css( $blocks, $style_options ); + $css = $data['google_fonts']; + $css .= ''; + + return $css; + } + + /** + * @internal + */ + public function _theme_action_print_styling_switcher() { + + echo $this->render_view( 'panel', array( + 'options' => $this->options, + 'description' => $this->get_config( 'description' ), + ) ); + + // add static + { + wp_enqueue_style( + 'fw-ext-' . $this->get_name(), + $this->locate_URI( '/static/css/panel.css' ), + array(), + $this->manifest->get_version() + ); + wp_enqueue_script( + 'fw-ext-' . $this->get_name(), + $this->locate_URI( '/static/js/panel.js' ), + array( 'jquery' ), + $this->manifest->get_version() + ); + + wp_localize_script( 'fw-ext-' . $this->get_name(), 'fwGoogleFonts', fw_get_google_fonts() ); + wp_localize_script( 'fw-ext-' . $this->get_name(), 'fwSwitchStylePanel', array( 'cache_key' => $this->cache_key ) ); + } + + } +} diff --git a/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/config.php b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/config.php new file mode 100644 index 00000000..7b9affec --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/config.php @@ -0,0 +1,8 @@ + true, + 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam in dui mauris. Vivamus hendrerit arcu sed erat molestie vehicula. Sed.' +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/includes/class-fw-switch-style-panel-css-generator.php b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/includes/class-fw-switch-style-panel-css-generator.php new file mode 100644 index 00000000..baf1e939 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/includes/class-fw-switch-style-panel-css-generator.php @@ -0,0 +1,189 @@ + array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p' ), + 'links' => array( 'links', 'links_hover' ), + ); + + private static $initialized = false; + + private static $google_fonts; + + private static $remote_fonts = array(); + + static public function get_css( $blocks, $style_options ) { + + if ( ! self::$initialized ) { + self::$google_fonts = fw_get_google_fonts(); + self::$initialized = true; + } + + return array( + 'css' => self::generate_css( $blocks, $style_options['blocks'] ), + 'google_fonts' => self::get_remote_fonts() + ); + } + + private static function generate_css( $blocks, $style_options ) { + + $css = ''; + + foreach ( $blocks as $block_id => $block_settings ) { + if ( empty( $block_settings['css_selector'] ) || empty($style_options[ $block_id ])) { + continue; + } + $css_selectors = (array) $block_settings['css_selector']; + $block_elements = (array) $block_settings['elements']; + + foreach ( $block_elements as $element ) { + if ( in_array( $element, self::$tags['typography'] ) ) { + $css .= self::generate_typography_css( $css_selectors, $element, $style_options[ $block_id ][ $element ] ); + } elseif ( in_array( $element, self::$tags['links'] ) ) { + $css .= self::generate_links_css( $css_selectors, $element, $style_options[ $block_id ][ $element ] ); + } elseif ( $element === 'background' ) { + $css .= self::generate_background_css( $css_selectors, $style_options[ $block_id ][ $element ] ); + } + } + } + + return $css; + } + + private static function generate_typography_css( $selectors, $tag, $options ) { + $css = ''; + + $current_family = $options['family']; + + $current_style = $options['style']; + + if ( $current_style === 'regular' ) { + $current_style = '400'; + } + if ( $current_style == 'italic' ) { + $current_style = '400italic'; + } + + $font_style = ( strpos( $current_style, 'italic' ) ) ? 'font-style: italic;' : ''; + $font_weight = 'font-weight: ' . intval( $current_style ) . ';'; + + self::insert_remote_font( $current_family, $current_style ); + + foreach ( $selectors as $selector ) { + $css .= $selector . ' ' . $tag . "{ + color: " . $options['color'] . "; + font-size: " . $options['size'] . "px; + font-family: '" . $current_family . "';" + . $font_style . "" . $font_weight . " + + }\n"; + } + + return $css; + } + + private static function insert_remote_font( $font, $style ) { + + if ( ! isset( self::$google_fonts[ $font ] ) ) { + return false; + } + + if ( ! isset( self::$remote_fonts[ $font ] ) ) { + self::$remote_fonts[ $font ] = array(); + } + + if ( ! in_array( $style, self::$remote_fonts[ $font ] ) ) { + self::$remote_fonts[ $font ][] = $style; + } + + return true; + } + + private static function generate_links_css( $selectors, $tag, $color ) { + $css = ''; + if ( ! is_string( $color ) || ! self::is_valid_hex_color( $color ) ) { + return $css; + } + $tag = ( $tag === 'links' ) ? 'a' : 'a:hover'; + foreach ( $selectors as $selector ) { + $css .= $selector . ' ' . $tag . '{color: ' . $color . '}'; + } + + return $css; + } + + private static function is_valid_hex_color( $color ) { + return preg_match( '/^#[a-f0-9]{6}$/i', $color ); + } + + private static function generate_background_css( $selectors, $options ) { + $css = ''; + $bgImageCss = ''; + if ( ! empty( $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-image'] ) ) { + $bgImageCss .= $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-image']; + if ( ! empty( $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-repeat'] ) ) { + $bgImageCss .= ' ' . $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-repeat']; + } + $bgImageCss .= ', '; + } + $fallback = 'background-color: ' . $options['background-color']['primary'] . ';'; + $fallback .= ( ! empty( $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-image'] ) ) ? 'background-image: ' . $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-image'] . ';' : ''; + $fallback .= ( ! empty( $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-repeat'] ) ) ? 'background-repeat: ' . $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-repeat'] . ';' : ''; + + foreach ( $selectors as $selector ) { + //Gradient http://css-tricks.com/examples/CSS3Gradient/ + $css .= $selector . ' ' . '{ + /* fallback */ + ' . $fallback . ' + /* Safari 4-5, Chrome 1-9 */ + background: ' . $bgImageCss . '-webkit-gradient(linear, left top, right top, from(' . $options['background-color']['primary'] . '), to(' . $options['background-color']['secondary'] . ')); + + /* Safari 5.1, Chrome 10+ */ + background: ' . $bgImageCss . '-webkit-linear-gradient(left, ' . $options['background-color']['primary'] . ', ' . $options['background-color']['secondary'] . '); + + /* Firefox 3.6+ */ + background: ' . $bgImageCss . '-moz-linear-gradient(left, ' . $options['background-color']['primary'] . ', ' . $options['background-color']['secondary'] . '); + + /* IE 10 */ + background: ' . $bgImageCss . '-ms-linear-gradient(left, ' . $options['background-color']['primary'] . ', ' . $options['background-color']['secondary'] . '); + + /* Opera 11.10+ */ + background: ' . $bgImageCss . '-o-linear-gradient(left, ' . $options['background-color']['primary'] . ', ' . $options['background-color']['secondary'] . '); + }'; + + //Background-image + unset( $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-image'] ); + unset( $options['background-image']['choices'][ $options['background-image']['value'] ]['css']['background-repeat'] ); + if ( sizeof( $options['background-image']['choices'][ $options['background-image']['value'] ]['css'] ) ) { + $css .= $selector . ' ' . '{'; + foreach ( $options['background-image']['choices'][ $options['background-image']['value'] ]['css'] as $css_property => $css_value ) { + $css .= $css_property . ': ' . $css_value . ';'; + } + $css .= '}'; + } + } + + + return $css; + } + + private static function get_remote_fonts() { + if ( ! sizeof( self::$remote_fonts ) ) { + return ''; + } + + $html = "' + css + ''); + setCookie(fwSwitchStylePanel['cache_key'], $(event.target).attr('data-key')); + return false; + } + + function generateTypographyCss(selectors, tag, options) { + var css = '', style, weight, variants; + + $.each(selectors, function (index, selector) { + css += selector + ' ' + tag + '{'; + if (typeof options['size'] === 'number') { + css += 'font-size: ' + options['size'] + 'px;' + } + if (typeof options['color'] === 'string' && isValidColor(options['color'])) { + css += 'color: ' + options['color'] + ';' + } + if (typeof options['style'] === 'string') { + style = (/italic/i.test(options['style'])) ? 'italic' : 'normal'; + weight = (parseInt(options['style'])) ? parseInt(options['style']) : '400'; + css += 'font-style: ' + style + ';' + 'font-weight: ' + weight + ';'; + } + if (typeof options['family'] === 'string') { + if (fwGoogleFonts.hasOwnProperty(options['family']) && $.inArray(options['family'], + loadedGoogleFonts) === -1) { + variants = fwGoogleFonts[options['family']]['variants'].join(','); + $('head').append(''); + loadedGoogleFonts.push(options['family']); + } + css += 'font-family: ' + options['family']; + } + css += '}'; + }); + + return css; + } + + function generateLinksCss(selectors, tag, color) { + var css = ''; + + tag = (tag === 'links') ? 'a' : 'a:hover'; + + $.each(selectors, function (index, selector) { + if (typeof color === 'string' && isValidColor(color)) { + css += selector + ' ' + tag + '{'; + css += 'color: ' + color + ';'; + css += '}'; + } + }); + + return css; + } + + function generateBackgroundCss(selectors, options) { + var css = '', fallback = '', bgImageCss = ''; + $.each(selectors, function (index, selector) { + css += selector + '{'; + if (options['background-image']['choices'][options['background-image']['value']]['css'].hasOwnProperty('background-image')) { + bgImageCss += options['background-image']['choices'][options['background-image']['value']]['css']['background-image']; + fallback += 'background-image: ' + options['background-image']['choices'][options['background-image']['value']]['css']['background-image'] + ';'; + if (options['background-image']['choices'][options['background-image']['value']]['css'].hasOwnProperty('background-repeat')) { + bgImageCss += ' ' + options['background-image']['choices'][options['background-image']['value']]['css']['background-repeat']; + fallback += 'background-repeat: ' + options['background-image']['choices'][options['background-image']['value']]['css']['background-repeat'] + ';'; + } + bgImageCss += ', '; + } + + css += 'background-color: ' + options['background-color']['primary'] + ';' + fallback; + css += 'background: ' + bgImageCss + '-webkit-gradient(linear, left top, right top, from(' + options['background-color']['primary'] + '), to(' + options['background-color']['secondary'] + '));'; + css += 'background: ' + bgImageCss + '-webkit-linear-gradient(left, ' + options['background-color']['primary'] + ', ' + options['background-color']['secondary'] + '); '; + css += 'background: ' + bgImageCss + '-moz-linear-gradient(left, ' + options['background-color']['primary'] + ', ' + options['background-color']['secondary'] + ');'; + css += 'background: ' + bgImageCss + '-ms-linear-gradient(left, ' + options['background-color']['primary'] + ', ' + options['background-color']['secondary'] + ');'; + css += 'background: ' + bgImageCss + '-o-linear-gradient(left, ' + options['background-color']['primary'] + ', ' + options['background-color']['secondary'] + ');'; + + for (var i in options['background-image']['choices'][options['background-image']['value']]['css']) { + if (!options['background-image']['choices'][options['background-image']['value']]['css'].hasOwnProperty(i)) { + continue; + } + if (i !== 'background-image' && index !== 'background-repeat') { + css += i + ': ' + options['background-image']['choices'][options['background-image']['value']]['css'][i] + ';'; + } + } + css += '}'; + }); + + return css; + } + + function setCookie(c_name, value) { + var exdays = 365, exdate = new Date(); + exdate.setDate(exdate.getDate() + exdays); + var c_value = value + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString() + "; path=/;"); + document.cookie = c_name + "=" + c_value; + } + + function checkSelector(selector) { + if (typeof selector === 'string') { + selector = [ selector ] + } + return selector; + } + + function isValidColor(str) { + return str.match(/^#[a-f0-9]{6}$/i) !== null; + } + }; + + switchPanel($('.wrap-style-panel')); + +})(jQuery); diff --git a/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/views/panel.php b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/views/panel.php new file mode 100644 index 00000000..89e7a24b --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/extensions/switch-style-panel/views/panel.php @@ -0,0 +1,28 @@ + + +
    +

    +
      '> + $style ) : ?> +
    • + +
    + +
    + + diff --git a/scratch-parent/framework-customizations/extensions/styling/options/includes/index.html b/scratch-parent/framework-customizations/extensions/styling/options/includes/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/extensions/styling/options/includes/predefined-styles.php b/scratch-parent/framework-customizations/extensions/styling/options/includes/predefined-styles.php new file mode 100644 index 00000000..23730636 --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/options/includes/predefined-styles.php @@ -0,0 +1,333 @@ + 'none', + 'choices' => array( + 'none' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/no_pattern.jpg', + 'css' => array( + 'background-image' => 'none' + ) + ), + 'bg-1' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/diagonal_bottom_to_top_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-2' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/diagonal_top_to_bottom_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-3' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/dots_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/dots_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-4' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/romb_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/romb_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-5' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/square_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/square_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-6' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/noise_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/noise_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-7' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/vertical_lines_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/vertical_lines_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-8' => array( + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/waves_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_EXTENSIONS_URI . '/styling/static/images/patterns/waves_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + ) +); + +$styles = array( + 'black' => array( + 'name' => 'Black', + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/black_predefined_style.jpg', + 'blocks' => array( + 'header' => array( + 'h1' => array( + 'size' => 18, + 'family' => 'Merienda One', + 'style' => 'regular', + 'color' => '#ffffff' + ), + 'links' => '#ffffff', + 'links_hover' => '#f17e12', + 'background' => array( + 'background-color' => array( + 'primary' => '#111111', + 'secondary' => '#111111' + ), + 'background-image' => $background_image, + ), + ), + 'content' => array( + 'h2' => array( + 'size' => 24, + 'family' => 'Merienda One', + 'style' => 'regular', + 'color' => '#2b2b2b' + ), + 'h3' => array( + 'size' => 22, + 'family' => 'Merienda One', + 'style' => 'regular', + 'color' => '#2b2b2b' + ), + 'p' => array( + 'size' => 16, + 'family' => 'Open Sans', + 'style' => 'regular', + 'color' => '#2b2b2b' + ), + 'links' => '#f17e12', + 'links_hover' => '#834a15', + 'background' => array( + 'background-color' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff' + ), + 'background-image' => $background_image, + ), + ), + 'sidebar' => array( + 'h1' => array( + 'size' => 11, + 'family' => 'Lato', + 'style' => '900', + 'color' => '#ffffff' + ), + 'links' => '#ffffff', + 'links_hover' => '#f17e12', + 'background' => array( + 'background-color' => array( + 'primary' => '#111111', + 'secondary' => '#111111' + ), + 'background-image' => $background_image, + ), + ), + 'footer' => array( + 'h1' => array( + 'size' => 11, + 'family' => 'Lato', + 'style' => '900', + 'color' => '#ffffff' + ), + 'links' => '#ffffff', + 'links_hover' => '#f17e12', + 'background' => array( + 'background-color' => array( + 'primary' => '#111111', + 'secondary' => '#111111' + ), + 'background-image' => $background_image, + ), + ) + ) + ), + 'green' => array( + 'name' => 'Green', + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/green_predefined_style.jpg', + 'blocks' => array( + 'header' => array( + 'h1' => array( + 'size' => 18, + 'family' => 'Philosopher', + 'style' => 'regular', + 'color' => '#ffffff' + ), + 'links' => '#04d19b', + 'links_hover' => '#34fdbe', + 'background' => array( + 'background-color' => array( + 'primary' => '#006c4f', + 'secondary' => '#006c4f' + ), + 'background-image' => $background_image, + ), + ), + 'content' => array( + 'h2' => array( + 'size' => 24, + 'family' => 'Philosopher', + 'style' => 'regular', + 'color' => '#2b2b2b' + ), + 'h3' => array( + 'size' => 22, + 'family' => 'Philosopher', + 'style' => 'regular', + 'color' => '#2b2b2b' + ), + 'p' => array( + 'size' => 16, + 'family' => 'Gafata', + 'style' => 'regular', + 'color' => '#2b2b2b' + ), + 'links' => '#006c4f', + 'links_hover' => '#00a77a', + 'background' => array( + 'background-color' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff' + ), + 'background-image' => $background_image, + ), + ), + 'sidebar' => array( + 'h1' => array( + 'size' => 12, + 'family' => 'Philosopher', + 'style' => 'regular', + 'color' => '#ffffff' + ), + 'links' => '#04d19b', + 'links_hover' => '#34fdbe', + 'background' => array( + 'background-color' => array( + 'primary' => '#006c4f', + 'secondary' => '#006c4f' + ), + 'background-image' => $background_image, + ), + ), + 'footer' => array( + 'h1' => array( + 'size' => 12, + 'family' => 'Philosopher', + 'style' => 'regular', + 'color' => '#ffffff' + ), + 'links' => '#04d19b', + 'links_hover' => '#34fbde', + 'background' => array( + 'background-color' => array( + 'primary' => '#006c4f', + 'secondary' => '#006c4f' + ), + 'background-image' => $background_image, + ), + ), + ) + ), + 'blue' => array( + 'name' => 'Blue', + 'icon' => FW_PT_EXTENSIONS_URI . '/styling/static/images/blue_predefined_style.jpg', + 'blocks' => array( + 'header' => array( + 'h1' => array( + 'size' => 18, + 'family' => 'Fugaz One', + 'style' => 'regular', + 'color' => '#ffffff' + ), + 'links' => '#b7d3f5', + 'links_hover' => '#ffffff', + 'background' => array( + 'background-color' => array( + 'primary' => '#206bb6', + 'secondary' => '#206bb6' + ), + 'background-image' => $background_image, + ), + ), + 'content' => array( + 'h2' => array( + 'size' => 24, + 'family' => 'Fugaz One', + 'style' => 'regular', + 'color' => '#11385e' + ), + 'h3' => array( + 'size' => 22, + 'family' => 'Fugaz One', + 'style' => 'regular', + 'color' => '#11385e' + ), + 'p' => array( + 'size' => 16, + 'family' => 'Lato', + 'style' => 'regular', + 'color' => '#11385e' + ), + 'links' => '#206bb6', + 'links_hover' => '#11385e', + 'background' => array( + 'background-color' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff' + ), + 'background-image' => $background_image, + ), + ), + 'sidebar' => array( + 'h1' => array( + 'size' => 11, + 'family' => 'Lato', + 'style' => '700', + 'color' => '#ffffff' + ), + 'links' => '#b7d3f5', + 'links_hover' => '#ffffff', + 'background' => array( + 'background-color' => array( + 'primary' => '#206bb6', + 'secondary' => '#206bb6' + ), + 'background-image' => $background_image, + ), + ), + 'footer' => array( + 'h1' => array( + 'size' => 11, + 'family' => 'Lato', + 'style' => '700', + 'color' => '#ffffff' + ), + 'links' => '#b7d3f5', + 'links_hover' => '#ffffff', + 'background' => array( + 'background-color' => array( + 'primary' => '#206bb6', + 'secondary' => '#206bb6' + ), + 'background-image' => $background_image, + ), + ), + ) + ) +); +return apply_filters( 'fw_ext_styling_predefined_styles', $styles ); diff --git a/scratch-parent/framework-customizations/extensions/styling/options/settings.php b/scratch-parent/framework-customizations/extensions/styling/options/settings.php new file mode 100644 index 00000000..31aacb9d --- /dev/null +++ b/scratch-parent/framework-customizations/extensions/styling/options/settings.php @@ -0,0 +1,53 @@ + array( + 'label' => false, + 'type' => 'style', + 'predefined' => $predefined = include( 'includes/predefined-styles.php' ), + 'value' => $predefined['black']['blocks'], + 'blocks' => array( + 'header' => array( + 'title' => __( 'Header', 'fw' ), + 'elements' => array( 'h1', 'links', 'links_hover', 'background' ), + //all allowed array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'links', 'links_hover', 'background') + 'css_selector' => array( + '#masthead', + '.primary-navigation .mega-menu', + '.primary-navigation .mega-col', + '.primary-navigation .mega-row', + ), + //css selectors (string|array) + ), + 'content' => array( + 'title' => __( 'Content', 'fw' ), + 'elements' => array( 'h2', 'h3', 'p', 'links', 'links_hover', 'background' ), + 'css_selector' => array( + '#primary.content-area', + '#primary.portfolio-content', + '#content header', + '#content article .entry-content', + '#content article .entry-meta' + ) + ), + 'sidebar' => array( + 'title' => __( 'Sidebar', 'fw' ), + 'elements' => array( 'h1', 'links', 'links_hover', 'background' ), + 'css_selector' => array( '#secondary', '.site:before' ) + ), + 'footer' => array( + 'title' => __( 'Footer', 'fw' ), + 'elements' => array( 'h1', 'links', 'links_hover', 'background' ), + 'css_selector' => '#colophon' + ), + ), + ), + 'quick_css' => array( + 'label' => __( 'Quick CSS', 'fw' ), + 'desc' => __( 'Just want to do some quick CSS changes? Enter them here, they will be
    applied to the theme. If you need to change major portions of the theme
    please use the custom.css file.', 'fw' ), + 'type' => 'textarea', + 'value' => '', + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/black_predefined_style.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/black_predefined_style.jpg new file mode 100644 index 00000000..1fbb1894 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/black_predefined_style.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/blue_predefined_style.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/blue_predefined_style.jpg new file mode 100644 index 00000000..40903dbd Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/blue_predefined_style.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/green_predefined_style.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/green_predefined_style.jpg new file mode 100644 index 00000000..d8f50bbb Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/green_predefined_style.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_bottom_to_top_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_bottom_to_top_pattern.png new file mode 100644 index 00000000..08273451 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_bottom_to_top_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg new file mode 100644 index 00000000..245781fd Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_top_to_bottom_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_top_to_bottom_pattern.png new file mode 100644 index 00000000..2fcc54d6 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_top_to_bottom_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg new file mode 100644 index 00000000..df001483 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/dots_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/dots_pattern.png new file mode 100644 index 00000000..d64b3190 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/dots_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/dots_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/dots_pattern_preview.jpg new file mode 100644 index 00000000..9fe354e2 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/dots_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/no_pattern.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/no_pattern.jpg new file mode 100644 index 00000000..393a4d3d Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/no_pattern.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/noise_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/noise_pattern.png new file mode 100644 index 00000000..312ee416 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/noise_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/noise_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/noise_pattern_preview.jpg new file mode 100644 index 00000000..5190e96b Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/noise_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/romb_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/romb_pattern.png new file mode 100644 index 00000000..c447c3f2 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/romb_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/romb_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/romb_pattern_preview.jpg new file mode 100644 index 00000000..4e621998 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/romb_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/square_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/square_pattern.png new file mode 100644 index 00000000..3bff4f3c Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/square_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/square_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/square_pattern_preview.jpg new file mode 100644 index 00000000..a0237b1c Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/square_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/vertical_lines_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/vertical_lines_pattern.png new file mode 100644 index 00000000..b14996e7 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/vertical_lines_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/vertical_lines_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/vertical_lines_pattern_preview.jpg new file mode 100644 index 00000000..8e9eab86 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/vertical_lines_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/waves_pattern.png b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/waves_pattern.png new file mode 100644 index 00000000..e64b1e80 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/waves_pattern.png differ diff --git a/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/waves_pattern_preview.jpg b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/waves_pattern_preview.jpg new file mode 100644 index 00000000..36a50822 Binary files /dev/null and b/scratch-parent/framework-customizations/extensions/styling/static/images/patterns/waves_pattern_preview.jpg differ diff --git a/scratch-parent/framework-customizations/theme/config.php b/scratch-parent/framework-customizations/theme/config.php new file mode 100644 index 00000000..d153697e --- /dev/null +++ b/scratch-parent/framework-customizations/theme/config.php @@ -0,0 +1,8 @@ + $post->post_parent, + 'fields' => 'ids', + 'numberposts' => -1, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => 'ASC', + 'orderby' => 'menu_order ID', + ) ); + + // If there is more than 1 attachment in a gallery... + if ( count( $attachment_ids ) > 1 ) { + foreach ( $attachment_ids as $attachment_id ) { + if ( $attachment_id == $post->ID ) { + $next_id = current( $attachment_ids ); + break; + } + } + + // get the URL of the next image attachment... + if ( $next_id ) { + $next_attachment_url = get_attachment_link( $next_id ); + } + + // or get the URL of the first image attachment. + else { + $next_attachment_url = get_attachment_link( array_shift( $attachment_ids ) ); + } + } + + printf( '%2$s', + esc_url( $next_attachment_url ), + wp_get_attachment_image( $post->ID, $attachment_size ) + ); + } +endif; + +if ( ! function_exists( 'fw_theme_list_authors' ) ) : + /** + * Print a list of all site contributors who published at least one post. + */ + function fw_theme_list_authors() { + $contributor_ids = get_users( array( + 'fields' => 'ID', + 'orderby' => 'post_count', + 'order' => 'DESC', + 'who' => 'authors', + ) ); + + foreach ( $contributor_ids as $contributor_id ) : + $post_count = count_user_posts( $contributor_id ); + + // Move on if user has not published a post (yet). + if ( ! $post_count ) { + continue; + } + ?> + +
    +
    +
    +
    +

    +

    + +

    + + + +
    +
    +
    + + max_num_pages < 2 ) { + return; + } + + $paged = get_query_var( 'paged' ) ? intval( get_query_var( 'paged' ) ) : 1; + $pagenum_link = html_entity_decode( get_pagenum_link() ); + $query_args = array(); + $url_parts = explode( '?', $pagenum_link ); + + if ( isset( $url_parts[1] ) ) { + wp_parse_str( $url_parts[1], $query_args ); + } + + $pagenum_link = remove_query_arg( array_keys( $query_args ), $pagenum_link ); + $pagenum_link = trailingslashit( $pagenum_link ) . '%_%'; + + $format = $GLOBALS['wp_rewrite']->using_index_permalinks() && ! strpos( $pagenum_link, 'index.php' ) ? 'index.php/' : ''; + $format .= $GLOBALS['wp_rewrite']->using_permalinks() ? user_trailingslashit( 'page/%#%', 'paged' ) : '?paged=%#%'; + + // Set up paginated links. + $links = paginate_links( array( + 'base' => $pagenum_link, + 'format' => $format, + 'total' => $wp_query->max_num_pages, + 'current' => $paged, + 'mid_size' => 1, + 'add_args' => array_map( 'urlencode', $query_args ), + 'prev_text' => __( '← Previous', 'unyson' ), + 'next_text' => __( 'Next →', 'unyson' ), + ) ); + + if ( $links ) : + + ?> + + post_parent ) : get_adjacent_post( false, '', true ); + $next = get_adjacent_post( false, '', false ); + + if ( ! $next && ! $previous ) { + return; + } + + ?> + + ' . __( 'Sticky', 'unyson' ) . ''; + } + + // Set up and print post meta information. + printf( ' ', + esc_url( get_permalink() ), + esc_attr( get_the_date( 'c' ) ), + esc_html( get_the_date() ), + esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ), + get_the_author() + ); + } + endif; + + /** + * Find out if blog has more than one category. + * + * @return boolean true if blog has more than 1 category + */ + function fw_theme_categorized_blog() { + if ( false === ( $all_the_cool_cats = get_transient( 'fw_theme_category_count' ) ) ) { + // Create an array of all the categories that are attached to posts + $all_the_cool_cats = get_categories( array( + 'hide_empty' => 1, + ) ); + + // Count the number of categories that are attached to the posts + $all_the_cool_cats = count( $all_the_cool_cats ); + + set_transient( 'fw_theme_category_count', $all_the_cool_cats ); + } + + if ( 1 !== (int) $all_the_cool_cats ) { + // This blog has more than 1 category so fw_theme_categorized_blog should return true + return true; + } else { + // This blog has only 1 category so fw_theme_categorized_blog should return false + return false; + } + } + + /** + * Display an optional post thumbnail. + * + * Wraps the post thumbnail in an anchor element on index + * views, or a div element when on single views. + */ + function fw_theme_post_thumbnail() { + if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) { + return; + } + + if ( is_singular() ) : + ?> + +
    + +
    + + + + + + + + ' . $quick_css . ''; + } + } + add_action( 'wp_head', '_action_print_quick_css', 100 ); +} + +/** + * Enqueue Google fonts style to admin screen for custom header display. + * @internal + */ +function _action_theme_admin_fonts() { + wp_enqueue_style( 'fw-theme-lato', fw_theme_font_url(), array(), fw()->theme->manifest->get_version() ); +} +add_action( 'admin_print_scripts-appearance_page_custom-header', '_action_theme_admin_fonts' ); + +if ( ! function_exists( '_action_theme_setup' ) ) : + /** + * Theme setup. + * + * Set up theme defaults and registers support for various WordPress features. + * + * Note that this function is hooked into the after_setup_theme hook, which + * runs before the init hook. The init hook is too late for some features, such + * as indicating support post thumbnails. + * @internal + */ + function _action_theme_setup() { + + /* + * Make Theme available for translation. + */ + load_theme_textdomain( 'unyson', get_template_directory() . '/languages' ); + + // This theme styles the visual editor to resemble the theme style. + add_editor_style( array( 'css/editor-style.css', fw_theme_font_url() ) ); + + // Add RSS feed links to for posts and comments. + add_theme_support( 'automatic-feed-links' ); + + // Enable support for Post Thumbnails, and declare two sizes. + add_theme_support( 'post-thumbnails' ); + set_post_thumbnail_size( 811, 372, true ); + add_image_size( 'fw-theme-full-width', 1038, 576, true ); + + /* + * Switch default core markup for search form, comment form, and comments + * to output valid HTML5. + */ + add_theme_support( 'html5', array( + 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption' + ) ); + + /* + * Enable support for Post Formats. + * See http://codex.wordpress.org/Post_Formats + */ + add_theme_support( 'post-formats', array( + 'aside', 'image', 'video', 'audio', 'quote', 'link', 'gallery', + ) ); + + // Add support for featured content. + add_theme_support( 'featured-content', array( + 'featured_content_filter' => 'fw_theme_get_featured_posts', + 'max_posts' => 6, + ) ); + + // This theme uses its own gallery styles. + add_filter( 'use_default_gallery_style', '__return_false' ); + } +endif; +add_action( 'after_setup_theme', '_action_theme_setup' ); + +/** + * Adjust content_width value for image attachment template. + * @internal + */ +function _action_theme_content_width() { + if ( is_attachment() && wp_attachment_is_image() ) { + $GLOBALS['content_width'] = 810; + } +} +add_action( 'template_redirect', '_action_theme_content_width' ); + +/** + * Extend the default WordPress body classes. + * + * Adds body classes to denote: + * 1. Single or multiple authors. + * 2. Presence of header image. + * 3. Index views. + * 4. Full-width content layout. + * 5. Presence of footer widgets. + * 6. Single views. + * 7. Featured content layout. + * + * @param array $classes A list of existing body class values. + * @return array The filtered body class list. + * @internal + */ +function _filter_theme_body_classes( $classes ) { + if ( is_multi_author() ) { + $classes[] = 'group-blog'; + } + + if ( get_header_image() ) { + $classes[] = 'header-image'; + } else { + $classes[] = 'masthead-fixed'; + } + + if ( is_archive() || is_search() || is_home() ) { + $classes[] = 'list-view'; + } + + if ( in_array(fw_ext_sidebars_get_current_position(), array('full', 'left')) + || is_page_template( 'page-templates/full-width.php' ) + || is_page_template( 'page-templates/contributors.php' ) + || is_attachment() ) { + $classes[] = 'full-width'; + } + + if ( is_active_sidebar( 'sidebar-1' ) ) { + $classes[] = 'footer-widgets'; + } + + if ( is_singular() && ! is_front_page() ) { + $classes[] = 'singular'; + } + + if ( is_front_page() && 'slider' == get_theme_mod( 'featured_content_layout' ) ) { + $classes[] = 'slider'; + } elseif ( is_front_page() ) { + $classes[] = 'grid'; + } + + return $classes; +} +add_filter( 'body_class', '_filter_theme_body_classes' ); + +/** + * Extend the default WordPress post classes. + * + * Adds a post class to denote: + * Non-password protected page with a post thumbnail. + * + * @param array $classes A list of existing post class values. + * @return array The filtered post class list. + * @internal + */ +function _filter_theme_post_classes( $classes ) { + if ( ! post_password_required() && ! is_attachment() && has_post_thumbnail() ) { + $classes[] = 'has-post-thumbnail'; + } + + return $classes; +} +add_filter( 'post_class', '_filter_theme_post_classes' ); + +/** + * Create a nicely formatted and more specific title element text for output + * in head of document, based on current view. + * + * @param string $title Default title text for current view. + * @param string $sep Optional separator. + * @return string The filtered title. + * @internal + */ +function _filter_theme_wp_title( $title, $sep ) { + global $paged, $page; + + if ( is_feed() ) { + return $title; + } + + // Add the site name. + $title .= get_bloginfo( 'name', 'display' ); + + // Add the site description for the home/front page. + $site_description = get_bloginfo( 'description', 'display' ); + if ( $site_description && ( is_home() || is_front_page() ) ) { + $title = "$title $sep $site_description"; + } + + // Add a page number if necessary. + if ( $paged >= 2 || $page >= 2 ) { + $title = "$title $sep " . sprintf( __( 'Page %s', 'unyson' ), max( $paged, $page ) ); + } + + return $title; +} +add_filter( 'wp_title', '_filter_theme_wp_title', 10, 2 ); + + +/** + * Flush out the transients used in fw_theme_categorized_blog. + * @internal + */ +function _action_theme_category_transient_flusher() { + // Like, beat it. Dig? + delete_transient( 'fw_theme_category_count' ); +} +add_action( 'edit_category', '_action_theme_category_transient_flusher' ); +add_action( 'save_post', '_action_theme_category_transient_flusher' ); + +/** + * Theme Customizer support + */ +{ + /** + * Implement Theme Customizer additions and adjustments. + * + * @param WP_Customize_Manager $wp_customize Theme Customizer object. + * @internal + */ + function _action_theme_customize_register( $wp_customize ) { + // Add custom description to Colors and Background sections. + $wp_customize->get_section( 'colors' )->description = __( 'Background may only be visible on wide screens.', 'unyson' ); + $wp_customize->get_section( 'background_image' )->description = __( 'Background may only be visible on wide screens.', 'unyson' ); + + // Add postMessage support for site title and description. + $wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; + $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; + $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage'; + + // Rename the label to "Site Title Color" because this only affects the site title in this theme. + $wp_customize->get_control( 'header_textcolor' )->label = __( 'Site Title Color', 'unyson' ); + + // Rename the label to "Display Site Title & Tagline" in order to make this option extra clear. + $wp_customize->get_control( 'display_header_text' )->label = __( 'Display Site Title & Tagline', 'unyson' ); + + // Add the featured content section in case it's not already there. + $wp_customize->add_section( 'featured_content', array( + 'title' => __( 'Featured Content', 'unyson' ), + 'description' => sprintf( __( 'Use a tag to feature your posts. If no posts match the tag, sticky posts will be displayed instead.', 'unyson' ), + esc_url( add_query_arg( 'tag', _x( 'featured', 'featured content default tag slug', 'unyson' ), admin_url( 'edit.php' ) ) ), + admin_url( 'edit.php?show_sticky=1' ) + ), + 'priority' => 130, + ) ); + + // Add the featured content layout setting and control. + $wp_customize->add_setting( 'featured_content_layout', array( + 'default' => 'grid', + 'sanitize_callback' => '_fw_theme_sanitize_layout', + ) ); + + $wp_customize->add_control( 'featured_content_layout', array( + 'label' => __( 'Layout', 'unyson' ), + 'section' => 'featured_content', + 'type' => 'select', + 'choices' => array( + 'grid' => __( 'Grid', 'unyson' ), + 'slider' => __( 'Slider', 'unyson' ), + ), + ) ); + } + add_action( 'customize_register', '_action_theme_customize_register' ); + + /** + * Sanitize the Featured Content layout value. + * + * @param string $layout Layout type. + * @return string Filtered layout type (grid|slider). + * @internal + */ + function _fw_theme_sanitize_layout( $layout ) { + if ( ! in_array( $layout, array( 'grid', 'slider' ) ) ) { + $layout = 'grid'; + } + + return $layout; + } + + /** + * Bind JS handlers to make Theme Customizer preview reload changes asynchronously. + * @internal + */ + function _action_theme_customize_preview_js() { + wp_enqueue_script( + 'fw-theme-customizer', + get_template_directory_uri() . '/js/customizer.js', + array( 'customize-preview' ), + fw()->theme->manifest->get_version(), + true + ); + } + add_action( 'customize_preview_init', '_action_theme_customize_preview_js' ); +} + +/** + * Register widget areas. + * @internal + */ +function _action_theme_widgets_init() { + register_sidebar( array( + 'name' => __( 'Footer Widget Area', 'unyson' ), + 'id' => 'sidebar-1', + 'description' => __( 'Appears in the footer section of the site.', 'unyson' ), + 'before_widget' => '', + 'before_title' => '

    ', + 'after_title' => '

    ', + ) ); +} +add_action( 'widgets_init', '_action_theme_widgets_init' ); + +/** + * Display current submitted FW_Form errors + * @return array + */ +if (!function_exists('_action_theme_display_form_errors')): + function _action_theme_display_form_errors() { + $form = FW_Form::get_submitted(); + + if (!$form || $form->is_valid()) { + return; + } + + wp_enqueue_script( + '', + get_template_directory_uri() . '/js/form-errors.js', + array('jquery'), + fw()->theme->manifest->get_version(), + true + ); + + wp_localize_script('fw-theme-show-form-errors', '_localized_form_errors', array( + 'errors' => $form->get_errors(), + 'form_attr' => $form->attr() + )); + } +endif; +add_action('wp_enqueue_scripts', '_action_theme_display_form_errors'); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/includes/content-width.php b/scratch-parent/framework-customizations/theme/includes/content-width.php new file mode 100644 index 00000000..bfaac4b0 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/includes/content-width.php @@ -0,0 +1,10 @@ + $post_ids, + 'posts_per_page' => count( $post_ids ), + ) ); + + return $featured_posts; + } + + /** + * Get featured post IDs + * + * This function will return the an array containing the + * post IDs of all featured posts. + * + * Sets the "featured_content_ids" transient. + * + * @static + * @access public + * + * @return array Array of post IDs. + */ + public static function get_featured_post_ids() { + // Return array of cached results if they exist. + $featured_ids = get_transient( 'featured_content_ids' ); + if ( ! empty( $featured_ids ) ) { + return array_map( 'absint', (array) $featured_ids ); + } + + $settings = self::get_setting(); + + // Return sticky post ids if no tag name is set. + $term = get_term_by( 'name', $settings['tag-name'], 'post_tag' ); + if ( $term ) { + $tag = $term->term_id; + } else { + return self::get_sticky_posts(); + } + + // Query for featured posts. + $featured = get_posts( array( + 'numberposts' => self::$max_posts, + 'tax_query' => array( + array( + 'field' => 'term_id', + 'taxonomy' => 'post_tag', + 'terms' => $tag, + ), + ), + ) ); + + // Return array with sticky posts if no Featured Content exists. + if ( ! $featured ) { + return self::get_sticky_posts(); + } + + // Ensure correct format before save/return. + $featured_ids = wp_list_pluck( (array) $featured, 'ID' ); + $featured_ids = array_map( 'absint', $featured_ids ); + + set_transient( 'featured_content_ids', $featured_ids ); + + return $featured_ids; + } + + /** + * Return an array with IDs of posts maked as sticky. + * + * @static + * @access public + * + * @return array Array of sticky posts. + */ + public static function get_sticky_posts() { + $settings = self::get_setting(); + return array_slice( get_option( 'sticky_posts', array() ), 0, self::$max_posts ); + } + + /** + * Delete featured content ids transient. + * + * Hooks in the "save_post" action. + * + * @see FW_Theme_Featured_Content::validate_settings(). + * + * @static + * @access public + */ + public static function delete_transient() { + delete_transient( 'featured_content_ids' ); + } + + /** + * Exclude featured posts from the home page blog query. + * + * Filter the home page posts, and remove any featured post ID's from it. + * Hooked onto the 'pre_get_posts' action, this changes the parameters of + * the query before it gets any posts. + * + * @static + * @access public + * + * @param WP_Query $query WP_Query object. + * @return WP_Query Possibly-modified WP_Query. + */ + public static function pre_get_posts( $query ) { + + // Bail if not home or not main query. + if ( ! $query->is_home() || ! $query->is_main_query() ) { + return; + } + + $page_on_front = get_option( 'page_on_front' ); + + // Bail if the blog page is not the front page. + if ( ! empty( $page_on_front ) ) { + return; + } + + $featured = self::get_featured_post_ids(); + + // Bail if no featured posts. + if ( ! $featured ) { + return; + } + + // We need to respect post ids already in the blacklist. + $post_not_in = $query->get( 'post_not_in' ); + + if ( ! empty( $post_not_in ) ) { + $featured = array_merge( (array) $post_not_in, $featured ); + $featured = array_unique( $featured ); + } + + $query->set( 'post_not_in', $featured ); + } + + /** + * Reset tag option when the saved tag is deleted. + * + * It's important to mention that the transient needs to be deleted, + * too. While it may not be obvious by looking at the function alone, + * the transient is deleted by FW_Theme_Featured_Content::validate_settings(). + * + * Hooks in the "delete_post_tag" action. + * + * @see FW_Theme_Featured_Content::validate_settings(). + * + * @static + * @access public + * + * @param int $tag_id The term_id of the tag that has been deleted. + */ + public static function delete_post_tag( $tag_id ) { + $settings = self::get_setting(); + + if ( empty( $settings['tag-id'] ) || $tag_id != $settings['tag-id'] ) { + return; + } + + $settings['tag-id'] = 0; + $settings = self::validate_settings( $settings ); + update_option( 'featured-content', $settings ); + } + + /** + * Hide featured tag from displaying when global terms are queried from the front-end. + * + * Hooks into the "get_terms" filter. + * + * @static + * @access public + * + * @param array $terms List of term objects. This is the return value of get_terms(). + * @param array $taxonomies An array of taxonomy slugs. + * @return array A filtered array of terms. + * + * @uses FW_Theme_Featured_Content::get_setting() + */ + public static function hide_featured_term( $terms, $taxonomies ) { + + // This filter is only appropriate on the front-end. + if ( is_admin() ) { + return $terms; + } + + // We only want to hide the featured tag. + if ( ! in_array( 'post_tag', $taxonomies ) ) { + return $terms; + } + + // Bail if no terms were returned. + if ( empty( $terms ) ) { + return $terms; + } + + $settings = self::get_setting(); + foreach( $terms as $order => $term ) { + if ( ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) && 'post_tag' === $term->taxonomy ) { + unset( $terms[ $order ] ); + } + } + + return $terms; + } + + /** + * Hide featured tag from display when terms associated with a post object + * are queried from the front-end. + * + * Hooks into the "get_the_terms" filter. + * + * @static + * @access public + * + * @param array $terms A list of term objects. This is the return value of get_the_terms(). + * @param int $id The ID field for the post object that terms are associated with. + * @param array $taxonomy An array of taxonomy slugs. + * @return array Filtered array of terms. + * + * @uses FW_Theme_Featured_Content::get_setting() + */ + public static function hide_the_featured_term( $terms, $id, $taxonomy ) { + + // This filter is only appropriate on the front-end. + if ( is_admin() ) { + return $terms; + } + + // Make sure we are in the correct taxonomy. + if ( 'post_tag' != $taxonomy ) { + return $terms; + } + + // No terms? Return early! + if ( empty( $terms ) ) { + return $terms; + } + + $settings = self::get_setting(); + foreach( $terms as $order => $term ) { + if ( ( $settings['tag-id'] === $term->term_id || $settings['tag-name'] === $term->name ) && 'post_tag' === $term->taxonomy ) { + unset( $terms[ $term->term_id ] ); + } + } + + return $terms; + } + + /** + * Register custom setting on the Settings -> Reading screen. + * + * @static + * @access public + */ + public static function register_setting() { + register_setting( 'featured-content', 'featured-content', array( __CLASS__, 'validate_settings' ) ); + } + + /** + * Add settings to the Customizer. + * + * @static + * @access public + * + * @param WP_Customize_Manager $wp_customize Theme Customizer object. + */ + public static function customize_register( $wp_customize ) { + $wp_customize->add_section( 'featured_content', array( + 'title' => __( 'Featured Content', 'unyson' ), + 'description' => sprintf( __( 'Use a tag to feature your posts. If no posts match the tag, sticky posts will be displayed instead.', 'unyson' ), + esc_url( add_query_arg( 'tag', _x( 'featured', 'featured content default tag slug', 'unyson' ), admin_url( 'edit.php' ) ) ), + admin_url( 'edit.php?show_sticky=1' ) + ), + 'priority' => 130, + 'theme_supports' => 'featured-content', + ) ); + + // Add Featured Content settings. + $wp_customize->add_setting( 'featured-content[tag-name]', array( + 'default' => _x( 'featured', 'featured content default tag slug', 'unyson' ), + 'type' => 'option', + 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ), + ) ); + $wp_customize->add_setting( 'featured-content[hide-tag]', array( + 'default' => true, + 'type' => 'option', + 'sanitize_js_callback' => array( __CLASS__, 'delete_transient' ), + ) ); + + // Add Featured Content controls. + $wp_customize->add_control( 'featured-content[tag-name]', array( + 'label' => __( 'Tag Name', 'unyson' ), + 'section' => 'featured_content', + 'priority' => 20, + ) ); + $wp_customize->add_control( 'featured-content[hide-tag]', array( + 'label' => __( 'Don’t display tag on front end.', 'unyson' ), + 'section' => 'featured_content', + 'type' => 'checkbox', + 'priority' => 30, + ) ); + } + + /** + * Enqueue the tag suggestion script. + * + * @static + * @access public + */ + public static function enqueue_scripts() { + wp_enqueue_script( + 'fw-theme-featured-content-suggest', + get_template_directory_uri() . '/js/featured-content-admin.js', + array( 'jquery', 'suggest' ), + fw()->theme->manifest->get_version(), + true + ); + } + + /** + * Get featured content settings. + * + * Get all settings recognized by this module. This function + * will return all settings whether or not they have been stored + * in the database yet. This ensures that all keys are available + * at all times. + * + * In the event that you only require one setting, you may pass + * its name as the first parameter to the function and only that + * value will be returned. + * + * @static + * @access public + * + * @param string $key The key of a recognized setting. + * @return mixed Array of all settings by default. A single value if passed as first parameter. + */ + public static function get_setting( $key = 'all' ) { + $saved = (array) get_option( 'featured-content' ); + + $defaults = array( + 'hide-tag' => 1, + 'tag-id' => 0, + 'tag-name' => _x( 'featured', 'featured content default tag slug', 'unyson' ), + ); + + $options = wp_parse_args( $saved, $defaults ); + $options = array_intersect_key( $options, $defaults ); + + if ( 'all' != $key ) { + return isset( $options[ $key ] ) ? $options[ $key ] : false; + } + + return $options; + } + + /** + * Validate featured content settings. + * + * Make sure that all user supplied content is in an expected + * format before saving to the database. This function will also + * delete the transient set in FW_Theme_Featured_Content::get_featured_content(). + * + * @static + * @access public + * + * @param array $input Array of settings input. + * @return array Validated settings output. + */ + public static function validate_settings( $input ) { + $output = array(); + + if ( empty( $input['tag-name'] ) ) { + $output['tag-id'] = 0; + } else { + $term = get_term_by( 'name', $input['tag-name'], 'post_tag' ); + + if ( $term ) { + $output['tag-id'] = $term->term_id; + } else { + $new_tag = wp_create_tag( $input['tag-name'] ); + + if ( ! is_wp_error( $new_tag ) && isset( $new_tag['term_id'] ) ) { + $output['tag-id'] = $new_tag['term_id']; + } + } + + $output['tag-name'] = $input['tag-name']; + } + + $output['hide-tag'] = isset( $input['hide-tag'] ) && $input['hide-tag'] ? 1 : 0; + + // Delete the featured post ids transient. + self::delete_transient(); + + return $output; + } +} // FW_Theme_Featured_Content + +FW_Theme_Featured_Content::setup(); diff --git a/scratch-parent/framework-customizations/theme/index.html b/scratch-parent/framework-customizations/theme/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/theme/manifest.php b/scratch-parent/framework-customizations/theme/manifest.php new file mode 100644 index 00000000..23696c9d --- /dev/null +++ b/scratch-parent/framework-customizations/theme/manifest.php @@ -0,0 +1,5 @@ + __( 'Top primary menu', 'unyson' ), + 'secondary' => __( 'Secondary menu in left sidebar', 'unyson' ), +) ); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/options/breadcrumbs.php b/scratch-parent/framework-customizations/theme/options/breadcrumbs.php new file mode 100644 index 00000000..8936b60d --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/breadcrumbs.php @@ -0,0 +1,27 @@ + array( + 'title' => __( 'Breadcrumbs', 'fw' ), + 'type' => 'tab', + 'options' => array( + 'breadcrumbs-box' => array( + 'title' => __( 'Breadcrumbs', 'fw' ), + 'type' => 'box', + 'options' => array( + 'breadcrumbs-option' => array( + 'label' => false, + 'desc' => false, + 'type' => 'breadcrumbs' + ) + ) + ), + ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/options/demo-2.php b/scratch-parent/framework-customizations/theme/options/demo-2.php new file mode 100644 index 00000000..02dfafb4 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/demo-2.php @@ -0,0 +1,793 @@ + array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_password_2' => array( + 'label' => __('Password', 'fw'), + 'type' => 'password', + 'value' => 'Dotted text', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_hidden_2' => array( + 'label' => false, + 'type' => 'hidden', + 'value' => '{some: "json"}', + 'desc' => false, + ), + 'demo_textarea_2' => array( + 'label' => __('Textarea', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => array( + 'icon' => 'video', + 'html' => '' + ), + ), + 'demo_wp_editor_2' => array( + 'label' => __('Rich Text Editor'), + 'type' => 'wp-editor', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_html_2' => array( + 'label' => __('HTML', 'fw'), + 'type' => 'html', + 'value' => '{some: "json"}', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'html' => 'Lorem ipsum ', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_checkbox_2' => array( + 'label' => __('Checkbox', 'fw'), + 'type' => 'checkbox', + 'value' => true, + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'text' => __('Custom text', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_checkboxes_2' => array( + 'label' => __('Checkboxes', 'fw'), + 'type' => 'checkboxes', + 'value' => array( + 'c1' => false, + 'c2' => true, + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'c1' => __('Checkbox 1 Custom Text', 'fw'), + 'c2' => __('Checkbox 2 Custom Text', 'fw'), + 'c3' => __('Checkbox 3 Custom Text', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_switch_2' => array( + 'label' => __('Switch', 'fw'), + 'type' => 'switch', + 'right-choice' => array( + 'value' => 'yes', + 'label' => __('Yes', 'fw') + ), + 'left-choice' => array( + 'value' => 'no', + 'label' => __('No', 'fw') + ), + 'value' => 'yes', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_select_2' => array( + 'label' => __('Select', 'fw'), + 'type' => 'select', + 'value' => 'c', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + '' => '---', + 'a' => __('Lorem ipsum', 'fw'), + 'b' => array( + 'text' => __('Consectetur', 'fw'), + 'attr' => array( + 'label' => 'Label overrides text', + 'data-whatever' => 'some data', + ), + ), + array( + 'attr' => array( + 'label' => __('Optgroup Label', 'fw'), + 'data-whatever' => 'some data', + ), + 'choices' => array( + 'c' => __('Sed ut perspiciatis', 'fw'), + 'd' => __('Excepteur sint occaecat', 'fw'), + ), + ), + 1 => __('One', 'fw'), + 2 => __('Two', 'fw'), + 3 => __('Three', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_select_multiple_2' => array( + 'label' => __('Select Multiple', 'fw'), + 'type' => 'select-multiple', + 'value' => array('c', '2'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + '' => '---', + 'a' => __('Lorem ipsum', 'fw'), + 'b' => array( + 'text' => __('Consectetur', 'fw'), + 'attr' => array( + 'label' => 'Label overrides text', + 'data-whatever' => 'some data', + ), + ), + array( + 'attr' => array( + 'label' => __('Optgroup Label', 'fw'), + 'data-whatever' => 'some data', + ), + 'choices' => array( + 'c' => __('Sed ut perspiciatis', 'fw'), + 'd' => __('Excepteur sint occaecat', 'fw'), + ), + ), + 1 => __('One', 'fw'), + 2 => __('Two', 'fw'), + 3 => __('Three', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_radio_2' => array( + 'label' => __('Radio', 'fw'), + 'type' => 'radio', + 'value' => 'c2', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'c1' => __('Radio 1 Custom Text', 'fw'), + 'c2' => __('Radio 2 Custom Text', 'fw'), + 'c3' => __('Radio 3 Custom Text', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_image_picker_2' => array( + 'label' => __('Image Picker', 'fw'), + 'type' => 'image-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'choice-1' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'choice-2' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_icon_2' => array( + 'label' => __('Icon', 'fw'), + 'type' => 'icon', + 'value' => 'fa-linux', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload_2' => array( + 'label' => __('Single Upload', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'images_only' => false, + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload_images_2' => array( + 'label' => __('Single Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_multi_upload_2' => array( + 'label' => __('Multi Upload', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'images_only' => false, + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_multi_upload_images_2' => array( + 'label' => __('Multi Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_color_picker_2' => array( + 'label' => __('Color Picker', 'fw'), + 'type' => 'color-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_gradient_2' => array( + 'label' => __('Gradient', 'fw'), + 'type' => 'gradient', + 'value' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff' + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_background_image_2' => array( + 'label' => __('Background Image', 'fw'), + 'type' => 'background-image', + 'value' => 'none', + 'choices' => array( + 'none' => array( + 'icon' => FW_PT_URI . '/images/patterns/no_pattern.jpg', + 'css' => array( + 'background-image' => 'none' + ) + ), + 'bg-1' => array( + 'icon' => FW_PT_URI . '/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/diagonal_bottom_to_top_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-2' => array( + 'icon' => FW_PT_URI . '/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/diagonal_top_to_bottom_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-3' => array( + 'icon' => FW_PT_URI . '/images/patterns/dots_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/dots_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-4' => array( + 'icon' => FW_PT_URI . '/images/patterns/romb_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/romb_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-5' => array( + 'icon' => FW_PT_URI . '/images/patterns/square_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/square_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-6' => array( + 'icon' => FW_PT_URI . '/images/patterns/noise_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/noise_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-7' => array( + 'icon' => FW_PT_URI . '/images/patterns/vertical_lines_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/vertical_lines_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-8' => array( + 'icon' => FW_PT_URI . '/images/patterns/waves_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/waves_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_typography_2' => array( + 'label' => __('Typography', 'fw'), + 'type' => 'typography', + 'value' => array( + 'size' => 17, + 'family' => 'Verdana', + 'style' => '300italic', + 'color' => '#0000ff' + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_addable_popup_2' => array( + 'label' => __('Addable Popup', 'fw'), + 'type' => 'addable-popup', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'template' => '{{=demo_text}}', + 'popup-options' => array( + 'demo_text' => array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_image_picker' => array( + 'label' => __('Image Picker', 'fw'), + 'type' => 'image-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'attr' => array( + 'data-height' => 70 + ), + 'choices' => array( + 'choice-1' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'choice-2' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload_images' => array( + 'label' => __('Single Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_addable_popup_inner' => array( + 'label' => __('Addable Popup', 'fw'), + 'type' => 'addable-popup', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'template' => 'Title color-picker value : {{=demo_color_picker}}', + 'popup-options' => array( + 'demo_multi_upload_images' => array( + 'label' => __('Multi Upload (images only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_color_picker' => array( + 'label' => __('Color Picker', 'fw'), + 'type' => 'color-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ) + ) + ), + ), + ), + 'demo_addable_option_2' => array( + 'label' => __('Addable Option', 'fw'), + 'type' => 'addable-option', + 'option' => array( + 'type' => 'text', + ), + 'value' => array('Option 1', 'Option 2', 'Option 3'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ), + 'demo_addable_box_2' => array( + 'label' => __('Addable Box', 'fw'), + 'type' => 'addable-box', + 'value' => array(), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + 'box-controls' => array( + //'custom' => '', + ), + 'box-options' => array( + 'demo_text' => array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_textarea' => array( + 'label' => __('Textarea', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => array( + 'icon' => 'video', + 'html' => '' + ), + ), + ), + ), + 'demo_group_2' => array( + 'type' => 'group', + 'options' => array( + 'demo_text_in_group_2' => array( + 'label' => __('Text in Group', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_password_in_group_2' => array( + 'label' => __('Password in Group', 'fw'), + 'type' => 'password', + 'value' => 'Dotted text', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + ), + ), + 'demo_multi_2' => array( + 'label' => false, + 'type' => 'multi', + 'value' => array(), + 'desc' => false, + 'inner-options' => array( + 'demo_text' => array( + 'label' => __('Text in Multi', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_textarea' => array( + 'label' => __('Textarea in Multi', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + ), + ), + 'demo_multi_picker_select_2' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'gadget' => array( + 'label' => __('Multi Picker: Select', 'fw'), + 'type' => 'select', + 'choices' => array( + 'phone' => __('Phone', 'fw'), + 'laptop' => __('Laptop', 'fw') + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), + 'demo_multi_picker_radio_2' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'value' => array( + 'gadget' => 'laptop', + ), + 'picker' => array( + 'gadget' => array( + 'label' => __('Multi Picker: Radio', 'fw'), + 'type' => 'radio', + 'choices' => array( + 'phone' => __('Phone', 'fw'), + 'laptop' => __('Laptop', 'fw') + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), + 'demo_multi_picker_image_picker_2' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'gadget' => array( + 'label' => __('Multi Picker: Image Picker', 'fw'), + 'type' => 'image-picker', + 'choices' => array( + 'phone' => array( + 'label' => __('Phone', 'fw'), + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'laptop' => array( + 'label' => __('Laptop', 'fw'), + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ) + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), + 'demo_multi_picker_switch_2' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'gadget' => array( + 'label' => __('Switch', 'fw'), + 'type' => 'switch', + 'right-choice' => array( + 'value' => 'laptop', + 'label' => __('Laptop', 'fw') + ), + 'left-choice' => array( + 'value' => 'phone', + 'label' => __('Phone', 'fw') + ), + 'value' => 'yes', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), +); diff --git a/scratch-parent/framework-customizations/theme/options/demo-box.php b/scratch-parent/framework-customizations/theme/options/demo-box.php new file mode 100644 index 00000000..2b0d124d --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/demo-box.php @@ -0,0 +1,30 @@ + array( + 'title' => __('Demo Options', 'fw'), + 'type' => 'tab', + 'options' => array( + 'sub_tab_1' => array( + 'title' => __('Without Box', 'fw'), + 'type' => 'tab', + 'options' => array( + fw()->theme->get_options('demo-2'), + ), + ), + 'sub_tab_2' => array( + 'title' => __('With Box', 'fw'), + 'type' => 'tab', + 'options' => array( + 'demo_box' => array( + 'title' => __('Box', 'fw'), + 'type' => 'box', + 'options' => array( + fw()->theme->get_options('demo'), + ), + ), + ), + ), + ), + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/options/demo.php b/scratch-parent/framework-customizations/theme/options/demo.php new file mode 100644 index 00000000..2ff025a0 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/demo.php @@ -0,0 +1,792 @@ + array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_password' => array( + 'label' => __('Password', 'fw'), + 'type' => 'password', + 'value' => 'Dotted text', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_hidden' => array( + 'label' => false, + 'type' => 'hidden', + 'value' => '{some: "json"}', + 'desc' => false, + ), + 'demo_textarea' => array( + 'label' => __('Textarea', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => array( + 'icon' => 'video', + 'html' => '' + ), + ), + 'demo_wp_editor' => array( + 'label' => __('Rich Text Editor'), + 'type' => 'wp-editor', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_html' => array( + 'label' => __('HTML', 'fw'), + 'type' => 'html', + 'value' => '{some: "json"}', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'html' => 'Lorem ipsum ', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_checkbox' => array( + 'label' => __('Checkbox', 'fw'), + 'type' => 'checkbox', + 'value' => true, + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'text' => __('Custom text', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_checkboxes' => array( + 'label' => __('Checkboxes', 'fw'), + 'type' => 'checkboxes', + 'value' => array( + 'c1' => false, + 'c2' => true, + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'c1' => __('Checkbox 1 Custom Text', 'fw'), + 'c2' => __('Checkbox 2 Custom Text', 'fw'), + 'c3' => __('Checkbox 3 Custom Text', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_switch' => array( + 'label' => __('Switch', 'fw'), + 'type' => 'switch', + 'right-choice' => array( + 'value' => 'yes', + 'label' => __('Yes', 'fw') + ), + 'left-choice' => array( + 'value' => 'no', + 'label' => __('No', 'fw') + ), + 'value' => 'yes', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_select' => array( + 'label' => __('Select', 'fw'), + 'type' => 'select', + 'value' => 'c', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + '' => '---', + 'a' => __('Lorem ipsum', 'fw'), + 'b' => array( + 'text' => __('Consectetur', 'fw'), + 'attr' => array( + 'label' => 'Label overrides text', + 'data-whatever' => 'some data', + ), + ), + array( + 'attr' => array( + 'label' => __('Optgroup Label', 'fw'), + 'data-whatever' => 'some data', + ), + 'choices' => array( + 'c' => __('Sed ut perspiciatis', 'fw'), + 'd' => __('Excepteur sint occaecat', 'fw'), + ), + ), + 1 => __('One', 'fw'), + 2 => __('Two', 'fw'), + 3 => __('Three', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_select_multiple' => array( + 'label' => __('Select Multiple', 'fw'), + 'type' => 'select-multiple', + 'value' => array('c', '2'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + '' => '---', + 'a' => __('Lorem ipsum', 'fw'), + 'b' => array( + 'text' => __('Consectetur', 'fw'), + 'attr' => array( + 'label' => 'Label overrides text', + 'data-whatever' => 'some data', + ), + ), + array( + 'attr' => array( + 'label' => __('Optgroup Label', 'fw'), + 'data-whatever' => 'some data', + ), + 'choices' => array( + 'c' => __('Sed ut perspiciatis', 'fw'), + 'd' => __('Excepteur sint occaecat', 'fw'), + ), + ), + 1 => __('One', 'fw'), + 2 => __('Two', 'fw'), + 3 => __('Three', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_radio' => array( + 'label' => __('Radio', 'fw'), + 'type' => 'radio', + 'value' => 'c2', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'c1' => __('Radio 1 Custom Text', 'fw'), + 'c2' => __('Radio 2 Custom Text', 'fw'), + 'c3' => __('Radio 3 Custom Text', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_image_picker' => array( + 'label' => __('Image Picker', 'fw'), + 'type' => 'image-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'choice-1' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'choice-2' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_icon' => array( + 'label' => __('Icon', 'fw'), + 'type' => 'icon', + 'value' => 'fa-linux', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload' => array( + 'label' => __('Single Upload', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'images_only' => false, + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload_images' => array( + 'label' => __('Single Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_multi_upload' => array( + 'label' => __('Multi Upload', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'images_only' => false, + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_multi_upload_images' => array( + 'label' => __('Multi Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_color_picker' => array( + 'label' => __('Color Picker', 'fw'), + 'type' => 'color-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_gradient' => array( + 'label' => __('Gradient', 'fw'), + 'type' => 'gradient', + 'value' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff' + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_background_image' => array( + 'label' => __('Background Image', 'fw'), + 'type' => 'background-image', + 'value' => 'none', + 'choices' => array( + 'none' => array( + 'icon' => FW_PT_URI . '/images/patterns/no_pattern.jpg', + 'css' => array( + 'background-image' => 'none' + ) + ), + 'bg-1' => array( + 'icon' => FW_PT_URI . '/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/diagonal_bottom_to_top_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-2' => array( + 'icon' => FW_PT_URI . '/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/diagonal_top_to_bottom_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-3' => array( + 'icon' => FW_PT_URI . '/images/patterns/dots_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/dots_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-4' => array( + 'icon' => FW_PT_URI . '/images/patterns/romb_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/romb_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-5' => array( + 'icon' => FW_PT_URI . '/images/patterns/square_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/square_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-6' => array( + 'icon' => FW_PT_URI . '/images/patterns/noise_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/noise_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-7' => array( + 'icon' => FW_PT_URI . '/images/patterns/vertical_lines_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/vertical_lines_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-8' => array( + 'icon' => FW_PT_URI . '/images/patterns/waves_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/waves_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_typography' => array( + 'label' => __('Typography', 'fw'), + 'type' => 'typography', + 'value' => array( + 'size' => 17, + 'family' => 'Verdana', + 'style' => '300italic', + 'color' => '#0000ff' + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_addable_popup' => array( + 'label' => __('Addable Popup', 'fw'), + 'type' => 'addable-popup', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'template' => '{{=demo_text}}', + 'popup-options' => array( + 'demo_text' => array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_image_picker' => array( + 'label' => __('Image Picker', 'fw'), + 'type' => 'image-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'choice-1' => array( + 'label' => __('First Image', 'fw'), + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'choice-2' => array( + 'label' => __('Second Image', 'fw'), + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload_images' => array( + 'label' => __('Single Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_addable_popup_inner' => array( + 'label' => __('Addable Popup', 'fw'), + 'type' => 'addable-popup', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'template' => 'Title color-picker value : {{=demo_color_picker}}', + 'popup-options' => array( + 'demo_multi_upload_images' => array( + 'label' => __('Multi Upload (images only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_color_picker' => array( + 'label' => __('Color Picker', 'fw'), + 'type' => 'color-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ) + ) + ), + ), + ), + 'demo_addable_option' => array( + 'label' => __('Addable Option', 'fw'), + 'type' => 'addable-option', + 'option' => array( + 'type' => 'text', + ), + 'value' => array('Option 1', 'Option 2', 'Option 3'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ), + 'demo_addable_box' => array( + 'label' => __('Addable Box', 'fw'), + 'type' => 'addable-box', + 'value' => array(), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + 'box-controls' => array( + //'custom' => '', + ), + 'box-options' => array( + 'demo_text' => array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_textarea' => array( + 'label' => __('Textarea', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => array( + 'icon' => 'video', + 'html' => '' + ), + ), + ), + ), + 'demo_group' => array( + 'type' => 'group', + 'options' => array( + 'demo_text_in_group' => array( + 'label' => __('Text in Group', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_password_in_group' => array( + 'label' => __('Password in Group', 'fw'), + 'type' => 'password', + 'value' => 'Dotted text', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + ), + ), + 'demo_multi' => array( + 'label' => false, + 'type' => 'multi', + 'value' => array(), + 'desc' => false, + 'inner-options' => array( + 'demo_text' => array( + 'label' => __('Text in Multi', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_textarea' => array( + 'label' => __('Textarea in Multi', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + ), + ), + 'demo_multi_picker_select' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'gadget' => array( + 'label' => __('Multi Picker: Select', 'fw'), + 'type' => 'select', + 'choices' => array( + 'phone' => __('Phone', 'fw'), + 'laptop' => __('Laptop', 'fw') + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), + 'demo_multi_picker_radio' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'value' => array( + 'gadget' => 'laptop', + ), + 'picker' => array( + 'gadget' => array( + 'label' => __('Multi Picker: Radio', 'fw'), + 'type' => 'radio', + 'choices' => array( + 'phone' => __('Phone', 'fw'), + 'laptop' => __('Laptop', 'fw') + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), + 'demo_multi_picker_image_picker' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'gadget' => array( + 'label' => __('Multi Picker: Image Picker', 'fw'), + 'type' => 'image-picker', + 'choices' => array( + 'phone' => array( + 'label' => __('Phone', 'fw'), + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'laptop' => array( + 'label' => __('Laptop', 'fw'), + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ) + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), + 'demo_multi_picker_switch' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'gadget' => array( + 'label' => __('Switch', 'fw'), + 'type' => 'switch', + 'right-choice' => array( + 'value' => 'laptop', + 'label' => __('Laptop', 'fw') + ), + 'left-choice' => array( + 'value' => 'phone', + 'label' => __('Phone', 'fw') + ), + 'value' => 'yes', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ) + ), + 'choices' => array( + 'phone' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'memory' => array( + 'type' => 'select', + 'label' => __('Memory', 'fw'), + 'choices' => array( + '16' => __('16Gb', 'fw'), + '32' => __('32Gb', 'fw'), + '64' => __('64Gb', 'fw'), + ) + ) + ), + 'laptop' => array( + 'price' => array( + 'type' => 'text', + 'label' => __('Price', 'fw'), + ), + 'webcam' => array( + 'type' => 'switch', + 'label' => __('Webcam', 'fw'), + ) + ), + ), + 'show_borders' => false, + ), +); diff --git a/scratch-parent/framework-customizations/theme/options/general-settings.php b/scratch-parent/framework-customizations/theme/options/general-settings.php new file mode 100644 index 00000000..03e83bad --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/general-settings.php @@ -0,0 +1,36 @@ + array( + 'title' => __( 'General', 'fw' ), + 'type' => 'tab', + 'options' => array( + 'general-settings' => array( + 'title' => __( 'General Settings', 'fw' ), + 'type' => 'tab', + 'options' => array( + 'general-box' => array( + 'title' => __( 'General Settings', 'fw' ), + 'type' => 'box', + 'options' => array( + 'logo' => array( + 'label' => __( 'Logo', 'fw' ), + 'desc' => __( 'Write your website logo name', 'fw' ), + 'type' => 'text', + 'value' => get_bloginfo( 'name' ) + ), + 'favicon' => array( + 'label' => __( 'Favicon', 'fw' ), + 'desc' => __( 'Upload favicon image', 'fw' ), + 'type' => 'upload' + ) + ) + ), + ) + ), + fw()->theme->get_options( 'breadcrumbs' ), + ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/options/index.html b/scratch-parent/framework-customizations/theme/options/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/theme/options/posts/index.html b/scratch-parent/framework-customizations/theme/options/posts/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/theme/options/posts/post.php b/scratch-parent/framework-customizations/theme/options/posts/post.php new file mode 100644 index 00000000..8e467d36 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/posts/post.php @@ -0,0 +1,11 @@ + array( + 'title' => false, + 'type' => 'box', + 'options' => array( + fw()->theme->get_options('demo-box'), + ), + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/options/settings.php b/scratch-parent/framework-customizations/theme/options/settings.php new file mode 100644 index 00000000..8a0f8d33 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/settings.php @@ -0,0 +1,11 @@ +theme->get_options('general-settings'), + fw()->theme->get_options('demo-box'), +); diff --git a/scratch-parent/framework-customizations/theme/options/taxonomies/category.php b/scratch-parent/framework-customizations/theme/options/taxonomies/category.php new file mode 100644 index 00000000..2c8848f4 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/options/taxonomies/category.php @@ -0,0 +1,400 @@ + array( + 'label' => __('Text', 'fw'), + 'type' => 'text', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_password' => array( + 'label' => __('Password', 'fw'), + 'type' => 'password', + 'value' => 'Dotted text', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_hidden' => array( + 'label' => false, + 'type' => 'hidden', + 'value' => '{some: "json"}', + 'desc' => false, + ), + 'demo_textarea' => array( + 'label' => __('Textarea', 'fw'), + 'type' => 'textarea', + 'value' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => array( + 'icon' => 'video', + 'html' => '' + ), + ), + 'demo_wp_editor' => array( + 'label' => __('Rich Text Editor'), + 'type' => 'wp-editor', + 'value' => 'Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_html' => array( + 'label' => __('HTML', 'fw'), + 'type' => 'html', + 'value' => '{some: "json"}', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'html' => 'Lorem ipsum ', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_checkbox' => array( + 'label' => __('Checkbox', 'fw'), + 'type' => 'checkbox', + 'value' => true, + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'text' => __('Custom text', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_checkboxes' => array( + 'label' => __('Checkboxes', 'fw'), + 'type' => 'checkboxes', + 'value' => array( + 'c1' => false, + 'c2' => true, + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'c1' => __('Checkbox 1 Custom Text', 'fw'), + 'c2' => __('Checkbox 2 Custom Text', 'fw'), + 'c3' => __('Checkbox 3 Custom Text', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_switch' => array( + 'label' => __('Switch', 'fw'), + 'type' => 'switch', + 'right-choice' => array( + 'value' => 'yes', + 'label' => __('Yes', 'fw') + ), + 'left-choice' => array( + 'value' => 'no', + 'label' => __('No', 'fw') + ), + 'value' => 'yes', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_select' => array( + 'label' => __('Select', 'fw'), + 'type' => 'select', + 'value' => 'c', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + '' => '---', + 'a' => __('Lorem ipsum', 'fw'), + 'b' => array( + 'text' => __('Consectetur', 'fw'), + 'attr' => array( + 'label' => 'Label overrides text', + 'data-whatever' => 'some data', + ), + ), + array( + 'attr' => array( + 'label' => __('Optgroup Label', 'fw'), + 'data-whatever' => 'some data', + ), + 'choices' => array( + 'c' => __('Sed ut perspiciatis', 'fw'), + 'd' => __('Excepteur sint occaecat', 'fw'), + ), + ), + 1 => __('One', 'fw'), + 2 => __('Two', 'fw'), + 3 => __('Three', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_select_multiple' => array( + 'label' => __('Select Multiple', 'fw'), + 'type' => 'select-multiple', + 'value' => array('c', '2'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + '' => '---', + 'a' => __('Lorem ipsum', 'fw'), + 'b' => array( + 'text' => __('Consectetur', 'fw'), + 'attr' => array( + 'label' => 'Label overrides text', + 'data-whatever' => 'some data', + ), + ), + array( + 'attr' => array( + 'label' => __('Optgroup Label', 'fw'), + 'data-whatever' => 'some data', + ), + 'choices' => array( + 'c' => __('Sed ut perspiciatis', 'fw'), + 'd' => __('Excepteur sint occaecat', 'fw'), + ), + ), + 1 => __('One', 'fw'), + 2 => __('Two', 'fw'), + 3 => __('Three', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_radio' => array( + 'label' => __('Radio', 'fw'), + 'type' => 'radio', + 'value' => 'c2', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'choices' => array( + 'c1' => __('Radio 1 Custom Text', 'fw'), + 'c2' => __('Radio 2 Custom Text', 'fw'), + 'c3' => __('Radio 3 Custom Text', 'fw'), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_image_picker' => array( + 'label' => __('Image Picker', 'fw'), + 'type' => 'image-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'attr' => array( + 'data-height' => 70, + ), + 'choices' => array( + 'choice-1' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb1.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip1.jpg' + ), + ), + 'choice-2' => array( + 'small' => array( + 'height' => 70, + 'src' => FW_PT_URI .'/images/image-picker-demo/thumb2.jpg' + ), + 'large' => array( + 'height' => 214, + 'src' => FW_PT_URI .'/images/image-picker-demo/tooltip2.jpg' + ), + ), + ), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_icon' => array( + 'label' => __('Icon', 'fw'), + 'type' => 'icon', + 'value' => 'fa-linux', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload' => array( + 'label' => __('Single Upload', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'images_only' => false, + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_upload_images' => array( + 'label' => __('Single Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_multi_upload' => array( + 'label' => __('Multi Upload', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'images_only' => false, + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_multi_upload_images' => array( + 'label' => __('Multi Upload (Images Only)', 'fw'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'type' => 'multi-upload', + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + + 'demo_color_picker' => array( + 'label' => __('Color Picker', 'fw'), + 'type' => 'color-picker', + 'value' => '', + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_gradient' => array( + 'label' => __('Gradient', 'fw'), + 'type' => 'gradient', + 'value' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff' + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_background_image' => array( + 'label' => __('Background Image', 'fw'), + 'type' => 'background-image', + 'value' => 'none', + 'choices' => array( + 'none' => array( + 'icon' => FW_PT_URI . '/images/patterns/no_pattern.jpg', + 'css' => array( + 'background-image' => 'none' + ) + ), + 'bg-1' => array( + 'icon' => FW_PT_URI . '/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/diagonal_bottom_to_top_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-2' => array( + 'icon' => FW_PT_URI . '/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/diagonal_top_to_bottom_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-3' => array( + 'icon' => FW_PT_URI . '/images/patterns/dots_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/dots_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-4' => array( + 'icon' => FW_PT_URI . '/images/patterns/romb_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/romb_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-5' => array( + 'icon' => FW_PT_URI . '/images/patterns/square_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/square_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-6' => array( + 'icon' => FW_PT_URI . '/images/patterns/noise_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/noise_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-7' => array( + 'icon' => FW_PT_URI . '/images/patterns/vertical_lines_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/vertical_lines_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + 'bg-8' => array( + 'icon' => FW_PT_URI . '/images/patterns/waves_pattern_preview.jpg', + 'css' => array( + 'background-image' => 'url("' . FW_PT_URI . '/images/patterns/waves_pattern.png' . '")', + 'background-repeat' => 'repeat', + ) + ), + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_typography' => array( + 'label' => __('Typography', 'fw'), + 'type' => 'typography', + 'value' => array( + 'size' => 17, + 'family' => 'Verdana', + 'style' => '300italic', + 'color' => '#0000ff' + ), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ), + ), + 'demo_addable_option' => array( + 'label' => __('Addable Option', 'fw'), + 'type' => 'addable-option', + 'option' => array( + 'type' => 'text', + ), + 'value' => array('Option 1', 'Option 2', 'Option 3'), + 'desc' => __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + 'help' => sprintf("%s \n\n'\"

    \n\n %s", + __('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'fw'), + __('Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium', 'fw') + ) + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/options/taxonomies/index.html b/scratch-parent/framework-customizations/theme/options/taxonomies/index.html new file mode 100644 index 00000000..e69de29b diff --git a/scratch-parent/framework-customizations/theme/posts.php b/scratch-parent/framework-customizations/theme/posts.php new file mode 100644 index 00000000..401d0543 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/posts.php @@ -0,0 +1,4 @@ +get_uri() . '/static/js/scripts.js', + array( 'jquery-ui-accordion' ), + fw()->theme->manifest->get_version(), + true + ); + + return fw_render_view( $this->get_path() . '/views/view.php', array( + 'atts' => $atts, + 'content' => $content, + 'tag' => $tag + ) ); + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/accordion/config.php b/scratch-parent/framework-customizations/theme/shortcodes/accordion/config.php new file mode 100644 index 00000000..e73db15a --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/accordion/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Accordion', 'fw' ), + 'description' => __( 'Create an accordion on the fly', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/accordion/options.php b/scratch-parent/framework-customizations/theme/shortcodes/accordion/options.php new file mode 100644 index 00000000..dd22c976 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/accordion/options.php @@ -0,0 +1,23 @@ + array( + 'type' => 'addable-popup', + 'label' => __( 'Tabs', 'fw' ), + 'popup-title' => __( 'Add/Edit Tabs', 'fw' ), + 'desc' => __( 'Create your tabs', 'fw' ), + 'template' => '{{=tab_title}}', + 'popup-options' => array( + 'tab_title' => array( + 'type' => 'text', + 'label' => __('Title', 'fw') + ), + 'tab_content' => array( + 'type' => 'textarea', + 'label' => __('Content', 'fw') + ) + ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/accordion/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/accordion/static/img/layout_builder.png new file mode 100644 index 00000000..97d2813b Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/accordion/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/accordion/static/js/scripts.js b/scratch-parent/framework-customizations/theme/shortcodes/accordion/static/js/scripts.js new file mode 100644 index 00000000..4542d34f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/accordion/static/js/scripts.js @@ -0,0 +1,3 @@ +jQuery(document).ready(function($){ + $( ".accordion" ).accordion(); +}); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/accordion/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/accordion/views/view.php new file mode 100644 index 00000000..273ad556 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/accordion/views/view.php @@ -0,0 +1,17 @@ + +
    + +

    +
    +

    +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/button/config.php b/scratch-parent/framework-customizations/theme/shortcodes/button/config.php new file mode 100644 index 00000000..097d1882 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/button/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Button', 'fw' ), + 'description' => __( 'A very awesome button', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/button/options.php b/scratch-parent/framework-customizations/theme/shortcodes/button/options.php new file mode 100644 index 00000000..b877bb8b --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/button/options.php @@ -0,0 +1,41 @@ + array( + 'label' => __( 'Button Label', 'fw' ), + 'desc' => __( 'This is the text that appears on your button', 'fw' ), + 'type' => 'text', + 'value' => 'Submit' + ), + 'link' => array( + 'label' => __( 'Button Link', 'fw' ), + 'desc' => __( 'Where should your button link to', 'fw' ), + 'type' => 'text', + 'value' => '#' + ), + 'target' => array( + 'type' => 'switch', + 'label' => __( 'Open Link in New Window', 'fw' ), + 'desc' => __( 'Select here if you want to open the linked page in a new window', 'fw' ), + 'right-choice' => array( + 'value' => '_blank', + 'label' => __('Yes', 'fw'), + ), + 'left-choice' => array( + 'value' => '_self', + 'label' => __('No', 'fw'), + ), + ), + 'color' => array( + 'label' => __( 'Button Color', 'fw' ), + 'desc' => __( 'Choose a color for your button', 'fw' ), + 'type' => 'select', + 'choices' => array( + 'black' => __( 'Black', 'fw' ), + 'blue' => __( 'Blue', 'fw' ), + 'green' => __( 'Green', 'fw' ), + ) + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/button/static/css/styles.css b/scratch-parent/framework-customizations/theme/shortcodes/button/static/css/styles.css new file mode 100644 index 00000000..55a152cb --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/button/static/css/styles.css @@ -0,0 +1,122 @@ +a.button-link { + outline: none; + display: inline-block; + margin: 5px; + text-align: center; + text-decoration: none; + border-radius: 5px; + border-width: 2px; + border-style: solid; + +} + +.button-link-wrapper { + display: inline-block; + text-align: center; + width: 100%; +} + +.button-link.grey { + background-color: #555; + border-color: #556; + text-shadow: 0 1px 0 rgba(0, 0, 0, 1); + color: #fff !important; +} + +.button-link.black { + background-color: #222; + border-color: #223; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 1); + color: #fff !important; +} + +.button-link.red { + background-color: #B02B2C; + border-color: #B02B20; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); + color: #5d1a1b !important; +} + +.button-link.orange { + background-color: #edae44; + border-color: #edae45; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #745521 !important; +} + +.button-link.green { + background-color: #83a846; + border-color: #83a847; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #415324 !important; +} + +.button-link.blue { + background-color: #7bb0e7; + border-color: #7bb0e8; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #3f5871 !important; +} + +.button-link.aqua { + background-color: #4ecac2; + border-color: #4ecac4; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #286460 !important; +} + +.button-link.teal { + background-color: #5f8789; + border-color: #5f8790; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #314445 !important; +} + +.button-link.purple { + background-color: #745f7e; + border-color: #745f7f; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #3c3240 !important; +} + +.button-link.pink { + background-color: #d65799; + border-color: #d65796; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); + color: #692b4b !important; +} + +.button-link.silver { + background-color: #d7d7d7; + border-color: #d7d7d9; + text-shadow: 0 1px 0 rgba(255, 255, 255, 1); + color: #444 !important; +} + +.button-link.small { + padding: 9px 10px 7px; + font-size: 13px; + min-width: 80px; +} + +.button-link.medium { + padding: 12px 16px 10px; + font-size: 13px; + min-width: 90px; +} + +.button-link.large { + padding: 15px 30px 13px; + font-size: 13px; + min-width: 127px; +} + +.button-link.position-right { + float: right; + display: block; +} + +.button-link.position-left { + float: left; + display: block; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/button/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/button/static/img/layout_builder.png new file mode 100644 index 00000000..917f4e05 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/button/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/button/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/button/views/view.php new file mode 100644 index 00000000..f4aa720a --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/button/views/view.php @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/class-fw-shortcode-column.php b/scratch-parent/framework-customizations/theme/shortcodes/column/class-fw-shortcode-column.php new file mode 100644 index 00000000..3cca90f5 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/column/class-fw-shortcode-column.php @@ -0,0 +1,23 @@ +load_item_type(); + } + } + + /** + * Loads a layout builder custom item type + */ + private function load_item_type() + { + require $this->get_path() . + '/includes/fw-option-type-layout-builder-column-item/class-fw-option-type-layout-builder-column-item.php'; + } +} diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/class-fw-option-type-layout-builder-column-item.php b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/class-fw-option-type-layout-builder-column-item.php new file mode 100644 index 00000000..8ddca5ac --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/class-fw-option-type-layout-builder-column-item.php @@ -0,0 +1,163 @@ +extensions->get('shortcodes')->get_shortcode('column'); + $static_uri = $column_shortcode->get_uri() . '/includes/fw-option-type-layout-builder-column-item/static/'; + wp_enqueue_style( + $this->get_builder_type() . '_item_type_' . $this->get_type(), + $static_uri . 'css/styles.css', + array(), + fw()->theme->manifest->get_version() + ); + wp_enqueue_script( + $this->get_builder_type() . '_item_type_' . $this->get_type(), + $static_uri . 'js/scripts.js', + array('fw-events', 'underscore'), + fw()->theme->manifest->get_version(), + true + ); + wp_localize_script( + $this->get_builder_type() . '_item_type_' . $this->get_type(), + str_replace('-', '_', $this->get_builder_type()) . '_item_type_' . $this->get_type() . '_data', + array( + 'restrictedTypes' => $this->restricted_types + ) + ); + } + + /** + * @return array( + * array( + * 'tab' => __('Tab 1', 'fw'), + * 'title' => __('thumb title 1', 'fw'), + * 'data' => array( // optional + * 'key1' => 'value1', + * 'key2' => 'value2' + * ) + * ), + * array( + * 'tab' => __('Tab 2', 'fw'), + * 'title' => __('thumb title 2', 'fw'), + * 'data' => array( // optional + * 'key1' => 'value1', + * ) + * ), + * ... + * ) + */ + protected function get_thumbnails_data() + { + $column_shortcode = fw()->extensions->get('shortcodes')->get_shortcode('column'); + $img_uri = $column_shortcode->get_uri() . '/includes/fw-option-type-layout-builder-column-item/static/img/'; + return array( + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('1/5', 'fw'), + 'description' => __('Creates a 1/5 column' ,'fw'), + 'image' => $img_uri . '1-5.png', + 'data' => array( + 'subtype' => '1-5' + ) + ), + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('1/4', 'fw'), + 'description' => __('Creates a 1/4 column' ,'fw'), + 'image' => $img_uri . '1-4.png', + 'data' => array( + 'subtype' => '1-4' + ) + ), + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('1/3', 'fw'), + 'description' => __('Creates a 1/3 column' ,'fw'), + 'image' => $img_uri . '1-3.png', + 'data' => array( + 'subtype' => '1-3' + ) + ), + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('1/2', 'fw'), + 'description' => __('Creates a 1/2 column' ,'fw'), + 'image' => $img_uri . '1-2.png', + 'data' => array( + 'subtype' => '1-2' + ) + ), + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('2/3', 'fw'), + 'description' => __('Creates a 2/3 column' ,'fw'), + 'image' => $img_uri . '2-3.png', + 'data' => array( + 'subtype' => '2-3' + ) + ), + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('3/4', 'fw'), + 'description' => __('Creates a 3/4 column' ,'fw'), + 'image' => $img_uri . '3-4.png', + 'data' => array( + 'subtype' => '3-4' + ) + ), + array( + 'tab' => __('Layout Elements', 'fw'), + 'title' => __('1/1', 'fw'), + 'description' => __('Creates a 1/1 column' ,'fw'), + 'image' => $img_uri . '1-1.png', + 'data' => array( + 'subtype' => '1-1' + ) + ) + ); + } + + /** + * Transforms the array representation of the shortcode to shortcode notation + * + * @param $atts array The array representation of the shortcode ex: + * array( + * 'type' => 'simple', + * 'subtype' => 'button', + * 'optionValues' => array( + * 'size' => 'large', + * 'type' => 'primary' + * ) + * ) + * @param $registered_items Option_Type_Layout_Builder_Item[] The layout builder items, useful when + * the shortcode accepts nested shortcodes + * @return string The shortcode notation of the shortcode ex: [button size="large" type="primary"] + */ + public function get_shortcode_notation($atts, $registered_items) + { + $attributes = 'type="' . base64_encode($atts['subtype']) . '"'; + if (isset($atts['firstInRow']) && $atts['firstInRow']) { + $attributes .= ' first_in_row="' . base64_encode('true') . '"'; + } + + $content = ''; + if (!empty($atts['_items'])) { + foreach ($atts['_items'] as $item) { + if (!in_array($item['type'], $this->restricted_types)) { + $content .= $registered_items[$item['type']]->get_shortcode_notation($item, $registered_items); + } + } + } + return "[column {$attributes}]{$content}[/column]"; + } +} +FW_Option_Type_Builder::register_item_type('FW_Option_Type_Layout_Builder_Column_Item'); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/css/styles.css b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/css/styles.css new file mode 100644 index 00000000..2b2e29bb --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/css/styles.css @@ -0,0 +1,75 @@ +/* Thumb */ +.fw-option-type-layout-builder .builder-item-type[data-builder-item-type="column"] img { + width: 30px; + height: 25px; +} + +/* Column Builder Item */ +.lb-item-type-column { + background-color: #f8f8f8; + border: 1px dashed #d8d8d8; + color: #01729c; + min-height: 50px; +} + +/* Panel */ +.lb-item-type-column > .panel { + padding: 10px 5px; + font-size: 12px; +} +.lb-item-type-column > .panel i { + cursor: pointer; + font-size: 16px; +} +.lb-item-type-column > .panel i:hover { + color: #019aca; +} +.lb-item-type-column > .panel .controls { + position: absolute; + top: 0; + right: 0; + display: none; +} +.lb-item-type-column:hover > .panel .controls { + display: block; +} +.builder-item.ui-sortable-helper > .lb-item-type-column:hover > .panel .controls { + display: none; +} + +/* Inner Items */ +.lb-item-type-column > .builder-items { + padding: 7px 0 13px; + min-height: 83px; +} +.lb-item-type-column > .builder-items > .builder-item { + padding: 0 11px 11px; +} + +/* Accept / Deny Incoming Items */ +.builder-item.fw-builder-item-deny-incoming-type > .lb-item-type-column .ui-sortable-placeholder { + display: none; +} + +/* Widths */ +.lb-column-1-5 { + width: 20%; +} +.lb-column-1-4 { + width: 25%; +} +.lb-column-1-3 { + width: 33.33333333%; +} +.lb-column-1-2 { + width: 50%; +} +.lb-column-2-3 { + width: 66.66666667%; +} +.lb-column-3-4 { + width: 75%; +} +.lb-column-1-1 { + width: 100%; +} diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-1.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-1.png new file mode 100644 index 00000000..83629a6f Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-1.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-2.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-2.png new file mode 100644 index 00000000..618c60d2 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-2.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-3.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-3.png new file mode 100644 index 00000000..ebdc6238 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-3.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-4.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-4.png new file mode 100644 index 00000000..89cd34ea Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-4.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-5.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-5.png new file mode 100644 index 00000000..d2d8e346 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/1-5.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/2-3.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/2-3.png new file mode 100644 index 00000000..61439319 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/2-3.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/3-4.png b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/3-4.png new file mode 100644 index 00000000..deec2cc4 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/img/3-4.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/js/scripts.js b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/js/scripts.js new file mode 100644 index 00000000..47907f7f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/column/includes/fw-option-type-layout-builder-column-item/static/js/scripts.js @@ -0,0 +1,199 @@ +(function(fwe, _, data) { + fwe.one('fw-builder:' + 'layout-builder' + ':register-items', function(builder) { + var LayoutBuilderColumnItem, + LayoutBuilderColumnItemView; + + LayoutBuilderColumnItemView = builder.classes.ItemView.extend({ + initialize: function() { + this.widthChangerView = new FwBuilderComponents.ItemView.WidthChanger({ + model: this.model, + view: this, + widths: [ + { + text: '1/5', + value: '1-5', + itemViewClass: 'lb-column-1-5' + }, + { + text: '1/4', + value: '1-4', + itemViewClass: 'lb-column-1-4' + }, + { + text: '1/3', + value: '1-3', + itemViewClass: 'lb-column-1-3' + }, + { + text: '1/2', + value: '1-2', + itemViewClass: 'lb-column-1-2' + }, + { + text: '2/3', + value: '2-3', + itemViewClass: 'lb-column-2-3' + }, + { + text: '3/4', + value: '3-4', + itemViewClass: 'lb-column-3-4' + }, + { + text: '1/1', + value: '1-1', + itemViewClass: 'lb-column-1-1' + } + ], + modelAttribute: 'subtype' + }); + this.defaultInitialize(); + }, + template: _.template( + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '' + + '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + ), + render: function() { + this.defaultRender(); + + this.$('.width-changer').append(this.widthChangerView.$el); + this.widthChangerView.delegateEvents(); + }, + events: { + 'click .column-item-clone': 'cloneItem', + 'click .column-item-delete': 'removeItem' + }, + cloneItem: function() { + var index = this.model.collection.indexOf(this.model), + attributes = this.model.toJSON(), + _items = attributes['_items'], + clonedColumn; + + delete attributes['_items']; + + clonedColumn = new LayoutBuilderColumnItem(attributes); + this.model.collection.add(clonedColumn, {at: index + 1}); + clonedColumn.get('_items').reset(_items); + }, + removeItem: function() { + this.remove(); + this.model.collection.remove(this.model); + } + }); + + LayoutBuilderColumnItem = builder.classes.Item.extend({ + defaults: { + type: 'column' + }, + restrictedTypes: data.restrictedTypes, + initialize: function(atts, opts) { + var subtype = this.get('subtype') || opts.$thumb.find('.item-data').attr('data-subtype'); + + if (!this.get('subtype')) { + this.set('subtype', subtype); + } + + this.view = new LayoutBuilderColumnItemView({ + id: 'layout-builder-item-'+ this.cid, + model: this + }); + + this.defaultInitialize(); + }, + allowIncomingType: function(type) { + return _.indexOf(this.restrictedTypes, type) === -1; + } + }); + + + var setFirstRowColumns = (function() { + var Fraction = (function() { + var f = function(numerator, denominator) { + this.n = numerator; + this.d = denominator; + }; + + f.createFromString = function(fractionString) { + var splitted = fractionString.split('-'); + return new f(splitted[0], splitted[1]).simplify(); + }; + + f.prototype.simplify = function() { + var euclid = function(a, b) { + if (b === 0) return a; + else return euclid(b, a % b); + }, + gcd = euclid(this.n, this.d); + this.n /= gcd; + this.d /= gcd; + return this; + }; + + f.prototype.add = function(f) { + this.n = this.n * f.d + this.d * f.n; + this.d = this.d * f.d; + return this.simplify(); + }; + + f.prototype.toNumber = function() { + return this.n / this.d; + }; + + return f; + })(); + + return function(items) { + var type = 'column', + columnSumm; + + items.each(function(item, index, list) { + + if (item.get('type') === type) { + item.unset('firstInRow', {silent: true}); + + // checking if the previous element exists + if (!list[index - 1]) { + item.set('firstInRow', true, {silent: true}); + columnSumm = Fraction.createFromString(item.get('subtype')); + return; + } + + // checking if the previous element is not a column + if (list[index - 1].get('type') !== type) { + item.set('firstInRow', true, {silent: true}); + columnSumm = Fraction.createFromString(item.get('subtype')); + return; + } + + // if here then the previos is also a column + // summ it and see if new row + columnSumm.add(Fraction.createFromString(item.get('subtype'))); + if (columnSumm.toNumber() > 1) { + item.set('firstInRow', true, {silent: true}); + columnSumm = Fraction.createFromString(item.get('subtype')); + } + } + + }); + }; + })(); + + builder.rootItems.on('change add remove reset', function() { + setFirstRowColumns(builder.rootItems); + }); + + builder.registerItemClass(LayoutBuilderColumnItem); + }); +})(fwEvents, _, layout_builder_item_type_column_data); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/column/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/column/views/view.php new file mode 100644 index 00000000..d46ed1df --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/column/views/view.php @@ -0,0 +1,17 @@ + + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/hr/config.php b/scratch-parent/framework-customizations/theme/shortcodes/hr/config.php new file mode 100644 index 00000000..b6f7a244 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/hr/config.php @@ -0,0 +1,10 @@ + array( + 'title' => __('Horizontal Ruler', 'fw'), + 'description' => __('A very awesome hr', 'fw'), + 'tab' => __('Content Elements', 'fw'), + 'popup_size' => 'small' + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/hr/options.php b/scratch-parent/framework-customizations/theme/shortcodes/hr/options.php new file mode 100644 index 00000000..280faee6 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/hr/options.php @@ -0,0 +1,32 @@ + array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'ruler_type' => array( + 'type' => 'select', + 'label' => __( 'Ruler Type', 'fw' ), + 'desc' => __( 'Here you can set the styling and size of the HR element', 'fw' ), + 'choices' => array( + 'line' => __( 'Line', 'fw' ), + 'space' => __( 'Whitespace', 'fw' ), + ) + ) + ), + 'choices' => array( + 'space' => array( + 'height' => array( + 'label' => __( 'Height', 'fw' ), + 'desc' => __( 'How much whitespace do you need? Enter a pixel value. Positive value will increase the whitespace, negative value will reduce it. eg: \'50\', \'-25\', \'200\'', 'fw' ), + 'type' => 'text', + 'value' => '50' + ) + ) + ) + ) +); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/hr/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/hr/static/img/layout_builder.png new file mode 100644 index 00000000..62fd6dbd Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/hr/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/hr/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/hr/views/view.php new file mode 100644 index 00000000..bef19097 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/hr/views/view.php @@ -0,0 +1,14 @@ + +
    +
    +
    + + + +
    + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon-box/config.php b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/config.php new file mode 100644 index 00000000..5197f4df --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/config.php @@ -0,0 +1,9 @@ + array( + 'title' => __('Icon Box', 'fw'), + 'description' => __('Create icon boxes', 'fw'), + 'tab' => __('Content Elements', 'fw') + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon-box/options.php b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/options.php new file mode 100644 index 00000000..fa02abb3 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/options.php @@ -0,0 +1,27 @@ + array( + 'type' => 'select', + 'label' => __( 'Select Box Type', 'fw' ), + 'choices' => array( + '' => __( 'Default', 'fw' ), + 'vertical' => __( 'Vertical line', 'fw' ) + ) + ), + 'icon' => array( + 'type' => 'icon', + 'label' => 'Choose an Icon', + ), + 'title' => array( + 'type' => 'text', + 'label' => __( 'Title of the Box', 'fw' ), + ), + 'content' => array( + 'type' => 'textarea', + 'label' => __( 'Content', 'fw' ), + 'desc' => __( 'Enter the desired content', 'fw' ), + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon-box/static/css/styles.css b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/static/css/styles.css new file mode 100644 index 00000000..0bc7f754 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/static/css/styles.css @@ -0,0 +1,23 @@ +.box{ + width: 690px; + padding: 20px; + position: relative; + margin: 30px 0px; +} + +.box span{ + font-size: 64px; + position: absolute; + top:-32px; + left:45.5%; +} + +.box h4{ + margin: 15px; + padding: 0px; + text-align: center; +} + +.box p{ + text-align: justify; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon-box/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/static/img/layout_builder.png new file mode 100644 index 00000000..387eb3e6 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon-box/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/views/view.php new file mode 100644 index 00000000..7cce80d5 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon-box/views/view.php @@ -0,0 +1,18 @@ + + +
    + + + + + +
    +

    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon/class-shortcode-icon.php b/scratch-parent/framework-customizations/theme/shortcodes/icon/class-shortcode-icon.php new file mode 100644 index 00000000..fca0b3e5 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon/class-shortcode-icon.php @@ -0,0 +1,27 @@ +builder_type . '-shortcode-' . 'icon' . '-shortcode-notation', array($this, '_admin_filter_shortcode_notation'), 10, 2); + } + } + + + public function _admin_filter_shortcode_notation($notation, $atts){ + + $attributes = $atts['optionValues']; + + $attributes['color'] = (!empty($attributes['color'])) ? $attributes['color'] : '#000'; + $attributes['size'] = (!empty($attributes['size'])) ? $attributes['size'] : '40'; + + return '[icon '. fw_attr_to_html($attributes).']'; + } + +} diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon/config.php b/scratch-parent/framework-customizations/theme/shortcodes/icon/config.php new file mode 100644 index 00000000..c3784674 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon/config.php @@ -0,0 +1,9 @@ + array( + 'title' => __('Icon', 'fw'), + 'description' => __('A very awesome icon', 'fw'), + 'tab' => __('Content Elements', 'fw'), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon/options.php b/scratch-parent/framework-customizations/theme/shortcodes/icon/options.php new file mode 100644 index 00000000..a5634885 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon/options.php @@ -0,0 +1,15 @@ + array( + 'type' => 'icon', + 'label' => __( 'Icon', 'fw' ) + ), + 'tooltip' => array( + 'type' => 'text', + 'label' => __( 'Title', 'fw' ), + 'desc' => __( 'Icon title', 'fw' ), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/icon/static/img/layout_builder.png new file mode 100644 index 00000000..cfddeeaa Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/icon/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/icon/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/icon/views/view.php new file mode 100644 index 00000000..3f215bfd --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/icon/views/view.php @@ -0,0 +1,15 @@ + + + + +
    + + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/info-box/config.php b/scratch-parent/framework-customizations/theme/shortcodes/info-box/config.php new file mode 100644 index 00000000..57a149fe --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/info-box/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Info Box', 'fw' ), + 'description' => __( 'Create info boxes', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/info-box/options.php b/scratch-parent/framework-customizations/theme/shortcodes/info-box/options.php new file mode 100644 index 00000000..1417b16b --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/info-box/options.php @@ -0,0 +1,36 @@ + array( + 'type' => 'textarea', + 'label' => __( 'Content', 'fw' ), + 'desc' => __( 'Enter some content for this Info Box', 'fw' ) + ), + 'button_label' => array( + 'label' => __( 'Button Label', 'fw' ), + 'desc' => __( 'This is the text that appears on your button', 'fw' ), + 'type' => 'text', + 'value' => 'Click' + ), + 'button_link' => array( + 'label' => __( 'Button Link', 'fw' ), + 'desc' => __( 'Where should your button link to', 'fw' ), + 'type' => 'text', + 'value' => '#' + ), + 'button_target' => array( + 'type' => 'switch', + 'label' => __( 'Open Link in New Window', 'fw' ), + 'desc' => __( 'Select here if you want to open the linked page in a new window', 'fw' ), + 'right-choice' => array( + 'value' => '_blank', + 'label' => __('Yes', 'fw'), + ), + 'left-choice' => array( + 'value' => '_self', + 'label' => __('No', 'fw'), + ), + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/info-box/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/info-box/static/img/layout_builder.png new file mode 100644 index 00000000..d51c1958 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/info-box/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/info-box/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/info-box/views/view.php new file mode 100644 index 00000000..672f1e72 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/info-box/views/view.php @@ -0,0 +1,9 @@ + + +
    +

    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-image/config.php b/scratch-parent/framework-customizations/theme/shortcodes/media-image/config.php new file mode 100644 index 00000000..6fce0bc3 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/media-image/config.php @@ -0,0 +1,9 @@ + array( + 'title' => __('Image', 'fw'), + 'description' => __('Image Shortcode', 'fw'), + 'tab' => __('Media Elements', 'fw'), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-image/options.php b/scratch-parent/framework-customizations/theme/shortcodes/media-image/options.php new file mode 100644 index 00000000..45702028 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/media-image/options.php @@ -0,0 +1,52 @@ + array( + 'type' => 'upload', + 'label' => __( 'Choose Image', 'fw' ), + 'desc' => __( 'Either upload a new, or choose an existing image from your media library', 'fw' ) + ), + 'size' => array( + 'type' => 'group', + 'options' => array( + 'width' => array( + 'type' => 'text', + 'label' => __( 'Width', 'fw' ), + 'desc' => __( 'Set image width', 'fw' ), + 'value' => 300 + ), + 'height' => array( + 'type' => 'text', + 'label' => __( 'Height', 'fw' ), + 'desc' => __( 'Set image height', 'fw' ), + 'value' => 200 + ) + ) + ), + 'image-link-group' => array( + 'type' => 'group', + 'options' => array( + 'link' => array( + 'type' => 'text', + 'label' => __( 'Image Link', 'fw' ), + 'desc' => __( 'Where should your image link to?', 'fw' ) + ), + 'target' => array( + 'type' => 'switch', + 'label' => __( 'Open Link in New Window', 'fw' ), + 'desc' => __( 'Select here if you want to open the linked page in a new window', 'fw' ), + 'right-choice' => array( + 'value' => '_blank', + 'label' => __( 'Yes', 'fw' ), + ), + 'left-choice' => array( + 'value' => '_self', + 'label' => __( 'No', 'fw' ), + ), + ), + ) + ) +); + diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-image/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/media-image/static/img/layout_builder.png new file mode 100644 index 00000000..67a11214 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/media-image/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-image/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/media-image/views/view.php new file mode 100644 index 00000000..6ef6bc61 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/media-image/views/view.php @@ -0,0 +1,30 @@ + 0 ) ) ? $atts['width'] : ''; +$height = ( is_numeric( $atts['height'] ) && ( $atts['height'] > 0 ) ) ? $atts['height'] : ''; +if ( ! empty( $width ) && ! empty( $height ) ) { + $image = fw_resize( $atts['image']['attachment_id'], $width, $height, true ); +} else { + $image = $atts['image']['url']; +} +?> + + + <?php echo $image ?> + + + <?php echo $image ?> + + diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-video/config.php b/scratch-parent/framework-customizations/theme/shortcodes/media-video/config.php new file mode 100644 index 00000000..578d4a67 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/media-video/config.php @@ -0,0 +1,9 @@ + array( + 'title' => __('Video', 'fw'), + 'description' => __('Embed Video', 'fw'), + 'tab' => __('Media Elements', 'fw'), + ) +); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-video/options.php b/scratch-parent/framework-customizations/theme/shortcodes/media-video/options.php new file mode 100644 index 00000000..d8402c7b --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/media-video/options.php @@ -0,0 +1,23 @@ + array( + 'type' => 'text', + 'label' => __( 'Insert Video URL', 'fw' ), + 'desc' => __( 'Insert Video URL to embed this video', 'fw' ) + ), + 'width' => array( + 'type' => 'text', + 'label' => __( 'Video Width', 'fw' ), + 'desc' => __( 'Enter a value for the width', 'fw' ), + 'value' => 300 + ), + 'height' => array( + 'type' => 'text', + 'label' => __( 'Video Height', 'fw' ), + 'desc' => __( 'Enter a value for the height', 'fw' ), + 'value' => 200 + ) +); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-video/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/media-video/static/img/layout_builder.png new file mode 100644 index 00000000..446f8853 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/media-video/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/media-video/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/media-video/views/view.php new file mode 100644 index 00000000..44f20b1a --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/media-video/views/view.php @@ -0,0 +1,17 @@ + 0 ) ) ? $atts['width'] : '300'; +$height = ( is_numeric( $atts['height'] ) && ( $atts['height'] > 0 ) ) ? $atts['height'] : '200'; +$iframe = $wp_embed->run_shortcode( '[embed width="' . $width . '" height="' . $height . '"]' . trim( $atts['url'] ) . '[/embed]' ); +?> +
    + +
    diff --git a/scratch-parent/framework-customizations/theme/shortcodes/notification/config.php b/scratch-parent/framework-customizations/theme/shortcodes/notification/config.php new file mode 100644 index 00000000..70c18aa0 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/notification/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Notification', 'fw' ), + 'description' => __( 'A very awesome notification', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/notification/options.php b/scratch-parent/framework-customizations/theme/shortcodes/notification/options.php new file mode 100644 index 00000000..d9cacd44 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/notification/options.php @@ -0,0 +1,23 @@ + array( + 'label' => __( 'Message', 'fw' ), + 'desc' => __( 'Notification message', 'fw' ), + 'type' => 'text', + 'value' => __( 'Message!', 'fw' ), + ), + 'type' => array( + 'label' => __( 'Type', 'fw' ), + 'desc' => __( 'Notification type', 'fw' ), + 'type' => 'select', + 'choices' => array( + 'success' => __( 'Congratulations', 'fw' ), + 'info' => __( 'Information', 'fw' ), + 'alert' => __( 'Alert', 'fw' ), + 'error' => __( 'Error', 'fw' ), + ) + ), +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/notification/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/notification/static/img/layout_builder.png new file mode 100644 index 00000000..43b91b8d Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/notification/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/notification/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/notification/views/view.php new file mode 100644 index 00000000..fd0ed099 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/notification/views/view.php @@ -0,0 +1,23 @@ + + +
    + '; + break; + case 'info' : + echo ''; + break; + case 'alert' : + echo ''; + break; + case 'error' : + echo ''; + break; + } + ?> + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/special-heading/config.php b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/config.php new file mode 100644 index 00000000..df4b55c4 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/config.php @@ -0,0 +1,9 @@ + array( + 'title' => __('Special Heading', 'fw'), + 'description' => __('Make special headings', 'fw'), + 'tab' => __('Content Elements', 'fw'), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/special-heading/options.php b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/options.php new file mode 100644 index 00000000..47cc55a5 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/options.php @@ -0,0 +1,34 @@ + array( + 'type' => 'group', + 'options' => array( + 'title' => array( + 'type' => 'text', + 'label' => __( 'Heading Title', 'fw' ), + 'desc' => __( 'Write the heading title content', 'fw' ), + ), + 'subtitle' => array( + 'type' => 'text', + 'label' => __( 'Heading Subtitle', 'fw' ), + 'desc' => __( 'Write the heading subtitle content', 'fw' ), + ), + ) + ), + 'heading' => array( + 'type' => 'select', + 'label' => 'Choose Your Heading Size', + 'choices' => array( + 'h1' => 'H1', + 'h2' => 'H2', + 'h3' => 'H3', + 'h4' => 'H4', + 'h5' => 'H5', + 'h6' => 'H6', + ) + ), + +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/special-heading/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/static/img/layout_builder.png new file mode 100644 index 00000000..e0b01540 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/special-heading/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/views/view.php new file mode 100644 index 00000000..d6b83755 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/special-heading/views/view.php @@ -0,0 +1,20 @@ + + + + < class="shortcode-container">> + + + <>> + + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/class-fw-shortcode-table.php b/scratch-parent/framework-customizations/theme/shortcodes/table/class-fw-shortcode-table.php new file mode 100644 index 00000000..a9c34337 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/class-fw-shortcode-table.php @@ -0,0 +1,38 @@ +load_option_type(); + } + } + + private function load_option_type() { + require $this->get_path() . '/includes/fw-option-type-table-builder/class-fw-option-type-table-builder.php'; + } + + protected function handle_shortcode( $atts, $content, $tag ) { + + $view_file = $this->get_path() . '/views/' . $atts['table_purpose'] . '.php'; + + if ( ! file_exists( $view_file ) ) { + trigger_error( + sprintf( __( 'No default view (views/view.php) found for shortcode: %s', 'fw' ), $tag ), + E_USER_ERROR + ); + } + + return fw_render_view( $view_file, array( + 'atts' => $atts, + 'content' => $content, + 'tag' => $tag + ) ); + } + + +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/config.php b/scratch-parent/framework-customizations/theme/shortcodes/table/config.php new file mode 100644 index 00000000..d4baf659 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/config.php @@ -0,0 +1,12 @@ + array( + 'title' => __( 'Table Builder', 'fw' ), + 'description' => __( 'A very awesome table', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + 'popup_size' => 'large' + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/class-fw-option-type-table-builder.php b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/class-fw-option-type-table-builder.php new file mode 100644 index 00000000..dd515e57 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/class-fw-option-type-table-builder.php @@ -0,0 +1,137 @@ +extensions->get( 'shortcodes' )->get_shortcode( 'table' ); + if ( ! $table_shortcode ) { + trigger_error( + __( 'table-builder option type must be inside the table shortcode', 'fw' ), + E_USER_ERROR + ); + } + + $static_uri = $table_shortcode->get_uri() . '/includes/fw-option-type-table-builder/static/'; + wp_enqueue_style( + 'fw-option-' . $this->get_type() . '-default', + $static_uri . 'css/default-styles.css', + array(), + fw()->theme->manifest->get_version() + ); + wp_enqueue_style( + 'fw-option-' . $this->get_type() . '-extended', + $static_uri . 'css/extended-styles.css', + array(), + fw()->theme->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + $static_uri . 'js/scripts.js', + array( 'jquery', 'fw-events' ), + fw()->theme->manifest->get_version(), + true + ); + + if ( ! isset( $data['value'] ) || empty( $data['value'] ) ) { + $data['value'] = $option['value']; + } + + $this->replace_with_defaults( $option ); + $views_path = $table_shortcode->get_path() . '/includes/fw-option-type-table-builder/views/'; + + return fw_render_view( $views_path . 'view.php', array( + 'id' => $option['attr']['id'], + 'option' => $option, + 'data' => $data + ) ); + } + + protected function replace_with_defaults( &$option ) { + $option['row_options']['attr']['class'] = 'fw-table-builder-row-style'; + $option['columns_options']['attr']['class'] = 'fw-table-builder-col-style'; + $defaults = $this->_get_defaults(); + $option['row_options']['choices'] = $defaults['row_options']['choices']; + $option['columns_options']['choices'] = $defaults['columns_options']['choices']; + } + + /** + * @internal + */ + protected function _get_value_from_input( $option, $input_value ) { + if ( ! is_array( $input_value ) ) { + return $option['value']; + } + + $this->set_default_values( $input_value, $option ); + + if ( isset( $input_value['textarea']['_template_key_row_'] ) ) { + unset( $input_value['textarea']['_template_key_row_'] ); + } + + if ( isset( $input_value['rows']['_template_key_row_'] ) ) { + unset( $input_value['rows']['_template_key_row_'] ); + } + + return $input_value; + } + + private function set_default_values( &$input_value, &$option ) { + if ( ! isset( $input_value['textarea'] ) || empty( $input_value['textarea'] ) ) { + $input_value['textarea'] = $option['value']['textarea']; + } + + if ( ! isset( $input_value['rows'] ) || empty( $input_value['rows'] ) ) { + $input_value['rows'] = $option['value']['rows']; + } + + if ( ! isset( $input_value['cols'] ) || empty( $input_value['cols'] ) ) { + $input_value['cols'] = $option['value']['cols']; + } + } + + /** + * @internal + */ + protected function _get_defaults() { + return array( + 'row_options' => array( + 'choices' => array( + '' => __( 'Default row', 'fw' ), + 'heading-row' => __( 'Heading row', 'fw' ), + 'pricing-row' => __( 'Pricing row', 'fw' ), + //'button-row' => __('Button Row', 'fw') + ) + ), + 'columns_options' => array( + 'choices' => array( + '' => __( 'Default column', 'fw' ), + 'highlight-col' => __( 'Highlight column', 'fw' ), + 'desc-col' => __( 'Description column', 'fw' ), + 'center-col' => __( 'Center text column', 'fw' ) + ) + ), + 'value' => array( + 'cols' => array( '', '', '' ), + 'rows' => array( '', '', '' ), + 'textarea' => array( array( '', '', '' ), array( '', '', '' ), array( '', '', '' ) ) + ) + ); + } + + /** + * @internal + */ + public function _get_backend_width_type() { + return 'full'; + } +} + +FW_Option_Type::register( 'FW_Option_Type_Table_Builder' ); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/css/default-styles.css b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/css/default-styles.css new file mode 100644 index 00000000..4672e1f3 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/css/default-styles.css @@ -0,0 +1,160 @@ +/** table builder start **/ + +/** buttons start**/ +.fw-option-type-table-builder .fw-add-buttons-builder { + float: right; +} + +/** buttons end **/ + +/** table start **/ +.fw-option-type-table-builder .fw-table { + width: 100%; + display: table; + table-layout: fixed; +} + +/** row start **/ +.fw-option-type-table-builder .fw-table-row { + width: 100%; + line-height: 1.5em; + display: table-row; + position: relative; +} + +.fw-option-type-table-builder .fw-template-row { + display: none; +} + +/** cell start **/ +/* +.fw-option-type-table-builder .fw-table-row:first-child select { + width: 150px; +} +*/ + +.fw-option-type-table-builder .fw-table-cell { + display: table-cell; + border-left: 1px solid #e1e1e1; + border-bottom: 1px solid #e1e1e1; + padding: 10px; + background: #fff; + cursor: pointer; + height: 18px; + vertical-align: middle; + position: relative; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + padding-bottom: 9.1px; +} + +.fw-option-type-table-builder .fw-table-cell-worksheet:hover, +.fw-option-type-table-builder .fw-table-cell-worksheet.fw-cell-show-editor { + background: #f8f8f8; +} + +.fw-option-type-table-builder .fw-table-col-option { + border-left: none; + padding-bottom: 18px; +} + +.fw-option-type-table-builder .fw-table-row-delete { + width: 23px; + border-bottom: none; + position: relative; +} + +.fw-option-type-table-builder .fw-table-col-delete, +.fw-option-type-table-builder .fw-table-cell-options { + border-left: none; + border-bottom: none; +} + +.fw-option-type-table-builder .empty-cell { + border: none; +} + +.fw-option-type-table-builder .fw-table-col-delete { + text-align: center; + vertical-align: middle; +} + +/** cell editor start **/ +.fw-option-type-table-builder .fw-table-cell.fw-cell-show-editor textarea { + display: block; +} + +.fw-option-type-table-builder .fw-table-cell.fw-cell-show-editor .fw-table-cell-content { + display: none; +} + +.fw-option-type-table-builder .fw-table-cell .fw-table-cell-content { + display: block; +} + +.fw-option-type-table-builder .fw-table-cell textarea { + display: none; +} + +/** cell editor end **/ + +.fw-option-type-table-builder .fw-table-cell-options { + width: 180px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.fw-option-type-table-builder .fw-table-row .fw-table-cell-options select { + width: 150px; +} + +.fw-option-type-table-builder .fw-table-col-options select { + max-width: 250px; + width: 50%; +} + +.fw-option-type-table-builder .fw-backend-option .fw-backend-option-input .fw-table-cell-options select { + width: auto; +} + +.fw-option-type-table-builder .fw-table-add-column { + display: none; + float: right; +} + +.fw-option-type-table-builder .fw-table-col-options > :nth-last-child(2) > .fw-table-add-column { + display: inline-block; +} + +.fw-option-type-table-builder .fw-table-add-row { + float: right; + margin-right: 10px; +} + +.fw-option-type-table-builder .fw-table-col-options > .fw-table-cell { + padding-top: 0; +} + +.fw-option-type-table-builder .fw-table-col-options > :nth-last-child(2) { + padding-right: 0; +} + +.fw-option-type-table-builder .fw-table-col-options > :nth-child(2) { + padding-left: 0; +} + +.fw-option-type-table-builder .fw-table-row-delete-btn { + padding-left: 4px; +} + +/** cell end **/ +/** row end **/ +/** table end **/ +/** tablebuilder end **/ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/css/extended-styles.css b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/css/extended-styles.css new file mode 100644 index 00000000..f8c7b41e --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/css/extended-styles.css @@ -0,0 +1,24 @@ +.fw-option-type-table-builder .fw-table-cell-worksheet.highlight-col { + -moz-box-shadow: 0px 3px 13px 0px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0px 3px 13px 0px rgba(0, 0, 0, 0.2); + box-shadow: 0px 3px 13px 0px rgba(0, 0, 0, 0.2); + z-index: 10; + position: relative; +} + +.fw-option-type-table-builder .fw-table-cell-worksheet.desc-col { + text-align: right; + color: #999; + border-bottom-style: dotted !important; + font-style: italic; + background: transparent; + width: 150px; +} + +.fw-option-type-table-builder .pricing-row .fw-table-cell-worksheet { + font-size: 20px; +} + +.fw-option-type-table-builder .fw-table-cell-worksheet.center-col { + text-align: center; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/js/scripts.js b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/js/scripts.js new file mode 100644 index 00000000..8267f53f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/static/js/scripts.js @@ -0,0 +1,239 @@ +( function ($) { + $(document).ready(function () { + + function FwTableBuilder($tableBuilder) { + var $table = $tableBuilder.find('.fw-table'), + lastRow = parseInt($tableBuilder.find('.fw-table-last-row').val()), + lastCol = parseInt($tableBuilder.find('.fw-table-last-col').val()), + worksheetSelector = '.fw-table-cell-worksheet:not(.fw-template-row .fw-table-cell, fw-table-cols-delete .fw-table-cell, .fw-table-col-delete)', + $currentCell = false, + isAllowedTabMove = true; + + var process = { + initialize: function () { + process.tableBuilderEvents(); + }, + + onTabKeyUp: function (e) { + var keyCode = e.keyCode || e.which; + if (keyCode == 9) { + isAllowedTabMove = true; + } + }, + + onTabKeyDown: function (e) { + var keyCode = e.keyCode || e.which; + if (keyCode == 9) { + if (isAllowedTabMove === true && $currentCell) { + isAllowedTabMove = false; + process.onTabPress(e); + } else if ($currentCell) { + isAllowedTabMove = false; + e.stopPropagation(); + e.preventDefault(); + } + } + }, + + onTabPress: function (e) { + var $cells = $table.find(worksheetSelector), + currentCellIndex = $cells.index($currentCell), + order = e.shiftKey ? -1 : 1, + $nextCell = $cells.filter(':eq(' + (currentCellIndex + order) + ')'); + + if (!$nextCell.length) { + $nextCell = order == 1 ? $cells.filter(':eq(0)') : $cells.filter(':last'); + } + + e.stopPropagation(); + e.preventDefault(); + $nextCell.trigger('click'); + }, + + changeTableRowStyle: function () { + var $select = $(this), + newClass = $select.val(), + classNames = $select.find('option').map(function () { + return this.value + }).get().join(" "), + $selectCell = $select.parent(), + $row = $selectCell.parent(); + + $row.removeClass(classNames).addClass(newClass); + $selectCell.removeClass(classNames).addClass(newClass); + + return false; + }, + + /** + * Generate string of class names (from select values), which need tobe removed, after add new class for specific cells + */ + changeTableColumnStyle: function () { + var $select = $(this), + newClass = $select.val(), + classNames = $select.find('option').map(function () { + return this.value + }).get().join(" "), + $cell = $select.parent(), + colId = parseInt($cell.data('col')), + $elements = $table.find('[data-col=' + colId + ']'); + + $elements.removeClass(classNames).addClass(newClass); + + return false; + }, + + removeTableColumn: function () { + var columns = $table.find('.fw-template-row .fw-table-cell'); + + if (columns.length > 3) { + var colId = parseInt($(this).data('col')); + $table.find('.fw-table-cell[data-col=' + colId + ']').remove(); + } + + return false; + }, + + removeTableRow: function () { + var $row = $(this).parent('.fw-table-row'); + + if (false === $(this).hasClass('empty-cell') && false === $row.hasClass('fw-template-row') && $table.find('.fw-table-row').length > 4) { + $row.remove(); + } + + return false; + }, + + addTableColumn: function () { + var columns = $table.find('.fw-template-row .fw-table-cell'); + lastCol++; + + //max cols + if (columns.length <= 6) { + /** + * Clone worksheet (data cells) and insert it before last row's cell + */ + var $dropdownColCell = $table.find('.fw-table-row:eq(0) .fw-table-cell:eq(1)'), + dropDownDefaultColValue = $dropdownColCell.find('select option:eq(0)').val(), + $worksheetCellTemplate = $table.find('.fw-template-row .fw-table-cell:eq(1)'), + $beforeDeleteRowCell = $table.find('.fw-table-row:not(.fw-table-row:eq(0), .fw-table-cols-delete) .fw-table-row-delete'), + $insertedDropDownCell = $worksheetCellTemplate.clone().addClass(dropDownDefaultColValue).insertBefore($beforeDeleteRowCell); + $insertedDropDownCell.attr('data-col', lastCol); + $insertedDropDownCell.each(function () { + if (false === $(this).parent().hasClass('fw-template-row')) { + var rowId = $(this).parent().data('row'), + $textarea = $(this).find('textarea'); + + $textarea.attr('name', $textarea.attr('name').replace(/_template_key_row_/, rowId).replace(/_template_key_col_/, lastCol)); + $textarea.attr('id', $textarea.attr('id').replace(/_template_key_row_/, rowId).replace(/_template_key_col_/, lastCol)); + } + + }); + + /** + * Clone first cell with select and insert it before last row's cell + */ + var $lastEmptyCellFirstRow = $table.find('.fw-table-row:eq(0) .fw-table-row-delete'), + clone2 = $dropdownColCell.clone().insertBefore($lastEmptyCellFirstRow); + clone2.attr('data-col', lastCol).find('select').val(dropDownDefaultColValue); + clone2.find('select').attr('name', clone2.find('select').attr('name').replace(/\[\d+]$/, '[' + lastCol + ']')); //add column number to select + clone2.find('select').attr('id', clone2.find('select').attr('id').replace(/\-\d+$/, '-' + lastCol)); + + /** + * Clone last row (row which consists with remove cols buttons) and insert it before last row's cell + */ + var deleteCellTemplate = $table.find('.fw-table-cols-delete .fw-table-cell:eq(1)'), + $lastEmptyCellLastRow = $table.find('.fw-table-cols-delete .fw-table-cell:last'), + clone3 = deleteCellTemplate.clone().insertBefore($lastEmptyCellLastRow); + clone3.attr('data-col', lastCol); + + /** + * set column default style + */ + process.changeTableColumnStyle.apply(clone2.find('select')); + } + + return false; + }, + + addTableRow: function () { + lastRow++; + var $templateRow = $tableBuilder.find('.fw-template-row'), + $insertedRow = $templateRow.clone().removeClass('fw-template-row').attr('data-row', lastRow).insertBefore($templateRow); + + + /** + * replace textarea templates names & id's + */ + $insertedRow.each(function () { + if (false === $(this).hasClass('fw-template-row')) { + + var $textareas = $(this).find('textarea'); + + $textareas.each(function () { + var colId = $(this).parent().data('col'); + + $(this).attr('name', $(this).attr('name').replace(/_template_key_row_/, lastRow).replace(/_template_key_col_/, colId)); + $(this).attr('id', $(this).attr('id').replace(/_template_key_row_/, lastRow).replace(/_template_key_col_/, colId)); + }); + + } + }); + + var $select = $insertedRow.find('select'); + $select.attr('name', $select.attr('name').replace(/_template_key_row_/, lastRow)); + $select.attr('id', $select.attr('id').replace(/_template_key_row_/, lastRow)); + + return false; + }, + + changeContent: function () { + var value = $(this).val(); + $(this).parent().find('.fw-table-cell-content').text(value); + }, + + openEditor: function (e) { + e.stopPropagation(); + var $cell = $(this); + process.closeEditor(); + + if ($cell.find('textarea').length) { + $cell.addClass('fw-cell-show-editor').find('textarea').focus(); + } + $currentCell = $cell; + }, + + closeEditor: function () { + if ($currentCell) { + $currentCell.removeClass('fw-cell-show-editor'); + $currentCell = false; + } + }, + + tableBuilderEvents: function () { + $table.on('click', '.fw-table-col-delete:not(.empty-cell)', process.removeTableColumn); + $table.on('click', '.fw-table-row-delete:not(.empty-cell)', process.removeTableRow); + $table.on('click', worksheetSelector, process.openEditor); + $table.on('change', '.fw-table-cell textarea', process.changeContent); + $table.on('change', 'select.fw-table-builder-col-style', process.changeTableColumnStyle); + $table.on('change', 'select.fw-table-builder-row-style', process.changeTableRowStyle); + $table.on('keydown', process.onTabKeyDown); + $table.on('keyup', process.onTabKeyUp); + $table.on('click', '.fw-table-add-column', process.addTableColumn); + $table.on('click', '.fw-table-add-row', process.addTableRow); + $(document).on('click', ':not(.fw-table-cell)', process.closeEditor); + } + + }; + + process.initialize(); + + }; + + fwEvents.on('fw:options:init', function (data) { + data.$elements.find('.fw-option-type-table-builder:not(.fw-option-initialized)').each(function () { + new FwTableBuilder($(this)); + }).addClass('fw-option-initialized'); + }); + }); +}(jQuery)); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/views/view.php new file mode 100644 index 00000000..6dea71a5 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/includes/fw-option-type-table-builder/views/view.php @@ -0,0 +1,149 @@ + + +
    > + +
    + + + + +
    + +
     
    + + $val ) : { ?> + $data['value']['cols'][ $key_col ], + 'id_prefix' => $option['attr']['id'] . '-cols-', + 'name_prefix' => $option['attr']['name'] . '[cols]' + ); + ?> + +
    + backend->option_type( 'select' )->render( $key_col, $option['columns_options'], $data_cols ); ?> + +
    + + +
     
    + +
    + + + + + $row ) : { ?> + + $data['value']['rows'][ $key_row ], + 'id_prefix' => $option['attr']['id'] . '-rows-', + 'name_prefix' => $option['attr']['name'] . '[rows]' + );?> + +
    +
    '> + backend->option_type( 'select' )->render( $key_row, $option['row_options'], $data_rows ); ?> +
    + + $cell_value ): { ?> +
    ' + data-col=""> +
    + ' . $cell_value . '' ?> +
    + + +
    + +
    + +
    + + + + + +
    + +
    + '', + 'id_prefix' => $option['attr']['id'] . '-rows-', + 'name_prefix' => $option['attr']['name'] . '[rows]' + ); + + ?> + backend->option_type( 'select' )->render( '_template_key_row_', $option['row_options'], $data_rows ); ?> +
    + + $val ) : { ?> + $data['value']['cols'][ $key_col ], + 'id_prefix' => $option['attr']['id'] . '-cols-', + 'name_prefix' => $option['attr']['name'] . '[cols]' + ); + ?> +
    ' + data-col=""> +
    + + ' ?> +
    + + +
    + +
    + +
    + + + +
    + +
    +
    + + $val ) : { ?> + $data['value']['cols'][ $key_col ], + 'id_prefix' => $option['attr']['id'] . '-cols-', + 'name_prefix' => $option['attr']['name'] . '[cols]' + ); + ?> +
    + +
    + + +
     
    + +
    + + +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/options.php b/scratch-parent/framework-customizations/theme/shortcodes/table/options.php new file mode 100644 index 00000000..d39b4e14 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/options.php @@ -0,0 +1,21 @@ + array( + 'type' => 'select', + 'label' => __( 'Table Styling', 'fw' ), + 'help' => 'There you can select some styling for your table.', + 'desc' => __( 'Choose table styling options', 'fw' ), + 'choices' => array( + 'pricing' => __( 'Use the table as a pricing table', 'fw' ), + 'tabular' => __( 'Use the table to display tabular data', 'fw' ) + ), + ), + 'table' => array( + 'type' => 'table-builder', + 'label' => false, + 'desc' => false, + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/table/static/img/layout_builder.png new file mode 100644 index 00000000..132f724b Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/table/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/views/pricing.php b/scratch-parent/framework-customizations/theme/shortcodes/table/views/pricing.php new file mode 100644 index 00000000..516d1fe0 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/views/pricing.php @@ -0,0 +1,38 @@ + + +
    + $col ) : ?> + +
    + +
    + $row ) : + if( $row == 'heading-row' ) : ?> +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/table/views/tabular.php b/scratch-parent/framework-customizations/theme/shortcodes/table/views/tabular.php new file mode 100644 index 00000000..66d20f2c --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/table/views/tabular.php @@ -0,0 +1,28 @@ + + + + $row ) : ?> + + + + $col ) : ?> + + + + + + + $col ) : ?> + + + + + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/tabs/config.php b/scratch-parent/framework-customizations/theme/shortcodes/tabs/config.php new file mode 100644 index 00000000..f67f15ca --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/tabs/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Tabs', 'fw' ), + 'description' => __( 'Create awesome tabs', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/tabs/options.php b/scratch-parent/framework-customizations/theme/shortcodes/tabs/options.php new file mode 100644 index 00000000..321a32ef --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/tabs/options.php @@ -0,0 +1,23 @@ + array( + 'type' => 'addable-popup', + 'label' => __( 'Tabs', 'fw' ), + 'popup-title' => __( 'Add/Edit Tab', 'fw' ), + 'desc' => __( 'Create your tabs', 'fw' ), + 'template' => '{{=tab_title}}', + 'popup-options' => array( + 'tab_title' => array( + 'type' => 'text', + 'label' => __('Title', 'fw') + ), + 'tab_content' => array( + 'type' => 'textarea', + 'label' => __('Content', 'fw') + ) + ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/tabs/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/tabs/static/img/layout_builder.png new file mode 100644 index 00000000..3b75db8b Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/tabs/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/tabs/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/tabs/views/view.php new file mode 100644 index 00000000..f357425d --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/tabs/views/view.php @@ -0,0 +1,33 @@ + + +
    +
    +
      + +
    • + +
    +
    + +
    +

    +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/team-member/config.php b/scratch-parent/framework-customizations/theme/shortcodes/team-member/config.php new file mode 100644 index 00000000..648d376f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/team-member/config.php @@ -0,0 +1,12 @@ + array( + 'title' => __( 'Team Member', 'fw' ), + 'description' => __( 'A very awesome team member', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + 'popup_size' => 'medium' + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/team-member/options.php b/scratch-parent/framework-customizations/theme/shortcodes/team-member/options.php new file mode 100644 index 00000000..2699fee1 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/team-member/options.php @@ -0,0 +1,41 @@ + array( + 'label' => __( 'Team Member Name', 'fw' ), + 'desc' => __( 'Name of the person', 'fw' ), + 'type' => 'text', + 'value' => '' + ), + 'image' => array( + 'label' => __( 'Team Member Image', 'fw' ), + 'desc' => __( 'Either upload a new, or choose an existing image from your media library', 'fw' ), + 'type' => 'upload' + ), + 'desc' => array( + 'label' => __( 'Team Member Description', 'fw' ), + 'desc' => __( 'Enter a few words that describe the person', 'fw' ), + 'type' => 'textarea', + 'value' => '' + ), + 'job' => array( + 'label' => __( 'Team Member Job Title', 'fw' ), + 'desc' => __( 'Job title of the person.', 'fw' ), + 'type' => 'text', + 'value' => '' + ), + 'site' => array( + 'label' => __( 'Company Name', 'fw' ), + 'desc' => __( 'Team Member Company name', 'fw' ), + 'type' => 'text', + 'value' => '' + ), + 'link' => array( + 'label' => __( 'Web Site Link', 'fw' ), + 'desc' => __( 'Job web site link address of the person.', 'fw' ), + 'type' => 'text', + 'value' => '' + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/team-member/static/css/styles.css b/scratch-parent/framework-customizations/theme/shortcodes/team-member/static/css/styles.css new file mode 100644 index 00000000..c228a71f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/team-member/static/css/styles.css @@ -0,0 +1,16 @@ +.team-member-wrapper { + width: 100%; + display: block; +} + +.team-member-wrapper div { + float: left; +} + +.team-member-wrapper div span { + float: left; +} + +.team-member-wrapper div span a { + padding: 10px; +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/team-member/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/team-member/static/img/layout_builder.png new file mode 100644 index 00000000..7d8e287a Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/team-member/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/team-member/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/team-member/views/view.php new file mode 100644 index 00000000..77c189a2 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/team-member/views/view.php @@ -0,0 +1,21 @@ + +
    + <?php echo $atts['name'] ?> + + + - + + +

    +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/testimonials/class-fw-shortcode-testimonials.php b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/class-fw-shortcode-testimonials.php new file mode 100644 index 00000000..6c826c8f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/class-fw-shortcode-testimonials.php @@ -0,0 +1,29 @@ +get_uri() . '/static/js/jquery.carouFredSel-6.2.1-packed.js', + array( 'jquery' ), + fw()->theme->manifest->get_version(), + true + ); + } +} \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/testimonials/config.php b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/config.php new file mode 100644 index 00000000..ba0b2b18 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Testimonials', 'fw' ), + 'description' => __( 'Add related testimonials about you', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/testimonials/options.php b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/options.php new file mode 100644 index 00000000..6a88134f --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/options.php @@ -0,0 +1,46 @@ + array( + 'label' => __( 'Testimonials', 'fw' ), + 'popup-title' => __( 'Add/Edit Testimonial', 'fw' ), + 'desc' => __( 'Here you can add, remove and edit your Testimonials.', 'fw' ), + 'type' => 'addable-popup', + 'template' => '{{=author_name}}', + 'popup-options' => array( + 'content' => array( + 'label' => __( 'Quote', 'fw' ), + 'desc' => __( 'Enter the testimonial here', 'fw' ), + 'type' => 'textarea', + 'teeny' => true + ), + 'author_avatar' => array( + 'label' => __( 'Image', 'fw' ), + 'desc' => __( 'Either upload a new, or choose an existing image from your media library', 'fw' ), + 'type' => 'upload', + ), + 'author_name' => array( + 'label' => __( 'Name', 'fw' ), + 'desc' => __( 'Enter the Name of the Person to quote', 'fw' ), + 'type' => 'text' + ), + 'author_job' => array( + 'label' => __( 'Position', 'fw' ), + 'desc' => __( 'Can be used for a job description', 'fw' ), + 'type' => 'text' + ), + 'site_name' => array( + 'label' => __( 'Website Name', 'fw' ), + 'desc' => __( 'Linktext for the above Link', 'fw' ), + 'type' => 'text' + ), + 'site_url' => array( + 'label' => __( 'Website Link', 'fw' ), + 'desc' => __( 'Link to the Persons website', 'fw' ), + 'type' => 'text' + ) + ) + ) +); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/testimonials/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/static/img/layout_builder.png new file mode 100644 index 00000000..8083b222 Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/testimonials/static/js/jquery.carouFredSel-6.2.1-packed.js b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/static/js/jquery.carouFredSel-6.2.1-packed.js new file mode 100644 index 00000000..cb62fe96 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/static/js/jquery.carouFredSel-6.2.1-packed.js @@ -0,0 +1,1289 @@ +/* + * jQuery carouFredSel 6.2.1 + * Demo's and documentation: + * caroufredsel.dev7studios.com + * + * Copyright (c) 2013 Fred Heusschen + * www.frebsite.nl + * + * Dual licensed under the MIT and GPL licenses. + * http://en.wikipedia.org/wiki/MIT_License + * http://en.wikipedia.org/wiki/GNU_General_Public_License + */ + + +(function ($) { + function sc_setScroll(a, b, c) { + return "transition" == c.transition && "swing" == b && (b = "ease"), { + anims: [], + duration: a, + orgDuration: a, + easing: b, + startTime: getTime() + } + } + + function sc_startScroll(a, b) { + for (var c = 0, d = a.anims.length; d > c; c++) { + var e = a.anims[c]; + e && e[0][b.transition](e[1], a.duration, a.easing, e[2]) + } + } + + function sc_stopScroll(a, b) { + is_boolean(b) || (b = !0), is_object(a.pre) && sc_stopScroll(a.pre, b); + for (var c = 0, d = a.anims.length; d > c; c++) { + var e = a.anims[c]; + e[0].stop(!0), b && (e[0].css(e[1]), is_function(e[2]) && e[2]()) + } + is_object(a.post) && sc_stopScroll(a.post, b) + } + + function sc_afterScroll(a, b, c) { + switch (b && b.remove(), c.fx) { + case"fade": + case"crossfade": + case"cover-fade": + case"uncover-fade": + a.css("opacity", 1), a.css("filter", "") + } + } + + function sc_fireCallbacks(a, b, c, d, e) { + if (b[c] && b[c].call(a, d), e[c].length)for (var f = 0, g = e[c].length; g > f; f++)e[c][f].call(a, d); + return [] + } + + function sc_fireQueue(a, b, c) { + return b.length && (a.trigger(cf_e(b[0][0], c), b[0][1]), b.shift()), b + } + + function sc_hideHiddenItems(a) { + a.each(function () { + var a = $(this); + a.data("_cfs_isHidden", a.is(":hidden")).hide() + }) + } + + function sc_showHiddenItems(a) { + a && a.each(function () { + var a = $(this); + a.data("_cfs_isHidden") || a.show() + }) + } + + function sc_clearTimers(a) { + return a.auto && clearTimeout(a.auto), a.progress && clearInterval(a.progress), a + } + + function sc_mapCallbackArguments(a, b, c, d, e, f, g) { + return { + width: g.width, + height: g.height, + items: {old: a, skipped: b, visible: c}, + scroll: {items: d, direction: e, duration: f} + } + } + + function sc_getDuration(a, b, c, d) { + var e = a.duration; + return "none" == a.fx ? 0 : ("auto" == e ? e = b.scroll.duration / b.scroll.items * c : 10 > e && (e = d / e), 1 > e ? 0 : ("fade" == a.fx && (e /= 2), Math.round(e))) + } + + function nv_showNavi(a, b, c) { + var d = is_number(a.items.minimum) ? a.items.minimum : a.items.visible + 1; + if ("show" == b || "hide" == b)var e = b; else if (d > b) { + debug(c, "Not enough items (" + b + " total, " + d + " needed): Hiding navigation."); + var e = "hide" + } else var e = "show"; + var f = "show" == e ? "removeClass" : "addClass", g = cf_c("hidden", c); + a.auto.button && a.auto.button[e]()[f](g), a.prev.button && a.prev.button[e]()[f](g), a.next.button && a.next.button[e]()[f](g), a.pagination.container && a.pagination.container[e]()[f](g) + } + + function nv_enableNavi(a, b, c) { + if (!a.circular && !a.infinite) { + var d = "removeClass" == b || "addClass" == b ? b : !1, e = cf_c("disabled", c); + if (a.auto.button && d && a.auto.button[d](e), a.prev.button) { + var f = d || 0 == b ? "addClass" : "removeClass"; + a.prev.button[f](e) + } + if (a.next.button) { + var f = d || b == a.items.visible ? "addClass" : "removeClass"; + a.next.button[f](e) + } + } + } + + function go_getObject(a, b) { + return is_function(b) ? b = b.call(a) : is_undefined(b) && (b = {}), b + } + + function go_getItemsObject(a, b) { + return b = go_getObject(a, b), is_number(b) ? b = {visible: b} : "variable" == b ? b = { + visible: b, + width: b, + height: b + } : is_object(b) || (b = {}), b + } + + function go_getScrollObject(a, b) { + return b = go_getObject(a, b), is_number(b) ? b = 50 >= b ? {items: b} : {duration: b} : is_string(b) ? b = {easing: b} : is_object(b) || (b = {}), b + } + + function go_getNaviObject(a, b) { + if (b = go_getObject(a, b), is_string(b)) { + var c = cf_getKeyCode(b); + b = -1 == c ? $(b) : c + } + return b + } + + function go_getAutoObject(a, b) { + return b = go_getNaviObject(a, b), is_jquery(b) ? b = {button: b} : is_boolean(b) ? b = {play: b} : is_number(b) && (b = {timeoutDuration: b}), b.progress && (is_string(b.progress) || is_jquery(b.progress)) && (b.progress = {bar: b.progress}), b + } + + function go_complementAutoObject(a, b) { + return is_function(b.button) && (b.button = b.button.call(a)), is_string(b.button) && (b.button = $(b.button)), is_boolean(b.play) || (b.play = !0), is_number(b.delay) || (b.delay = 0), is_undefined(b.pauseOnEvent) && (b.pauseOnEvent = !0), is_boolean(b.pauseOnResize) || (b.pauseOnResize = !0), is_number(b.timeoutDuration) || (b.timeoutDuration = 10 > b.duration ? 2500 : 5 * b.duration), b.progress && (is_function(b.progress.bar) && (b.progress.bar = b.progress.bar.call(a)), is_string(b.progress.bar) && (b.progress.bar = $(b.progress.bar)), b.progress.bar ? (is_function(b.progress.updater) || (b.progress.updater = $.fn.carouFredSel.progressbarUpdater), is_number(b.progress.interval) || (b.progress.interval = 50)) : b.progress = !1), b + } + + function go_getPrevNextObject(a, b) { + return b = go_getNaviObject(a, b), is_jquery(b) ? b = {button: b} : is_number(b) && (b = {key: b}), b + } + + function go_complementPrevNextObject(a, b) { + return is_function(b.button) && (b.button = b.button.call(a)), is_string(b.button) && (b.button = $(b.button)), is_string(b.key) && (b.key = cf_getKeyCode(b.key)), b + } + + function go_getPaginationObject(a, b) { + return b = go_getNaviObject(a, b), is_jquery(b) ? b = {container: b} : is_boolean(b) && (b = {keys: b}), b + } + + function go_complementPaginationObject(a, b) { + return is_function(b.container) && (b.container = b.container.call(a)), is_string(b.container) && (b.container = $(b.container)), is_number(b.items) || (b.items = !1), is_boolean(b.keys) || (b.keys = !1), is_function(b.anchorBuilder) || is_false(b.anchorBuilder) || (b.anchorBuilder = $.fn.carouFredSel.pageAnchorBuilder), is_number(b.deviation) || (b.deviation = 0), b + } + + function go_getSwipeObject(a, b) { + return is_function(b) && (b = b.call(a)), is_undefined(b) && (b = {onTouch: !1}), is_true(b) ? b = {onTouch: b} : is_number(b) && (b = {items: b}), b + } + + function go_complementSwipeObject(a, b) { + return is_boolean(b.onTouch) || (b.onTouch = !0), is_boolean(b.onMouse) || (b.onMouse = !1), is_object(b.options) || (b.options = {}), is_boolean(b.options.triggerOnTouchEnd) || (b.options.triggerOnTouchEnd = !1), b + } + + function go_getMousewheelObject(a, b) { + return is_function(b) && (b = b.call(a)), is_true(b) ? b = {} : is_number(b) ? b = {items: b} : is_undefined(b) && (b = !1), b + } + + function go_complementMousewheelObject(a, b) { + return b + } + + function gn_getItemIndex(a, b, c, d, e) { + if (is_string(a) && (a = $(a, e)), is_object(a) && (a = $(a, e)), is_jquery(a) ? (a = e.children().index(a), is_boolean(c) || (c = !1)) : is_boolean(c) || (c = !0), is_number(a) || (a = 0), is_number(b) || (b = 0), c && (a += d.first), a += b, d.total > 0) { + for (; a >= d.total;)a -= d.total; + for (; 0 > a;)a += d.total + } + return a + } + + function gn_getVisibleItemsPrev(a, b, c) { + for (var d = 0, e = 0, f = c; f >= 0; f--) { + var g = a.eq(f); + if (d += g.is(":visible") ? g[b.d.outerWidth](!0) : 0, d > b.maxDimension)return e; + 0 == f && (f = a.length), e++ + } + } + + function gn_getVisibleItemsPrevFilter(a, b, c) { + return gn_getItemsPrevFilter(a, b.items.filter, b.items.visibleConf.org, c) + } + + function gn_getScrollItemsPrevFilter(a, b, c, d) { + return gn_getItemsPrevFilter(a, b.items.filter, d, c) + } + + function gn_getItemsPrevFilter(a, b, c, d) { + for (var e = 0, f = 0, g = d, h = a.length; g >= 0; g--) { + if (f++, f == h)return f; + var i = a.eq(g); + if (i.is(b) && (e++, e == c))return f; + 0 == g && (g = h) + } + } + + function gn_getVisibleOrg(a, b) { + return b.items.visibleConf.org || a.children().slice(0, b.items.visible).filter(b.items.filter).length + } + + function gn_getVisibleItemsNext(a, b, c) { + for (var d = 0, e = 0, f = c, g = a.length - 1; g >= f; f++) { + var h = a.eq(f); + if (d += h.is(":visible") ? h[b.d.outerWidth](!0) : 0, d > b.maxDimension)return e; + if (e++, e == g + 1)return e; + f == g && (f = -1) + } + } + + function gn_getVisibleItemsNextTestCircular(a, b, c, d) { + var e = gn_getVisibleItemsNext(a, b, c); + return b.circular || c + e > d && (e = d - c), e + } + + function gn_getVisibleItemsNextFilter(a, b, c) { + return gn_getItemsNextFilter(a, b.items.filter, b.items.visibleConf.org, c, b.circular) + } + + function gn_getScrollItemsNextFilter(a, b, c, d) { + return gn_getItemsNextFilter(a, b.items.filter, d + 1, c, b.circular) - 1 + } + + function gn_getItemsNextFilter(a, b, c, d) { + for (var f = 0, g = 0, h = d, i = a.length - 1; i >= h; h++) { + if (g++, g >= i)return g; + var j = a.eq(h); + if (j.is(b) && (f++, f == c))return g; + h == i && (h = -1) + } + } + + function gi_getCurrentItems(a, b) { + return a.slice(0, b.items.visible) + } + + function gi_getOldItemsPrev(a, b, c) { + return a.slice(c, b.items.visibleConf.old + c) + } + + function gi_getNewItemsPrev(a, b) { + return a.slice(0, b.items.visible) + } + + function gi_getOldItemsNext(a, b) { + return a.slice(0, b.items.visibleConf.old) + } + + function gi_getNewItemsNext(a, b, c) { + return a.slice(c, b.items.visible + c) + } + + function sz_storeMargin(a, b, c) { + b.usePadding && (is_string(c) || (c = "_cfs_origCssMargin"), a.each(function () { + var a = $(this), d = parseInt(a.css(b.d.marginRight), 10); + is_number(d) || (d = 0), a.data(c, d) + })) + } + + function sz_resetMargin(a, b, c) { + if (b.usePadding) { + var d = is_boolean(c) ? c : !1; + is_number(c) || (c = 0), sz_storeMargin(a, b, "_cfs_tempCssMargin"), a.each(function () { + var a = $(this); + a.css(b.d.marginRight, d ? a.data("_cfs_tempCssMargin") : c + a.data("_cfs_origCssMargin")) + }) + } + } + + function sz_storeOrigCss(a) { + a.each(function () { + var a = $(this); + a.data("_cfs_origCss", a.attr("style") || "") + }) + } + + function sz_restoreOrigCss(a) { + a.each(function () { + var a = $(this); + a.attr("style", a.data("_cfs_origCss") || "") + }) + } + + function sz_setResponsiveSizes(a, b) { + var d = (a.items.visible, a.items[a.d.width]), e = a[a.d.height], f = is_percentage(e); + b.each(function () { + var b = $(this), c = d - ms_getPaddingBorderMargin(b, a, "Width"); + b[a.d.width](c), f && b[a.d.height](ms_getPercentage(c, e)) + }) + } + + function sz_setSizes(a, b) { + var c = a.parent(), d = a.children(), e = gi_getCurrentItems(d, b), f = cf_mapWrapperSizes(ms_getSizes(e, b, !0), b, !1); + if (c.css(f), b.usePadding) { + var g = b.padding, h = g[b.d[1]]; + b.align && 0 > h && (h = 0); + var i = e.last(); + i.css(b.d.marginRight, i.data("_cfs_origCssMargin") + h), a.css(b.d.top, g[b.d[0]]), a.css(b.d.left, g[b.d[3]]) + } + return a.css(b.d.width, f[b.d.width] + 2 * ms_getTotalSize(d, b, "width")), a.css(b.d.height, ms_getLargestSize(d, b, "height")), f + } + + function ms_getSizes(a, b, c) { + return [ms_getTotalSize(a, b, "width", c), ms_getLargestSize(a, b, "height", c)] + } + + function ms_getLargestSize(a, b, c, d) { + return is_boolean(d) || (d = !1), is_number(b[b.d[c]]) && d ? b[b.d[c]] : is_number(b.items[b.d[c]]) ? b.items[b.d[c]] : (c = c.toLowerCase().indexOf("width") > -1 ? "outerWidth" : "outerHeight", ms_getTrueLargestSize(a, b, c)) + } + + function ms_getTrueLargestSize(a, b, c) { + for (var d = 0, e = 0, f = a.length; f > e; e++) { + var g = a.eq(e), h = g.is(":visible") ? g[b.d[c]](!0) : 0; + h > d && (d = h) + } + return d + } + + function ms_getTotalSize(a, b, c, d) { + if (is_boolean(d) || (d = !1), is_number(b[b.d[c]]) && d)return b[b.d[c]]; + if (is_number(b.items[b.d[c]]))return b.items[b.d[c]] * a.length; + for (var e = c.toLowerCase().indexOf("width") > -1 ? "outerWidth" : "outerHeight", f = 0, g = 0, h = a.length; h > g; g++) { + var i = a.eq(g); + f += i.is(":visible") ? i[b.d[e]](!0) : 0 + } + return f + } + + function ms_getParentSize(a, b, c) { + var d = a.is(":visible"); + d && a.hide(); + var e = a.parent()[b.d[c]](); + return d && a.show(), e + } + + function ms_getMaxDimension(a, b) { + return is_number(a[a.d.width]) ? a[a.d.width] : b + } + + function ms_hasVariableSizes(a, b, c) { + for (var d = !1, e = !1, f = 0, g = a.length; g > f; f++) { + var h = a.eq(f), i = h.is(":visible") ? h[b.d[c]](!0) : 0; + d === !1 ? d = i : d != i && (e = !0), 0 == d && (e = !0) + } + return e + } + + function ms_getPaddingBorderMargin(a, b, c) { + return a[b.d["outer" + c]](!0) - a[b.d[c.toLowerCase()]]() + } + + function ms_getPercentage(a, b) { + if (is_percentage(b)) { + if (b = parseInt(b.slice(0, -1), 10), !is_number(b))return a; + a *= b / 100 + } + return a + } + + function cf_e(a, b, c, d, e) { + return is_boolean(c) || (c = !0), is_boolean(d) || (d = !0), is_boolean(e) || (e = !1), c && (a = b.events.prefix + a), d && (a = a + "." + b.events.namespace), d && e && (a += b.serialNumber), a + } + + function cf_c(a, b) { + return is_string(b.classnames[a]) ? b.classnames[a] : a + } + + function cf_mapWrapperSizes(a, b, c) { + is_boolean(c) || (c = !0); + var d = b.usePadding && c ? b.padding : [0, 0, 0, 0], e = {}; + return e[b.d.width] = a[0] + d[1] + d[3], e[b.d.height] = a[1] + d[0] + d[2], e + } + + function cf_sortParams(a, b) { + for (var c = [], d = 0, e = a.length; e > d; d++)for (var f = 0, g = b.length; g > f; f++)if (b[f].indexOf(typeof a[d]) > -1 && is_undefined(c[f])) { + c[f] = a[d]; + break + } + return c + } + + function cf_getPadding(a) { + if (is_undefined(a))return [0, 0, 0, 0]; + if (is_number(a))return [a, a, a, a]; + if (is_string(a) && (a = a.split("px").join("").split("em").join("").split(" ")), !is_array(a))return [0, 0, 0, 0]; + for (var b = 0; 4 > b; b++)a[b] = parseInt(a[b], 10); + switch (a.length) { + case 0: + return [0, 0, 0, 0]; + case 1: + return [a[0], a[0], a[0], a[0]]; + case 2: + return [a[0], a[1], a[0], a[1]]; + case 3: + return [a[0], a[1], a[2], a[1]]; + default: + return [a[0], a[1], a[2], a[3]] + } + } + + function cf_getAlignPadding(a, b) { + var c = is_number(b[b.d.width]) ? Math.ceil(b[b.d.width] - ms_getTotalSize(a, b, "width")) : 0; + switch (b.align) { + case"left": + return [0, c]; + case"right": + return [c, 0]; + case"center": + default: + return [Math.ceil(c / 2), Math.floor(c / 2)] + } + } + + function cf_getDimensions(a) { + for (var b = [["width", "innerWidth", "outerWidth", "height", "innerHeight", "outerHeight", "left", "top", "marginRight", 0, 1, 2, 3], ["height", "innerHeight", "outerHeight", "width", "innerWidth", "outerWidth", "top", "left", "marginBottom", 3, 2, 1, 0]], c = b[0].length, d = "right" == a.direction || "left" == a.direction ? 0 : 1, e = {}, f = 0; c > f; f++)e[b[0][f]] = b[d][f]; + return e + } + + function cf_getAdjust(a, b, c, d) { + var e = a; + if (is_function(c))e = c.call(d, e); else if (is_string(c)) { + var f = c.split("+"), g = c.split("-"); + if (g.length > f.length)var h = !0, i = g[0], j = g[1]; else var h = !1, i = f[0], j = f[1]; + switch (i) { + case"even": + e = 1 == a % 2 ? a - 1 : a; + break; + case"odd": + e = 0 == a % 2 ? a - 1 : a; + break; + default: + e = a + } + j = parseInt(j, 10), is_number(j) && (h && (j = -j), e += j) + } + return (!is_number(e) || 1 > e) && (e = 1), e + } + + function cf_getItemsAdjust(a, b, c, d) { + return cf_getItemAdjustMinMax(cf_getAdjust(a, b, c, d), b.items.visibleConf) + } + + function cf_getItemAdjustMinMax(a, b) { + return is_number(b.min) && b.min > a && (a = b.min), is_number(b.max) && a > b.max && (a = b.max), 1 > a && (a = 1), a + } + + function cf_getSynchArr(a) { + is_array(a) || (a = [[a]]), is_array(a[0]) || (a = [a]); + for (var b = 0, c = a.length; c > b; b++)is_string(a[b][0]) && (a[b][0] = $(a[b][0])), is_boolean(a[b][1]) || (a[b][1] = !0), is_boolean(a[b][2]) || (a[b][2] = !0), is_number(a[b][3]) || (a[b][3] = 0); + return a + } + + function cf_getKeyCode(a) { + return "right" == a ? 39 : "left" == a ? 37 : "up" == a ? 38 : "down" == a ? 40 : -1 + } + + function cf_setCookie(a, b, c) { + if (a) { + var d = b.triggerHandler(cf_e("currentPosition", c)); + $.fn.carouFredSel.cookie.set(a, d) + } + } + + function cf_getCookie(a) { + var b = $.fn.carouFredSel.cookie.get(a); + return "" == b ? 0 : b + } + + function in_mapCss(a, b) { + for (var c = {}, d = 0, e = b.length; e > d; d++)c[b[d]] = a.css(b[d]); + return c + } + + function in_complementItems(a, b, c, d) { + return is_object(a.visibleConf) || (a.visibleConf = {}), is_object(a.sizesConf) || (a.sizesConf = {}), 0 == a.start && is_number(d) && (a.start = d), is_object(a.visible) ? (a.visibleConf.min = a.visible.min, a.visibleConf.max = a.visible.max, a.visible = !1) : is_string(a.visible) ? ("variable" == a.visible ? a.visibleConf.variable = !0 : a.visibleConf.adjust = a.visible, a.visible = !1) : is_function(a.visible) && (a.visibleConf.adjust = a.visible, a.visible = !1), is_string(a.filter) || (a.filter = c.filter(":hidden").length > 0 ? ":visible" : "*"), a[b.d.width] || (b.responsive ? (debug(!0, "Set a " + b.d.width + " for the items!"), a[b.d.width] = ms_getTrueLargestSize(c, b, "outerWidth")) : a[b.d.width] = ms_hasVariableSizes(c, b, "outerWidth") ? "variable" : c[b.d.outerWidth](!0)), a[b.d.height] || (a[b.d.height] = ms_hasVariableSizes(c, b, "outerHeight") ? "variable" : c[b.d.outerHeight](!0)), a.sizesConf.width = a.width, a.sizesConf.height = a.height, a + } + + function in_complementVisibleItems(a, b) { + return "variable" == a.items[a.d.width] && (a.items.visibleConf.variable = !0), a.items.visibleConf.variable || (is_number(a[a.d.width]) ? a.items.visible = Math.floor(a[a.d.width] / a.items[a.d.width]) : (a.items.visible = Math.floor(b / a.items[a.d.width]), a[a.d.width] = a.items.visible * a.items[a.d.width], a.items.visibleConf.adjust || (a.align = !1)), ("Infinity" == a.items.visible || 1 > a.items.visible) && (debug(!0, 'Not a valid number of visible items: Set to "variable".'), a.items.visibleConf.variable = !0)), a + } + + function in_complementPrimarySize(a, b, c) { + return "auto" == a && (a = ms_getTrueLargestSize(c, b, "outerWidth")), a + } + + function in_complementSecondarySize(a, b, c) { + return "auto" == a && (a = ms_getTrueLargestSize(c, b, "outerHeight")), a || (a = b.items[b.d.height]), a + } + + function in_getAlignPadding(a, b) { + var c = cf_getAlignPadding(gi_getCurrentItems(b, a), a); + return a.padding[a.d[1]] = c[1], a.padding[a.d[3]] = c[0], a + } + + function in_getResponsiveValues(a, b) { + var d = cf_getItemAdjustMinMax(Math.ceil(a[a.d.width] / a.items[a.d.width]), a.items.visibleConf); + d > b.length && (d = b.length); + var e = Math.floor(a[a.d.width] / d); + return a.items.visible = d, a.items[a.d.width] = e, a[a.d.width] = d * e, a + } + + function bt_pauseOnHoverConfig(a) { + if (is_string(a))var b = a.indexOf("immediate") > -1 ? !0 : !1, c = a.indexOf("resume") > -1 ? !0 : !1; else var b = c = !1; + return [b, c] + } + + function bt_mousesheelNumber(a) { + return is_number(a) ? a : null + } + + function is_null(a) { + return null === a + } + + function is_undefined(a) { + return is_null(a) || a === void 0 || "" === a || "undefined" === a + } + + function is_array(a) { + return a instanceof Array + } + + function is_jquery(a) { + return a instanceof jQuery + } + + function is_object(a) { + return (a instanceof Object || "object" == typeof a) && !is_null(a) && !is_jquery(a) && !is_array(a) && !is_function(a) + } + + function is_number(a) { + return (a instanceof Number || "number" == typeof a) && !isNaN(a) + } + + function is_string(a) { + return (a instanceof String || "string" == typeof a) && !is_undefined(a) && !is_true(a) && !is_false(a) + } + + function is_function(a) { + return a instanceof Function || "function" == typeof a + } + + function is_boolean(a) { + return a instanceof Boolean || "boolean" == typeof a || is_true(a) || is_false(a) + } + + function is_true(a) { + return a === !0 || "true" === a + } + + function is_false(a) { + return a === !1 || "false" === a + } + + function is_percentage(a) { + return is_string(a) && "%" == a.slice(-1) + } + + function getTime() { + return (new Date).getTime() + } + + function deprecated(a, b) { + debug(!0, a + " is DEPRECATED, support for it will be removed. Use " + b + " instead.") + } + + function debug(a, b) { + if (!is_undefined(window.console) && !is_undefined(window.console.log)) { + if (is_object(a)) { + var c = " (" + a.selector + ")"; + a = a.debug + } else var c = ""; + if (!a)return !1; + b = is_string(b) ? "carouFredSel" + c + ": " + b : ["carouFredSel" + c + ":", b], window.console.log(b) + } + return !1 + } + + $.fn.carouFredSel || ($.fn.caroufredsel = $.fn.carouFredSel = function (options, configs) { + if (0 == this.length)return debug(!0, 'No element found for "' + this.selector + '".'), this; + if (this.length > 1)return this.each(function () { + $(this).carouFredSel(options, configs) + }); + var $cfs = this, $tt0 = this[0], starting_position = !1; + $cfs.data("_cfs_isCarousel") && (starting_position = $cfs.triggerHandler("_cfs_triggerEvent", "currentPosition"), $cfs.trigger("_cfs_triggerEvent", ["destroy", !0])); + var FN = {}; + FN._init = function (a, b, c) { + a = go_getObject($tt0, a), a.items = go_getItemsObject($tt0, a.items), a.scroll = go_getScrollObject($tt0, a.scroll), a.auto = go_getAutoObject($tt0, a.auto), a.prev = go_getPrevNextObject($tt0, a.prev), a.next = go_getPrevNextObject($tt0, a.next), a.pagination = go_getPaginationObject($tt0, a.pagination), a.swipe = go_getSwipeObject($tt0, a.swipe), a.mousewheel = go_getMousewheelObject($tt0, a.mousewheel), b && (opts_orig = $.extend(!0, {}, $.fn.carouFredSel.defaults, a)), opts = $.extend(!0, {}, $.fn.carouFredSel.defaults, a), opts.d = cf_getDimensions(opts), crsl.direction = "up" == opts.direction || "left" == opts.direction ? "next" : "prev"; + var d = $cfs.children(), e = ms_getParentSize($wrp, opts, "width"); + if (is_true(opts.cookie) && (opts.cookie = "caroufredsel_cookie_" + conf.serialNumber), opts.maxDimension = ms_getMaxDimension(opts, e), opts.items = in_complementItems(opts.items, opts, d, c), opts[opts.d.width] = in_complementPrimarySize(opts[opts.d.width], opts, d), opts[opts.d.height] = in_complementSecondarySize(opts[opts.d.height], opts, d), opts.responsive && (is_percentage(opts[opts.d.width]) || (opts[opts.d.width] = "100%")), is_percentage(opts[opts.d.width]) && (crsl.upDateOnWindowResize = !0, crsl.primarySizePercentage = opts[opts.d.width], opts[opts.d.width] = ms_getPercentage(e, crsl.primarySizePercentage), opts.items.visible || (opts.items.visibleConf.variable = !0)), opts.responsive ? (opts.usePadding = !1, opts.padding = [0, 0, 0, 0], opts.align = !1, opts.items.visibleConf.variable = !1) : (opts.items.visible || (opts = in_complementVisibleItems(opts, e)), opts[opts.d.width] || (!opts.items.visibleConf.variable && is_number(opts.items[opts.d.width]) && "*" == opts.items.filter ? (opts[opts.d.width] = opts.items.visible * opts.items[opts.d.width], opts.align = !1) : opts[opts.d.width] = "variable"), is_undefined(opts.align) && (opts.align = is_number(opts[opts.d.width]) ? "center" : !1), opts.items.visibleConf.variable && (opts.items.visible = gn_getVisibleItemsNext(d, opts, 0))), "*" == opts.items.filter || opts.items.visibleConf.variable || (opts.items.visibleConf.org = opts.items.visible, opts.items.visible = gn_getVisibleItemsNextFilter(d, opts, 0)), opts.items.visible = cf_getItemsAdjust(opts.items.visible, opts, opts.items.visibleConf.adjust, $tt0), opts.items.visibleConf.old = opts.items.visible, opts.responsive)opts.items.visibleConf.min || (opts.items.visibleConf.min = opts.items.visible), opts.items.visibleConf.max || (opts.items.visibleConf.max = opts.items.visible), opts = in_getResponsiveValues(opts, d, e); else switch (opts.padding = cf_getPadding(opts.padding), "top" == opts.align ? opts.align = "left" : "bottom" == opts.align && (opts.align = "right"), opts.align) { + case"center": + case"left": + case"right": + "variable" != opts[opts.d.width] && (opts = in_getAlignPadding(opts, d), opts.usePadding = !0); + break; + default: + opts.align = !1, opts.usePadding = 0 == opts.padding[0] && 0 == opts.padding[1] && 0 == opts.padding[2] && 0 == opts.padding[3] ? !1 : !0 + } + is_number(opts.scroll.duration) || (opts.scroll.duration = 500), is_undefined(opts.scroll.items) && (opts.scroll.items = opts.responsive || opts.items.visibleConf.variable || "*" != opts.items.filter ? "visible" : opts.items.visible), opts.auto = $.extend(!0, {}, opts.scroll, opts.auto), opts.prev = $.extend(!0, {}, opts.scroll, opts.prev), opts.next = $.extend(!0, {}, opts.scroll, opts.next), opts.pagination = $.extend(!0, {}, opts.scroll, opts.pagination), opts.auto = go_complementAutoObject($tt0, opts.auto), opts.prev = go_complementPrevNextObject($tt0, opts.prev), opts.next = go_complementPrevNextObject($tt0, opts.next), opts.pagination = go_complementPaginationObject($tt0, opts.pagination), opts.swipe = go_complementSwipeObject($tt0, opts.swipe), opts.mousewheel = go_complementMousewheelObject($tt0, opts.mousewheel), opts.synchronise && (opts.synchronise = cf_getSynchArr(opts.synchronise)), opts.auto.onPauseStart && (opts.auto.onTimeoutStart = opts.auto.onPauseStart, deprecated("auto.onPauseStart", "auto.onTimeoutStart")), opts.auto.onPausePause && (opts.auto.onTimeoutPause = opts.auto.onPausePause, deprecated("auto.onPausePause", "auto.onTimeoutPause")), opts.auto.onPauseEnd && (opts.auto.onTimeoutEnd = opts.auto.onPauseEnd, deprecated("auto.onPauseEnd", "auto.onTimeoutEnd")), opts.auto.pauseDuration && (opts.auto.timeoutDuration = opts.auto.pauseDuration, deprecated("auto.pauseDuration", "auto.timeoutDuration")) + }, FN._build = function () { + $cfs.data("_cfs_isCarousel", !0); + var a = $cfs.children(), b = in_mapCss($cfs, ["textAlign", "float", "position", "top", "right", "bottom", "left", "zIndex", "width", "height", "marginTop", "marginRight", "marginBottom", "marginLeft"]), c = "relative"; + switch (b.position) { + case"absolute": + case"fixed": + c = b.position + } + "parent" == conf.wrapper ? sz_storeOrigCss($wrp) : $wrp.css(b), $wrp.css({ + overflow: "hidden", + position: c + }), sz_storeOrigCss($cfs), $cfs.data("_cfs_origCssZindex", b.zIndex), $cfs.css({ + textAlign: "left", + "float": "none", + position: "absolute", + top: 0, + right: "auto", + bottom: "auto", + left: 0, + marginTop: 0, + marginRight: 0, + marginBottom: 0, + marginLeft: 0 + }), sz_storeMargin(a, opts), sz_storeOrigCss(a), opts.responsive && sz_setResponsiveSizes(opts, a) + }, FN._bind_events = function () { + FN._unbind_events(), $cfs.bind(cf_e("stop", conf), function (a, b) { + return a.stopPropagation(), crsl.isStopped || opts.auto.button && opts.auto.button.addClass(cf_c("stopped", conf)), crsl.isStopped = !0, opts.auto.play && (opts.auto.play = !1, $cfs.trigger(cf_e("pause", conf), b)), !0 + }), $cfs.bind(cf_e("finish", conf), function (a) { + return a.stopPropagation(), crsl.isScrolling && sc_stopScroll(scrl), !0 + }), $cfs.bind(cf_e("pause", conf), function (a, b, c) { + if (a.stopPropagation(), tmrs = sc_clearTimers(tmrs), b && crsl.isScrolling) { + scrl.isStopped = !0; + var d = getTime() - scrl.startTime; + scrl.duration -= d, scrl.pre && (scrl.pre.duration -= d), scrl.post && (scrl.post.duration -= d), sc_stopScroll(scrl, !1) + } + if (crsl.isPaused || crsl.isScrolling || c && (tmrs.timePassed += getTime() - tmrs.startTime), crsl.isPaused || opts.auto.button && opts.auto.button.addClass(cf_c("paused", conf)), crsl.isPaused = !0, opts.auto.onTimeoutPause) { + var e = opts.auto.timeoutDuration - tmrs.timePassed, f = 100 - Math.ceil(100 * e / opts.auto.timeoutDuration); + opts.auto.onTimeoutPause.call($tt0, f, e) + } + return !0 + }), $cfs.bind(cf_e("play", conf), function (a, b, c, d) { + a.stopPropagation(), tmrs = sc_clearTimers(tmrs); + var e = [b, c, d], f = ["string", "number", "boolean"], g = cf_sortParams(e, f); + if (b = g[0], c = g[1], d = g[2], "prev" != b && "next" != b && (b = crsl.direction), is_number(c) || (c = 0), is_boolean(d) || (d = !1), d && (crsl.isStopped = !1, opts.auto.play = !0), !opts.auto.play)return a.stopImmediatePropagation(), debug(conf, "Carousel stopped: Not scrolling."); + crsl.isPaused && opts.auto.button && (opts.auto.button.removeClass(cf_c("stopped", conf)), opts.auto.button.removeClass(cf_c("paused", conf))), crsl.isPaused = !1, tmrs.startTime = getTime(); + var h = opts.auto.timeoutDuration + c; + return dur2 = h - tmrs.timePassed, perc = 100 - Math.ceil(100 * dur2 / h), opts.auto.progress && (tmrs.progress = setInterval(function () { + var a = getTime() - tmrs.startTime + tmrs.timePassed, b = Math.ceil(100 * a / h); + opts.auto.progress.updater.call(opts.auto.progress.bar[0], b) + }, opts.auto.progress.interval)), tmrs.auto = setTimeout(function () { + opts.auto.progress && opts.auto.progress.updater.call(opts.auto.progress.bar[0], 100), opts.auto.onTimeoutEnd && opts.auto.onTimeoutEnd.call($tt0, perc, dur2), crsl.isScrolling ? $cfs.trigger(cf_e("play", conf), b) : $cfs.trigger(cf_e(b, conf), opts.auto) + }, dur2), opts.auto.onTimeoutStart && opts.auto.onTimeoutStart.call($tt0, perc, dur2), !0 + }), $cfs.bind(cf_e("resume", conf), function (a) { + return a.stopPropagation(), scrl.isStopped ? (scrl.isStopped = !1, crsl.isPaused = !1, crsl.isScrolling = !0, scrl.startTime = getTime(), sc_startScroll(scrl, conf)) : $cfs.trigger(cf_e("play", conf)), !0 + }), $cfs.bind(cf_e("prev", conf) + " " + cf_e("next", conf), function (a, b, c, d, e) { + if (a.stopPropagation(), crsl.isStopped || $cfs.is(":hidden"))return a.stopImmediatePropagation(), debug(conf, "Carousel stopped or hidden: Not scrolling."); + var f = is_number(opts.items.minimum) ? opts.items.minimum : opts.items.visible + 1; + if (f > itms.total)return a.stopImmediatePropagation(), debug(conf, "Not enough items (" + itms.total + " total, " + f + " needed): Not scrolling."); + var g = [b, c, d, e], h = ["object", "number/string", "function", "boolean"], i = cf_sortParams(g, h); + b = i[0], c = i[1], d = i[2], e = i[3]; + var j = a.type.slice(conf.events.prefix.length); + if (is_object(b) || (b = {}), is_function(d) && (b.onAfter = d), is_boolean(e) && (b.queue = e), b = $.extend(!0, {}, opts[j], b), b.conditions && !b.conditions.call($tt0, j))return a.stopImmediatePropagation(), debug(conf, 'Callback "conditions" returned false.'); + if (!is_number(c)) { + if ("*" != opts.items.filter)c = "visible"; else for (var k = [c, b.items, opts[j].items], i = 0, l = k.length; l > i; i++)if (is_number(k[i]) || "page" == k[i] || "visible" == k[i]) { + c = k[i]; + break + } + switch (c) { + case"page": + return a.stopImmediatePropagation(), $cfs.triggerHandler(cf_e(j + "Page", conf), [b, d]); + case"visible": + opts.items.visibleConf.variable || "*" != opts.items.filter || (c = opts.items.visible) + } + } + if (scrl.isStopped)return $cfs.trigger(cf_e("resume", conf)), $cfs.trigger(cf_e("queue", conf), [j, [b, c, d]]), a.stopImmediatePropagation(), debug(conf, "Carousel resumed scrolling."); + if (b.duration > 0 && crsl.isScrolling)return b.queue && ("last" == b.queue && (queu = []), ("first" != b.queue || 0 == queu.length) && $cfs.trigger(cf_e("queue", conf), [j, [b, c, d]])), a.stopImmediatePropagation(), debug(conf, "Carousel currently scrolling."); + if (tmrs.timePassed = 0, $cfs.trigger(cf_e("slide_" + j, conf), [b, c]), opts.synchronise)for (var m = opts.synchronise, n = [b, c], o = 0, l = m.length; l > o; o++) { + var p = j; + m[o][2] || (p = "prev" == p ? "next" : "prev"), m[o][1] || (n[0] = m[o][0].triggerHandler("_cfs_triggerEvent", ["configuration", p])), n[1] = c + m[o][3], m[o][0].trigger("_cfs_triggerEvent", ["slide_" + p, n]) + } + return !0 + }), $cfs.bind(cf_e("slide_prev", conf), function (a, b, c) { + a.stopPropagation(); + var d = $cfs.children(); + if (!opts.circular && 0 == itms.first)return opts.infinite && $cfs.trigger(cf_e("next", conf), itms.total - 1), a.stopImmediatePropagation(); + if (sz_resetMargin(d, opts), !is_number(c)) { + if (opts.items.visibleConf.variable)c = gn_getVisibleItemsPrev(d, opts, itms.total - 1); else if ("*" != opts.items.filter) { + var e = is_number(b.items) ? b.items : gn_getVisibleOrg($cfs, opts); + c = gn_getScrollItemsPrevFilter(d, opts, itms.total - 1, e) + } else c = opts.items.visible; + c = cf_getAdjust(c, opts, b.items, $tt0) + } + if (opts.circular || itms.total - c < itms.first && (c = itms.total - itms.first), opts.items.visibleConf.old = opts.items.visible, opts.items.visibleConf.variable) { + var f = cf_getItemsAdjust(gn_getVisibleItemsNext(d, opts, itms.total - c), opts, opts.items.visibleConf.adjust, $tt0); + f >= opts.items.visible + c && itms.total > c && (c++, f = cf_getItemsAdjust(gn_getVisibleItemsNext(d, opts, itms.total - c), opts, opts.items.visibleConf.adjust, $tt0)), opts.items.visible = f + } else if ("*" != opts.items.filter) { + var f = gn_getVisibleItemsNextFilter(d, opts, itms.total - c); + opts.items.visible = cf_getItemsAdjust(f, opts, opts.items.visibleConf.adjust, $tt0) + } + if (sz_resetMargin(d, opts, !0), 0 == c)return a.stopImmediatePropagation(), debug(conf, "0 items to scroll: Not scrolling."); + for (debug(conf, "Scrolling " + c + " items backward."), itms.first += c; itms.first >= itms.total;)itms.first -= itms.total; + opts.circular || (0 == itms.first && b.onEnd && b.onEnd.call($tt0, "prev"), opts.infinite || nv_enableNavi(opts, itms.first, conf)), $cfs.children().slice(itms.total - c, itms.total).prependTo($cfs), itms.total < opts.items.visible + c && $cfs.children().slice(0, opts.items.visible + c - itms.total).clone(!0).appendTo($cfs); + var d = $cfs.children(), g = gi_getOldItemsPrev(d, opts, c), h = gi_getNewItemsPrev(d, opts), i = d.eq(c - 1), j = g.last(), k = h.last(); + sz_resetMargin(d, opts); + var l = 0, m = 0; + if (opts.align) { + var n = cf_getAlignPadding(h, opts); + l = n[0], m = n[1] + } + var o = 0 > l ? opts.padding[opts.d[3]] : 0, p = !1, q = $(); + if (c > opts.items.visible && (q = d.slice(opts.items.visibleConf.old, c), "directscroll" == b.fx)) { + var r = opts.items[opts.d.width]; + p = q, i = k, sc_hideHiddenItems(p), opts.items[opts.d.width] = "variable" + } + var s = !1, t = ms_getTotalSize(d.slice(0, c), opts, "width"), u = cf_mapWrapperSizes(ms_getSizes(h, opts, !0), opts, !opts.usePadding), v = 0, w = {}, x = {}, y = {}, z = {}, A = {}, B = {}, C = {}, D = sc_getDuration(b, opts, c, t); + switch (b.fx) { + case"cover": + case"cover-fade": + v = ms_getTotalSize(d.slice(0, opts.items.visible), opts, "width") + } + p && (opts.items[opts.d.width] = r), sz_resetMargin(d, opts, !0), m >= 0 && sz_resetMargin(j, opts, opts.padding[opts.d[1]]), l >= 0 && sz_resetMargin(i, opts, opts.padding[opts.d[3]]), opts.align && (opts.padding[opts.d[1]] = m, opts.padding[opts.d[3]] = l), B[opts.d.left] = -(t - o), C[opts.d.left] = -(v - o), x[opts.d.left] = u[opts.d.width]; + var E = function () { + }, F = function () { + }, G = function () { + }, H = function () { + }, I = function () { + }, J = function () { + }, K = function () { + }, L = function () { + }, M = function () { + }, N = function () { + }, O = function () { + }; + switch (b.fx) { + case"crossfade": + case"cover": + case"cover-fade": + case"uncover": + case"uncover-fade": + s = $cfs.clone(!0).appendTo($wrp) + } + switch (b.fx) { + case"crossfade": + case"uncover": + case"uncover-fade": + s.children().slice(0, c).remove(), s.children().slice(opts.items.visibleConf.old).remove(); + break; + case"cover": + case"cover-fade": + s.children().slice(opts.items.visible).remove(), s.css(C) + } + if ($cfs.css(B), scrl = sc_setScroll(D, b.easing, conf), w[opts.d.left] = opts.usePadding ? opts.padding[opts.d[3]] : 0, ("variable" == opts[opts.d.width] || "variable" == opts[opts.d.height]) && (E = function () { + $wrp.css(u) + }, F = function () { + scrl.anims.push([$wrp, u]) + }), opts.usePadding) { + switch (k.not(i).length && (y[opts.d.marginRight] = i.data("_cfs_origCssMargin"), 0 > l ? i.css(y) : (K = function () { + i.css(y) + }, L = function () { + scrl.anims.push([i, y]) + })), b.fx) { + case"cover": + case"cover-fade": + s.children().eq(c - 1).css(y) + } + k.not(j).length && (z[opts.d.marginRight] = j.data("_cfs_origCssMargin"), G = function () { + j.css(z) + }, H = function () { + scrl.anims.push([j, z]) + }), m >= 0 && (A[opts.d.marginRight] = k.data("_cfs_origCssMargin") + opts.padding[opts.d[1]], I = function () { + k.css(A) + }, J = function () { + scrl.anims.push([k, A]) + }) + } + O = function () { + $cfs.css(w) + }; + var P = opts.items.visible + c - itms.total; + N = function () { + if (P > 0 && ($cfs.children().slice(itms.total).remove(), g = $($cfs.children().slice(itms.total - (opts.items.visible - P)).get().concat($cfs.children().slice(0, P).get()))), sc_showHiddenItems(p), opts.usePadding) { + var a = $cfs.children().eq(opts.items.visible + c - 1); + a.css(opts.d.marginRight, a.data("_cfs_origCssMargin")) + } + }; + var Q = sc_mapCallbackArguments(g, q, h, c, "prev", D, u); + switch (M = function () { + sc_afterScroll($cfs, s, b), crsl.isScrolling = !1, clbk.onAfter = sc_fireCallbacks($tt0, b, "onAfter", Q, clbk), queu = sc_fireQueue($cfs, queu, conf), crsl.isPaused || $cfs.trigger(cf_e("play", conf)) + }, crsl.isScrolling = !0, tmrs = sc_clearTimers(tmrs), clbk.onBefore = sc_fireCallbacks($tt0, b, "onBefore", Q, clbk), b.fx) { + case"none": + $cfs.css(w), E(), G(), I(), K(), O(), N(), M(); + break; + case"fade": + scrl.anims.push([$cfs, {opacity: 0}, function () { + E(), G(), I(), K(), O(), N(), scrl = sc_setScroll(D, b.easing, conf), scrl.anims.push([$cfs, {opacity: 1}, M]), sc_startScroll(scrl, conf) + }]); + break; + case"crossfade": + $cfs.css({opacity: 0}), scrl.anims.push([s, {opacity: 0}]), scrl.anims.push([$cfs, {opacity: 1}, M]), F(), G(), I(), K(), O(), N(); + break; + case"cover": + scrl.anims.push([s, w, function () { + G(), I(), K(), O(), N(), M() + }]), F(); + break; + case"cover-fade": + scrl.anims.push([$cfs, {opacity: 0}]), scrl.anims.push([s, w, function () { + G(), I(), K(), O(), N(), M() + }]), F(); + break; + case"uncover": + scrl.anims.push([s, x, M]), F(), G(), I(), K(), O(), N(); + break; + case"uncover-fade": + $cfs.css({opacity: 0}), scrl.anims.push([$cfs, {opacity: 1}]), scrl.anims.push([s, x, M]), F(), G(), I(), K(), O(), N(); + break; + default: + scrl.anims.push([$cfs, w, function () { + N(), M() + }]), F(), H(), J(), L() + } + return sc_startScroll(scrl, conf), cf_setCookie(opts.cookie, $cfs, conf), $cfs.trigger(cf_e("updatePageStatus", conf), [!1, u]), !0 + }), $cfs.bind(cf_e("slide_next", conf), function (a, b, c) { + a.stopPropagation(); + var d = $cfs.children(); + if (!opts.circular && itms.first == opts.items.visible)return opts.infinite && $cfs.trigger(cf_e("prev", conf), itms.total - 1), a.stopImmediatePropagation(); + if (sz_resetMargin(d, opts), !is_number(c)) { + if ("*" != opts.items.filter) { + var e = is_number(b.items) ? b.items : gn_getVisibleOrg($cfs, opts); + c = gn_getScrollItemsNextFilter(d, opts, 0, e) + } else c = opts.items.visible; + c = cf_getAdjust(c, opts, b.items, $tt0) + } + var f = 0 == itms.first ? itms.total : itms.first; + if (!opts.circular) { + if (opts.items.visibleConf.variable)var g = gn_getVisibleItemsNext(d, opts, c), e = gn_getVisibleItemsPrev(d, opts, f - 1); else var g = opts.items.visible, e = opts.items.visible; + c + g > f && (c = f - e) + } + if (opts.items.visibleConf.old = opts.items.visible, opts.items.visibleConf.variable) { + for (var g = cf_getItemsAdjust(gn_getVisibleItemsNextTestCircular(d, opts, c, f), opts, opts.items.visibleConf.adjust, $tt0); opts.items.visible - c >= g && itms.total > c;)c++, g = cf_getItemsAdjust(gn_getVisibleItemsNextTestCircular(d, opts, c, f), opts, opts.items.visibleConf.adjust, $tt0); + opts.items.visible = g + } else if ("*" != opts.items.filter) { + var g = gn_getVisibleItemsNextFilter(d, opts, c); + opts.items.visible = cf_getItemsAdjust(g, opts, opts.items.visibleConf.adjust, $tt0) + } + if (sz_resetMargin(d, opts, !0), 0 == c)return a.stopImmediatePropagation(), debug(conf, "0 items to scroll: Not scrolling."); + for (debug(conf, "Scrolling " + c + " items forward."), itms.first -= c; 0 > itms.first;)itms.first += itms.total; + opts.circular || (itms.first == opts.items.visible && b.onEnd && b.onEnd.call($tt0, "next"), opts.infinite || nv_enableNavi(opts, itms.first, conf)), itms.total < opts.items.visible + c && $cfs.children().slice(0, opts.items.visible + c - itms.total).clone(!0).appendTo($cfs); + var d = $cfs.children(), h = gi_getOldItemsNext(d, opts), i = gi_getNewItemsNext(d, opts, c), j = d.eq(c - 1), k = h.last(), l = i.last(); + sz_resetMargin(d, opts); + var m = 0, n = 0; + if (opts.align) { + var o = cf_getAlignPadding(i, opts); + m = o[0], n = o[1] + } + var p = !1, q = $(); + if (c > opts.items.visibleConf.old && (q = d.slice(opts.items.visibleConf.old, c), "directscroll" == b.fx)) { + var r = opts.items[opts.d.width]; + p = q, j = k, sc_hideHiddenItems(p), opts.items[opts.d.width] = "variable" + } + var s = !1, t = ms_getTotalSize(d.slice(0, c), opts, "width"), u = cf_mapWrapperSizes(ms_getSizes(i, opts, !0), opts, !opts.usePadding), v = 0, w = {}, x = {}, y = {}, z = {}, A = {}, B = sc_getDuration(b, opts, c, t); + switch (b.fx) { + case"uncover": + case"uncover-fade": + v = ms_getTotalSize(d.slice(0, opts.items.visibleConf.old), opts, "width") + } + p && (opts.items[opts.d.width] = r), opts.align && 0 > opts.padding[opts.d[1]] && (opts.padding[opts.d[1]] = 0), sz_resetMargin(d, opts, !0), sz_resetMargin(k, opts, opts.padding[opts.d[1]]), opts.align && (opts.padding[opts.d[1]] = n, opts.padding[opts.d[3]] = m), A[opts.d.left] = opts.usePadding ? opts.padding[opts.d[3]] : 0; + var C = function () { + }, D = function () { + }, E = function () { + }, F = function () { + }, G = function () { + }, H = function () { + }, I = function () { + }, J = function () { + }, K = function () { + }; + switch (b.fx) { + case"crossfade": + case"cover": + case"cover-fade": + case"uncover": + case"uncover-fade": + s = $cfs.clone(!0).appendTo($wrp), s.children().slice(opts.items.visibleConf.old).remove() + } + switch (b.fx) { + case"crossfade": + case"cover": + case"cover-fade": + $cfs.css("zIndex", 1), s.css("zIndex", 0) + } + if (scrl = sc_setScroll(B, b.easing, conf), w[opts.d.left] = -t, x[opts.d.left] = -v, 0 > m && (w[opts.d.left] += m), ("variable" == opts[opts.d.width] || "variable" == opts[opts.d.height]) && (C = function () { + $wrp.css(u) + }, D = function () { + scrl.anims.push([$wrp, u]) + }), opts.usePadding) { + var L = l.data("_cfs_origCssMargin"); + n >= 0 && (L += opts.padding[opts.d[1]]), l.css(opts.d.marginRight, L), j.not(k).length && (z[opts.d.marginRight] = k.data("_cfs_origCssMargin")), E = function () { + k.css(z) + }, F = function () { + scrl.anims.push([k, z]) + }; + var M = j.data("_cfs_origCssMargin"); + m > 0 && (M += opts.padding[opts.d[3]]), y[opts.d.marginRight] = M, G = function () { + j.css(y) + }, H = function () { + scrl.anims.push([j, y]) + } + } + K = function () { + $cfs.css(A) + }; + var N = opts.items.visible + c - itms.total; + J = function () { + N > 0 && $cfs.children().slice(itms.total).remove(); + var a = $cfs.children().slice(0, c).appendTo($cfs).last(); + if (N > 0 && (i = gi_getCurrentItems(d, opts)), sc_showHiddenItems(p), opts.usePadding) { + if (itms.total < opts.items.visible + c) { + var b = $cfs.children().eq(opts.items.visible - 1); + b.css(opts.d.marginRight, b.data("_cfs_origCssMargin") + opts.padding[opts.d[1]]) + } + a.css(opts.d.marginRight, a.data("_cfs_origCssMargin")) + } + }; + var O = sc_mapCallbackArguments(h, q, i, c, "next", B, u); + switch (I = function () { + $cfs.css("zIndex", $cfs.data("_cfs_origCssZindex")), sc_afterScroll($cfs, s, b), crsl.isScrolling = !1, clbk.onAfter = sc_fireCallbacks($tt0, b, "onAfter", O, clbk), queu = sc_fireQueue($cfs, queu, conf), crsl.isPaused || $cfs.trigger(cf_e("play", conf)) + }, crsl.isScrolling = !0, tmrs = sc_clearTimers(tmrs), clbk.onBefore = sc_fireCallbacks($tt0, b, "onBefore", O, clbk), b.fx) { + case"none": + $cfs.css(w), C(), E(), G(), K(), J(), I(); + break; + case"fade": + scrl.anims.push([$cfs, {opacity: 0}, function () { + C(), E(), G(), K(), J(), scrl = sc_setScroll(B, b.easing, conf), scrl.anims.push([$cfs, {opacity: 1}, I]), sc_startScroll(scrl, conf) + }]); + break; + case"crossfade": + $cfs.css({opacity: 0}), scrl.anims.push([s, {opacity: 0}]), scrl.anims.push([$cfs, {opacity: 1}, I]), D(), E(), G(), K(), J(); + break; + case"cover": + $cfs.css(opts.d.left, $wrp[opts.d.width]()), scrl.anims.push([$cfs, A, I]), D(), E(), G(), J(); + break; + case"cover-fade": + $cfs.css(opts.d.left, $wrp[opts.d.width]()), scrl.anims.push([s, {opacity: 0}]), scrl.anims.push([$cfs, A, I]), D(), E(), G(), J(); + break; + case"uncover": + scrl.anims.push([s, x, I]), D(), E(), G(), K(), J(); + break; + case"uncover-fade": + $cfs.css({opacity: 0}), scrl.anims.push([$cfs, {opacity: 1}]), scrl.anims.push([s, x, I]), D(), E(), G(), K(), J(); + break; + default: + scrl.anims.push([$cfs, w, function () { + K(), J(), I() + }]), D(), F(), H() + } + return sc_startScroll(scrl, conf), cf_setCookie(opts.cookie, $cfs, conf), $cfs.trigger(cf_e("updatePageStatus", conf), [!1, u]), !0 + }), $cfs.bind(cf_e("slideTo", conf), function (a, b, c, d, e, f, g) { + a.stopPropagation(); + var h = [b, c, d, e, f, g], i = ["string/number/object", "number", "boolean", "object", "string", "function"], j = cf_sortParams(h, i); + return e = j[3], f = j[4], g = j[5], b = gn_getItemIndex(j[0], j[1], j[2], itms, $cfs), 0 == b ? !1 : (is_object(e) || (e = !1), "prev" != f && "next" != f && (f = opts.circular ? itms.total / 2 >= b ? "next" : "prev" : 0 == itms.first || itms.first > b ? "next" : "prev"), "prev" == f && (b = itms.total - b), $cfs.trigger(cf_e(f, conf), [e, b, g]), !0) + }), $cfs.bind(cf_e("prevPage", conf), function (a, b, c) { + a.stopPropagation(); + var d = $cfs.triggerHandler(cf_e("currentPage", conf)); + return $cfs.triggerHandler(cf_e("slideToPage", conf), [d - 1, b, "prev", c]) + }), $cfs.bind(cf_e("nextPage", conf), function (a, b, c) { + a.stopPropagation(); + var d = $cfs.triggerHandler(cf_e("currentPage", conf)); + return $cfs.triggerHandler(cf_e("slideToPage", conf), [d + 1, b, "next", c]) + }), $cfs.bind(cf_e("slideToPage", conf), function (a, b, c, d, e) { + a.stopPropagation(), is_number(b) || (b = $cfs.triggerHandler(cf_e("currentPage", conf))); + var f = opts.pagination.items || opts.items.visible, g = Math.ceil(itms.total / f) - 1; + return 0 > b && (b = g), b > g && (b = 0), $cfs.triggerHandler(cf_e("slideTo", conf), [b * f, 0, !0, c, d, e]) + }), $cfs.bind(cf_e("jumpToStart", conf), function (a, b) { + if (a.stopPropagation(), b = b ? gn_getItemIndex(b, 0, !0, itms, $cfs) : 0, b += itms.first, 0 != b) { + if (itms.total > 0)for (; b > itms.total;)b -= itms.total; + $cfs.prepend($cfs.children().slice(b, itms.total)) + } + return !0 + }), $cfs.bind(cf_e("synchronise", conf), function (a, b) { + if (a.stopPropagation(), b)b = cf_getSynchArr(b); else { + if (!opts.synchronise)return debug(conf, "No carousel to synchronise."); + b = opts.synchronise + } + for (var c = $cfs.triggerHandler(cf_e("currentPosition", conf)), d = !0, e = 0, f = b.length; f > e; e++)b[e][0].triggerHandler(cf_e("slideTo", conf), [c, b[e][3], !0]) || (d = !1); + return d + }), $cfs.bind(cf_e("queue", conf), function (a, b, c) { + return a.stopPropagation(), is_function(b) ? b.call($tt0, queu) : is_array(b) ? queu = b : is_undefined(b) || queu.push([b, c]), queu + }), $cfs.bind(cf_e("insertItem", conf), function (a, b, c, d, e) { + a.stopPropagation(); + var f = [b, c, d, e], g = ["string/object", "string/number/object", "boolean", "number"], h = cf_sortParams(f, g); + if (b = h[0], c = h[1], d = h[2], e = h[3], is_object(b) && !is_jquery(b) ? b = $(b) : is_string(b) && (b = $(b)), !is_jquery(b) || 0 == b.length)return debug(conf, "Not a valid object."); + is_undefined(c) && (c = "end"), sz_storeMargin(b, opts), sz_storeOrigCss(b); + var i = c, j = "before"; + "end" == c ? d ? (0 == itms.first ? (c = itms.total - 1, j = "after") : (c = itms.first, itms.first += b.length), 0 > c && (c = 0)) : (c = itms.total - 1, j = "after") : c = gn_getItemIndex(c, e, d, itms, $cfs); + var k = $cfs.children().eq(c); + return k.length ? k[j](b) : (debug(conf, "Correct insert-position not found! Appending item to the end."), $cfs.append(b)), "end" == i || d || itms.first > c && (itms.first += b.length), itms.total = $cfs.children().length, itms.first >= itms.total && (itms.first -= itms.total), $cfs.trigger(cf_e("updateSizes", conf)), $cfs.trigger(cf_e("linkAnchors", conf)), !0 + }), $cfs.bind(cf_e("removeItem", conf), function (a, b, c, d) { + a.stopPropagation(); + var e = [b, c, d], f = ["string/number/object", "boolean", "number"], g = cf_sortParams(e, f); + if (b = g[0], c = g[1], d = g[2], b instanceof $ && b.length > 1)return i = $(), b.each(function () { + var e = $cfs.trigger(cf_e("removeItem", conf), [$(this), c, d]); + e && (i = i.add(e)) + }), i; + if (is_undefined(b) || "end" == b)i = $cfs.children().last(); else { + b = gn_getItemIndex(b, d, c, itms, $cfs); + var i = $cfs.children().eq(b); + i.length && itms.first > b && (itms.first -= i.length) + } + return i && i.length && (i.detach(), itms.total = $cfs.children().length, $cfs.trigger(cf_e("updateSizes", conf))), i + }), $cfs.bind(cf_e("onBefore", conf) + " " + cf_e("onAfter", conf), function (a, b) { + a.stopPropagation(); + var c = a.type.slice(conf.events.prefix.length); + return is_array(b) && (clbk[c] = b), is_function(b) && clbk[c].push(b), clbk[c] + }), $cfs.bind(cf_e("currentPosition", conf), function (a, b) { + if (a.stopPropagation(), 0 == itms.first)var c = 0; else var c = itms.total - itms.first; + return is_function(b) && b.call($tt0, c), c + }), $cfs.bind(cf_e("currentPage", conf), function (a, b) { + a.stopPropagation(); + var e, c = opts.pagination.items || opts.items.visible, d = Math.ceil(itms.total / c - 1); + return e = 0 == itms.first ? 0 : itms.first < itms.total % c ? 0 : itms.first != c || opts.circular ? Math.round((itms.total - itms.first) / c) : d, 0 > e && (e = 0), e > d && (e = d), is_function(b) && b.call($tt0, e), e + }), $cfs.bind(cf_e("currentVisible", conf), function (a, b) { + a.stopPropagation(); + var c = gi_getCurrentItems($cfs.children(), opts); + return is_function(b) && b.call($tt0, c), c + }), $cfs.bind(cf_e("slice", conf), function (a, b, c, d) { + if (a.stopPropagation(), 0 == itms.total)return !1; + var e = [b, c, d], f = ["number", "number", "function"], g = cf_sortParams(e, f); + if (b = is_number(g[0]) ? g[0] : 0, c = is_number(g[1]) ? g[1] : itms.total, d = g[2], b += itms.first, c += itms.first, items.total > 0) { + for (; b > itms.total;)b -= itms.total; + for (; c > itms.total;)c -= itms.total; + for (; 0 > b;)b += itms.total; + for (; 0 > c;)c += itms.total + } + var i, h = $cfs.children(); + return i = c > b ? h.slice(b, c) : $(h.slice(b, itms.total).get().concat(h.slice(0, c).get())), is_function(d) && d.call($tt0, i), i + }), $cfs.bind(cf_e("isPaused", conf) + " " + cf_e("isStopped", conf) + " " + cf_e("isScrolling", conf), function (a, b) { + a.stopPropagation(); + var c = a.type.slice(conf.events.prefix.length), d = crsl[c]; + return is_function(b) && b.call($tt0, d), d + }), $cfs.bind(cf_e("configuration", conf), function (e, a, b, c) { + e.stopPropagation(); + var reInit = !1; + if (is_function(a))a.call($tt0, opts); else if (is_object(a))opts_orig = $.extend(!0, {}, opts_orig, a), b !== !1 ? reInit = !0 : opts = $.extend(!0, {}, opts, a); else if (!is_undefined(a))if (is_function(b)) { + var val = eval("opts." + a); + is_undefined(val) && (val = ""), b.call($tt0, val) + } else { + if (is_undefined(b))return eval("opts." + a); + "boolean" != typeof c && (c = !0), eval("opts_orig." + a + " = b"), c !== !1 ? reInit = !0 : eval("opts." + a + " = b") + } + if (reInit) { + sz_resetMargin($cfs.children(), opts), FN._init(opts_orig), FN._bind_buttons(); + var sz = sz_setSizes($cfs, opts); + $cfs.trigger(cf_e("updatePageStatus", conf), [!0, sz]) + } + return opts + }), $cfs.bind(cf_e("linkAnchors", conf), function (a, b, c) { + return a.stopPropagation(), is_undefined(b) ? b = $("body") : is_string(b) && (b = $(b)), is_jquery(b) && 0 != b.length ? (is_string(c) || (c = "a.caroufredsel"), b.find(c).each(function () { + var a = this.hash || ""; + a.length > 0 && -1 != $cfs.children().index($(a)) && $(this).unbind("click").click(function (b) { + b.preventDefault(), $cfs.trigger(cf_e("slideTo", conf), a) + }) + }), !0) : debug(conf, "Not a valid object.") + }), $cfs.bind(cf_e("updatePageStatus", conf), function (a, b) { + if (a.stopPropagation(), opts.pagination.container) { + var d = opts.pagination.items || opts.items.visible, e = Math.ceil(itms.total / d); + b && (opts.pagination.anchorBuilder && (opts.pagination.container.children().remove(), opts.pagination.container.each(function () { + for (var a = 0; e > a; a++) { + var b = $cfs.children().eq(gn_getItemIndex(a * d, 0, !0, itms, $cfs)); + $(this).append(opts.pagination.anchorBuilder.call(b[0], a + 1)) + } + })), opts.pagination.container.each(function () { + $(this).children().unbind(opts.pagination.event).each(function (a) { + $(this).bind(opts.pagination.event, function (b) { + b.preventDefault(), $cfs.trigger(cf_e("slideTo", conf), [a * d, -opts.pagination.deviation, !0, opts.pagination]) + }) + }) + })); + var f = $cfs.triggerHandler(cf_e("currentPage", conf)) + opts.pagination.deviation; + return f >= e && (f = 0), 0 > f && (f = e - 1), opts.pagination.container.each(function () { + $(this).children().removeClass(cf_c("selected", conf)).eq(f).addClass(cf_c("selected", conf)) + }), !0 + } + }), $cfs.bind(cf_e("updateSizes", conf), function () { + var b = opts.items.visible, c = $cfs.children(), d = ms_getParentSize($wrp, opts, "width"); + if (itms.total = c.length, crsl.primarySizePercentage ? (opts.maxDimension = d, opts[opts.d.width] = ms_getPercentage(d, crsl.primarySizePercentage)) : opts.maxDimension = ms_getMaxDimension(opts, d), opts.responsive ? (opts.items.width = opts.items.sizesConf.width, opts.items.height = opts.items.sizesConf.height, opts = in_getResponsiveValues(opts, c, d), b = opts.items.visible, sz_setResponsiveSizes(opts, c)) : opts.items.visibleConf.variable ? b = gn_getVisibleItemsNext(c, opts, 0) : "*" != opts.items.filter && (b = gn_getVisibleItemsNextFilter(c, opts, 0)), !opts.circular && 0 != itms.first && b > itms.first) { + if (opts.items.visibleConf.variable)var e = gn_getVisibleItemsPrev(c, opts, itms.first) - itms.first; else if ("*" != opts.items.filter)var e = gn_getVisibleItemsPrevFilter(c, opts, itms.first) - itms.first; else var e = opts.items.visible - itms.first; + debug(conf, "Preventing non-circular: sliding " + e + " items backward."), $cfs.trigger(cf_e("prev", conf), e) + } + opts.items.visible = cf_getItemsAdjust(b, opts, opts.items.visibleConf.adjust, $tt0), opts.items.visibleConf.old = opts.items.visible, opts = in_getAlignPadding(opts, c); + var f = sz_setSizes($cfs, opts); + return $cfs.trigger(cf_e("updatePageStatus", conf), [!0, f]), nv_showNavi(opts, itms.total, conf), nv_enableNavi(opts, itms.first, conf), f + }), $cfs.bind(cf_e("destroy", conf), function (a, b) { + return a.stopPropagation(), tmrs = sc_clearTimers(tmrs), $cfs.data("_cfs_isCarousel", !1), $cfs.trigger(cf_e("finish", conf)), b && $cfs.trigger(cf_e("jumpToStart", conf)), sz_restoreOrigCss($cfs.children()), sz_restoreOrigCss($cfs), FN._unbind_events(), FN._unbind_buttons(), "parent" == conf.wrapper ? sz_restoreOrigCss($wrp) : $wrp.replaceWith($cfs), !0 + }), $cfs.bind(cf_e("debug", conf), function () { + return debug(conf, "Carousel width: " + opts.width), debug(conf, "Carousel height: " + opts.height), debug(conf, "Item widths: " + opts.items.width), debug(conf, "Item heights: " + opts.items.height), debug(conf, "Number of items visible: " + opts.items.visible), opts.auto.play && debug(conf, "Number of items scrolled automatically: " + opts.auto.items), opts.prev.button && debug(conf, "Number of items scrolled backward: " + opts.prev.items), opts.next.button && debug(conf, "Number of items scrolled forward: " + opts.next.items), conf.debug + }), $cfs.bind("_cfs_triggerEvent", function (a, b, c) { + return a.stopPropagation(), $cfs.triggerHandler(cf_e(b, conf), c) + }) + }, FN._unbind_events = function () { + $cfs.unbind(cf_e("", conf)), $cfs.unbind(cf_e("", conf, !1)), $cfs.unbind("_cfs_triggerEvent") + }, FN._bind_buttons = function () { + if (FN._unbind_buttons(), nv_showNavi(opts, itms.total, conf), nv_enableNavi(opts, itms.first, conf), opts.auto.pauseOnHover) { + var a = bt_pauseOnHoverConfig(opts.auto.pauseOnHover); + $wrp.bind(cf_e("mouseenter", conf, !1), function () { + $cfs.trigger(cf_e("pause", conf), a) + }).bind(cf_e("mouseleave", conf, !1), function () { + $cfs.trigger(cf_e("resume", conf)) + }) + } + if (opts.auto.button && opts.auto.button.bind(cf_e(opts.auto.event, conf, !1), function (a) { + a.preventDefault(); + var b = !1, c = null; + crsl.isPaused ? b = "play" : opts.auto.pauseOnEvent && (b = "pause", c = bt_pauseOnHoverConfig(opts.auto.pauseOnEvent)), b && $cfs.trigger(cf_e(b, conf), c) + }), opts.prev.button && (opts.prev.button.bind(cf_e(opts.prev.event, conf, !1), function (a) { + a.preventDefault(), $cfs.trigger(cf_e("prev", conf)) + }), opts.prev.pauseOnHover)) { + var a = bt_pauseOnHoverConfig(opts.prev.pauseOnHover); + opts.prev.button.bind(cf_e("mouseenter", conf, !1), function () { + $cfs.trigger(cf_e("pause", conf), a) + }).bind(cf_e("mouseleave", conf, !1), function () { + $cfs.trigger(cf_e("resume", conf)) + }) + } + if (opts.next.button && (opts.next.button.bind(cf_e(opts.next.event, conf, !1), function (a) { + a.preventDefault(), $cfs.trigger(cf_e("next", conf)) + }), opts.next.pauseOnHover)) { + var a = bt_pauseOnHoverConfig(opts.next.pauseOnHover); + opts.next.button.bind(cf_e("mouseenter", conf, !1), function () { + $cfs.trigger(cf_e("pause", conf), a) + }).bind(cf_e("mouseleave", conf, !1), function () { + $cfs.trigger(cf_e("resume", conf)) + }) + } + if (opts.pagination.container && opts.pagination.pauseOnHover) { + var a = bt_pauseOnHoverConfig(opts.pagination.pauseOnHover); + opts.pagination.container.bind(cf_e("mouseenter", conf, !1), function () { + $cfs.trigger(cf_e("pause", conf), a) + }).bind(cf_e("mouseleave", conf, !1), function () { + $cfs.trigger(cf_e("resume", conf)) + }) + } + if ((opts.prev.key || opts.next.key) && $(document).bind(cf_e("keyup", conf, !1, !0, !0), function (a) { + var b = a.keyCode; + b == opts.next.key && (a.preventDefault(), $cfs.trigger(cf_e("next", conf))), b == opts.prev.key && (a.preventDefault(), $cfs.trigger(cf_e("prev", conf))) + }), opts.pagination.keys && $(document).bind(cf_e("keyup", conf, !1, !0, !0), function (a) { + var b = a.keyCode; + b >= 49 && 58 > b && (b = (b - 49) * opts.items.visible, itms.total >= b && (a.preventDefault(), $cfs.trigger(cf_e("slideTo", conf), [b, 0, !0, opts.pagination]))) + }), $.fn.swipe) { + var b = "ontouchstart"in window; + if (b && opts.swipe.onTouch || !b && opts.swipe.onMouse) { + var c = $.extend(!0, {}, opts.prev, opts.swipe), d = $.extend(!0, {}, opts.next, opts.swipe), e = function () { + $cfs.trigger(cf_e("prev", conf), [c]) + }, f = function () { + $cfs.trigger(cf_e("next", conf), [d]) + }; + switch (opts.direction) { + case"up": + case"down": + opts.swipe.options.swipeUp = f, opts.swipe.options.swipeDown = e; + break; + default: + opts.swipe.options.swipeLeft = f, opts.swipe.options.swipeRight = e + } + crsl.swipe && $cfs.swipe("destroy"), $wrp.swipe(opts.swipe.options), $wrp.css("cursor", "move"), crsl.swipe = !0 + } + } + if ($.fn.mousewheel && opts.mousewheel) { + var g = $.extend(!0, {}, opts.prev, opts.mousewheel), h = $.extend(!0, {}, opts.next, opts.mousewheel); + crsl.mousewheel && $wrp.unbind(cf_e("mousewheel", conf, !1)), $wrp.bind(cf_e("mousewheel", conf, !1), function (a, b) { + a.preventDefault(), b > 0 ? $cfs.trigger(cf_e("prev", conf), [g]) : $cfs.trigger(cf_e("next", conf), [h]) + }), crsl.mousewheel = !0 + } + if (opts.auto.play && $cfs.trigger(cf_e("play", conf), opts.auto.delay), crsl.upDateOnWindowResize) { + var i = function () { + $cfs.trigger(cf_e("finish", conf)), opts.auto.pauseOnResize && !crsl.isPaused && $cfs.trigger(cf_e("play", conf)), sz_resetMargin($cfs.children(), opts), $cfs.trigger(cf_e("updateSizes", conf)) + }, j = $(window), k = null; + if ($.debounce && "debounce" == conf.onWindowResize)k = $.debounce(200, i); else if ($.throttle && "throttle" == conf.onWindowResize)k = $.throttle(300, i); else { + var l = 0, m = 0; + k = function () { + var a = j.width(), b = j.height(); + (a != l || b != m) && (i(), l = a, m = b) + } + } + j.bind(cf_e("resize", conf, !1, !0, !0), k) + } + }, FN._unbind_buttons = function () { + var b = (cf_e("", conf), cf_e("", conf, !1)); + ns3 = cf_e("", conf, !1, !0, !0), $(document).unbind(ns3), $(window).unbind(ns3), $wrp.unbind(b), opts.auto.button && opts.auto.button.unbind(b), opts.prev.button && opts.prev.button.unbind(b), opts.next.button && opts.next.button.unbind(b), opts.pagination.container && (opts.pagination.container.unbind(b), opts.pagination.anchorBuilder && opts.pagination.container.children().remove()), crsl.swipe && ($cfs.swipe("destroy"), $wrp.css("cursor", "default"), crsl.swipe = !1), crsl.mousewheel && (crsl.mousewheel = !1), nv_showNavi(opts, "hide", conf), nv_enableNavi(opts, "removeClass", conf) + }, is_boolean(configs) && (configs = {debug: configs}); + var crsl = { + direction: "next", + isPaused: !0, + isScrolling: !1, + isStopped: !1, + mousewheel: !1, + swipe: !1 + }, itms = {total: $cfs.children().length, first: 0}, tmrs = { + auto: null, + progress: null, + startTime: getTime(), + timePassed: 0 + }, scrl = {isStopped: !1, duration: 0, startTime: 0, easing: "", anims: []}, clbk = { + onBefore: [], + onAfter: [] + }, queu = [], conf = $.extend(!0, {}, $.fn.carouFredSel.configs, configs), opts = {}, opts_orig = $.extend(!0, {}, options), $wrp = "parent" == conf.wrapper ? $cfs.parent() : $cfs.wrap("<" + conf.wrapper.element + ' class="' + conf.wrapper.classname + '" />').parent(); + if (conf.selector = $cfs.selector, conf.serialNumber = $.fn.carouFredSel.serialNumber++, conf.transition = conf.transition && $.fn.transition ? "transition" : "animate", FN._init(opts_orig, !0, starting_position), FN._build(), FN._bind_events(), FN._bind_buttons(), is_array(opts.items.start))var start_arr = opts.items.start; else { + var start_arr = []; + 0 != opts.items.start && start_arr.push(opts.items.start) + } + if (opts.cookie && start_arr.unshift(parseInt(cf_getCookie(opts.cookie), 10)), start_arr.length > 0)for (var a = 0, l = start_arr.length; l > a; a++) { + var s = start_arr[a]; + if (0 != s) { + if (s === !0) { + if (s = window.location.hash, 1 > s.length)continue + } else"random" === s && (s = Math.floor(Math.random() * itms.total)); + if ($cfs.triggerHandler(cf_e("slideTo", conf), [s, 0, !0, {fx: "none"}]))break + } + } + var siz = sz_setSizes($cfs, opts), itm = gi_getCurrentItems($cfs.children(), opts); + return opts.onCreate && opts.onCreate.call($tt0, { + width: siz.width, + height: siz.height, + items: itm + }), $cfs.trigger(cf_e("updatePageStatus", conf), [!0, siz]), $cfs.trigger(cf_e("linkAnchors", conf)), conf.debug && $cfs.trigger(cf_e("debug", conf)), $cfs + }, $.fn.carouFredSel.serialNumber = 1, $.fn.carouFredSel.defaults = { + synchronise: !1, + infinite: !0, + circular: !0, + responsive: !1, + direction: "left", + items: {start: 0}, + scroll: {easing: "swing", duration: 500, pauseOnHover: !1, event: "click", queue: !1} + }, $.fn.carouFredSel.configs = { + debug: !1, + transition: !1, + onWindowResize: "throttle", + events: {prefix: "", namespace: "cfs"}, + wrapper: {element: "div", classname: "caroufredsel_wrapper"}, + classnames: {} + }, $.fn.carouFredSel.pageAnchorBuilder = function (a) { + return '' + a + "" + }, $.fn.carouFredSel.progressbarUpdater = function (a) { + $(this).css("width", a + "%") + }, $.fn.carouFredSel.cookie = { + get: function (a) { + a += "="; + for (var b = document.cookie.split(";"), c = 0, d = b.length; d > c; c++) { + for (var e = b[c]; " " == e.charAt(0);)e = e.slice(1); + if (0 == e.indexOf(a))return e.slice(a.length) + } + return 0 + }, set: function (a, b, c) { + var d = ""; + if (c) { + var e = new Date; + e.setTime(e.getTime() + 1e3 * 60 * 60 * 24 * c), d = "; expires=" + e.toGMTString() + } + document.cookie = a + "=" + b + d + "; path=/" + }, remove: function (a) { + $.fn.carouFredSel.cookie.set(a, "", -1) + } + }, $.extend($.easing, { + quadratic: function (a) { + var b = a * a; + return a * (-b * a + 4 * b - 6 * a + 4) + }, cubic: function (a) { + return a * (4 * a * a - 9 * a + 6) + }, elastic: function (a) { + var b = a * a; + return a * (33 * b * b - 106 * b * a + 126 * b - 67 * a + 15) + } + })) +})(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/shortcodes/testimonials/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/views/view.php new file mode 100644 index 00000000..7c95a756 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/testimonials/views/view.php @@ -0,0 +1,75 @@ + + +
    +
      + +
    • +
      +
      <?php echo $testimonial['author_name'] ?>
      + + - + +
      +

      +
    • + +
    +
    + + +
    diff --git a/scratch-parent/framework-customizations/theme/shortcodes/text-block/config.php b/scratch-parent/framework-customizations/theme/shortcodes/text-block/config.php new file mode 100644 index 00000000..d5d4c16a --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/text-block/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Text Block', 'fw' ), + 'description' => __( 'A very awesome text block', 'fw' ), + 'tab' => __( 'Content Elements', 'fw' ), + ) +); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/text-block/options.php b/scratch-parent/framework-customizations/theme/shortcodes/text-block/options.php new file mode 100644 index 00000000..1979973c --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/text-block/options.php @@ -0,0 +1,13 @@ + array( + 'type' => 'wp-editor', + 'teeny' => true, + 'reinit' => true, + 'label' => __( 'Content', 'fw' ), + 'desc' => __( 'Enter some content for this texblock', 'fw' ) + ) +); diff --git a/scratch-parent/framework-customizations/theme/shortcodes/text-block/static/img/layout_builder.png b/scratch-parent/framework-customizations/theme/shortcodes/text-block/static/img/layout_builder.png new file mode 100644 index 00000000..de44cfdb Binary files /dev/null and b/scratch-parent/framework-customizations/theme/shortcodes/text-block/static/img/layout_builder.png differ diff --git a/scratch-parent/framework-customizations/theme/shortcodes/text-block/views/view.php b/scratch-parent/framework-customizations/theme/shortcodes/text-block/views/view.php new file mode 100644 index 00000000..02beee0c --- /dev/null +++ b/scratch-parent/framework-customizations/theme/shortcodes/text-block/views/view.php @@ -0,0 +1,6 @@ + +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/static.php b/scratch-parent/framework-customizations/theme/static.php new file mode 100644 index 00000000..338af447 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/static.php @@ -0,0 +1,100 @@ +theme->manifest->get_version() +); + +// Add Genericons font, used in the main stylesheet. +wp_enqueue_style( + 'genericons', + get_template_directory_uri() . '/genericons/genericons.css', + array(), + fw()->theme->manifest->get_version() +); + +// Load our main stylesheet. +wp_enqueue_style( + 'fw-theme-style', + get_stylesheet_uri(), + array( 'genericons' ), + fw()->theme->manifest->get_version() +); + +// Load the Internet Explorer specific stylesheet. +wp_enqueue_style( + 'fw-theme-ie', + get_template_directory_uri() . '/css/ie.css', + array( 'fw-theme-style', 'genericons' ), + fw()->theme->manifest->get_version() +); +wp_style_add_data( 'fw-theme-ie', 'conditional', 'lt IE 9' ); + +if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { + wp_enqueue_script( 'comment-reply' ); +} + +if ( is_singular() && wp_attachment_is_image() ) { + wp_enqueue_script( + 'fw-theme-keyboard-image-navigation', + get_template_directory_uri() . '/js/keyboard-image-navigation.js', + array( 'jquery' ), + fw()->theme->manifest->get_version() + ); +} + +if ( is_active_sidebar( 'sidebar-1' ) ) { + wp_enqueue_script( 'jquery-masonry' ); +} + +if ( is_front_page() && 'slider' == get_theme_mod( 'featured_content_layout' ) ) { + wp_enqueue_script( + 'fw-theme-slider', + get_template_directory_uri() . '/js/slider.js', + array( 'jquery' ), + fw()->theme->manifest->get_version(), + true + ); + wp_localize_script( 'fw-theme-slider', 'featuredSliderDefaults', array( + 'prevText' => __( 'Previous', 'unyson' ), + 'nextText' => __( 'Next', 'unyson' ) + ) ); +} + +wp_enqueue_script( + 'jquery-ui-tabs', + get_template_directory_uri() . '/js/jquery-ui-1.10.4.custom.js', + array( 'jquery' ), + fw()->theme->manifest->get_version(), + true +); + +wp_enqueue_script( + 'fw-theme-script', + get_template_directory_uri() . '/js/functions.js', + array( 'jquery' ), + fw()->theme->manifest->get_version(), + true +); + +// Font Awesome stylesheet +wp_enqueue_style( + 'font-awesome', + get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css', + array(), + fw()->theme->manifest->get_version() +); diff --git a/scratch-parent/framework-customizations/theme/widgets/blog-tabs/class-fw-widget-blog-tabs.php b/scratch-parent/framework-customizations/theme/widgets/blog-tabs/class-fw-widget-blog-tabs.php new file mode 100644 index 00000000..2a8c1d37 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/widgets/blog-tabs/class-fw-widget-blog-tabs.php @@ -0,0 +1,100 @@ + '' ); + parent::WP_Widget( false, __( 'Blog Tabs', 'fw' ), $widget_ops ); + } + + public function widget( $args, $instance ) { + extract( $args ); + $number = ( (int)( $instance['number'] ) > 0 ) ? esc_attr( $instance['number'] ) : 5; + + $recent_posts = $this->fw_get_posts_with_info( array( + 'sort' => 'post_date', + 'items' => $number, + ) ); + + $popular_posts = $this->fw_get_posts_with_info( array( + 'sort' => 'comment_count', + 'items' => $number, + ) ); + + $this->_theme_action_add_static(); + + $filepath = dirname( __FILE__ ) . '/views/widget.php'; + + $data = array( + 'before_widget' => str_replace( 'class="', 'class="wrap-tabs ', $before_widget ), + 'after_widget' => $after_widget, + 'recent_posts' => $recent_posts, + 'popular_posts' => $popular_posts + ); + + echo fw_render_view( $filepath, $data ); + } + + public function fw_get_posts_with_info( $args = array() ) { + $defaults = array( + 'sort' => 'recent', + 'items' => 5, + 'image_post' => true, + 'date_post' => true, + 'date_format' => 'F jS, Y', + 'post_type' => 'post', + ); + + extract( wp_parse_args( $args, $defaults ) ); + + $query = new WP_Query( array( + 'post_type' => $post_type, + 'orderby' => $sort, + 'order ' => 'DESC', + 'posts_per_page' => $items + ) ); + $result_posts = $query->posts; + + $posts_with_info = array(); + + foreach ( $result_posts as $post ) { + $posts_with_info[ $post->ID ]['post_title'] = $post->post_title; + $posts_with_info[ $post->ID ]['post_link'] = $post->guid; + } + + wp_reset_query(); + + return $posts_with_info; + } + + /** + * @internal + */ + public function _theme_action_add_static() { + wp_enqueue_script( + 'fw-theme-blog-tabs-widget', + FW_PT_THEME_URI . '/widgets/blog-tabs/static/js/scripts.js', + array( 'jquery' ), + fw()->theme->manifest->get_version() + ); + } + + public function update( $new_instance, $old_instance ) { + return $new_instance; + } + + public function form( $instance ) { + $instance = wp_parse_args( (array) $instance, array( 'number' => '', 'title' => '' ) ); + $number = esc_attr( $instance['number'] ); + ?> +

    + + +

    + +
    +
      +
    • + / +
    • +
    +
    + +
    +
      + +
    • + +
    • + +
    +
    + diff --git a/scratch-parent/framework-customizations/theme/widgets/flickr/class-fw-widget-flickr.php b/scratch-parent/framework-customizations/theme/widgets/flickr/class-fw-widget-flickr.php new file mode 100644 index 00000000..1e422640 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/widgets/flickr/class-fw-widget-flickr.php @@ -0,0 +1,68 @@ + '' ); + parent::WP_Widget( false, __( 'Flickr', 'fw' ), $widget_ops ); + } + + function widget( $args, $instance ) { + extract( $args ); + + $flickr_id = esc_attr( $instance['flickr_id'] ); + $title = esc_attr( $instance['title'] ); + $number = ( (int)( esc_attr( $instance['number'] ) ) > 0 ) ? esc_attr( $instance['number'] ) : 9; + + wp_enqueue_script( + 'fw-theme-flickr-widget', + FW_PT_THEME_URI . '/widgets/flickr/static/js/scripts.js', + array( 'jquery' ), + fw()->theme->manifest->get_version() + ); + + $filepath = dirname( __FILE__ ) . '/views/widget.php'; + + $data = array( + 'number' => $number, + 'flickr_id' => $flickr_id, + 'before_widget' => str_replace( 'class="', 'class="widget_flickr_image_gallery ', $before_widget ), + 'after_widget' => $after_widget, + 'title' => str_replace( 'class="', 'class="widget_flickr_image_gallery ', $before_title ) . $title . $after_title, + ); + + echo fw_render_view( $filepath, $data ); + } + + function update( $new_instance, $old_instance ) { + return $new_instance; + } + + function form( $instance ) { + $instance = wp_parse_args( (array) $instance, array( 'flickr_id' => '', 'number' => '', 'title' => '' ) ); + ?> +

    + + +

    +

    + + +

    +

    + + +

    + '); +}); \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/widgets/flickr/views/widget.php b/scratch-parent/framework-customizations/theme/widgets/flickr/views/widget.php new file mode 100644 index 00000000..366e662c --- /dev/null +++ b/scratch-parent/framework-customizations/theme/widgets/flickr/views/widget.php @@ -0,0 +1,22 @@ + +
    +
      + +
    +
    + \ No newline at end of file diff --git a/scratch-parent/framework-customizations/theme/widgets/social/class-fw-widget-social.php b/scratch-parent/framework-customizations/theme/widgets/social/class-fw-widget-social.php new file mode 100644 index 00000000..eb7ee275 --- /dev/null +++ b/scratch-parent/framework-customizations/theme/widgets/social/class-fw-widget-social.php @@ -0,0 +1,68 @@ + __( 'Social links', 'fw' ) ); + + parent::WP_Widget( false, __( 'Social', 'fw' ), $widget_ops ); + } + + function widget( $args, $instance ) { + extract( $args ); + $params = array(); + + foreach ( $instance as $key => $value ) { + $params[ $key ] = $value; + } + + $title = $before_title . $params['widget-title'] . $after_title; + unset($params['widget-title']); + + $filepath = dirname( __FILE__ ) . '/views/widget.php'; + + $data = array( + 'instance' => $params, + 'title' => $title, + 'before_widget' => str_replace( 'class="', 'class="widget_social_links ', $before_widget ), + 'after_widget' => $after_widget, + ); + + echo fw_render_view( $filepath, $data ); + } + + function update( $new_instance, $old_instance ) { + $instance = wp_parse_args( (array) $new_instance, $old_instance ); + + return $instance; + } + + function form( $instance ) { + + $titles = array( + 'widget-title' => __( 'Social Title:', 'fw' ), + 'google' => __( 'Google URL:', 'fw' ), + 'facebook' => __( 'Facebook URL:', 'fw' ), + 'twitter' => __( 'Twitter URL:', 'fw' ), + 'dribbble' => __( 'Dribbble URL:', 'fw' ), + 'vimeo-square' => __( 'Vimeo-square URL:', 'fw' ), + 'linkedin' => __( 'Linkedin URL:', 'fw' ), + 'instagram' => __( 'Instagram URL:', 'fw' ) + ); + + $instance = wp_parse_args( (array) $instance, $titles ); + + foreach ( $instance as $key => $value ) { + ?> +

    + + +

    + + + +
    + +
      + $value ) : + if ( empty( $value ) ) { + continue; + } + ?> +
    • + + + +
    • + +
    +
    + + \ No newline at end of file diff --git a/scratch-parent/framework/LICENSE b/scratch-parent/framework/LICENSE new file mode 100644 index 00000000..ef7e7efc --- /dev/null +++ b/scratch-parent/framework/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/scratch-parent/framework/bootstrap.php b/scratch-parent/framework/bootstrap.php new file mode 100644 index 00000000..3180b8ae --- /dev/null +++ b/scratch-parent/framework/bootstrap.php @@ -0,0 +1,179 @@ + $component) { + if ($component_name === 'manifest') + continue; + + /** @var FW_Component $component */ + $component->_call_init(); +} + +/** + * For Flash Message Helper: + * just start session before headers sent + * to prevent: Warning: session_start(): Cannot send session cookie - headers already sent if flash added to late + */ +FW_Session::get(-1); + +do_action('fw_init'); diff --git a/scratch-parent/framework/core/Fw.php b/scratch-parent/framework/core/Fw.php new file mode 100644 index 00000000..55a8c14e --- /dev/null +++ b/scratch-parent/framework/core/Fw.php @@ -0,0 +1,89 @@ +manifest = new FW_Framework_Manifest($manifest); + } + + require FW_DIR .'/core/extends/class-fw-extension.php'; + require FW_DIR .'/core/extends/class-fw-option-type.php'; + + // components + { + require FW_DIR .'/core/components/extensions.php'; + $this->extensions = new _FW_Component_Extensions(); + + require FW_DIR .'/core/components/backend.php'; + $this->backend = new _FW_Component_Backend(); + + require FW_DIR .'/core/components/theme.php'; + $this->theme = new _FW_Component_Theme(); + } + } +} + +/** + * All framework components should extend this + */ +abstract class FW_Component +{ + /** + * Called after all components instances was created + */ + abstract protected function _init(); + + /** + * If _init() was called + * @var bool + */ + private $initialized = false; + + /** + * @internal + */ + final public function _call_init() + { + if ($this->initialized) { + trigger_error('Already initialized', E_USER_ERROR); + } else { + $this->initialized = true; + } + + $this->_init(); + } +} diff --git a/scratch-parent/framework/core/class-fw-manifest.php b/scratch-parent/framework/core/class-fw-manifest.php new file mode 100644 index 00000000..b45988ae --- /dev/null +++ b/scratch-parent/framework/core/class-fw-manifest.php @@ -0,0 +1,401 @@ + 'wordpress|framework', + * 'requirements' => array('min_version' => '1.2.3', ...) + * ) + * or + * array( + * 'requirement' => 'extension', + * 'extension' => 'extension_name', + * 'requirements' => array('min_version' => '1.2.3', ...) + * ) + */ + private $not_met_requirement; + + /** + * When an requirement that sure will not change is not met and have no sense to execute check_requirements() again + * @var bool + */ + private $not_met_is_final = false; + + /** + * Not met requirement and skipped (not verified) requirements after $this->not_met_requirement was found + * @var array + */ + private $requirements_for_verification; + + private $requirements_verification_never_called = true; + + /** + * @param array $manifest + */ + protected function __construct(array $manifest) + { + $manifest = array_merge(array( + 'name' => null, // title + 'uri' => null, + 'description' => null, + 'version' => '0.0.0', + 'author' => null, + 'author_uri' => null, + + // Custom fields + 'requirements' => array(), + ), $manifest); + + /** + * Merge $manifest['requirements'] + */ + { + $requirements = $manifest['requirements']; + + $manifest['requirements'] = array(); + + foreach ($this->get_default_requirements() as $default_requirement => $default_requirements) { + $manifest['requirements'][ $default_requirement ] = isset($requirements[$default_requirement]) + ? array_merge( + $default_requirements, + $requirements[$default_requirement] + ) + : $default_requirements; + } + + unset($requirements); + } + + $this->requirements_for_verification = $manifest['requirements']; + + $this->manifest = $manifest; + } + + /** + * @return array { 'requirement' => array('min_version' => '..', 'max_version' => '..') } + */ + abstract protected function get_default_requirements(); + + /** + * @return bool + */ + public function requirements_met() + { + if ($this->not_met_is_final) { + return false; + } + + if ($this->requirements_verification_never_called) { + $this->requirements_verification_never_called = false; + + $this->check_requirements(); + } + + return empty($this->requirements_for_verification) && empty($this->not_met_requirement); + } + + /** + * @return bool + */ + public function check_requirements() + { + if ($this->not_met_is_final) { + return false; + } + + if ($this->requirements_met()) { + return true; + } + + $this->not_met_requirement = array(); + + global $wp_version; + + foreach ($this->requirements_for_verification as $requirement => $requirements) { + switch ($requirement) { + case 'wordpress': + if ( + isset($requirements['min_version']) + && + version_compare($wp_version, $requirements['min_version'], '<') + ) { + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'requirements' => $requirements + ); + $this->not_met_is_final = true; + break 2; + } + + if ( + isset($requirements['max_version']) + && + version_compare($wp_version, $requirements['max_version'], '>') + ) { + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'requirements' => $requirements + ); + $this->not_met_is_final = true; + break 2; + } + + // met + unset($this->requirements_for_verification[$requirement]); + break; + case 'framework': + if ( + isset($requirements['min_version']) + && + version_compare(fw()->manifest->get_version(), $requirements['min_version'], '<') + ) { + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'requirements' => $requirements + ); + $this->not_met_is_final = true; + break 2; + } + + if ( + isset($requirements['max_version']) + && + version_compare(fw()->manifest->get_version(), $requirements['max_version'], '>') + ) { + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'requirements' => $requirements + ); + $this->not_met_is_final = true; + break 2; + } + + // met + unset($this->requirements_for_verification[$requirement]); + break; + case 'extensions': + $extensions =& $requirements; + + foreach ($extensions as $extension => $extension_requirements) { + $extension_instance = fw()->extensions->get($extension); + + if (!$extension_instance) { + /** + * extension in requirements does not exists + * maybe try call this method later and maybe will exist, or it really does not exists + */ + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'extension' => $extension, + 'requirements' => $extension_requirements + ); + break 3; + } + + if ( + isset($extension_requirements['min_version']) + && + version_compare($extension_instance->manifest->get_version(), $extension_requirements['min_version'], '<') + ) { + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'extension' => $extension, + 'requirements' => $extension_requirements + ); + $this->not_met_is_final = true; + break 3; + } + + if ( + isset($extension_requirements['max_version']) + && + version_compare($extension_instance->manifest->get_version(), $extension_requirements['max_version'], '>') + ) { + $this->not_met_requirement = array( + 'requirement' => $requirement, + 'extension' => $extension, + 'requirements' => $extension_requirements + ); + $this->not_met_is_final = true; + break 3; + } + + // met + unset($this->requirements_for_verification[$requirement][$extension]); + + } + + if (empty($this->requirements_for_verification[$requirement])) { + // all extensions requirements met + unset($this->requirements_for_verification[$requirement]); + } + break; + } + } + + return $this->requirements_met(); + } + + public function get_version() + { + return $this->manifest['version']; + } + + public function get_name() + { + return $this->manifest['name']; + } + + /** + * @param string $multi_key + * @return mixed|null + */ + public function get($multi_key) + { + return fw_akg($multi_key, $this->manifest); + } +} + +class FW_Framework_Manifest extends FW_Manifest +{ + public function __construct(array $manifest) + { + parent::__construct($manifest); + + if (empty($manifest['name'])) { + $manifest['name'] = __('Framework', 'fw'); + } + + unset($manifest); + } + + protected function get_default_requirements() + { + return array( + 'wordpress' => array( + 'min_version' => '3.9', + /*'max_version' => '10000.0.0',*/ + ), + ); + } +} + +class FW_Theme_Manifest extends FW_Manifest +{ + public function __construct(array $manifest) + { + $manifest_defaults = array( + 'id' => 'default', + ); + + $theme = wp_get_theme(); + + foreach(array( + 'name' => 'Name', + 'uri' => 'ThemeURI', + 'description' => 'Description', + 'version' => 'Version', + 'author' => 'Author', + 'author_uri' => 'AuthorURI', + ) as $manifest_key => $stylesheet_header) { + $header_value = trim($theme->get($stylesheet_header)); + + if (FW_CT) { + switch ($manifest_key) { + case 'version': + case 'uri': + case 'author': + case 'author_uri': + case 'license': + // force parent theme value + $header_value = $theme->parent()->get($stylesheet_header); + break; + default: + if (!$header_value) { + // use parent theme value only if child theme value is empty + $header_value = $theme->parent()->get($stylesheet_header); + } + } + } + + if ($header_value) { + $manifest_defaults[$manifest_key] = $header_value; + } + } + + parent::__construct(array_merge($manifest_defaults, $manifest)); + } + + protected function get_default_requirements() + { + return array( + 'wordpress' => array( + 'min_version' => '3.9', + /*'max_version' => '10000.0.0',*/ + ), + 'framework' => array( + /*'min_version' => '0.0.0', + 'max_version' => '1000.0.0'*/ + ), + 'extensions' => array( + /*'extension_name' => array( + 'min_version' => '0.0.0', + 'max_version' => '1000.0.0' + )*/ + ) + ); + } + + public function get_id() + { + return $this->manifest['id']; + } +} + +class FW_Extension_Manifest extends FW_Manifest +{ + public function __construct(array $manifest) + { + parent::__construct($manifest); + + unset($manifest); + + // unset unnecessary keys + unset($this->manifest['id']); + } + + protected function get_default_requirements() + { + return array( + 'wordpress' => array( + 'min_version' => '3.9', + /*'max_version' => '10000.0.0',*/ + ), + 'framework' => array( + /*'min_version' => '0.0.0', + 'max_version' => '1000.0.0'*/ + ), + 'extensions' => array( + /*'extension_name' => array( + 'min_version' => '0.0.0', + 'max_version' => '1000.0.0' + )*/ + ) + ); + } + + public function get_required_extensions() + { + return $this->manifest['requirements']['extensions']; + } +} \ No newline at end of file diff --git a/scratch-parent/framework/core/components/backend.php b/scratch-parent/framework/core/components/backend.php new file mode 100644 index 00000000..b32dd420 --- /dev/null +++ b/scratch-parent/framework/core/components/backend.php @@ -0,0 +1,1015 @@ + null, + 'term_id' => 0, + ); + + do { + if (!is_admin()) { + break; + } + + // code from /wp-admin/admin.php line 110 + { + if ( isset( $_REQUEST['taxonomy'] ) && taxonomy_exists( $_REQUEST['taxonomy'] ) ) + $taxnow = $_REQUEST['taxonomy']; + else + $taxnow = ''; + } + + if (empty($taxnow)) + break; + + $result['taxonomy'] = $taxnow; + + if (empty($_REQUEST['tag_ID'])) + return $result; + + // code from /wp-admin/edit-tags.php + { + $tag_ID = (int) $_REQUEST['tag_ID']; + } + + $result['term_id'] = $tag_ID; + } while(false); + + $cache_current_taxonomy_data = $result; + + return $cache_current_taxonomy_data; + } + + public function __construct() + { + $this->print_meta_box_content_callback = create_function('$post,$args', 'echo $args["args"];'); + + add_filter('fw_get_settings_page_slug', create_function('', 'return "fw-settings";')); + + { + $this->undefined_option_type = new FW_Option_Type_Undefined(); + + $this->option_types[$this->undefined_option_type->get_type()] = $this->undefined_option_type; + } + } + + protected function _init() + { + if (!is_admin()) { + return; + } + + $this->settings_form = new FW_Form('fw_settings', array( + 'render' => array($this, '_settings_form_render'), + 'validate' => array($this, '_settings_form_validate'), + 'save' => array($this, '_settings_form_save'), + )); + + $this->add_actions(); + } + + private function add_actions() + { + add_action('admin_menu', array($this, '_action_admin_menu'), 10); + add_action('admin_menu', array($this, '_action_admin_change_theme_settings_order'), 9999); + add_action('add_meta_boxes', array($this, '_action_create_post_meta_boxes'), 10, 2); + add_action('save_post', array($this, '_action_save_post'), 10, 2); + add_action('init', array($this, '_action_init'), 20); + add_action('admin_enqueue_scripts', array($this, '_action_admin_enqueue_scripts')); + + // render and submit options from javascript + { + add_action('wp_ajax_fw_backend_options_render', array($this, '_action_ajax_options_render')); + add_action('wp_ajax_fw_backend_options_get_values', array($this, '_action_ajax_options_get_values')); + } + } + + /** + * @param string|FW_Option_Type $option_type_class + * @internal + */ + private function register_option_type($option_type_class) + { + if (is_array($this->option_types_pending_registration)) { + // Option types never requested. Continue adding to pending + $this->option_types_pending_registration[] = $option_type_class; + } else { + if (is_string($option_type_class)) { + $option_type_class = new $option_type_class; + } + + if (!is_subclass_of($option_type_class, 'FW_Option_Type')) { + trigger_error('Invalid option type class '. get_class($option_type_class), E_USER_WARNING); + return; + } + + /** + * @var FW_Option_Type $option_type_class + */ + + $type = $option_type_class->get_type(); + + if (isset($this->option_types[$type])) { + trigger_error('Option type "'. $type .'" already registered', E_USER_WARNING); + return; + } + + $this->option_types[$type] = $option_type_class; + } + } + + private function register_static() + { + if ($this->static_registered) { + return; + } + + wp_register_script( + 'fw-events', + FW_URI .'/static/js/fw-events.js', + array('backbone'), + fw()->manifest->get_version(), + true + ); + wp_register_script( + 'fw-ie-fixes', + FW_URI .'/static/js/ie-fixes.js', + array(), + fw()->manifest->get_version(), + true + ); + + { + wp_register_style( + 'fw', + FW_URI .'/static/css/fw.css', + array(), + fw()->manifest->get_version() + ); + + wp_register_script( + 'fw', + FW_URI .'/static/js/fw.js', + array('jquery', 'fw-events', 'backbone'), + fw()->manifest->get_version(), + true + ); + + wp_localize_script('fw', '_fw_localized', array( + 'FW_URI' => FW_URI, + 'SITE_URI' => site_url(), + )); + } + + { + wp_register_style( + 'fw-backend-options', + FW_URI .'/static/css/backend-options.css', + array('fw', 'qtip'), + fw()->manifest->get_version() + ); + wp_register_script( + 'fw-backend-options', + FW_URI .'/static/js/backend-options.js', + array('fw-events', 'postbox', 'qtip', 'jquery-ui-tabs', 'fw'), + fw()->manifest->get_version(), + true + ); + } + + { + wp_register_style('qtip', + FW_URI .'/static/lib/qtip/css/jquery.qtip.min.css', + array(), + fw()->manifest->get_version() + ); + wp_register_script( + 'qtip', + FW_URI .'/static/lib/qtip/jquery.qtip.min.js', + array('jquery'), + fw()->manifest->get_version() + ); + } + + { + wp_register_style( + 'fw-selectize', + FW_URI .'/static/css/selectize.css', + array(), + fw()->manifest->get_version() + ); + wp_register_script( + 'fw-selectize', + FW_URI .'/static/js/selectize.min.js', + array('jquery', 'fw-ie-fixes'), + fw()->manifest->get_version(), + true + ); + } + + { + wp_register_script( + 'fw-mousewheel', + FW_URI .'/static/js/jquery.mousewheel.min.js', + array('jquery'), + fw()->manifest->get_version(), + true + ); + } + + { + wp_register_style( + 'fw-jscrollpane', + FW_URI . '/static/css/jquery.jscrollpane.css', + array(), + fw()->manifest->get_version() + ); + wp_register_script( 'fw-jscrollpane', + FW_URI . '/static/js/jquery.jscrollpane.min.js', + array( 'jquery', 'fw-mousewheel' ), + fw()->manifest->get_version(), + true + ); + } + + { + wp_register_style( + 'fw-font-awesome', + FW_URI . '/static/lib/font-awesome/css/font-awesome.min.css', + array(), + fw()->manifest->get_version() + ); + } + + { + wp_register_script( + 'backbone-relational', + FW_URI .'/static/lib/backbone-relational/backbone-relational.js', + array('backbone'), + fw()->manifest->get_version(), + true + ); + } + + $this->static_registered = true; + } + + public function _action_admin_menu() + { + add_submenu_page( + 'themes.php', + __('Theme Settings', 'fw'), + __('Theme Settings', 'fw'), + 'manage_options', + apply_filters('fw_get_settings_page_slug', null), + array($this, '_print_settings_page') + ); + } + + public function _action_admin_change_theme_settings_order() { + global $submenu; + + if (!isset($submenu['themes.php'])) { + // probably current user doesn't have this item in menu + return; + } + + $id = apply_filters( 'fw_get_settings_page_slug', '' ); + $index = null; + + foreach ( $submenu['themes.php'] as $key => $sm ) { + if ( $sm[2] == $id ) { + $index = $key; + break; + } + } + + if ( ! empty( $index ) ) { + $item = $submenu['themes.php'][ $index ]; + unset($submenu['themes.php'][$index]); + array_unshift( $submenu['themes.php'], $item ); + } + } + + public function _print_settings_page() + { + echo '
    '; + + $this->settings_form->render(); + + echo '
    '; + } + + /** + * @param string $post_type + * @param WP_Post $post + */ + public function _action_create_post_meta_boxes($post_type, $post) + { + $options = fw()->theme->get_post_options($post_type); + + if (empty($options)) { + return; + } + + $collected = array(); + + fw_collect_first_level_options($collected, $options); + + unset($options); // free memory + + if (empty($collected['boxes'])) + return; // only boxes are allowed on edit post page + + $boxes =& $collected['boxes']; + + unset($collected); // free memory + + $values = fw_get_db_post_option($post->ID); + + foreach ($boxes as $id => &$box) { + $context = isset($box['context']) ? $box['context'] : 'normal'; + $priority = isset($box['priority']) ? $box['priority'] : 'default'; + + add_meta_box( + 'fw-options-box-'. $id, + empty($box['title']) ? ' ' : $box['title'], + $this->print_meta_box_content_callback, + $post_type, + $context, + $priority, + $this->render_options($box['options'], $values) + ); + + unset($box[$id]); // free memory + } + } + + /** + * @param object $term + */ + public function _action_create_taxonomy_options($term) + { + $options = fw()->theme->get_taxonomy_options($term->taxonomy); + + if (empty($options)) + return; + + $collected = array(); + + fw_collect_first_level_options($collected, $options); + + unset($options); + + if (empty($collected['options'])) + return; // only simple options are allowed on taxonomy edit page + + $values = fw_get_db_term_option($term->term_id, $term->taxonomy); + + // fixes word_press style: .form-field input { width: 95% } + echo ''; + + echo $this->render_options($collected['options'], $values, array(), 'taxonomy'); + + unset($options); + } + + public function _action_init() + { + $current_edit_taxonomy = $this->get_current_edit_taxonomy(); + + if ($current_edit_taxonomy['taxonomy']) { + add_action($current_edit_taxonomy['taxonomy'] .'_edit_form_fields', array($this, '_action_create_taxonomy_options'), 10); + } + + if (!empty($_POST)) { + // is form submit + add_action('edited_term', array($this, '_action_term_edit'), 10, 3); // fixme: remove options on term delete + } + } + + /** + * @param int $post_id + * @param WP_Post $post + */ + public function _action_save_post($post_id, $post) + { + if (!fw_is_real_post_save($post_id)) { + return; + } + + $options_values = array_merge( + (array)fw_get_db_post_option($post_id), + fw_get_options_values_from_input( + fw()->theme->get_post_options($post->post_type) + ) + ); + + fw_set_db_post_option($post_id, null, $options_values); + + // find options that requested to be saved in separate meta + foreach (fw_extract_only_options(fw()->theme->get_post_options($post->post_type)) as $option_id => $option) { + if (isset($option['save-to-separate-meta']) && $option['save-to-separate-meta']) { // think of a better key name + fw_update_post_meta($post_id, 'fw_option_'. $option_id, $options_values[$option_id]); + } + } + + do_action('fw_save_post_options', $post_id, $post, $options_values); + } + + public function _action_term_edit($term_id, $tt_id, $taxonomy) + { + if (!isset($_POST['action']) || !isset($_POST['taxonomy'])) { + return; // this is not real term form submit, abort save + } + + fw_set_db_term_option($term_id, $taxonomy, null, + fw_get_options_values_from_input( + fw()->theme->get_taxonomy_options($taxonomy) + ) + ); + } + + public function _action_admin_enqueue_scripts() + { + $this->register_static(); + } + + /** + * Render options html from input json + * + * POST vars: + * - options: '[{option_id: {...}}, {option_id: {...}}, ...]' // Required // String JSON + * - values: {option_id: value, option_id: {...}, ...} // Optional // Object + * - data: {id_prefix: 'fw_options-a-b-', name_prefix: 'fw_options[a][b]'} // Optional // Object + */ + public function _action_ajax_options_render() + { + // options + { + if (!isset($_POST['options'])) { + wp_send_json_error(array( + 'message' => 'No options' + )); + } + + $options = json_decode(FW_Request::POST('options'), true); + + if (!$options) { + wp_send_json_error(array( + 'message' => 'Wrong options' + )); + } + } + + // values + { + if (isset($_POST['values'])) { + $values = FW_Request::POST('values'); + } else { + $values = array(); + } + } + + // data + { + if (isset($_POST['data'])) { + $data = FW_Request::POST('data'); + } else { + $data = array(); + } + } + + /** + * Fix booleans + * + * In POST, booleans are transformed to strings: 'true' and 'false' + * Transform them back to booleans + */ + { + foreach (fw_extract_only_options($options) as $option_id => $option) { + if (!isset($values[$option_id])) { + continue; + } + + /** + * We detect if option is using booleans by sending it a boolean input value + * If it returns a boolean, then it works with booleans + */ + if (!is_bool( + fw()->backend->option_type($option['type'])->get_value_from_input($option, true) + )) { + continue; + } + + if (is_bool($values[$option_id])) { + // value is already boolean, does not need to fix + continue; + } + + $values[$option_id] = ($values[$option_id] === 'true'); + } + } + + wp_send_json_success(array( + 'html' => fw()->backend->render_options($options, $values, $data) + )); + } + + /** + * Get options values from html generated with 'fw_backend_options_render' ajax action + * + * POST vars: + * - options: '[{option_id: {...}}, {option_id: {...}}, ...]' // Required // String JSON + * - fw_options... // Use a jQuery "ajax form submit" to emulate real form submit + * + * Tip: Inside form html, add: + */ + public function _action_ajax_options_get_values() + { + // options + { + if (!isset($_POST['options'])) { + wp_send_json_error(array( + 'message' => 'No options' + )); + } + + $options = json_decode(FW_Request::POST('options'), true); + + if (!$options) { + wp_send_json_error(array( + 'message' => 'Wrong options' + )); + } + } + + // name_prefix + { + if (isset($_POST['name_prefix'])) { + $name_prefix = FW_Request::POST('name_prefix'); + } else { + $name_prefix = FW_Option_Type::get_default_name_prefix(); + } + } + + wp_send_json_success(array( + 'values' => fw_get_options_values_from_input( + $options, + FW_Request::POST($name_prefix, array()) + ) + )); + } + + public function _settings_form_render($data) + { + /** + * wp moves flash message error with js after first h2 + * if there are any h2 on the page it shows it wrong + */ + echo '

    '; + + $options = fw()->theme->get_settings_options(); + + if (empty($options)) { + return $data; + } + + $values = FW_Request::POST(FW_Option_Type::get_default_name_prefix(), fw_get_db_settings_option()); + + echo fw()->backend->render_options($options, $values); + + $data['submit']['html'] = ''; + + return $data; + } + + public function _settings_form_validate($errors) + { + if (!current_user_can('manage_options')) { + $errors['_no_permission'] = __('You have no permissions to change settings options', 'fw');; + } + + return $errors; + } + + public function _settings_form_save($data) + { + fw_set_db_settings_option( + null, + array_merge( + (array)fw_get_db_settings_option(), + fw_get_options_values_from_input( + fw()->theme->get_settings_options() + ) + ) + ); + + FW_Flash_Messages::add('fw_settings_form_saved', __('Options successfuly saved', 'fw'), 'success'); + + $data['redirect'] = fw_current_url(); + + return $data; + } + + /** + * Render options array and return HTML + * Can contain: tabs, boxes and options + */ + public function render_options(&$options, &$values = array(), $options_data = array(), $design = 'default') + { + { + /** + * register scripts and styles + * in case if this method is called before enqueue_scripts action + * and option types has some of these in their dependencies + */ + $this->register_static(); + + + wp_enqueue_style('fw-backend-options'); + wp_enqueue_script('fw-backend-options'); + } + + $collected = array(); + + fw_collect_first_level_options($collected, $options); + + ob_start(); + + if (!empty($collected['tabs'])) { + echo fw_render_view(FW_DIR .'/views/backend-tabs.php', array( + 'tabs' => &$collected['tabs'], + 'values' => &$values, + 'options_data' => $options_data, + )); + } + unset($collected['tabs']); + + if (!empty($collected['boxes'])) { + echo '
    '; + + foreach ($collected['boxes'] as $id => &$box) { + // prepare attributes + { + $attr = isset($box['attr']) ? $box['attr'] : array(); + + unset($attr['id']); // do not allow id overwrite, it is sent in first argument of render_box() + } + + echo $this->render_box( + 'fw-options-box-'. $id, + empty($box['title']) ? ' ' : $box['title'], + $this->render_options($box['options'], $values, $options_data), + array( + 'attr' => $attr + ) + ); + } + + echo '
    '; + } + unset($collected['boxes']); + + if (!empty($collected['groups_and_options'])) { + foreach ($collected['groups_and_options'] as $id => &$option) { + if (isset($option['options'])) { // group + // prepare attributes + { + $attr = isset($option['attr']) ? $option['attr'] : array(); + + $attr['id'] = 'fw-backend-options-group-'. esc_attr($id); + + if (!isset($attr['class'])) { + $attr['class'] = 'fw-backend-options-group'; + } else { + $attr['class'] = 'fw-backend-options-group '. $attr['class']; + } + } + + echo '
    '; + echo $this->render_options($option['options'], $values, $options_data); + echo '
    '; + } else { // option + $data = $options_data; + + $data['value'] = isset($values[$id]) ? $values[$id] : null; + + echo $this->render_option( + $id, + $option, + $data, + $design + ); + } + } + } + unset($collected['options']); + + return ob_get_clean(); + } + + /** + * Render option enclosed in backend design + */ + public function render_option($id, $option, $data = array(), $design = 'default') + { + /** + * register scripts and styles + * in case if this method is called before enqueue_scripts action + * and option types has some of these in their dependencies + */ + $this->register_static(); + + if (!in_array($design, $this->available_render_designs)) { + trigger_error('Invalid render design specified: '. $design, E_USER_WARNING); + $design = 'post'; + } + + if (!isset($data['id_prefix'])) { + $data['id_prefix'] = FW_Option_Type::get_default_id_prefix(); + } + + return fw_render_view(FW_DIR .'/views/backend-option-design-'. $design .'.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + )); + } + + /** + * Render a meta box + * @param string $id + * @param string $title + * @param string $content HTML + * @param array $other Optional elements + * @return string Generated meta box html + */ + public function render_box($id, $title, $content, $other = array()) + { + if (!function_exists('add_meta_box')) { + trigger_error('Try call this method later (\'admin_init\' action), add_meta_box() function does not exists yet.', E_USER_WARNING); + return ''; + } + + $other = array_merge(array( + 'html_before_title' => false, + 'html_after_title' => false, + 'attr' => array(), + ), $other); + + { + $placeholders = array( + 'id' => '{{meta_box_id}}', + 'title' => '{{meta_box_title}}', + 'content' => '{{meta_box_content}}', + ); + + // other placeholders + { + $placeholders['html_before_title'] = '{{meta_box_html_before_title}}'; + $placeholders['html_after_title'] = '{{meta_box_html_after_title}}'; + $placeholders['attr'] = '{{meta_box_attr}}'; + $placeholders['attr_class'] = '{{meta_box_attr_class}}'; + } + } + + $cache_key = 'fw_meta_box_template'; + + try { + $meta_box_template = FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $temp_screen_id = 'fw-temp-meta-box-screen-id-'. fw_unique_increment(); + $context = 'normal'; + + add_meta_box( + $placeholders['id'], + $placeholders['title'], + $this->print_meta_box_content_callback, + $temp_screen_id, + $context, + 'default', + $placeholders['content'] + ); + + ob_start(); + + do_meta_boxes($temp_screen_id, $context, null); + + $meta_box_template = ob_get_clean(); + + remove_meta_box($id, $temp_screen_id, $context); + + // remove wrapper div, leave only meta box div + { + //
    + { + $meta_box_template = str_replace( + '
    ', + '', + $meta_box_template + ); + } + + //
    + { + $meta_box_template = explode('
    ', $meta_box_template); + array_pop($meta_box_template); + $meta_box_template = implode('
    ', $meta_box_template); + } + } + + // add 'fw-postbox' class and some attr related placeholders + $meta_box_template = str_replace( + 'class="postbox', + $placeholders['attr'] .' class="postbox fw-postbox'. $placeholders['attr_class'], + $meta_box_template + ); + + // add html_before|after_title placeholders + { + $meta_box_template = str_replace( + ''. $placeholders['title'] .'', + + /** + * used not because there is a lot of css and js + * that thinks inside

    there is only one + * so do not brake their logic + */ + ''. $placeholders['html_before_title'] .''. + ''. $placeholders['title'] .''. + ''. $placeholders['html_after_title'] .'', + + $meta_box_template + ); + } + + FW_Cache::set($cache_key, $meta_box_template); + } + + // prepare attributes + { + $attr_class = ''; + if (isset($other['attr']['class'])) { + $attr_class = ' '. $other['attr']['class']; + + unset($other['attr']['class']); + } + + unset($other['attr']['id']); + } + + // replace placeholders with data/content + return str_replace( + array( + $placeholders['id'], + $placeholders['title'], + $placeholders['content'], + + $placeholders['html_before_title'], + $placeholders['html_after_title'], + $placeholders['attr'], + $placeholders['attr_class'], + ), + array( + esc_attr($id), + $title, + $content, + + $other['html_before_title'], + $other['html_after_title'], + fw_attr_to_html($other['attr']), + esc_attr($attr_class) + ), + $meta_box_template + ); + } + + /** + * @param FW_Access_Key $access_key + * @param string|FW_Option_Type $option_type_class + * @internal + */ + public function _register_option_type(FW_Access_Key $access_key, $option_type_class) + { + if ($access_key->get_key() !== 'register_option_type') { + trigger_error('Call denied', E_USER_ERROR); + } + + $this->register_option_type($option_type_class); + } + + /** + * @param string $option_type + * @return FW_Option_Type|FW_Option_Type_Undefined + */ + public function option_type($option_type) + { + if (is_array($this->option_types_pending_registration)) { + // This method is called first time. Register pending option types + $pending_option_types = $this->option_types_pending_registration; + + // clear this property, so register_option_type() will not add option types to pending anymore + $this->option_types_pending_registration = false; + + foreach ($pending_option_types as $option_type_class) { + $this->register_option_type($option_type_class); + } + + unset($pending_option_types); + } + + if (isset($this->option_types[$option_type])) { + return $this->option_types[$option_type]; + } else { + if (is_admin()) { + FW_Flash_Messages::add( + 'fw-get-option-type-undefined-'. $option_type, + sprintf(__('Undefined option type: %s', 'fw'), $option_type), + 'warning' + ); + } + + return $this->undefined_option_type; + } + } +} + +/** + * This will be returned when tried to get not existing option type + * to prevent fatal errors for cases when just one option type was typed wrong + * or any other minor bug that has no sense to crash the whole site + */ +final class FW_Option_Type_Undefined extends FW_Option_Type +{ + public function get_type() + { + return ''; + } + + /** + * @internal + */ + protected function _render($id, $name, $data) + { + return '/* '. __('UNDEFINED OPTION TYPE', 'fw') .' */'; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return $option['value']; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array() + ); + } +} \ No newline at end of file diff --git a/scratch-parent/framework/core/components/extensions.php b/scratch-parent/framework/core/components/extensions.php new file mode 100644 index 00000000..33885bcb --- /dev/null +++ b/scratch-parent/framework/core/components/extensions.php @@ -0,0 +1,549 @@ + instance } + */ + private static $all_extensions = array(); + + /** + * All existing extensions names arranged in hierarchical tree like they are in directories + * @var array + */ + private static $all_extensions_tree = array(); + + /** + * Active extensions + * Only this extensions should be available for other, inactive extensions = + * @var FW_Extension[] { 'extension_name' => instance } + */ + private static $active_extensions = array(); + + /** + * Active extensions names arranged in hierarchical tree like they are in directories + * @var array + */ + private static $active_extensions_tree = array(); + + /** + * Used on extensions load + * Indicates from where are currently extensions loaded + * @var string|null framework|parent|child + */ + private static $current_declaring_source; + + /** + * @var array { 'extension_name' => array('required_by', 'required_by') } + */ + private static $extensions_required_by_extensions = array(); + + /** + * @var array { 'extension_name' => &array() } + */ + private static $extension_to_all_tree = array(); + + /** + * @var array { 'extension_name' => &array() } + */ + private static $extension_to_active_tree = array(); + + private static $blacklist = array(); + + /** + * Load extension from directory + * + * @param null|FW_Extension $parent + * @param array $all_extensions_tree + * @param FW_Extension[] $all_extensions + * @param string $dir + * @param string $URI + * @var int $current_depth + */ + private static function load_extensions($dir, &$parent, &$all_extensions_tree, &$all_extensions, $URI, $current_depth) + { + $dirs = glob($dir .'/*', GLOB_ONLYDIR); + + if (empty($dirs)) { + return; + } + + foreach ($dirs as $extension_dir) { + $extension_name = basename($extension_dir); + + if (isset($all_extensions_tree[$extension_name])) { + if ($all_extensions[$extension_name]->get_parent() !== $parent) { + // extension with the same name exists in another tree + trigger_error('Extension "'. $extension_name .'" already loaded', E_USER_ERROR); + } + + // this is not original extension, it contains only settings, has no class + + self::load_extensions( + $extension_dir .'/extensions', + $all_extensions[$extension_name], + $all_extensions_tree[$extension_name], + $all_extensions, + $URI, + $current_depth + 1 + ); + } else { + $class_file_name = 'class-fw-extension-'. $extension_name .'.php'; + + if (file_exists($extension_dir .'/'. $class_file_name)) { + $all_extensions_tree[$extension_name] = array(); + + self::$extension_to_all_tree[$extension_name] =& $all_extensions_tree[$extension_name]; + + require $extension_dir .'/'. $class_file_name; + + $class_name = 'FW_Extension_'. fw_dirname_to_classname($extension_name); + + $all_extensions[$extension_name] = new $class_name( + $parent, + $extension_dir, + self::$current_declaring_source, + $URI, + $current_depth + ); + + if (!($all_extensions[$extension_name] instanceof FW_Extension)) { + trigger_error('Extension "'. $extension_name .'" should extend FW_Extension class', E_USER_ERROR); + } + } elseif (file_exists($extension_dir .'/manifest.php')) { + /** + * extension class does not exists, but exists manifest, create an instance of default class + */ + + $all_extensions_tree[$extension_name] = array(); + + self::$extension_to_all_tree[$extension_name] =& $all_extensions_tree[$extension_name]; + + $default_class_name = 'FW_Extension_Default'; + + // check if parent class defined custom Default class for it's children extensions + $parent_class_name = get_class($parent); + if (class_exists($parent_class_name .'_Default')) { + $default_class_name = $parent_class_name .'_Default'; + } + + $all_extensions[$extension_name] = new $default_class_name( + $parent, + $extension_dir, + self::$current_declaring_source, + $URI, + $current_depth + ); + } else { + /** + * class or manifest does not exists, do not load this extension + * maybe it's a directory with configurations for a not existing extension + */ + continue; + } + + self::load_extensions( + $all_extensions[$extension_name]->get_declared_path() .'/extensions', + $all_extensions[$extension_name], + $all_extensions_tree[$extension_name], + $all_extensions, + $URI, + $current_depth + 1 + ); + } + } + } + + /** + * Include file from all extension's locations: framework, child, parent + * @param string|FW_Extension $extension + * @param string $extension_file_rel_path + */ + private static function include_extension_file_all($extension, $extension_file_rel_path) + { + if (is_string($extension)) { + $extension = fw()->extensions->get($extension); + } + + list( + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ) = $extension->correct_search_in_locations( + true, + true, + true + ); + + $rel_path = $extension->get_rel_path() . $extension_file_rel_path; + + if ($search_in_framework) { + fw_include_file_isolated(FW_DIR .'/extensions'. $rel_path); + } + + if ($search_in_child_theme) { + fw_include_file_isolated(FW_CT_CUSTOM_DIR .'/extensions'. $rel_path); + } + + if ($search_in_parent_theme) { + fw_include_file_isolated(FW_PT_CUSTOM_DIR .'/extensions'. $rel_path); + } + } + + /** + * Include all files from directory, from all extension's locations: framework, child, parent + * @param string|FW_Extension $extension + * @param string $extension_dir_rel_path + */ + private static function include_extension_directory_all($extension, $extension_dir_rel_path) + { + if (is_string($extension)) { + $extension = fw()->extensions->get($extension); + } + + list( + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ) = $extension->correct_search_in_locations( + true, + true, + true + ); + + $rel_path = $extension->get_rel_path() . $extension_dir_rel_path; + $paths = array(); + + if ($search_in_framework) { + $paths[] = FW_DIR .'/extensions'. $rel_path; + } + + if ($search_in_child_theme) { + $paths[] = FW_CT_CUSTOM_DIR .'/extensions'. $rel_path; + } + + if ($search_in_parent_theme) { + $paths[] = FW_PT_CUSTOM_DIR .'/extensions'. $rel_path; + } + + foreach ($paths as $path) { + if ($files = glob($path .'/*.php')) { + foreach ($files as $dir_file_path) { + fw_include_file_isolated($dir_file_path); + } + } + } + } + + private function load_all_extensions() + { + $parent = null; + + self::$current_declaring_source = 'framework'; + self::load_extensions(FW_DIR .'/extensions', $parent, self::$all_extensions_tree, self::$all_extensions, FW_EXTENSIONS_URI, 1); + + self::$current_declaring_source = 'parent'; + self::load_extensions(FW_PT_CUSTOM_DIR .'/extensions', $parent, self::$all_extensions_tree, self::$all_extensions, FW_PT_EXTENSIONS_URI, 1); + + if (FW_CT) { + self::$current_declaring_source = 'child'; + self::load_extensions(FW_CT_CUSTOM_DIR .'/extensions', $parent, self::$all_extensions_tree, self::$all_extensions, FW_CT_EXTENSIONS_URI, 1); + } + + self::$current_declaring_source = null; + } + + /** + * Activate extensions from given tree point + */ + private function activate_extensions($parent_extension_name = null) + { + if ($parent_extension_name === null) { + $all_tree =& self::$all_extensions_tree; + } else { + $all_tree =& self::$extension_to_all_tree[$parent_extension_name]; + } + + foreach ($all_tree as $extension_name => &$sub_extensions) { + if (fw()->extensions->get($extension_name)) { + // extension already active + continue; + } + + $extension =& self::$all_extensions[$extension_name]; + + if ($extension->manifest->check_requirements()) { + if (isset(self::$blacklist[$extension_name])) { + // do not activate blacklisted extension + } elseif ( + $extension->get_parent() + && + !$extension->get_parent()->_child_extension_is_valid($extension) + ) { + if (is_admin()) { // show warning only in admin side + FW_Flash_Messages::add( + 'fw-invalid-extension', + sprintf(__('Extension %s is invalid.', 'fw'), $extension->get_name()), + 'warning' + ); + } + } else { + // all requirements met, activate extension + $this->activate_extension($extension_name); + } + } else { + // requirements not met, tell required extensions that this extension is waiting for them + + foreach ($extension->manifest->get_required_extensions() as $required_extension_name => $requirements) { + if (!isset(self::$extensions_required_by_extensions[$required_extension_name])) { + self::$extensions_required_by_extensions[$required_extension_name] = array(); + } + + self::$extensions_required_by_extensions[$required_extension_name][] = $extension_name; + } + } + } + } + + /** + * @param string $extension_name + * @return bool + */ + private function activate_extension($extension_name) + { + if (fw()->extensions->get($extension_name)) { + // already active + return false; + } + + if (!self::$all_extensions[$extension_name]->manifest->requirements_met()) { + trigger_error('Wrong '. __METHOD__ .' call', E_USER_WARNING); + return false; + } + + // add to active extensions so inside includes/ and extension it will be accessible from fw()->extensions->get(...) + self::$active_extensions[$extension_name] =& self::$all_extensions[$extension_name]; + + $parent = self::$all_extensions[$extension_name]->get_parent(); + + if ($parent) { + self::$extension_to_active_tree[ $parent->get_name() ][$extension_name] = array(); + self::$extension_to_active_tree[$extension_name] =& self::$extension_to_active_tree[ $parent->get_name() ][$extension_name]; + } else { + self::$active_extensions_tree[$extension_name] = array(); + self::$extension_to_active_tree[$extension_name] =& self::$active_extensions_tree[$extension_name]; + } + + self::include_extension_directory_all($extension_name, '/includes'); + self::include_extension_file_all($extension_name, '/helpers.php'); + self::include_extension_file_all($extension_name, '/hooks.php'); + + if (self::$all_extensions[$extension_name]->_call_init() !== false) { + $this->activate_extensions($extension_name); + } + + // check if other extensions are waiting for this extension and try to activate them + if (isset(self::$extensions_required_by_extensions[$extension_name])) { + foreach (self::$extensions_required_by_extensions[$extension_name] as $waiting_extension_name) { + if (self::$all_extensions[$waiting_extension_name]->manifest->check_requirements()) { + $waiting_extension = self::$all_extensions[$waiting_extension_name]; + + if (isset(self::$blacklist[$waiting_extension_name])) { + // do not activate blacklisted extensions + } elseif ( + $waiting_extension->get_parent() + && + !$waiting_extension->get_parent()->_child_extension_is_valid($waiting_extension) + ) { + if (is_admin()) { // show warning only in admin side + FW_Flash_Messages::add( + 'fw-invalid-extension', + sprintf(__('Extension %s is invalid.', 'fw'), $waiting_extension_name), + 'warning' + ); + } + } else { + $this->activate_extension($waiting_extension_name); + } + } + } + + unset(self::$extensions_required_by_extensions[$extension_name]); + } + + return true; + } + + private function add_actions() + { + add_action('fw_init', array($this, '_action_init_extensions')); + add_action('init', array($this, '_action_init')); + add_action('wp_enqueue_scripts', array($this, '_action_enqueue_scripts')); + add_action('admin_enqueue_scripts', array($this, '_action_enqueue_scripts')); + } + + /** + * Give extensions possibility to access their active_tree + * @internal + */ + public function _get_extension_tree(FW_Access_Key $access_key, $extension_name) + { + if ($access_key->get_key() !== 'extension') { + trigger_error('Call denied', E_USER_ERROR); + } + + return self::$extension_to_active_tree[$extension_name]; + } + + protected function _init() + { + $this->load_all_extensions(); + $this->add_actions(); + } + + public function _action_init_extensions() + { + /** Prepare BlackList */ + { + self::$blacklist = fw()->theme->get_config('extensions_blacklist'); + + if (empty(self::$blacklist)) { + self::$blacklist = array(); + } else { + self::$blacklist = array_fill_keys(self::$blacklist, true); + } + } + + $this->activate_extensions(); + + /** + * Now $this->get_children() is available + */ + do_action('fw_extensions_init'); + } + + public function _action_init() + { + foreach (self::$active_extensions as &$extension) { + /** register posts */ + self::include_extension_file_all($extension, '/posts.php'); + } + } + + public function _action_enqueue_scripts() + { + foreach (self::$active_extensions as &$extension) { + /** js and css */ + self::include_extension_file_all($extension, '/static.php'); + } + } + + /** + * @param string $extension_name returned by FW_Extension::get_name() + * @return FW_Extension|null + */ + public function get($extension_name) + { + if (isset(self::$active_extensions[$extension_name])) { + return self::$active_extensions[$extension_name]; + } else { + return null; + } + } + + /** + * Get all active extensions + * @return FW_Extension[] + */ + public function get_all() + { + return self::$active_extensions; + } + + /** + * Get extensions tree (how they are arranged in directories) + * @return array + */ + public function get_tree() + { + return self::$active_extensions_tree; + } + + /** + * Search relative path in: child theme -> parent theme -> framework extensions directory and return full path + * + * @param string $rel_path '//path_to_dir' or '//extensions//path_to_file.php' + * @param bool $search_in_framework + * @param bool $search_in_parent_theme + * @param bool $search_in_child_theme + * @return false|string Full path or false if not found + */ + public function locate_path($rel_path, $search_in_framework = true, $search_in_parent_theme = true, $search_in_child_theme = true) + { + if ($search_in_child_theme && FW_CT) { + if (file_exists(FW_CT_EXTENSIONS_DIR . $rel_path)) { + return FW_CT_EXTENSIONS_DIR . $rel_path; + } + } + + if ($search_in_parent_theme) { + if (file_exists(FW_PT_EXTENSIONS_DIR . $rel_path)) { + return FW_PT_EXTENSIONS_DIR . $rel_path; + } + } + + if ($search_in_framework) { + if (file_exists(FW_EXTENSIONS_DIR . $rel_path)) { + return FW_EXTENSIONS_DIR . $rel_path; + } + } + + return false; + } + + /** + * Search relative path in: child theme -> parent theme -> framework extensions directory and return URI + * + * @param string $rel_path '//path_to_dir' or '//extensions//path_to_file.php' + * @param bool $search_in_framework + * @param bool $search_in_parent_theme + * @param bool $search_in_child_theme + * @return false|string URI or false if not found + */ + public function locate_path_URI($rel_path, $search_in_framework = true, $search_in_parent_theme = true, $search_in_child_theme = true) + { + if ($search_in_child_theme && FW_CT) { + if (file_exists(FW_CT_EXTENSIONS_DIR . $rel_path)) { + return FW_CT_EXTENSIONS_URI . $rel_path; + } + } + + if ($search_in_parent_theme) { + if (file_exists(FW_PT_EXTENSIONS_DIR . $rel_path)) { + return FW_PT_EXTENSIONS_URI . $rel_path; + } + } + + if ($search_in_framework) { + if (file_exists(FW_EXTENSIONS_DIR . $rel_path)) { + return FW_EXTENSIONS_URI . $rel_path; + } + } + + return false; + } +} + +/** + * Instances of this class will be created for extensions without class + */ +class FW_Extension_Default extends FW_Extension +{ + protected function _init() + { + } +} diff --git a/scratch-parent/framework/core/components/theme.php b/scratch-parent/framework/core/components/theme.php new file mode 100644 index 00000000..1cab597f --- /dev/null +++ b/scratch-parent/framework/core/components/theme.php @@ -0,0 +1,266 @@ +manifest = new FW_Theme_Manifest($manifest); + } + } + + /** + * Include file from child and parent theme + * @param string $rel_path + */ + private static function include_file_all($rel_path) + { + if (FW_CT) { + fw_include_file_isolated(FW_CT_CUSTOM_DIR .'/theme'. $rel_path); + } + + fw_include_file_isolated(FW_PT_CUSTOM_DIR .'/theme'. $rel_path); + } + + /** + * Include all files from directory, from parent and child theme + * @param string $rel_path + */ + private static function include_directory_all($rel_path) + { + $paths = array(); + + if (FW_CT) { + $paths[] = FW_CT_CUSTOM_DIR .'/theme'. $rel_path; + } + + $paths[] = FW_PT_CUSTOM_DIR .'/theme'. $rel_path; + + foreach ($paths as $path) { + if ($files = glob($path .'/*.php')) { + foreach ($files as $dir_file_path) { + fw_include_file_isolated($dir_file_path); + } + } + } + } + + /** + * @internal + */ + protected function _init() + { + self::include_file_all('/hooks.php'); + + add_action('fw_init', array($this, '_action_fw_init')); + add_action('init', array($this, '_action_init')); + add_action('wp_enqueue_scripts', array($this, '_action_enqueue_scripts')); + add_action('admin_enqueue_scripts', array($this, '_action_enqueue_scripts')); + add_action('widgets_init', array($this, '_action_widgets_init')); + } + + /** + * @internal + */ + public function _action_fw_init() + { + self::include_file_all('/helpers.php'); + self::include_directory_all('/includes'); + } + + /** + * @internal + */ + public function _action_init() + { + self::include_file_all('/posts.php'); + self::include_file_all('/menus.php'); + } + + /** + * @internal + */ + public function _action_enqueue_scripts() + { + self::include_file_all('/static.php'); + } + + /** + * @internal + */ + public function _action_widgets_init() + { + $paths = array(); + + if (FW_CT) { + $paths[] = FW_CT_CUSTOM_DIR .'/theme/widgets'; + } + + $paths[] = FW_PT_CUSTOM_DIR .'/theme/widgets'; + + $included_widgets = array(); + + foreach ($paths as $path) { + $dirs = glob($path .'/*', GLOB_ONLYDIR); + + if (!$dirs) { + continue; + } + + foreach ($dirs as $dir_path) { + $dirname = basename($dir_path); + + if (isset($included_widgets[$dirname])) { + // this happens when a widget in child theme wants to overwrite the widget from parent theme + continue; + } else { + $included_widgets[$dirname] = true; + } + + fw_include_file_isolated($dir_path .'/class-fw-widget-'. $dirname .'.php'); + + register_widget('FW_Widget_'. fw_dirname_to_classname($dirname)); + } + } + } + + /** + * Search relative path in: child theme -> parent "theme" directory and return full path + * @param string $rel_path + * @return false|string + */ + public function locate_path($rel_path) + { + if (FW_CT && file_exists(FW_CT_THEME_DIR . $rel_path)) { + return FW_CT_THEME_DIR . $rel_path; + } + + if (file_exists(FW_PT_THEME_DIR . $rel_path)) { + return FW_PT_THEME_DIR . $rel_path; + } + + return false; + } + + /** + * Return array with options from specified name/path + * @param string $name + * @return array + */ + public function get_options($name) + { + $path = $this->locate_path('/options/'. $name .'.php'); + + if (!$path) { + return array(); + } + + $variables = fw_get_variables_from_file($path, array('options' => array())); + + return $variables['options']; + } + + public function get_settings_options() + { + $cache_key = self::$cache_key .'/options/settings'; + + try { + return FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $options = apply_filters('fw_settings_options', $this->get_options('settings')); + + FW_Cache::set($cache_key, $options); + + return $options; + } + } + + public function get_post_options($post_type) + { + $cache_key = self::$cache_key .'/options/posts/'. $post_type; + + try { + return FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $options = apply_filters('fw_post_options', $this->get_options('posts/'. $post_type), $post_type); + + FW_Cache::set($cache_key, $options); + + return $options; + } + } + + public function get_taxonomy_options($taxonomy) + { + $cache_key = self::$cache_key .'/options/taxonomies/'. $taxonomy; + + try { + return FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $options = apply_filters('fw_taxonomy_options', $this->get_options('taxonomies/'. $taxonomy), + $taxonomy, + null + ); + + FW_Cache::set($cache_key, $options); + + return $options; + } + } + + /** + * Return config key value, or entire config array + * Config array is merged from child configs + * @param string|null $key Multi key format accepted: 'a/b/c' + * @return mixed|null + */ + final public function get_config($key = null) + { + $cache_key = self::$cache_key .'/config'; + + try { + $config = FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $config = array(); + + if (file_exists(FW_PT_CUSTOM_DIR .'/theme/config.php')) { + $variables = fw_get_variables_from_file(FW_PT_CUSTOM_DIR .'/theme/config.php', array('cfg' => null)); + + if (!empty($variables['cfg'])) { + $config = array_merge($config, $variables['cfg']); + unset($variables); + } + } + + if (FW_CT && file_exists(FW_CT_CUSTOM_DIR .'/theme/config.php')) { + $variables = fw_get_variables_from_file(FW_CT_CUSTOM_DIR .'/theme/config.php', array('cfg' => null)); + + if (!empty($variables['cfg'])) { + $config = array_merge($config, $variables['cfg']); + unset($variables); + } + } + + unset($path); + + FW_Cache::set($cache_key, $config); + } + + return $key === null ? $config : fw_akg($key, $config); + } +} diff --git a/scratch-parent/framework/core/extends/class-fw-extension.php b/scratch-parent/framework/core/extends/class-fw-extension.php new file mode 100644 index 00000000..3bf59f0d --- /dev/null +++ b/scratch-parent/framework/core/extends/class-fw-extension.php @@ -0,0 +1,472 @@ + parent theme -> child theme) + * @var string + */ + private $declared_dir; + + /** + * URI to directory where extension was first found/declared + * @var string + */ + private $declared_URI; + + /** + * On what directory depth is the extension + * + * 1 - Root extension + * 2 - Their children + * 3 - Sub children + * ... + * + * @var int + */ + private $depth; + + /** + * If _init() was called + * @var bool + */ + private $initialized = false; + + final public function __construct(&$parent, $declared_dir, $declared_source, $URI, $depth) + { + if (!self::$access_key) { + self::$access_key = new FW_Access_Key('extension'); + } + + $this->parent =& $parent; + $this->declared_source = $declared_source; + $this->declared_dir = $declared_dir; + $this->declared_URI = $URI . $this->get_rel_path(); // ! set $this->parent before calling get_rel_path() + $this->depth = $depth; + + { + $manifest = array(); + + if (file_exists($this->declared_dir .'/manifest.php')) { + $variables = fw_get_variables_from_file($this->declared_dir .'/manifest.php', array('manifest' => array())); + $manifest = $variables['manifest']; + unset($variables); + } + + if (empty($manifest['name'])) { + $manifest['name'] = $this->get_name(); + } + + $this->manifest = new FW_Extension_Manifest($manifest); + } + } + + /** + * Cache key for this extension + * + * Usage: + * FW_Cache::get( $this->get_cache_key() .'/something' ) + * + * @return string + */ + final public function get_cache_key() + { + return self::$cache_key .'/'. $this->get_name(); + } + + /** + * @param string $name View file name (without .php) from /views directory + * @param array $view_variables Keys will be variables names within view + * @return string HTML + */ + final protected function render_view($name, $view_variables = array()) + { + $full_path = $this->locate_path('/views/'. $name .'.php'); + + if (!$full_path) { + trigger_error('Extension view not found: '. $name, E_USER_WARNING); + return; + } + + return fw_render_view($full_path, $view_variables); + } + + /** + * @internal + */ + final public function _call_init() + { + if ($this->initialized) { // todo: use private key + trigger_error('Extension already initialized: '. $this->get_name(), E_USER_ERROR); + } else { + $this->initialized = true; + } + + return $this->_init(); + } + + /** + * Tree array with all sub extensions + * @return array + */ + final public function get_tree() + { + return fw()->extensions->_get_extension_tree(self::$access_key, $this->get_name()); + } + + /** + * @param string $rel_path E.g. `/views/test.php` + * @return false|string E.g. '/var/www/wordpress/wp-content/themes/theme-name/framework/extensions//views/test.php' + */ + final public function locate_path($rel_path) + { + list( + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ) = $this->correct_search_in_locations( + true, + true, + true + ); + + $rel_path = $this->get_rel_path() . $rel_path; + + return fw()->extensions->locate_path($rel_path, + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ); + } + + /** + * @param string $rel_path E.g. '/static/js/scripts.js' + * @return string URI E.g. 'http: //wordpress.com/wp-content/themes/theme-name/framework/extensions//static/js/scripts.js' + */ + final public function locate_URI($rel_path) + { + list( + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ) = $this->correct_search_in_locations( + true, + true, + true + ); + + $rel_path = $this->get_rel_path() . $rel_path; + + return fw()->extensions->locate_path_URI($rel_path, + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ); + } + + /** + * @return FW_Extension|null if has no parent extension + */ + final public function get_parent() + { + return $this->parent; + } + + /** + * @return string + */ + final public function get_name() + { + if ($this->name === null) { + $this->name = explode('/', $this->get_declared_path()); + $this->name = array_pop($this->name); + } + + return $this->name; + } + + /** + * @return string + */ + final public function get_declared_source() + { + return $this->declared_source; + } + + /** + * @param string $append_rel_path E.g. '/includes/something.php' + * @return string + */ + final public function get_declared_path($append_rel_path = '') + { + return $this->declared_dir . $append_rel_path; + } + + /** + * @param string $append_rel_path E.g. '/includes/foo/bar/script.js' + * @return string + */ + final public function get_declared_URI($append_rel_path = '') + { + return $this->declared_URI . $append_rel_path; + } + + /** + * Used to determine where to search files (options, views, static files) + * Because there is no sense to search (one level up) in framework, if extension is declared in parent theme + * @param bool $search_in_framework + * @param bool $search_in_parent_theme + * @param bool $search_in_child_theme + * @return array + */ + final public function correct_search_in_locations($search_in_framework, $search_in_parent_theme, $search_in_child_theme) + { + $source = $this->get_declared_source(); + + if ($source == 'parent') { + $search_in_framework = false; + } elseif ($source == 'child') { + $search_in_framework = $search_in_parent_theme = false; + } + + if (!FW_CT) { + $search_in_child_theme = false; + } + + return array($search_in_framework, $search_in_parent_theme, $search_in_child_theme); + } + + /** + * @param string $child_extension_name + * @return FW_Extension|null + */ + final public function get_child($child_extension_name) + { + $active_tree = $this->get_tree(); + + if (isset($active_tree[$child_extension_name])) { + return fw()->extensions->get($child_extension_name); + } else { + return null; + } + } + + /** + * Return all child extensions + * Only one level, not all sub levels + * @return FW_Extension[] + */ + final public function get_children() + { + $active_tree = $this->get_tree(); + + $result = array(); + + foreach ($active_tree as $extension_name => &$sub_extensions) { + $result[$extension_name] = fw()->extensions->get($extension_name); + } + + return $result; + } + + /** + * Get path relative to parent "extensions" directory where all extensions are located + * E.g.: /foo/extensions/bar/extensions/hello + * @return string + */ + final public function get_rel_path() + { + $cache_key = $this->get_cache_key() .'/rel_path'; + + try { + return FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $rel_path = array($this->get_name()); + + // balk back in parents and generate array(child, ..., parent) + $parent_walker = $this; + while ($parent_walker = $parent_walker->get_parent()) { + $rel_path[] = $parent_walker->get_name(); + } + unset($parent_walker); + + $rel_path = '/'. implode('/extensions/', array_reverse($rel_path)); + + FW_Cache::set($cache_key, $rel_path); + + return $rel_path; + } + } + + /** + * Return config key value, or entire config array + * Config array is merged from child configs + * @param string|null $key Multi key format accepted: 'a/b/c' + * @return mixed|null + */ + final public function get_config($key = null) + { + $cache_key = $this->get_cache_key() .'/config'; + + try { + $config = FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + list( + $search_in_framework, + $search_in_parent_theme, + $search_in_child_theme + ) = $this->correct_search_in_locations( + true, + true, + true + ); + + $rel_path = $this->get_rel_path() .'/config.php'; + $config = array(); + $paths = array(); + + if ($search_in_framework) { + $paths[] = FW_EXTENSIONS_DIR . $rel_path; + } + if ($search_in_parent_theme) { + $paths[] = FW_PT_EXTENSIONS_DIR . $rel_path; + } + if ($search_in_child_theme) { + $paths[] = FW_CT_EXTENSIONS_DIR . $rel_path; + } + + foreach ($paths as $path) { + if (file_exists($path)) { + $variables = fw_get_variables_from_file($path, array('cfg' => null)); + + if (!empty($variables['cfg'])) { + $config = array_merge($config, $variables['cfg']); + unset($variables); + } + } + } + + unset($path); + + FW_Cache::set($cache_key, $config); + } + + return $key === null ? $config : fw_akg($key, $config); + } + + /** + * Return array with options from specified name/path + * @param string $name Examples: 'framework', 'posts/portfolio' + * @return array + */ + final public function get_options($name) + { + $path = $this->locate_path('/options/'. $name .'.php'); + + if (!$path) { + return array(); + } + + $variables = fw_get_variables_from_file($path, array('options' => array())); + + return $variables['options']; + } + + final public function get_settings_options() + { + return $this->get_options('settings'); + } + + final public function get_post_options($post_type) + { + return $this->get_options('posts/'. $post_type); + } + + final public function get_taxonomy_options($taxonomy) + { + return $this->get_options('taxonomies/'. $taxonomy); + } + + /** + * @param string $name File name without extension, located in /static/js/$name.js + * @return string URI + */ + final public function locate_js_URI($name) + { + return $this->locate_URI('/static/js/'. $name .'.js'); + } + + /** + * @param string $name File name without extension, located in /static/js/$name.js + * @return string URI + */ + final public function locate_css_URI($name) + { + return $this->locate_URI('/static/css/'. $name .'.css'); + } + + /** + * @param string $name File name without extension, located in /views/$name.php + * @return false|string + */ + final public function locate_view_path($name) + { + return $this->locate_path('/views/'. $name .'.php'); + } + + final public function get_depth() + { + return $this->depth; + } + + /** + * Check if child extension is valid + * + * Used for special cases when an extension requires it's child extensions to extend some special class + * + * @param FW_Extension $child_extension_instance + * @return bool + * @internal + */ + public function _child_extension_is_valid($child_extension_instance) + { + return is_subclass_of($child_extension_instance, 'FW_Extension'); + } +} diff --git a/scratch-parent/framework/core/extends/class-fw-option-type.php b/scratch-parent/framework/core/extends/class-fw-option-type.php new file mode 100644 index 00000000..d65f83e9 --- /dev/null +++ b/scratch-parent/framework/core/extends/class-fw-option-type.php @@ -0,0 +1,234 @@ + '...') + * Other parameters are merged with array returned from this method + * + * @return array + * + * array( + * 'value' => '', + * ... + * ) + * @internal + */ + abstract protected function _get_defaults(); + + /** + * Used as prefix for attribute id="{$this->id_prefix}$id" + * @return string + */ + final public static function get_default_id_prefix() + { + return 'fw-option-'; + } + + /** + * Used as default prefix for attribute name="$prefix[$name]" + * Cannot contain [], it is used for $_POST[ self::get_default_name_prefix() ] + * @return string + */ + final public static function get_default_name_prefix() + { + return 'fw_options'; + } + + final public function __construct() + { + // does nothing at the moment, but maybe in the future will do something + + if (method_exists($this, '_init')) { + $this->_init(); + } + } + + /** + * Fix and prepare attributes + * + * @param string $id + * @param array $option + * @param array $data + * @return array + */ + private static function prepare($id, $option, $data) + { + if (!isset($option['attr'])) { + $option['attr'] = array(); + } + + $option['attr']['name'] = $data['name_prefix'] .'['. $id .']'; + $option['attr']['id'] = $data['id_prefix'] . $id; + $option['attr']['class'] = 'fw-option fw-option-type-'. $option['type'] .( + isset($option['attr']['class']) + ? ' '. $option['attr']['class'] + : '' + ); + $option['attr']['value'] = is_array($option['value']) ? '' : $option['value']; + + // remove some blacklisted attributes. this should be added only by render method + unset($option['attr']['type']); + unset($option['attr']['checked']); + unset($option['attr']['selected']); + + return $option; + } + + /** + * Generate option's html from option array + * @param string $id + * @param array $option + * @param array $data + * @return string HTML + */ + final public function render($id, $option, $data = array()) + { + $data = array_merge( + array( + 'id_prefix' => self::get_default_id_prefix(), // attribute id prefix + 'name_prefix' => self::get_default_name_prefix(), // attribute name prefix + ), + $data + ); + + $option = array_merge( + $this->get_defaults(), + $option, + array( + 'type' => $this->get_type() + ) + ); + + if (!isset($data['value'])) { + // if no input value, use default + $data['value'] = $option['value']; + } + + $option = self::prepare($id, $option, $data); + + { + wp_enqueue_style( + 'fw-option-types', + FW_URI .'/static/css/option-types.css', + array('fw', 'qtip'), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-types', + FW_URI .'/static/js/option-types.js', + array('fw-events', 'qtip'), + fw()->manifest->get_version(), + true + ); + } + + return $this->_render($id, $option, $data); + } + + /** + * Extract correct value for $option['value'] from input array + * If input value is empty, will be returned $option['value'] + * @param array $option + * @param mixed|null $input_value Option's value from $_POST or elsewhere. If is null, it means it does not exists + * @return array|string + */ + final public function get_value_from_input($option, $input_value) + { + $option = array_merge( + $this->get_defaults(), + $option, + array( + 'type' => $this->get_type() + ) + ); + + return $this->_get_value_from_input($option, $input_value); + } + + /** + * Default option array + * + * This makes possible an option array to have required only one parameter: array('type' => '...') + * Other parameters are merged with array returned from this method + * + * @return array + */ + final public function get_defaults() + { + $option = $this->_get_defaults(); + + $option['type'] = $this->get_type(); + + if (!isset($option['value'])) { + FW_Flash_Messages::add( + 'fw-option-type-no-default-value', + sprintf(__('Option type %s has no default value', 'fw'), $this->get_type()), + 'warning' + ); + + $option['value'] = array(); + } + + return $option; + } + + /** + * Exist 3 types of options widths: + * - auto (float left real width of the option (minimal) ) + * - fixed (inputs, select, textarea, and others - they have same width) + * - full (100% . eg. html option should expand to maximum width) + * Options can override this method to return another value + * @return bool + * @internal + */ + public function _get_backend_width_type() + { + return 'fixed'; + } + + /** + * Use this method to register a new option type + * @param string|FW_Option_Type $option_type_class + */ + final public static function register($option_type_class) { + static $registration_access_key = null; + + if ($registration_access_key === null) { + $registration_access_key = new FW_Access_Key('register_option_type'); + } + + fw()->backend->_register_option_type($registration_access_key, $option_type_class); + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/backup/class-fw-extension-backup.php b/scratch-parent/framework/extensions/backup/class-fw-extension-backup.php new file mode 100644 index 00000000..8cf8a31a --- /dev/null +++ b/scratch-parent/framework/extensions/backup/class-fw-extension-backup.php @@ -0,0 +1,1219 @@ +debug) { + // Create *** Now buttons for all Recurring Tasks + foreach ($this->cron as &$cron) { + $cron[3] = true; + } + } elseif (current_user_can('edit_posts')) { + if (isset($_GET['post_type']) && $_GET['post_type'] == $this->get_post_type() && isset($_GET['trashed'])) { + // Get rid of "1 post moved to the Trash" + wp_redirect(admin_url('edit.php?'.http_build_query(array('post_type' => $this->get_post_type())))); + exit; + } + } + + $this->add_actions(); + $this->add_filters(); + + if (is_admin()) { + $this->add_admin_actions(); + $this->add_admin_filters(); + } + } + + private function add_actions() + { + add_action('fw_extensions_init', array($this, '_action_fw_extensions_init')); + add_action('fw_backup_cron', array($this, '_action_fw_backup_cron')); + add_action('fw_backup_now', array($this, '_action_fw_backup_now')); + add_action('trashed_post', array($this, '_action_trashed_post')); + add_action('before_delete_post', array($this, '_action_before_delete_post')); + } + + private function add_filters() + { + add_filter('cron_schedules', array($this, '_filter_cron_schedules'), 5); + } + + private function add_admin_actions() + { + $post_type = $this->get_post_type(); + + add_action('admin_init', array($this, '_admin_action_admin_init')); + add_action('admin_enqueue_scripts', array($this, '_admin_action_admin_enqueue_scripts')); + add_action('wp_ajax_backup-progress', array($this, '_admin_action_wp_ajax_backup_progress')); + add_action('wp_ajax_backup-settings-save', array($this, '_admin_action_wp_ajax_backup_settings_save')); + add_action("manage_{$post_type}_posts_custom_column", array($this, '_admin_action_manage_xxx_posts_custom_column'), 10, 2); + } + + private function add_admin_filters() + { + $screen_id = "edit-{$this->get_post_type()}"; + + add_filter('post_row_actions', array($this, '_admin_filter_post_row_actions'), 10, 2); + add_filter("manage_{$screen_id}_columns", array($this, '_admin_filter_manage_xxx_columns')); + add_filter("views_{$screen_id}", array($this, '_admin_filter_views_xxx_hack')); + } + + // Public + + public function param($key) + { + if (!array_key_exists($key, $this->param)) { + throw new FW_Backup_Exception_Parameter_Not_Found($key); + } + + return $this->param[$key]; + } + + public function service($service_id, $instanceof = null) + { + if (!isset($this->service[$service_id])) { + throw new FW_Backup_Exception_Service_Not_Found($service_id); + } + + $service = $this->service[$service_id]; + + if (isset($instanceof)) { + if (!$service instanceof $instanceof) { + throw new FW_Backup_Exception_Service_Invalid_Interface($service_id, $instanceof); + } + } + + if (strpos($service_id, 'shared.') === 0) { + return $service; + } + + return clone $service; + } + + public function service_list($instanceof) + { + $ret = array(); + foreach ($this->service as $id => $inst) { + if ($inst instanceof $instanceof) { + $ret[$id] = $this->service($id); + } + } + return $ret; + } + + public function get_post_type() + { + return 'fw_backup'; + } + + public function get_backup_dir($create = false) + { + // Its important for $backup_dir parameter to use DIRECTORY_SEPARATOR. + // service('fs') relies on this convention. + + $upload_dir = wp_upload_dir(); + $backup_dir = str_replace('/', DIRECTORY_SEPARATOR, $upload_dir['basedir']) . DIRECTORY_SEPARATOR . 'backup'; + + if ($create && !file_exists($backup_dir . DIRECTORY_SEPARATOR . 'index.php')) { + if (! @wp_mkdir_p($backup_dir, 0777, true)) { + return false; + } + if (@file_put_contents("$backup_dir/index.php", 'Forbidden

    \');') === false) { + return false; + } + } + + return $backup_dir; + } + + public function url_backup() + { + return admin_url('edit.php?'.http_build_query(array('post_type' => $this->get_post_type()))); + } + + public function url_backup_progress($post_id) + { + $url = admin_url('edit.php?'.http_build_query(array('post_type' => $this->get_post_type(), 'post' => $post_id))); + return $this->wp_nonce_url_raw($url, 'backup-progress'); + } + + public function url_backup_now($cron_id) + { + return $this->wp_nonce_url_raw(admin_url("?cron=$cron_id"), 'backup-now'); + } + + public function url_backup_cancel($post_id) + { + return $this->wp_nonce_url_raw(admin_url("?post=$post_id"), 'backup-cancel'); + } + + public function url_backup_download($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + */ + + $meta = $this->service('post.meta'); + $meta->set_post_id($post_id); + + if ($a = $meta->get_backup_file()) { + return $a->get_download_url(); + } + + return false; + } + + public function url_backup_restore($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + */ + + $meta = $this->service('post.meta'); + $meta->set_post_id($post_id); + + if ($meta->get_backup_file($post_id)) { + $url = admin_url('edit.php?'.http_build_query(array('post_type' => $this->get_post_type(), 'post' => $post_id))); + return $this->wp_nonce_url_raw($url, 'backup-restore'); + } + + return false; + } + + public function url_backup_trash($post_id) + { + return $this->wp_nonce_url_raw("post.php?action=trash&post=$post_id", "trash-post_{$post_id}"); + } + + public function url_backup_unschedule($service_id) + { + return $this->wp_nonce_url_raw(admin_url('?service='.$service_id), 'backup-unschedule'); + } + + public function backup_now($cron_id) + { + /** + * @var FW_Backup_Interface_Cron $cron + */ + + try { + $cron = $this->service($cron_id, 'FW_Backup_Interface_Cron'); + + // Ensure that storage service is workable + $cron->get_storage()->ping(); + + $post_id = $this->backup_create($cron); + + wp_schedule_single_event(time(), 'fw_backup_now', array($post_id)); + wp_cron(); + wp_redirect($this->url_backup_progress($post_id)); + } + catch (FW_Backup_Exception $exception) { + FW_Flash_Messages::add(uniqid(), $exception->getMessage(), 'error'); + wp_redirect($this->url_backup()); + } + + exit; + } + + public function backup_cancel($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + */ + + $meta = $this->service('post.meta'); + $meta->set_post_id($post_id); + + if ($time = $meta->get_cron_started()) { + if ($time + self::BACKUP_TIMEOUT < time()) { + wp_delete_post($post_id); + FW_Flash_Messages::add(uniqid(), __('Backup timeout exceeded. The backup was deleted', 'fw')); + wp_redirect(admin_url('edit.php?post_type='.$this->get_post_type())); + exit; + } + } + + if ($time = $meta->get_cancelled()) { + if ($time + self::CANCEL_TIMEOUT < time()) { + wp_delete_post($post_id); + FW_Flash_Messages::add(uniqid(), __('Cancel timeout exceeded. The backup was deleted', 'fw')); + wp_redirect(admin_url('edit.php?post_type='.$this->get_post_type())); + exit; + } + } + + $meta->set_cancelled(); + + wp_redirect(admin_url('edit.php?post_type='.$this->get_post_type())); + exit; + } + + public function backup_unschedule($cron_id) + { + /** + * @var FW_Backup_Interface_Cron $cron + */ + + try { + $cron = $this->service($cron_id, 'FW_Backup_Interface_Cron'); + $this->set_option($cron_id, 'schedule', 'disabled'); + $this->reschedule(); // do reschedule + // $this->init_services_cron(); // make cron.xxx services to be up to date + if ($this->debug) { + FW_Flash_Messages::add(uniqid(), sprintf(__('The %s was unscheduled', 'fw'), $cron->get_title())); + } + } + catch (FW_Backup_Exception $exception) { + FW_Flash_Messages::add(uniqid(), $exception->getMessage(), 'error'); + } + + wp_redirect(admin_url('edit.php?post_type='.$this->get_post_type())); + exit; + } + + public function backup_render_progress($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + */ + + try { + $meta = $this->service('post.meta'); + $meta->set_post_id($post_id); + if ($a = $meta->get_progress()) { + $a['cron_title'] = $meta->get_cron_title(); + $html = $this->render_view('backend/backup-progress', $a); + } + } + catch (FW_Backup_Exception $exception) { + } + + return isset($html) ? $html : false; + } + + public function restore_now($post_id) + { + $redirect = true; + + try { + $redirect = $this->restore_run($post_id); + } + catch (FW_Backup_Exception $exception) { + FW_Flash_Messages::add(uniqid(), $exception->getMessage(), 'error'); + } + + if ($redirect) { + wp_redirect($this->url_backup()); + exit; + } + } + + /** + * @internal + */ + public function _action_fw_extensions_init() + { + try { + $this->init_param(); + $this->init_services(); + } + catch (FW_Backup_Exception $exception) { + FW_Flash_Messages::add(uniqid(), $exception->getMessage(), 'error'); + } + } + + /** + * @internal + */ + public function _action_fw_backup_cron($cron_id) + { + try { + $cron = $this->service($cron_id, 'FW_Backup_Interface_Cron'); + $post_id = $this->backup_create($cron); + $this->backup_run($post_id); + } + catch (FW_Backup_Exception_Service $exception) { + wp_clear_scheduled_hook('fw_backup_cron', array($cron_id)); + } + catch (Exception $exception) { + } + } + + /** + * @internal + */ + public function _action_fw_backup_now($post_id) + { + try { + $this->backup_run($post_id); + } + catch (Exception $exception) { + } + + wp_clear_scheduled_hook('fw_backup_now', array($post_id)); + } + + /** + * @internal + */ + public function _action_trashed_post($post_id) + { + // On debug mode use standard WordPress tables/functionality + if (!$this->debug && get_post_type($post_id) == $this->get_post_type()) { + wp_delete_post($post_id); + } + } + + /** + * @internal + */ + public function _action_before_delete_post($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + * @var FW_Backup_Interface_Storage $storage + */ + + if (get_post_type($post_id) == $this->get_post_type()) { + + // Remove associated backup file, if any + try { + $meta = $this->service('shared.post.meta'); + $meta->set_post_id($post_id); + $storage = $this->service($meta->get_storage_id(), 'FW_Backup_Interface_Storage'); + if ($a = $meta->get_backup_file()) { // take into account when backup was cancelled + $storage->remove($a); + } + } + catch (FW_Backup_Exception $exception) { + } + + } + } + + /** + * @internal + */ + public function _filter_cron_schedules($schedules) + { + // On debug mode use standard WordPress tables/functionality + if ($this->debug) { + $schedules['backup.1min'] = array('interval' => MINUTE_IN_SECONDS, 'display' => __('1 min', 'fw')); + $schedules['backup.4min'] = array('interval' => 4*MINUTE_IN_SECONDS, 'display' => __('4 min', 'fw')); + } + $schedules['backup.daily'] = array('interval' => DAY_IN_SECONDS, 'display' => __('Daily', 'fw')); + $schedules['backup.weekly'] = array('interval' => WEEK_IN_SECONDS, 'display' => __('Weekly', 'fw')); + $schedules['backup.monthly'] = array('interval' => 4*WEEK_IN_SECONDS, 'display' => __('Monthly', 'fw')); + return $schedules; + } + + /** + * @internal + */ + public function _admin_action_admin_init() + { + /** + * @var FW_Backup_Service_Post_Meta $meta + */ + + try { + + if ($this->wp_verify_nonce('backup-progress')) { + $meta = $this->service['shared.post.meta']; + $meta->set_post_id(FW_Request::GET('post')); + if (!$meta->get_progress()) { + wp_redirect(admin_url('edit.php?post_type='.$this->get_post_type())); + exit; + } + } + + if ($this->wp_verify_nonce('backup-now')) { + $this->backup_now(FW_Request::GET('cron')); + } + + if ($this->wp_verify_nonce('backup-cancel')) { + $this->backup_cancel(FW_Request::GET('post')); + } + + if ($this->wp_verify_nonce('backup-restore')) { + $this->restore_now(FW_Request::GET('post')); + } + + if ($this->wp_verify_nonce('backup-unschedule')) { + $this->backup_unschedule(FW_Request::GET('service')); + } + + } + catch (FW_Backup_Exception $exception) { + FW_Flash_Messages::add(uniqid(), $exception->getMessage(), 'error'); + } + } + + /** + * @internal + */ + public function _admin_action_admin_enqueue_scripts($hook) + { + global $post_type; + if ($hook == 'edit.php' && $post_type == $this->get_post_type()) { + + if ($this->wp_verify_nonce('backup-restore')) { + wp_enqueue_style( + "fw-ext-{$this->get_name()}-admin", + $this->locate_URI('/static/css/admin.css'), + array(), + $this->manifest->get_version() + ); + wp_enqueue_style( + "fw-ext-{$this->get_name()}-restore", + $this->locate_URI('/static/css/restore.css'), + array(), + $this->manifest->get_version() + ); + wp_enqueue_script( + "fw-ext-{$this->get_name()}-restore", + $this->locate_URI('/static/js/restore.js'), + array(), + $this->manifest->get_version() + ); + } + else { + + wp_enqueue_media(); + wp_enqueue_style( + "fw-ext-{$this->get_name()}-admin", + $this->locate_URI('/static/css/admin.css'), + array('fw-option-types'), + $this->manifest->get_version() + ); + + // Enqueue all the necessary files for Backup Schedule dialog + $options = $this->get_backup_settings_options(); + fw()->backend->render_options($options); + + // On debug mode use standard WordPress tables/functionality + if (!$this->debug) { + wp_enqueue_style( + "fw-ext-{$this->get_name()}-table", + $this->locate_URI('/static/css/table.css'), + array(), + $this->manifest->get_version() + ); + } + + wp_enqueue_script( + "fw-ext-{$this->get_name()}-backup", + $this->locate_URI('/static/js/backup.js'), + array(), + $this->manifest->get_version() + ); + wp_enqueue_script( + "fw-ext-{$this->get_name()}-settings", + $this->locate_URI('/static/js/settings.js'), + array('fw', 'fw-events'), + $this->manifest->get_version() + ); + + if ($this->wp_verify_nonce('backup-progress')) { + wp_enqueue_script( + "fw-ext-{$this->get_name()}-progress", + $this->locate_URI('/static/js/progress.js'), + array(), + $this->manifest->get_version() + ); + } + + } + } + } + + /** + * @internal + */ + public function _admin_action_wp_ajax_backup_progress() + { + if ($html = $this->backup_render_progress(FW_Request::POST('post'))) { + wp_send_json_success($html); + } + + wp_send_json_error(); + } + + /** + * @internal + */ + public function _admin_action_wp_ajax_backup_settings_save() + { + if (!current_user_can('manage_options')) { + wp_send_json_error(); + } + + $options = $this->get_backup_settings_options(); + $values = fw_get_options_values_from_input($options, FW_Request::POST('values')); + fw_set_db_extension_data($this->get_name(), 'settings', $values); + + $this->reschedule(); // do reschedule + // $this->init_services_cron(); // make cron.xxx services to be up to date + + wp_send_json_success(); + } + + /** + * @internal + */ + public function _admin_action_manage_xxx_posts_custom_column($column_name, $post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + */ + + // On debug mode use standard WordPress tables/functionality + if ($this->debug) { + return; + } + + if ($column_name == 'description') { + $meta = $this->service('post.meta'); + $meta->set_post_id($post_id); +?> +
    +

    +
    +
    +

    get_post_date()) ?>get_state_title()): ?>:

    +

    + get_cron_title()) ?> + + get_backup_file()): ?> + get_download_url()): ?> + | Download + + + get_progress()): ?> + | Cancel + + | Delete + +

    +
    +debug && get_post_type($post) == $this->get_post_type()) { + + unset($actions['edit']); + unset($actions['inline hide-if-no-js']); + + $post_id = get_post($post)->ID; + + if ($a = $this->url_backup_download($post_id)) { + $actions['download'] = sprintf(__('Download', 'fw'), $a); + } + + if ($a = $this->url_backup_restore($post_id)) { + $actions['restore'] = sprintf(__('Restore', 'fw'), $a); + } + + $meta = $this->service('post.meta'); + $meta->set_post_id($post_id); + if ($meta->get_progress()) { + $actions['progress'] = sprintf(__('Progress', 'fw'), $this->url_backup_progress($post_id)); + $actions['cancel'] = sprintf(__('Cancel', 'fw'), $this->url_backup_cancel($post_id)); + } + } + + return $actions; + } + + /** + * @internal + */ + public function _admin_filter_manage_xxx_columns($columns) + { + // On debug mode use standard WordPress tables/functionality + if ($this->debug) { + return $columns; + } + + return array( + 'description' => false, // Do not show checkbox on "Screen Options" + ); + } + + /** + * @internal + */ + public function _admin_filter_views_xxx_hack($views) + { + // NOTE This is a hack + // Output backup content just before [All (11) | Drafts (22) | Trash (33)] + + if ($this->wp_verify_nonce('backup-restore')) { + echo $this->render_view('backend/backup-restore', array('request_filesystem_credentials' => $this->request_filesystem_credentials)); + } + else { + echo $this->render_view('backend/backup-page'); + + // On debug mode use standard WordPress tables/functionality + if ($this->debug) { + return $views; + } + } + + return array(); + } + + // Internal + + private function init_param() + { + $this->param = array(); + $this->param['wordpress_dir'] = realpath(ABSPATH); + $this->param['backup_dir'] = $this->get_backup_dir(); + $this->param['backup_rel'] = trim(substr($this->param['backup_dir'], strlen($this->param['wordpress_dir'])), '/\\'); + } + + private function init_services() + { + $seconds_in_day = 86400; + $seconds_in_minute = 60; + + // N O T E + // Service names should not contain underscore character (_), for the reason + // look at encode_storage_id and decode_storage_id methods. + $this->service = array(); + + // The post.meta service is supposed for temporary access to post meta. + // It should be used like: + // + // $meta = $this->service('post.meta') + // $meta->set_post_id($post_id) + // ... + // + $this->service['post.meta'] = new FW_Backup_Service_Post_Meta(); + + // This services are intentionally shared. They should have the same instance + // among all of its clients. + $this->service['shared.post.meta'] = new FW_Backup_Service_Post_Meta(); + $this->service['shared.feedback'] = new FW_Backup_Service_Feedback($this->service['shared.post.meta']); + + $this->service['db'] = new FW_Backup_Service_Database(); + $this->service['fs'] = new FW_Backup_Service_File_System(); + $this->service['ie.settings'] = new FW_Backup_IE_Settings($this->get_name()); + $this->service['ie.history'] = new FW_Backup_IE_History($this->get_post_type()); + $this->service['ie.db'] = new FW_Backup_IE_Database($this->get_post_type(), $this->service('db'), $this->service('shared.feedback')); + $this->service['ie.fs'] = new FW_Backup_IE_File_System($this->param['wordpress_dir'], $this->param['backup_dir'], $this->service('fs'), $this->service('shared.feedback')); + $this->service['process.backup-restore'] = new FW_Backup_Process_Backup_Restore($this->param['wordpress_dir'], $this->param['backup_rel'], $this->service('fs'), $this->service('db'), $this->service('ie.fs'), $this->service('ie.db'), $this->service('ie.settings'), $this->service('ie.history'), $this->service('shared.feedback')); + $this->service['process.apply-age-limit'] = new FW_Backup_Process_Apply_Age_Limit(($this->debug ? $seconds_in_minute : $seconds_in_day), $this->get_post_type(), $this->service('post.meta'), $this->service('shared.feedback')); + + // N O T E + // One extension can introduce only one service (otherwise how to name this services?) + + // Introduce storage layer + foreach ($this->get_children() as $child_name => $inst) { + if ($inst instanceof FW_Backup_Interface_Storage_Factory) { + $this->service[$child_name] = $inst->create_storage(); + continue; + } + } + + // Introduce cron jobs + foreach ($this->cron as $cron) { + list ($cron_id, $cron_title, $backup_contents, $backup_now) = $cron; + $this->service[$cron_id] = $this->create_cron($cron_id, $cron_title, $backup_contents, $backup_now); + } + } + + private function create_cron($service_id, $title, array $contents, $backup_now = false) + { + $param = $this->get_option($service_id, 'storage'); + $storage_id = $this->decode_storage_id($param['selected']); + + $schedule_id = wp_get_schedule('fw_backup_cron', array($service_id)); + if ($schedule_id) { + $active = true; + $schedules = wp_get_schedules(); + $schedule_title = $schedules[$schedule_id]['display']; + $next_at_title = sprintf(__('Next Backup on %s', 'fw'), date('d.m.Y H:i:s', wp_next_scheduled('fw_backup_cron', array($service_id)))); + } + else { + $active = false; + $schedule_title = $next_at_title = __('Not Scheduled', 'fw'); + } + + $storage = $this->service($storage_id, 'FW_Backup_Interface_Storage'); + if ($storage instanceof FW_Backup_Interface_Multi_Picker_Set && isset($param['values'])) { + $storage->set_option_values($param['values']); + } + + return new FW_Backup_Service_Cron($active, $backup_now, $service_id, $title, $schedule_title, $next_at_title, $storage, $storage_id, $contents); + } + + private function backup_create(FW_Backup_Interface_Cron $cron) + { + $post_id = wp_insert_post(array( + 'post_type' => $this->get_post_type(), + 'post_title' => sprintf(__('%s: Initialization...', 'fw'), $cron->get_title())) + ); + if ($post_id == 0 || $post_id instanceof WP_Error) { + throw new FW_Backup_Exception(sprintf(__('wp_insert_post(post_type=%s) failed', 'fw'), $this->get_post_type())); + } + + /** + * @var FW_Backup_Service_Post_Meta $meta + * @var FW_Backup_Service_Feedback $feedback + */ + $meta = $this->service('shared.post.meta'); + $meta->set_post_id($post_id); + $meta->set_cron_id($cron->get_id()); + $meta->set_cron_title($cron->get_title()); + $meta->set_storage_id($cron->get_storage_id()); + $meta->set_backup_contents($cron->get_backup_contents()); + $meta->set_state_title(__('Waiting for start...', 'fw')); + + // this is necessary + $feedback = $this->service('shared.feedback'); + $feedback->set_task(__('Waiting for start...', 'fw')); + + return $post_id; + } + + private function backup_run($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + * @var FW_Backup_Interface_Storage $storage + * @var FW_Backup_Process_Backup_Restore $backup_restore + * @var FW_Backup_Process_Apply_Age_Limit $apply_age_limit + */ + + set_time_limit(0); + $meta = $this->service('shared.post.meta'); + $meta->set_post_id($post_id); + + try { + $meta->set_cron_started(); + + $storage = $this->service($meta->get_storage_id(), 'FW_Backup_Interface_Storage'); + $backup_restore = $this->service('process.backup-restore', 'FW_Backup_Process_Backup_Restore'); + $apply_age_limit = $this->service('process.apply-age-limit', 'FW_Backup_Process_Apply_Age_Limit'); + + // 1) Ensure that storage service is workable + $storage->ping(); + + // A way to exclude file system from backup + if (!in_array('fs', $meta->get_backup_contents())) { + $backup_restore->set_ie_fs(new FW_Backup_IE_File_System_Void()); + } + + // 2) Do backup + $backup_file = $backup_restore->backup($storage); + + // 3) Record the time it was completed + $this->set_option($meta->get_cron_id(), 'completed_at', time()); + + $meta->set_state_title(__('Complete', 'fw'), true); + $meta->set_backup_file($backup_file); + + // 4) Remove obsolete backup files of the same type (i.e. "Full Backup" or "Database Backup") + $apply_age_limit->run($meta->get_cron_id(), $this->get_option($meta->get_cron_id(), 'lifetime')); + } + catch (FW_Backup_Exception_Cancelled $exception) { + $meta->set_state_title(__('Cancelled', 'fw')); + } + catch (FW_Backup_Exception $exception) { + $meta->set_state_title(__('Failed', 'fw')); + } + + $meta->publish(isset($exception) ? $exception->getMessage() : null); + } + + private function restore_run($post_id) + { + /** + * @var FW_Backup_Service_Post_Meta $meta + * @var FW_Backup_Interface_Storage $storage + * @var FW_Backup_Process_Backup_Restore $backup_restore + * @var WP_Filesystem_Base $wp_filesystem + */ + + global $wp_filesystem; + + ob_start(); + $credentials = request_filesystem_credentials(fw_current_url(), '', false, false, null); + $this->request_filesystem_credentials = ob_get_clean(); + if ($credentials) { + if (!WP_Filesystem($credentials)) { + ob_start(); + request_filesystem_credentials(fw_current_url(), '', false, false, null); + $this->request_filesystem_credentials = ob_get_clean(); + } + } + + if ($this->request_filesystem_credentials) { + return false; + } + + if ($_SERVER['REQUEST_METHOD'] == 'GET') { + return false; + } + +// ob_start(); +// fw_print('Let\'s start the party!!!'); +// $this->request_filesystem_credentials = ob_get_clean(); +// return; + + set_time_limit(0); + $meta = $this->service('shared.post.meta'); + $meta->set_post_id($post_id); + + $storage = $this->service($meta->get_storage_id(), 'FW_Backup_Interface_Storage'); + $backup_restore = $this->service('process.backup-restore', 'FW_Backup_Process_Backup_Restore'); + + // 1) Do we have enough permissions for restoring file system / database? + // If no there is no need for fetching archive. + + if (in_array('fs', $meta->get_backup_contents())) { + $backup_restore->check_permissions_fs(); + } + if (in_array('db', $meta->get_backup_contents())) { + $backup_restore->check_permissions_db(); + } + + // 2) Do restore + $backup_restore->restore($storage, $meta->get_backup_file()); + + // 3) Actualize settings + $this->reschedule(); + + FW_Flash_Messages::add(uniqid(), __('The site was restored from backup', 'fw')); + + return true; + } + + /** + * @internal + */ + public function get_backup_settings_options() + { + /** + * @var FW_Backup_Interface_Cron $cron + * @var FW_Backup_Interface_Storage $storage + */ + + if (empty($this->service)) { + throw new FW_Backup_Exception(__('No Services: Did init_services was called?', 'fw')); + } + + $schedule_default = 'disabled'; + $schedule_choices = array( + 'disabled' => __('Disabled', 'fw'), + ); + foreach (wp_get_schedules() as $id => $schedule) { + if (strpos($id, 'backup.') === 0) { + $schedule_choices[$id] = $schedule['display']; + } + } + + $storage_default = null; + $storage_choices = array(); + $storage_multi_picker_sets = array(); + foreach ($this->service_list('FW_Backup_Interface_Storage') as $service_id => $storage) { + $storage_choices[$this->encode_storage_id($service_id)] = $storage->get_title(); + // default storage layer is Local + if ($storage instanceof FW_Backup_Storage_Local) { + $storage_default = $this->encode_storage_id($service_id); + } + if ($storage instanceof FW_Backup_Interface_Multi_Picker_Set) { + /** + * @var FW_Backup_Interface_Multi_Picker_Set $storage + */ + $storage_multi_picker_sets[$this->encode_storage_id($service_id)] = $storage->get_multi_picker_set(); + } + } + + $options = array(); + foreach ($this->cron as $cron) { + + list ($cron_id, $cron_title) = $cron; + + if ($this->debug) { + $desc = __('Age limit of backups in minutes', 'fw'); + } + else { + $desc = __('Age limit of backups in days', 'fw'); + } + + $attr = array( + 'type' => 'text', + 'name' => 'fw_options[' . $this->get_option_name($cron_id, 'lifetime') . ']', + 'value' => $this->get_option($cron_id, 'lifetime'), + 'id' => 'fw-option-' . $this->get_option_name($cron_id, 'lifetime'), + 'placeholder' => __('No Limit', 'fw'), + 'class' => 'fw-option fw-option-type-text', + 'style' => 'width: 90%', + ); + $html = fw_html_tag('input', $attr, ' ' . ($this->debug ? __('Minutes', 'fw') : __('Days', 'fw')) . ''); + + $options[] = array( + 'type' => 'tab', + 'title' => $cron_title, + 'attr' => array('data-container' => 'backup-settings'), + 'options' => array( + $this->get_option_name($cron_id, 'completed_at') => array( + 'type' => 'hidden', + 'value' => 0, + ), + $this->get_option_name($cron_id, 'schedule') => array( + 'type' => 'select', + 'attr' => array('data-type' => 'backup-schedule'), + 'label' => __('Backup Interval', 'fw'), + 'desc' => __('Select how often do you want to backup your website.', 'fw'), + 'value' => $schedule_default, + 'choices' => $schedule_choices, + ), + 'group' => array( + 'type' => 'group', + 'attr' => array('class' => 'hide-if-disabled'), + 'options' => array( + $this->get_option_name($cron_id, 'storage') => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'attr' => array('class' => 'hidden'), + 'value' => array( + 'selected' => $storage_default, + ), + 'picker' => array( + 'selected' => array( + 'type' => 'select', + 'label' => __('Backup On', 'fw'), + 'desc' => __('Select where do you want your backup to be saved', 'fw'), + 'choices' => $storage_choices, + ), + ), + 'sets' => $storage_multi_picker_sets, + ), + $this->get_option_name($cron_id, 'lifetime') => array( + 'type' => 'html-fixed', + 'label' => __('Backup Age Limit', 'fw'), + 'desc' => $desc, + 'html' => $html, + 'value' => '', + ), + ), + ), + ), + ); + } + + return $options; + } + + /** + * @internal + */ + public function get_backup_settings_values() + { + return fw_get_db_extension_data($this->get_name(), 'settings'); + } + + private function set_backup_settings_values() + { + } + + private function get_option($service_id, $key) + { + static $is_getting_option = false; + + if ($is_getting_option) { + // prevent recursion + return false; + } + + $is_getting_option = true; + + $values = fw_get_db_extension_data($this->get_name(), 'settings'); + + if (empty($values)) { + /** + * Settings options was never saved to database. + * Emulate save with default values. + * + * So on next refresh we will not need to call again + * fw_get_options_values_from_input( $this->get_backup_settings_options(), array() ) + * I think it's resource consuming to call that on every refresh + */ + + $options = $this->get_backup_settings_options(); + $values = fw_get_options_values_from_input($options, array()); + + fw_set_db_extension_data($this->get_name(), 'settings', $values); + } + + $option_name = $this->get_option_name($service_id, $key); + + $is_getting_option = false; + + if (isset($values[$option_name])) { + return $values[$option_name]; + } else { + return false; + } + } + + private function get_option_name($service_id, $key) + { + return strtr("$service_id-$key", '.', '-'); + } + + private function set_option($service_id, $key, $value) + { + $option_name = $this->get_option_name($service_id, $key); + + $settings = fw_get_db_extension_data($this->get_name(), 'settings'); + $settings[$option_name] = $value; + fw_set_db_extension_data($this->get_name(), 'settings', $settings); + } + + // option type multi-picker does not work when values in SELECT contains dot (.) + // i think that's because items in "sets" are selected by #. if will + // contain dot (.) that will treat as #xxx.yyy i.e. element with id #xxx and class .yyy + private function encode_storage_id($value) + { + return strtr($value, '.', '_'); + } + + private function decode_storage_id($value) + { + return strtr($value, '_', '.'); + } + + /** + * Reschedule all cron jobs + */ + private function reschedule() + { + /** + * N O T E + * If cron previously registered was not in here it will not be unscheduled now, + * but next time it will be fired. + */ + foreach (array_keys($this->service_list('FW_Backup_Interface_Cron')) as $cron_id) { + wp_clear_scheduled_hook('fw_backup_cron', array($cron_id)); + $schedule_id = $this->get_option($cron_id, 'schedule'); + $schedules = wp_get_schedules(); + if (isset($schedules[$schedule_id])) { + $schedule_interval = $schedules[$schedule_id]['interval']; + $completed_at = $this->get_option($cron_id, 'completed_at'); + // First time backup should be made right now. Then each time an interval was passed. + wp_schedule_event(max($completed_at + $schedule_interval, time()), $schedule_id, 'fw_backup_cron', array($cron_id)); + } + } + } + + // Helpers + + /** + * @internal + */ + public function wp_verify_nonce($action) + { + $nonce = FW_Request::GET('_wpnonce'); + return $nonce && wp_verify_nonce($nonce, $action); + } + + /** + * Version of wp_nonce_url() without esc_html() + */ + private function wp_nonce_url_raw($action_url, $action = -1, $name = '_wpnonce') + { + $action_url = str_replace('&', '&', $action_url); + return add_query_arg($name, wp_create_nonce($action), $action_url); + } +} diff --git a/scratch-parent/framework/extensions/backup/extensions/storage-local/class-fw-extension-storage-local.php b/scratch-parent/framework/extensions/backup/extensions/storage-local/class-fw-extension-storage-local.php new file mode 100644 index 00000000..828e9362 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/extensions/storage-local/class-fw-extension-storage-local.php @@ -0,0 +1,25 @@ +get_parent(); + + return new FW_Backup_Storage_Local($backup, $backup->service('shared.feedback')); + } + + // FW_Extension + + /** + * @internal + */ + public function _init() + { + } +} diff --git a/scratch-parent/framework/extensions/backup/extensions/storage-local/includes/class-fw-backup-file-local.php b/scratch-parent/framework/extensions/backup/extensions/storage-local/includes/class-fw-backup-file-local.php new file mode 100644 index 00000000..49741d32 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/extensions/storage-local/includes/class-fw-backup-file-local.php @@ -0,0 +1,21 @@ +path = $path; + } + + public function get_path() + { + return $this->path; + } + + public function get_download_url() + { + return site_url(str_replace(DIRECTORY_SEPARATOR, '/', substr($this->path, strlen(realpath(ABSPATH))))); + } +} diff --git a/scratch-parent/framework/extensions/backup/extensions/storage-local/includes/class-fw-backup-storage-local.php b/scratch-parent/framework/extensions/backup/extensions/storage-local/includes/class-fw-backup-storage-local.php new file mode 100644 index 00000000..ef975352 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/extensions/storage-local/includes/class-fw-backup-storage-local.php @@ -0,0 +1,78 @@ +backup = $backup; + $this->feedback = $feedback; + } + + // FW_Backup_Interface_Storage + + public function get_title($context = null) + { + return ($context == 'on') ? __('Locally', 'fw') : __('Local', 'fw'); + } + + public function ping() + { + $this->get_backup_dir(); + } + + public function move($file) + { + $ext = pathinfo($file, PATHINFO_EXTENSION); + $date = date('Y-m-d_H-i-s'); + $target = $this->get_backup_dir() . DIRECTORY_SEPARATOR . "backup-$date.$ext"; + + $this->feedback->set_task(sprintf(__('Storing as %s', 'fw'), $target)); + + if (!@rename($file, $target)) { + $error = error_get_last(); + throw new FW_Backup_Exception(sprintf(__('rename(%s, %s) failed with message "%s"', 'fw'), $file, $target, $error['message'])); + } + + return new FW_Backup_File_Local(realpath($target)); + } + + public function fetch(FW_Backup_Interface_File $backup_file) + { + if (!$backup_file instanceof FW_Backup_File_Local) { + throw new FW_Backup_Exception('$backup_file should be of class FW_Backup_File_Local'); + } + + $tmp = tempnam(sys_get_temp_dir(), 'backup'); + if (!@copy($backup_file->get_path(), $tmp)) { + $error = error_get_last(); + throw new FW_Backup_Exception(sprintf(__('copy(%s, %s) failed with message "%s"', 'fw'), $backup_file->get_path(), $tmp, $error['message'])); + } + + return $tmp; + } + + public function remove(FW_Backup_Interface_file $backup_file) + { + if (!$backup_file instanceof FW_Backup_File_Local) { + throw new FW_Backup_Exception('$backup_file should be of class FW_Backup_File_Local'); + } + + if (!@unlink($backup_file->get_path())) { + $error = error_get_last(); + throw new FW_Backup_Exception(sprintf('unlink(%s) failed with message "%s"', $backup_file->get_path(), $error['message'])); + } + } + + private function get_backup_dir() + { + $backup_dir = $this->backup->get_backup_dir(true); + if ($backup_dir === false) { + throw new FW_Backup_Exception(__('Cannot create local backup directory. Not enough permissions?', 'fw')); + } + + return $backup_dir; + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-database.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-database.php new file mode 100644 index 00000000..0aa80727 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-database.php @@ -0,0 +1,88 @@ +post_type = $post_type; + $this->db = $db; + $this->feedback = $feedback; + } + + public function import($fp) + { + list ($table, $view) = $this->db->query_schema(); + array_map(array($this->db, 'drop_table'), $table); + array_map(array($this->db, 'drop_view'), $view); + + $this->db->foreach_statement($fp, array($this->db, 'query')); + + wp_cache_flush(); + } + + public function export($fp) + { + global $wpdb; + + $this->feedback->set_task(__('Querying database...', 'fw')); + + list($table, $view) = $this->db->query_schema(); + + $this->feedback->set_task(sprintf(__('%d tables found', 'fw'), count($table))); + $this->feedback->set_task(sprintf(__('%d views found', 'fw'), count($view))); + + $table_sql = array_map(array($this->db, 'show_create_table'), $table); + $view_sql = array_map(array($this->db, 'show_create_view'), $view); + + $this->feedback->set_task(__('Dumping tables...', 'fw'), count($table)); + + $first = true; + $index = 0; + foreach (array_combine($table, $table_sql) as $name => $sql) { + + $this->feedback->set_task_progress($index, $name); + + fwrite($fp, ($first ? $first = false : PHP_EOL.PHP_EOL)); + fwrite($fp, $this->db->close_mysql_statement($sql)); + + // get rid of backup history as well as backup settings + switch ($name) { + case $wpdb->posts: + $query = sprintf('SELECT * FROM %s WHERE post_type != %s', + $this->db->escape_mysql_identifier($name), + $this->db->escape_mysql_value($this->post_type)); + break; + case $wpdb->postmeta: + $query = sprintf('SELECT a.* FROM %s AS a INNER JOIN %s AS b WHERE a.post_id = b.ID AND b.post_type != %s', + $this->db->escape_mysql_identifier($name), + $this->db->escape_mysql_identifier($wpdb->posts), + $this->db->escape_mysql_value($this->post_type) + ); + break; + case $wpdb->options: + $query = sprintf("SELECT * FROM %s WHERE option_name NOT LIKE 'fw_backup.%%'", + $this->db->escape_mysql_identifier($name) + ); + break; + default: + $query = sprintf('SELECT * FROM %s', $this->db->escape_mysql_identifier($name)); + break; + } + + $this->db->dump_query($fp, $query, $name); + $this->feedback->set_task_progress(++$index, $name); + } + + $this->feedback->set_task(__('Dumping views...', 'fw')); + + foreach (array_combine($view, $view_sql) as $name => $sql) { + // $log->append('dumping view '.$name); + fwrite($fp, ($first ? $first = false : PHP_EOL.PHP_EOL)); + fwrite($fp, $this->db->close_mysql_statement($sql)); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-file-system-void.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-file-system-void.php new file mode 100644 index 00000000..1d48946a --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-file-system-void.php @@ -0,0 +1,8 @@ +wordpress_dir = $wordpress_dir; + $this->backup_dir = $backup_dir; + $this->fs = $fs; + $this->feedback = $feedback; + } + + public function import(ZipArchive $zip) + { + if (is_dir($this->wordpress_dir)) { + throw new FW_Backup_Exception(sprintf(__('Directory already exists: %s', 'fw'), $this->wordpress_dir)); + } + + $zip->extractTo($this->wordpress_dir); + } + + public function export(ZipArchive $zip) + { + $this->feedback->set_task(__('Scanning file system...', 'fw')); + + // FIXME not enough permissions to some dirs ( ! ) Warning: scandir(/path/to/dir): failed to open dir: Permission denied + $file_list = array(); + $file_size = array(); + foreach ($this->fs->file_list($this->wordpress_dir, true) as $file) { + + // get rid of $wordpress_dir entry + if ($file == $this->wordpress_dir) { + continue; + } + + // exclude files under $backup_dir + if (strpos($file, $this->backup_dir) === 0) { + continue; + } + + // standard error message lacks $file + if (($size = filesize($file)) === false) { + trigger_error("\n\n\n$file\n\n\n"); + } + else { + $file_list[] = $file; + $file_size[] = $size; + } + + } + + $this->feedback->set_task(sprintf(__('%d file(s) found [%s]', 'fw'), count($file_list), $this->fs->format_bytes(array_sum($file_size)))); + $this->feedback->set_task(__('Adding files to archive...', 'fw'), count($file_list)); + + foreach ($file_list as $index => $file) { + $name_in_zip = trim(substr($file, strlen($this->wordpress_dir)), DIRECTORY_SEPARATOR); + if (is_dir($file)) { + $zip->addEmptyDir($name_in_zip); + } + else { + if (is_readable($file)) { + $zip->addFile($file, $name_in_zip); + } + else { + // $log->append("error: could not read file $file"); + } + } + $this->feedback->set_task_progress($index); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-history.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-history.php new file mode 100644 index 00000000..0a73fdf1 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-history.php @@ -0,0 +1,49 @@ +post_type = $post_type; + } + + public function import($fp) + { + /** + * @var int $post_id + */ + + $post_type = $this->post_type; + + while ($csv = fgetcsv($fp)) { + list ($post_title, $post_status, $post_date, $post_content, $post_meta) = $csv; + + $post_id = wp_insert_post(compact('post_type', 'post_title', 'post_status', 'post_date', 'post_content')); + if ($post_id == 0 || $post_id instanceof WP_Error) { + throw new FW_Backup_Exception('Could not create post of type '.$this->post_type); + } + + foreach (unserialize($post_meta) as $meta_key => $meta_value_list) { + update_post_meta($post_id, $meta_key, maybe_unserialize($meta_value_list[0])); + } + } + } + + public function export($fp) + { + $post_type = $this->post_type; + $posts_per_page = 50; + $count = wp_count_posts($this->post_type); + + foreach (array('publish', 'trash') as $post_status) { + for ($offset = 0; $offset < $count->$post_status; $offset += $posts_per_page) { + foreach (get_posts(compact('post_type', 'post_status', 'posts_per_page', 'offset')) as $post) { + fputcsv($fp, array($post->post_title, $post->post_status, $post->post_date, $post->post_content, serialize(get_post_meta($post->ID)))); + } + } + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-settings.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-settings.php new file mode 100644 index 00000000..c34d5016 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-ie-settings.php @@ -0,0 +1,26 @@ +name = $name; + } + + public function import($fp) + { + $json = ''; + while ($line = fgets($fp)) { + $json .= $line; + } + + fw_set_db_extension_data('backup', $this->name, json_decode($json, true)); + } + + public function export($fp) + { + fwrite($fp, json_encode(fw_get_db_extension_data('backup', $this->name))); + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-process-apply-age-limit.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-process-apply-age-limit.php new file mode 100644 index 00000000..6653fc01 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-process-apply-age-limit.php @@ -0,0 +1,65 @@ +seconds_in_unit = $seconds_in_unit; + $this->post_type = $post_type; + $this->meta = $meta; + $this->feedback = $feedback; + } + + public function run($cron_id, $age_limit_in_units) + { + if (empty($age_limit_in_units)) { + return; + } + + $this->feedback->set_task(__('Removing obsolete backup copies...', 'fw')); + + $this->cron_id = $cron_id; + $this->age_limit = time() - $age_limit_in_units*$this->seconds_in_unit; + $this->foreach_post('publish'); + } + + private function foreach_post($post_status = 'publish', $done = 0) + { + $default = array( + 'post_type' => $this->post_type, + 'posts_per_page' => 50 + ); + + $offset = 0; + while (true) { + $a = get_posts(array_merge($default, compact('post_status', 'offset'))); + if (empty($a)) { + break; + } + foreach ($a as $post) { + $this->apply_age_limit($post, $done + $offset); + $offset += 1; + } + } + + return $offset; + } + + private function apply_age_limit(WP_Post $post) + { + $this->meta->set_post_id($post->ID); + if ($this->meta->get_cron_id() == $this->cron_id) { + $post_date = strtotime($this->meta->get_post_date()); + if ($post_date < $this->age_limit) { + wp_trash_post($post->ID); + } + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-process-backup-restore.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-process-backup-restore.php new file mode 100644 index 00000000..98379258 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-process-backup-restore.php @@ -0,0 +1,349 @@ +wordpress_dir = $wordpress_dir; + $this->backup_rel = $backup_rel; + $this->fs = $fs; + $this->db = $db; + $this->ie_fs = $ie_fs; + $this->ie_db = $ie_db; + $this->ie_settings = $ie_settings; + $this->ie_history = $ie_history; + $this->feedback = $feedback; + } + + public function set_ie_fs(FW_Backup_IE_File_System $ie_fs) + { + $this->ie_fs = $ie_fs; + } + + public function set_ie_db(FW_Backup_Interface_IE $ie_db) + { + $this->ie_db = $ie_db; + } + + public function backup(FW_Backup_Interface_Storage $storage) + { + /** + * @var $backup_file + */ + + $tmp = array( + $tmp_zip = tempnam(sys_get_temp_dir(), 'backup'), + $tmp_db = tempnam(sys_get_temp_dir(), 'database'), + ); + $fp = array(); + + try { + + $zip = new ZipArchive(); + if (($errno = $zip->open($tmp_zip)) !== true) { + throw new FW_Backup_Exception(sprintf(__('$zip->open() failed: %d', 'fw'), $errno)); + } + + // Export File System + $this->ie_fs->export($zip); + + // Export Database + $fp[] = $fp_db = fopen($tmp_db, 'w'); + $this->ie_db->export($fp_db); + fclose($fp_db); + array_pop($fp); + + $zip->addFile($tmp_db, 'database.sql'); + + // The most lengthy process... + $this->feedback->set_task(__('Compressing...', 'fw')); + $zip->close(); + + // Save backup file somewhere (add .zip suffix to the file) + $tmp[] = $tmp_zip_zip = "$tmp_zip.zip"; + rename($tmp_zip, $tmp_zip_zip); + $backup_file = $storage->move($tmp_zip_zip); + + } + catch (Exception $exception) { + } + + // Clean up + array_map('fclose', $fp); + array_map('unlink', array_filter($tmp, 'file_exists')); + + if (isset($exception)) { + throw $exception; + } + + return $backup_file; + } + + public function restore(FW_Backup_Interface_Storage $storage, FW_Backup_Interface_File $backup_file) + { + /** + * @var WP_Filesystem_Base $wp_filesystem + */ + + global $wp_filesystem; + + if ($wp_filesystem->abspath() == '/') { + throw new FW_Backup_Exception('WordPress was located at root directory (/). Restoration for this scenario was not implemented.'); + } + + $wp = rtrim($wp_filesystem->abspath(), '/'); + $wp_new = rtrim(dirname($wp), '/') . '/' . uniqid(); + $wp_backup = $wp . '-' . date('Y-m-d_H-i_s'); + $backup_rel = str_replace(DIRECTORY_SEPARATOR, '/', $this->backup_rel); + + $tmp = array(); + $func = array(); + + try { + // Fetch archive + $tmp[] = $tmp_zip = $storage->fetch($backup_file); + $zip = new ZipArchive(); + if (($errno = $zip->open($tmp_zip)) !== true) { + throw new FW_Backup_Exception(sprintf(__('$zip->open() failed: %d'), $errno)); + } + $func[] = array($zip, 'close'); + + // Restore files (should come before database: rename wordpress dir can fail) + if (count(array_filter(array('index.php', 'wp-config.php'), array($zip, 'statName'))) > 0) { + + // Extract archive into temporary location + unzip_file($tmp_zip, $wp_new); + + // Get rid of database.sql file, if any + if ($wp_filesystem->exists("$wp_new/database.sql")) { + $wp_filesystem->delete("$wp_new/database.sql"); + } + + // Replace wordpress dir by version from backup + $move = true + && $wp_filesystem->move($wp, $wp_backup) + && $wp_filesystem->move($wp_new, $wp) + && $wp_filesystem->move("$wp_backup/$backup_rel", "$wp/$backup_rel"); + if (!$move) { + throw new FW_Backup_Exception('Replacing wordpress dir by version from backup failed'); + } + } + + // Restore database + if ($zip->statName('database.sql') !== false) { + $fp = array( + $fp_settings = tmpfile(), + $fp_history = tmpfile(), + ); + + // Preserve Backup History and Backup Settings across restore + $this->ie_history->export($fp_history); + $this->ie_settings->export($fp_settings); + + // .zip streams does not support seeking + array_map('rewind', $fp); + $fp[] = $fp_db = $zip->getStream('database.sql'); + + $this->ie_db->import($fp_db); + $this->ie_history->import($fp_history); + $this->ie_settings->import($fp_settings); + + array_map('fclose', $fp); + } + } + catch (Exception $exception) { + + // Delete directory .zip was extracted into + if ($wp_filesystem->exists($wp_new)) { + $wp_filesystem->delete($wp_new, true); + } + + // If backup copy was made + if ($wp_filesystem->exists($wp_backup)) { + // 3. Move backup_dir back + if ($wp_filesystem->exists("$wp/$backup_rel")) { + $wp_filesystem->move("$wp/$backup_rel", "$wp_backup/$backup_rel"); + } + // 2. Delete extracted version + if ($wp_filesystem->exists($wp)) { + $wp_filesystem->delete($wp, true); + } + // 1. Move backup'ed directory backup + $wp_filesystem->move($wp_backup, $wp); + } + } + + // on WAMP 2.5 with PHP 5.5.12 and Apache 2.4.9 this makes php crash + // array_map('call_user_func', $func); + foreach ($func as $callable) { + call_user_func($callable); + } + + array_map('unlink', array_filter($tmp, 'file_exists')); + + if (isset($exception)) { + throw $exception; + } + } + + private function restore_direct(FW_Backup_Interface_Storage $storage, FW_Backup_Interface_File $backup_file) + { + $wp = $this->wordpress_dir; + $wp_new = dirname($this->wordpress_dir) . DIRECTORY_SEPARATOR . uniqid(); + $wp_backup = $this->wordpress_dir . '-' . date('Y-m-d_H-i_s'); + $backup_rel = $this->backup_rel; + + $tmp = array(); + $func = array(); + + try { + // Fetch archive + $tmp[] = $tmp_zip = $storage->fetch($backup_file); + $zip = new ZipArchive(); + if (($errno = $zip->open($tmp_zip)) !== true) { + throw new FW_Backup_Exception(sprintf(__('$zip->open() failed: %d'), $errno)); + } + $func[] = array($zip, 'close'); + + // Restore files (should come before database: rename wordpress dir can fail) + if (count(array_filter(array('index.php', 'wp-config.php'), array($zip, 'statName'))) > 0) { + $this->extract($zip, $wp_new); + // Get rid of database.sql file, if any + array_map('unlink', array_filter(array("$wp_new/database.sql"), 'file_exists')); + $this->mv($wp, $wp_backup); + $this->mv($wp_new, $wp); + $this->mv("$wp_backup/$backup_rel", "$wp/$backup_rel"); + } + + // Restore database + if ($zip->statName('database.sql') !== false) { + $fp = array( + $fp_settings = tmpfile(), + $fp_history = tmpfile(), + ); + + // Preserve Backup History and Backup Settings across restore + $this->ie_history->export($fp_history); + $this->ie_settings->export($fp_settings); + + // .zip streams does not support seeking + array_map('rewind', $fp); + $fp[] = $fp_db = $zip->getStream('database.sql'); + + $this->ie_db->import($fp_db); + $this->ie_history->import($fp_history); + $this->ie_settings->import($fp_settings); + + array_map('fclose', $fp); + } + } + catch (Exception $exception) { + // get rid of directory .zip was extracted into + if (file_exists($wp_new)) { + $this->rm($wp_new); + } + // if backup copy was made + if (file_exists($wp_backup)) { + // even backup directory was moved to restored dir + if (file_exists("$wp/$backup_rel")) { + $this->mv("$wp/$backup_rel", "$wp_backup/$backup_rel"); + } + if (file_exists($wp)) { + $this->rm($wp); + } + $this->mv($wp_backup, $wp); + } + } + + // on WAMP 2.5 with PHP 5.5.12 and Apache 2.4.9 this makes php crash + // array_map('call_user_func', $func); + foreach ($func as $callable) { + call_user_func($callable); + } + + array_map('unlink', array_filter($tmp, 'file_exists')); + + if (isset($exception)) { + throw $exception; + } + } + + public function check_permissions_fs() + { + /** + * @var WP_Filesystem_Base $wp_filesystem + */ + + global $wp_filesystem; + + $wp_new = rtrim(dirname($wp_filesystem->abspath()), '/') . '/' . uniqid(); + + if (!$wp_filesystem->mkdir($wp_new)) { + throw new FW_Backup_Exception(sprintf(__('mkdir(%s) failed', 'fw'), $wp_new)); + } + + $wp_filesystem->rmdir($wp_new); + } + + private function check_permissions_fs_direct() + { + $wp_new = dirname($this->wordpress_dir) . DIRECTORY_SEPARATOR . uniqid(); + + if (!@mkdir($wp_new)) { + $error = error_get_last(); + throw new FW_Backup_Exception(sprintf(__('mkdir(%s) failed with message "%s"', 'fw'), $wp_new, $error['message'])); + } + + rmdir($wp_new); + } + + public function check_permissions_db() + { + $privileges = $this->db->show_privileges(); + + if (!isset($privileges['DROP']) || !in_array('TABLES', $privileges['DROP'])) { + throw new FW_Backup_Exception(__('MySQL lacks DROP TABLES privilege', 'fw')); + } + + if (!isset($privileges['CREATE']) || !in_array('TABLES', $privileges['CREATE'])) { + throw new FW_Backup_Exception(__('MySQL lacks CREATE TABLE privilege', 'fw')); + } + } + + private function extract(ZipArchive $zip, $dir) + { + if (!@$zip->extractTo($dir)) { + throw new FW_Backup_Exception(sprintf(__("\$zip->extractTo(%s) failed. Not enough permissions?", 'fw'), $dir)); + } + } + + private function mv($from, $to) + { + if (!@rename($from, $to)) { + $error = error_get_last(); + throw new FW_Backup_Exception(sprintf(__('rename(%s, %s) failed with message "%s"', 'fw'), $from, $to, $error['message'])); + } + } + + private function rm($base) + { + foreach (array_reverse($this->fs->file_list($base)) as $file) { + if (is_dir($file)) { + rmdir($file); + } + else { + unlink($file); + } + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-cron.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-cron.php new file mode 100644 index 00000000..5a85dfd8 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-cron.php @@ -0,0 +1,72 @@ +active = $active; + $this->backup_now = $backup_now; + $this->id = $id; + $this->title = $title; + $this->schedule_title = $schedule_title; + $this->next_at_title = $next_at_title; + $this->storage = $storage; + $this->storage_id = $storage_id; + $this->backup_contents = $backup_contents; + } + + public function is_active() + { + return $this->active; + } + + public function has_backup_now() + { + return $this->backup_now; + } + + public function get_id() + { + return $this->id; + } + + public function get_title() + { + return $this->title; + } + + public function get_schedule_title() + { + return $this->schedule_title; + } + + public function get_next_at_title() + { + return $this->next_at_title; + } + + public function get_storage() + { + return $this->storage; + } + + public function get_storage_id() + { + return $this->storage_id; + } + + public function get_backup_contents() + { + return $this->backup_contents; + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-database.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-database.php new file mode 100644 index 00000000..572614f4 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-database.php @@ -0,0 +1,199 @@ +get_results($sql, $mode); + } + + public function query_column($sql, $column) + { + foreach ($this->query($sql, ARRAY_N) as $row) { + return $row[$column]; + } + + throw new FW_Backup_Exception('Database Error'); + } + + public function close_mysql_statement($stmt) + { + // Without **end of statement** restoration process seems to be much complicated. + return $stmt . '; -- end of statement' . PHP_EOL; + } + + // https://github.com/vrana/adminer/blob/master/adminer/drivers/mysql.inc.php#L273 + // https://github.com/vrana/adminer/blob/73629178d8fa1bf08f10e0b86f85c4e1f6307c39/adminer/drivers/mysql.inc.php#L273 + public function escape_mysql_identifier($identifier) + { + return '`' . str_replace('`', '``', $identifier) . '`'; + } + + public function escape_mysql_value($value) + { + global $wpdb; /** @var wpdb $wpdb */ + return "'" . $wpdb->_real_escape($value) . "'"; + } + + public function query_schema() + { + $table = array(); + $view = array(); + + foreach ($this->query('SHOW FULL TABLES', ARRAY_N) as $row) { + list ($table_or_view, $type) = $row; + switch ($type) { + case 'BASE TABLE': + $table[] = $table_or_view; + break; + case 'VIEW': + $view[] = $table_or_view; + break; + default: + throw new FW_Backup_Exception("Invalid table type: $type"); + } + } + + return array($table, $view); + } + + public function show_create_table($table) + { + return $this->query_column('SHOW CREATE TABLE '.$this->escape_mysql_identifier($table), 1); + } + + public function show_create_view($view) + { + return $this->query_column('SHOW CREATE VIEW '.$this->escape_mysql_identifier($view), 1); + } + + // https://github.com/vrana/adminer/blob/master/adminer/drivers/mysql.inc.php#L454 + // https://github.com/vrana/adminer/blob/73629178d8fa1bf08f10e0b86f85c4e1f6307c39/adminer/drivers/mysql.inc.php#L454 + public function show_columns($table) + { + $field = array(); + + $result = $this->query('SHOW FULL COLUMNS FROM '.$this->escape_mysql_identifier($table)); + if (empty($result)) { + return null; + } + + foreach ($result as $row) { + preg_match('~^([^( ]+)(?:\\((.+)\\))?( unsigned)?( zerofill)?$~', $row['Type'], $m); + $field[$row['Field']] = array( + 'field' => $row['Field'], + 'full_type' => $row['Type'], + 'collation' => $row['Collation'], + 'null' => ($row['Null'] == 'YES'), + 'primary' => ($row['Key'] == 'PRI'), + 'default' => ($row['Default'] != '' || preg_match('~char|set~', @$m[1]) ? $row['Default'] : null), + 'auto_increment' => ($row['Extra'] == 'auto_increment'), + 'privileges' => preg_split('~, *~', $row['Privileges']), + 'comment' => $row['Comment'], + 'type' => @$m[1], + 'length' => @$m[2], + 'unsigned' => ltrim(@$m[3] . @$m[4]), + 'on_update' => (preg_match('~^on update (.+)~i', $row['Extra'], $m) ? $m[1] : ''), //! available since MySQL 5.1.23 + ); + } + + return $field; + } + + public function show_privileges() + { + $privileges = array(); + foreach ($this->query('SHOW PRIVILEGES', ARRAY_N) as $row) { + $privileges[strtoupper($row[0])] = explode(',', strtoupper($row[1])); + } + return $privileges; + } + + public function drop_table($table) + { + $this->query('DROP TABLE '.$this->escape_mysql_identifier($table)); + } + + public function drop_view($view) + { + $this->query('DROP VIEW '.$this->escape_mysql_identifier($view)); + } + + public function dump_table($fp, $table, $max_packet = 1048576) + { + $this->dump_query($fp, 'SELECT * FROM '.$this->escape_mysql_identifier($table), $table, $max_packet); + } + + // https://github.com/vrana/adminer/blob/master/adminer/include/adminer.inc.php#L666 + // https://github.com/vrana/adminer/blob/06f4346cfeec0e9f67a375708f9265557a738141/adminer/include/adminer.inc.php#L666 + public function dump_query($fp, $query, $table, $max_packet = 1048576) + { + $insert_into = ''; + $buffer = ''; + $end_of_stmt = $this->close_mysql_statement(''); + + $field = $this->show_columns($table); + foreach ($this->query($query) as $row) { + $row_escaped = array(); + foreach ($row as $key => $value) { + if ($value === null) { + $row_escaped[$key] = 'NULL'; + } + // https://github.com/vrana/adminer/blob/master/adminer/include/adminer.inc.php#L707 + // https://github.com/vrana/adminer/blob/06f4346cfeec0e9f67a375708f9265557a738141/adminer/include/adminer.inc.php#L707 + else if (preg_match('~(^|[^o])int|float|double|decimal~', $field[$key]['type']) && $value != '') { + $row_escaped[$key] = $value; + } + else { + $row_escaped[$key] = $this->escape_mysql_value($value); + } + } + if (!$insert_into) { + $insert_into = 'INSERT INTO '.$this->escape_mysql_identifier($table). ' (' . implode(', ', array_map(array($this, 'escape_mysql_identifier'), array_keys($row_escaped))) . ') VALUES'; + } + $value_list = ($max_packet == 0 ? ' ' : PHP_EOL.' ') . '(' . implode(', ', $row_escaped) . ')'; + if (!$buffer) { + $buffer = $insert_into . $value_list; + } + elseif (strlen($buffer) + 4 + strlen($value_list) + strlen($end_of_stmt) < $max_packet) { // 4 - length specification + $buffer .= ',' . $value_list; + } + else { + fwrite($fp, $buffer . $end_of_stmt); + $buffer = $insert_into . $value_list; + } + } + + if ($buffer) { + fwrite($fp, $buffer . $end_of_stmt); + } + } + + public function foreach_statement($fp, $callback, $read_size = 102400) + { + $delimiter = $this->close_mysql_statement(''); + $buf = ''; + + while (!feof($fp)) { + $buf .= fread($fp, $read_size); + while (true) { + $pos = strpos($buf, $delimiter); + if ($pos === false) { + break; + } + $statement = substr($buf, 0, $pos); + call_user_func($callback, $statement); + $buf = substr($buf, $pos + strlen($delimiter)); + } + } + if ($buf) { + call_user_func($callback, $buf); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-feedback.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-feedback.php new file mode 100644 index 00000000..e923696c --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-feedback.php @@ -0,0 +1,68 @@ +post_meta = $post_meta; + } + + public function set_task($task_title, $progress_total = 0) + { + $this->task_title = $task_title; + $this->task_progress = null; + $this->task_progress_total = $progress_total; + $this->task_progress_title = null; + $this->commit(true); + } + + public function set_task_progress($task_progress_complete, $task_progress_title = null) + { + if ($this->task_progress_total) { + $this->task_progress = number_format($task_progress_complete/$this->task_progress_total*100, 2).'%'; + } + else { + $this->task_progress = $task_progress_complete; + } + $this->task_progress_title = $task_progress_title; + $this->commit($task_progress_complete == $this->task_progress_total); + } + + public function get_task_title() + { + return $this->task_title; + } + + public function get_task_progress() + { + return $this->task_progress; + } + + public function get_task_progress_title() + { + return $this->task_progress_title; + } + + // Internals + + private function commit($force = false) + { + if ($force || microtime(true) - $this->commit_at > $this->commit_timeout) { + if ($this->post_meta->get_cancelled()) { + throw new FW_Backup_Exception_Cancelled(); + } + $this->post_meta->set_progress($this); + $this->commit_at = microtime(true); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-file-system.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-file-system.php new file mode 100644 index 00000000..fc8f5057 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-file-system.php @@ -0,0 +1,77 @@ +file_list($base . DIRECTORY_SEPARATOR . $file, $follow_symlink) as $a) { + $ret[] = $a; + } + + } + } + } + + return $ret; + } + + // http://stackoverflow.com/a/2510459 + public function format_bytes($bytes, $precision = 2) + { + $units = array('B', 'KB', 'MB', 'GB', 'TB'); + + $bytes = max($bytes, 0); + $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); + $pow = min($pow, count($units) - 1); + + # Uncomment one of the following alternatives + $bytes /= pow(1024, $pow); + # $bytes /= (1 << (10 * $pow)); + + return round($bytes, $precision).' '.$units[$pow]; + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-post-meta.php b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-post-meta.php new file mode 100644 index 00000000..f0c5b03e --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/classes/class-fw-backup-service-post-meta.php @@ -0,0 +1,187 @@ +post_id; + } + + public function set_post_id($post_id) + { + $this->post_id = $post_id; + } + + public function get_post_title() + { + return $this->get_post()->post_title; + } + + public function get_post_date() + { + return $this->get_post()->post_date; + } + + public function set_state_title($state_title, $clear_on_publish = false) + { + $this->update('state.title', $state_title); + $this->update('state.clear_on_publish', $clear_on_publish); + + $post = $this->get_post(); + $post->post_title = sprintf('%s: %s', $this->get_cron_title(), $state_title); + wp_update_post($post); + } + + public function get_state_title() + { + return $this->query('state.title'); + } + + public function publish($post_content = null) + { + $post = $this->get_post(); + $post->post_status = 'publish'; + $post->post_content = $post_content; + wp_update_post($post); + + // used in the end of restore for flash message + // $this->delete('cron.title'); + $this->delete('cron.start'); + $this->delete('cron.cancel'); + $this->delete('cron.progress'); + if ($this->query('state.clear_on_publish')) { + $this->delete('state.title'); + } + $this->delete('state.clear_on_publish'); + } + + public function get_cron_id() + { + return $this->query('cron'); + } + + public function set_cron_id($cron_id) + { + $this->update('cron', $cron_id); + } + + public function get_storage_id() + { + return $this->query('storage'); + } + + public function set_storage_id($storage_id) + { + $this->update('storage', $storage_id); + } + + public function get_backup_contents() + { + return $this->query('backup.contents'); + } + + public function set_backup_contents(array $backup_contents) + { + $this->update('backup.contents', $backup_contents); + } + + /** + * @return false|FW_Backup_Interface_File + */ + public function get_backup_file() + { + $backup_file = $this->query('backup.file'); + + if ($backup_file instanceof FW_Backup_Interface_File) { + return $backup_file; + } + + return false; + } + + public function set_backup_file(FW_Backup_Interface_File $backup_file) + { + $this->update('backup.file', $backup_file); + } + + public function get_cron_title() + { + return $this->query('cron.title'); + } + + public function set_cron_title($cron_title) + { + $this->update('cron.title', $cron_title); + } + + public function get_progress() + { + return $this->query('cron.progress'); + } + + public function set_progress(FW_Backup_Interface_Feedback $feedback) + { + $this->update('cron.progress', array( + 'task_title' => $feedback->get_task_title(), + 'task_progress' => $feedback->get_task_progress(), + 'task_progress_title' => $feedback->get_task_progress_title(), + )); + } + + public function get_cron_started() + { + return $this->query('cron.start'); + } + + public function set_cron_started() + { + $this->update('cron.start', time()); + $this->set_state_title(__('Running...', 'fw')); + } + + public function get_cancelled() + { + return $this->query('cron.cancel'); + } + + public function set_cancelled() + { + $this->update('cron.cancel', time()); + $this->set_state_title(__('Cancelling...', 'fw')); + } + + // Internal + + private function check() + { + if (empty($this->post_id)) { + throw new FW_Backup_Exception('post.meta was not initialized'); + } + } + + private function get_post() + { + $this->check(); + return get_post($this->post_id); + } + + private function query($key) + { + $this->check(); + return get_post_meta($this->post_id, $key, true); + } + + private function update($key, $value) + { + $this->check(); + fw_update_post_meta($this->post_id, $key, $value); + } + + private function delete($key) + { + $this->check(); + fw_delete_post_meta($this->post_id, $key); + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-cancelled.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-cancelled.php new file mode 100644 index 00000000..b28e8ab7 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-cancelled.php @@ -0,0 +1,10 @@ + $errno, + 'code' => $code, + 'response' => $response + ))); + + parent::__construct($message); + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-invalid-argument.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-invalid-argument.php new file mode 100644 index 00000000..a01ba24f --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-invalid-argument.php @@ -0,0 +1,19 @@ += 0) { + parent::__construct($message,$code,$previous); + } + else { + parent::__construct($message,$code); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-not-implemented.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-not-implemented.php new file mode 100644 index 00000000..c95f88d5 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-not-implemented.php @@ -0,0 +1,14 @@ += 0) { + parent::__construct($message,$code,$previous); + } + else { + parent::__construct($message,$code); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-parameter-not-found.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-parameter-not-found.php new file mode 100644 index 00000000..ff4ea03c --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-parameter-not-found.php @@ -0,0 +1,16 @@ += 0) { + parent::__construct($message,$code,$previous); + } + else { + parent::__construct($message,$code); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service-invalid-interface.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service-invalid-interface.php new file mode 100644 index 00000000..e9b69811 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service-invalid-interface.php @@ -0,0 +1,21 @@ += 0) { + parent::__construct($message,$code,$previous); + } + else { + parent::__construct($message,$code); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service-not-found.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service-not-found.php new file mode 100644 index 00000000..dc204a72 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service-not-found.php @@ -0,0 +1,21 @@ += 0) { + parent::__construct($message,$code,$previous); + } + else { + parent::__construct($message,$code); + } + } +} diff --git a/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service.php b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service.php new file mode 100644 index 00000000..8fa3e667 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/includes/exceptions/exception-fw-backup-service.php @@ -0,0 +1,10 @@ +extensions->get('backup')->get_post_type(), array( + 'labels' => array( + 'name' => __('Backups', 'fw'), + 'singular_name' => __('Backup', 'fw'), + 'add_new' => __('Add New', 'fw'), + 'add_new_item' => __('Add New Backup', 'fw'), + 'edit_item' => __('Edit Backup', 'fw'), + 'new_item' => __('New Backup', 'fw'), + 'all_items' => __('Backup', 'fw'), // __('All Backups', 'fw'), + 'view_item' => __('View Backup', 'fw'), + 'search_items' => __('Search Backups', 'fw'), + 'not_found' => __('Nothing found', 'fw'), + 'not_found_in_trash' => __('Nothing found in Trash', 'fw'), + 'parent_item_colon' => '' + ), + 'public' => false, + 'publicly_queryable' => false, + 'show_ui' => true, + 'show_in_nav_menus' => false, + 'show_in_menu' => 'tools.php', + + // WordPress: Disable “Add New” on Custom Post Type + // http://stackoverflow.com/a/16675677 + 'map_meta_cap' => true, + 'capability_type' => 'post', + 'capabilities' => array( + 'edit_post' => 'edit_files', + 'read_post' => 'edit_files', + 'delete_post' => 'edit_files', + 'edit_posts' => 'edit_files', + 'edit_others_posts' => 'edit_files', + 'publish_posts' => 'edit_files', + 'read_private_posts'=> 'edit_files', + + 'read' => 'edit_files', + 'delete_posts' => 'edit_files', + 'delete_private_posts' => 'edit_files', + 'delete_published_posts'=> 'edit_files', + 'delete_others_posts' => 'edit_files', + 'edit_private_posts' => 'edit_files', + 'edit_published_posts' => 'edit_files', + + 'create_posts' => false, + ), +)); diff --git a/scratch-parent/framework/extensions/backup/static/css/admin.css b/scratch-parent/framework/extensions/backup/static/css/admin.css new file mode 100644 index 00000000..3a42daa2 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/css/admin.css @@ -0,0 +1,67 @@ +.backup-subtitle { + margin-bottom: 24px !important; +} + +/* This .css file will be included on backup page only. + * So only .fw-flash-message classes on this page will be affected. */ +.fw-flash-message, +.backup-alert { + padding-left: 8px !important; + margin-top: 7px !important; + margin-bottom: 7px !important; +} + +.backup-alert .backup-spinner { + margin-top: -1px; + margin-right: -1px; +} + +.backup-controls { + line-height: 28px; + margin-top: 24px; + margin-bottom: 44px; +} + +.backup-spinner { + float: none; + display: inline-block; + margin: 0; + vertical-align: -5px; +} + +a.backup-icon-remove { + display: inline-block; + width: 13px; + height: 13px; + position: relative; + top: 2px; + padding: 0; + margin: 0 5px 0 1px; + background: url(../img/cross-1.png); + -webkit-transition: none; + transition: none; +} +a.backup-icon-remove:hover { + background: url(../img/cross-2.png); + -webkit-transition: none; + transition: none; +} + +.hide-fw-options-tabs-list .fw-options-tabs-list { + display: none; +} + +.border-orange { + border-color: #ffba00 !important; +} + +.disabled .hide-if-disabled { + display: none; +} + +/** + * Hide empty space below "Show on screen" + */ +#adv-settings .metabox-prefs { + display: none; +} diff --git a/scratch-parent/framework/extensions/backup/static/css/restore.css b/scratch-parent/framework/extensions/backup/static/css/restore.css new file mode 100644 index 00000000..56d73ae0 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/css/restore.css @@ -0,0 +1,49 @@ +#posts-filter { + display: none; +} + +.backup-restore-container { + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + z-index: 10000; +} + +.backup-restore-overlay { + position: absolute; + width: 100%; + height: 100%; + z-index: -1; + background: #000; + opacity: 0.5; +} + +.backup-restore-modal { + position: absolute; + top: 50%; + left: 50%; + width: 475px; + height: 300px; + margin: -133px 0 0 -238px; + background: #fff; + color: #a2a2a2; + text-align: center; + line-height: 300px; + border: 1px solid #a2a2a2; +} + +.backup-restore-modal-vertical { + display: inline-block; + vertical-align: middle; +} + +.backup-restore-modal h2 { + padding: 0; + color: inherit; +} + +.backup-restore-modal .backup-spinner { + vertical-align: -1px; +} diff --git a/scratch-parent/framework/extensions/backup/static/css/table.css b/scratch-parent/framework/extensions/backup/static/css/table.css new file mode 100644 index 00000000..c5c440a5 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/css/table.css @@ -0,0 +1,24 @@ +/** + * Stylize wordpress table + */ + +#backup-container ~ #posts-filter .search-box, +#backup-container ~ #posts-filter .tablenav .actions, +#backup-container ~ #posts-filter .tablenav .view-switch, +#backup-container ~ #posts-filter thead, +#backup-container ~ #posts-filter tfoot, +#backup-container ~ #posts-filter .row-actions { + display: none; +} + +#backup-container ~ #posts-filter .tablenav.top { + margin-top: -40px; +} + +#backup-container ~ #posts-filter .tablenav.bottom { + margin-bottom: -40px; +} + +#backup-container ~ #posts-filter .column-description p { + margin-bottom: 2px; +} diff --git a/scratch-parent/framework/extensions/backup/static/img/cross-1.png b/scratch-parent/framework/extensions/backup/static/img/cross-1.png new file mode 100644 index 00000000..aae4d15d Binary files /dev/null and b/scratch-parent/framework/extensions/backup/static/img/cross-1.png differ diff --git a/scratch-parent/framework/extensions/backup/static/img/cross-2.png b/scratch-parent/framework/extensions/backup/static/img/cross-2.png new file mode 100644 index 00000000..eba42ba2 Binary files /dev/null and b/scratch-parent/framework/extensions/backup/static/img/cross-2.png differ diff --git a/scratch-parent/framework/extensions/backup/static/js/backup.js b/scratch-parent/framework/extensions/backup/static/js/backup.js new file mode 100644 index 00000000..0ad63000 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/js/backup.js @@ -0,0 +1,39 @@ +jQuery(function ($) { + + var templ = '

    '; + var table = $('#posts-filter'); + + // Insert Restore button before and after table with posts + if (table.is(':visible')) { + $(templ).insertBefore(table); + $(templ).insertAfter(table); + } + + $('[data-action=backup-now]').click(function (event) { + if ($(this).prop('disabled')) { + event.preventDefault(); + } + else { + $(' ').insertAfter(this); + $('[data-action=backup-now]').prop('disabled', true).attr('disabled', true); + } + }); + + $('[data-action=backup-restore]').click(function () { + $('[data-action=backup-restore]').prop('disabled', true); + var url = $('[name=backup-radio]:checked').val(); + if (url) { + window.location = url; + } + }); + + $('[name=backup-radio]').change(function () { + $('[data-action=backup-restore]').prop('disabled', $('[name=backup-radio]:checked').val() === undefined); + }).first().change(); + + setTimeout(function () { + var subtitle = $('#backup-subtitle'); + subtitle.insertAfter(subtitle.closest('.wrap').children('h2').first()); + }, 1); + +}); diff --git a/scratch-parent/framework/extensions/backup/static/js/progress.js b/scratch-parent/framework/extensions/backup/static/js/progress.js new file mode 100644 index 00000000..5b7c3447 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/js/progress.js @@ -0,0 +1,43 @@ +jQuery(function ($) { + + var ping_timer_id; + var backup_progress_container = $('#backup-progress-container'); + + // Without it clicking on (x) sometimes doesn't work + backup_progress_container.on('click', 'a', function () { + clearTimeout(ping_timer_id); + }); + + function ping() { + $.ajax({ + url: ajaxurl, + type: 'POST', + data: { + action: 'backup-progress', + post: backup_progress_container.data('post') + }, + success: function (response, status, xhr) { + if (response.success) { + backup_progress_container.html(response.data); + schedule_ping(100); + } + else { + location.reload(); + } + }, + error: function (xhr, status, error) { + schedule_ping(250); + }, + complete: function (xhr, status) { + } + }); + } + + function schedule_ping(timeout) { + clearTimeout(ping_timer_id); + ping_timer_id = setTimeout(ping, timeout); + } + + ping(); + +}); diff --git a/scratch-parent/framework/extensions/backup/static/js/restore.js b/scratch-parent/framework/extensions/backup/static/js/restore.js new file mode 100644 index 00000000..5289e0d8 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/js/restore.js @@ -0,0 +1,18 @@ +jQuery(function ($) { + + var backup_restore_container = $('#backup-restore-container'); + var upgrade_button = $('#upgrade'); + + if (upgrade_button.length == 0) { + + backup_restore_container.show().focus(); + $('
    ').insertAfter($('body')).submit(); + + } + else { + upgrade_button.click(function () { + backup_restore_container.show().focus(); + }); + } + +}); diff --git a/scratch-parent/framework/extensions/backup/static/js/settings.js b/scratch-parent/framework/extensions/backup/static/js/settings.js new file mode 100644 index 00000000..2c7c2159 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/static/js/settings.js @@ -0,0 +1,41 @@ +jQuery(function ($) { + + $('[data-action=backup-settings]').click(function (event) { + + event.preventDefault(); + + var modal = new fw.OptionsModal({ + title: 'Backup Schedule', + options: $(this).data('options'), + values: $(this).data('values'), + size: 'small' + }); + + modal.on('change:values', function(modal, values) { + + // http://api.jquery.com/jQuery.ajax/ + $.ajax({ + url: ajaxurl, + type: 'POST', + data: { + action: 'backup-settings-save', + values: values + }, + complete: function () { + window.location.reload(); + } + }) + + }); + + modal.open(); + + }); + + fwEvents.on('fw:options:init', function (param) { + param.$elements.find('[data-type=backup-schedule]').change(function () { + $(this).closest('[data-container=backup-settings]').toggleClass('disabled', $(this).val() == 'disabled'); + }).change(); + }); + +}); diff --git a/scratch-parent/framework/extensions/backup/views/backend/backup-page.php b/scratch-parent/framework/extensions/backup/views/backend/backup-page.php new file mode 100644 index 00000000..b74dc8f5 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/views/backend/backup-page.php @@ -0,0 +1,85 @@ +extensions->get('backup'); +$active = array(); +$inactive = array(); +$backup_now = array(); + +foreach ($backup->service_list('FW_Backup_Interface_Cron') as $cron) { + if ($cron->is_active()) { + $active[] = $cron; + } + else { + $inactive[] = $cron; + } + if ($cron->has_backup_now()) { + $backup_now[] = $cron; + } +} + +?> + +

    Here you can create a backup schedule for your website.

    + +
    + + wp_verify_nonce('backup-progress')): ?> + +
    + backup_render_progress(FW_Request::GET('post')) ?> +
    + + + + + +
    +

    Important: No backup schedule created yet! We advise you to do it asap!

    +
    + + + + +
    +

    Important: No get_title()) ?> schedule created yet!

    +
    + + + +
    +

    + + get_title()) ?> schedule active: + get_schedule_title() ?> | + get_storage()->get_title('on') ?> | + get_next_at_title() ?> +

    +
    + + + + +
    + Edit Backup Schedule + wp_verify_nonce('backup-progress')): ?> +    Cancel + + + Create get_title()) ?> Now + + +
    + +
    + +

    Backup Archive

    + +debug && array_sum((array) wp_count_posts($backup->get_post_type())) == 0): ?> + +

    Nothing Found

    + diff --git a/scratch-parent/framework/extensions/backup/views/backend/backup-progress.php b/scratch-parent/framework/extensions/backup/views/backend/backup-progress.php new file mode 100644 index 00000000..90269054 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/views/backend/backup-progress.php @@ -0,0 +1,25 @@ + +
    +

    + + : + +

    +
    diff --git a/scratch-parent/framework/extensions/backup/views/backend/backup-restore.php b/scratch-parent/framework/extensions/backup/views/backend/backup-restore.php new file mode 100644 index 00000000..cd7e26b9 --- /dev/null +++ b/scratch-parent/framework/extensions/backup/views/backend/backup-restore.php @@ -0,0 +1,19 @@ + + + diff --git a/scratch-parent/framework/extensions/blog/class-fw-extension-blog.php b/scratch-parent/framework/extensions/blog/class-fw-extension-blog.php new file mode 100644 index 00000000..855d7d5e --- /dev/null +++ b/scratch-parent/framework/extensions/blog/class-fw-extension-blog.php @@ -0,0 +1,107 @@ +post_type; + + // Someone has changed this post type, always check for that! + if ( empty ( $wp_post_types[ $p ] ) + or ! is_object( $wp_post_types[ $p ] ) + or empty ( $wp_post_types[ $p ]->labels ) + ) { + return; + } + + $wp_post_types[ $p ]->has_archive = true; + + $wp_post_types[ $p ]->labels->name = __( 'Blog', 'fw' ); + $wp_post_types[ $p ]->labels->singular_name = __( 'Blog', 'fw' ); + $wp_post_types[ $p ]->labels->add_new = __( 'Add blog post', 'fw' ); + $wp_post_types[ $p ]->labels->add_new_item = __( 'Add new blog post', 'fw' ); + $wp_post_types[ $p ]->labels->all_items = __( 'All blog posts', 'fw' ); + $wp_post_types[ $p ]->labels->edit_item = __( 'Edit blog post', 'fw' ); + $wp_post_types[ $p ]->labels->name_admin_bar = __( 'Blog Post', 'fw' ); + $wp_post_types[ $p ]->labels->menu_name = __( 'Blog Post', 'fw' ); + $wp_post_types[ $p ]->labels->new_item = __( 'New blog post', 'fw' ); + $wp_post_types[ $p ]->labels->not_found = __( 'No blog posts found', 'fw' ); + $wp_post_types[ $p ]->labels->not_found_in_trash = __( 'No blog posts found in trash', 'fw' ); + $wp_post_types[ $p ]->labels->search_items = __( 'Search blog posts', 'fw' ); + $wp_post_types[ $p ]->labels->view_item = __( 'View blog post', 'fw' ); + } + + /** + * Changes the labels value od the posts type: post from Post to Blog Post + * @internal + */ + public function _admin_action_change_post_labels() { + global $wp_post_types, $wp_taxonomies; + $p = $this->post_type; + + // Someone has changed this post type, always check for that! + if ( empty ( $wp_post_types[ $p ] ) + or ! is_object( $wp_post_types[ $p ] ) + or empty ( $wp_post_types[ $p ]->labels ) + ) { + return; + } + + $wp_post_types[ $p ]->labels->name = __( 'Blog Posts', 'fw' ); + + if ( empty ( $wp_taxonomies['category'] ) + or ! is_object( $wp_taxonomies['category'] ) + or empty ( $wp_taxonomies['category']->labels ) + ) { + return; + } + + $wp_taxonomies['category']->labels->name = __( 'Blog Categories', 'fw' ); + } + + /** + * Changes the name in admin menu from Post to Blog Post + * @internal + */ + public function _admin_action_rename_post_menu() { + global $menu; + + if ( isset( $menu[5] ) ) { + $menu[5][0] = __( 'Blog Posts', 'fw' ); + } + } + + function add_admin_style() { + $screen = get_current_screen(); + if ( $screen->post_type != 'post' ) { + return; + } + + wp_enqueue_style( + 'fw-ext-'. $this->get_name() .'-admin-style', + $this->locate_css_URI('admin-style'), + array(), + $this->manifest->get_version() + ); + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/blog/static/css/admin-style.css b/scratch-parent/framework/extensions/blog/static/css/admin-style.css new file mode 100644 index 00000000..22caf8bb --- /dev/null +++ b/scratch-parent/framework/extensions/blog/static/css/admin-style.css @@ -0,0 +1,9 @@ +#posts-filter th.column-posts span{ + white-space: nowrap; +} + +@media screen and (max-width: 1450px) { + #posts-filter th.column-posts{ + width: 20%; + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/breadcrumbs/class-fw-extension-breadcrumbs.php b/scratch-parent/framework/extensions/breadcrumbs/class-fw-extension-breadcrumbs.php new file mode 100644 index 00000000..b35926b2 --- /dev/null +++ b/scratch-parent/framework/extensions/breadcrumbs/class-fw-extension-breadcrumbs.php @@ -0,0 +1,39 @@ +" ) { + $data = array(); + $settings = array(); + + $settings['labels'] = fw_get_db_settings_option( $this->get_option_id() ); + + $breadcrumbs = new Breadcrumbs_Builder( $settings ); + + $data['items'] = $breadcrumbs->get_breadcrumbs(); + $data['separator'] = $separator; + + return $this->render_view( 'breadcrumbs', $data ); + } + + /** + * Returns an hardcoded id for the breadcrumbs option + * @return string + */ + public function get_option_id( ){ + return $this->get_name() . '-option'; + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/breadcrumbs/helpers.php b/scratch-parent/framework/extensions/breadcrumbs/helpers.php new file mode 100644 index 00000000..f14c5369 --- /dev/null +++ b/scratch-parent/framework/extensions/breadcrumbs/helpers.php @@ -0,0 +1,14 @@ +" ) { + return fw()->extensions->get( 'breadcrumbs' )->render( $separator, false, 'breadcrumbs' ); +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/breadcrumbs/includes/class-breadcrumbs-builder.php b/scratch-parent/framework/extensions/breadcrumbs/includes/class-breadcrumbs-builder.php new file mode 100644 index 00000000..958d343f --- /dev/null +++ b/scratch-parent/framework/extensions/breadcrumbs/includes/class-breadcrumbs-builder.php @@ -0,0 +1,255 @@ +settings['labels'] = array( + 'homepage-title' => __( 'Homepage', 'fw' ), + 'blogpage-title' => __( 'Blog', 'fw' ), + '404-title' => __( '404 Not found', 'fw' ), + ); + + if ( isset( $settings['labels'] ) ) { + $this->settings['labels'] = array_merge( $this->settings['labels'], $settings['labels'] ); + } + } + + /** + * Determine if the page has parents and in case it has, adds all page parents hierarchy + * + * @param $id , page id + * + * @return array + */ + private function get_page_hierarchy( $id ) { + $page = get_post( $id ); + + if ( empty( $page ) || is_wp_error( $page ) ) { + return array(); + } + + $return = array(); + $page_obj = array(); + + $page_obj['type'] = 'post'; + $page_obj['post_type'] = $page->post_type; + $page_obj['name'] = $page->post_title; + $page_obj['id'] = $id; + $page_obj['url'] = get_permalink( $id ); + + $return[] = $page_obj; + if ( $page->post_parent > 0 ) { + $return = array_merge( $return, $this->get_page_hierarchy( $page->post_parent ) ); + } + + return $return; + } + + /** + * Determine if the term has parents and in case it has, adds all term parents hierarchy + * + * @param $id , term id + * @param $taxonomy , term taxonomy name + * + * @return array + */ + private function get_term_hierarchy( $id, $taxonomy ) { + $term = get_term( $id, $taxonomy ); + + if ( empty( $term ) || is_wp_error( $term ) ) { + return array(); + } + + $return = array(); + $term_obj = array(); + + $term_obj['type'] = 'taxonomy'; + $term_obj['name'] = $term->name; + $term_obj['id'] = $id; + $term_obj['url'] = get_term_link( $id, $taxonomy ); + $term_obj['taxonomy'] = $taxonomy; + + $return[] = $term_obj; + if ( $term->parent > 0 ) { + $return = array_merge( $return, $this->get_term_hierarchy( $term->parent, $taxonomy ) ); + } + + return $return; + } + + /** + * Determine the current frontend page location, in creates the breadcrumbs array + * @return array + */ + private function build_breadcrumbs() { + if ( is_admin() ) { + return array(); + } + + if ( did_action( 'wp' ) == 0 ) { + return array(); + } + + $return = array( + 0 => array( + 'name' => $this->settings['labels']['homepage-title'], + 'url' => home_url(), + 'type' => 'front_page' + ) + ); + + + if ( is_404() ) { + $page = array(); + + $page['type'] = '404'; + $page['name'] = $this->settings['labels']['404-title']; + $page['url'] = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + + $return[] = $page; + } elseif ( is_search() ) { + $search = array(); + + $search['type'] = 'search'; + $search['name'] = __( 'Searching for:' ) . ' ' . get_search_query(); + $s = '?s=' . apply_filters( 'fw_ext_breadcrumbs_search_query', get_search_query() ); + $search['url'] = home_url( '/' ) . $s; + + $return[] = $search; + } elseif ( is_front_page() ) { + } elseif ( is_home() ) { + $blog = array( + 'name' => $this->settings['labels']['blogpage-title'], + 'url' => $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], + 'type' => 'front_page' + ); + + $return[] = $blog; + } elseif ( is_page() ) { + global $post; + $return = array_merge( $return, array_reverse( $this->get_page_hierarchy( $post->ID ) ) ); + } elseif ( is_single() ) { + global $post; + + $taxonomies = get_object_taxonomies( $post->post_type, 'objects' ); + $slugs = array(); + if ( ! empty( $taxonomies ) ) { + foreach ( $taxonomies as $key => $tax ) { + if ( $tax->show_ui === true && $tax->public === true && $tax->hierarchical !== false ) { + array_push( $slugs, $tax->name ); + } + } + + $terms = wp_get_post_terms( $post->ID, $slugs ); + + $term = array_shift( $terms ); + unset( $terms ); + + $cat = array(); + $cat['name'] = $term->name; + $cat['url'] = get_term_link( $term, $term->taxonomy ); + $return[] = $cat; + } + + $return = array_merge( $return, array_reverse( $this->get_page_hierarchy( $post->ID ) ) ); + + } elseif ( is_category() ) { + $term_id = get_query_var( 'cat' ); + $return = array_merge( $return, array_reverse( $this->get_term_hierarchy( $term_id, 'category' ) ) ); + } elseif ( is_tag() ) { + $term_id = get_query_var( 'tag' ); + $term = get_term_by( 'slug', $term_id, 'post_tag' ); + + if ( empty( $term ) || is_wp_error( $term ) ) { + return array(); + } + + $tag = array(); + + $tag['type'] = 'taxonomy'; + $tag['name'] = $term->name; + $tag['url'] = get_term_link( $term_id, 'post_tag' ); + $tag['taxonomy'] = 'post_tag'; + $return[] = $tag; + } elseif ( is_tax() ) { + $term_id = get_queried_object()->term_id; + $taxonomy = get_query_var( 'taxonomy' ); + $return = array_merge( $return, array_reverse( $this->get_term_hierarchy( $term_id, $taxonomy ) ) ); + } elseif ( is_author() ) { + $author = array(); + + $author['name'] = get_queried_object()->data->display_name; + $author['id'] = get_queried_object()->data->ID; + $author['url'] = get_author_posts_url( $author['id'], get_queried_object()->data->user_nicename ); + $author['type'] = 'author'; + + $return[] = $author; + } elseif ( is_date() ) { + $date = array(); + $day = get_query_var( 'day' ); + $month = get_query_var( 'monthnum' ); + $year = get_query_var( 'year' ); + + if ( ! empty( $day ) ) { + $date['name'] = mysql2date( apply_filters( 'fw_ext_breadcrumbs_date_day_format', 'd F Y' ), $day . '-' . $month . '-' . $year ); + $date['url'] = get_day_link( $year, $month, $day ); + $date['date_type'] = 'daily'; + $date['day'] = $day; + $date['month'] = $month; + $date['year'] = $year; + } elseif ( ! empty( $month ) ) { + $date['name'] = mysql2date( apply_filters( 'fw_ext_breadcrumbs_date_month_format', 'F Y' ), '01.' . $month . '.' . $year ); + $date['url'] = get_month_link( $year, $month ); + $date['date_type'] = 'monthly'; + $date['month'] = $month; + $date['year'] = $year; + } else { + $date['name'] = mysql2date( apply_filters( 'fw_ext_breadcrumbs_date_year_format', 'Y' ), '01.01.' . $year ); + $date['url'] = get_year_link( $year ); + $date['date_type'] = 'yearly'; + $date['year'] = $year; + } + + $return[] = $date; + } elseif ( is_archive() ) { + $post_type = get_query_var( 'post_type' ); + if ( $post_type ) { + $post_type = get_post_type_object( $post_type ); + $archive = array(); + $archive['name'] = $post_type->labels->name; + $return[] = $archive; + } + } + + foreach ( $return as $key => $item ) { + if ( empty( $item['name'] ) ) { + $return[ $key ]['name'] = __( 'No title' ); + } + } + + + /* Reserved for pagination + * global $wp_query; + $paged = array(); + $paged['name'] = get_query_var('paged'); + $paged['max_pages'] = $wp_query->max_num_pages; + if( intval( $paged['name'] ) > 0 ){ + $paged['name'] = __('Page', 'fw') . ' ' . $paged['name']; + $return[] = $paged; + }*/ + + $return = apply_filters( 'fw_ext_breadcrumbs_build', $return ); + + return $return; + } + + /** + * Returns the breadcrumbs array + * @return string + */ + public function get_breadcrumbs() { + return $this->build_breadcrumbs(); + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/breadcrumbs/includes/option-types/breadcrumbs/class-fw-option-type-breadcrumbs.php b/scratch-parent/framework/extensions/breadcrumbs/includes/option-types/breadcrumbs/class-fw-option-type-breadcrumbs.php new file mode 100644 index 00000000..660baed7 --- /dev/null +++ b/scratch-parent/framework/extensions/breadcrumbs/includes/option-types/breadcrumbs/class-fw-option-type-breadcrumbs.php @@ -0,0 +1,90 @@ +internal_options = array( + 'label' => false, + 'desc' => false, + 'type' => 'multi', + 'inner-options' => array( + 'homepage-title' => array( + 'label' => __( 'Text for Homepage', 'fw' ), + 'desc' => __( 'The homepage anchor will have this text', 'fw' ), + 'type' => 'text', + 'value' => __( 'Homepage', 'fw' ) + ), + 'blogpage-title' => array( + 'label' => __( 'Text for Blog Page', 'fw' ), + 'desc' => __( 'The blog page anchor will have this text. In case homepage will be set as blog page, will be taken the homepage text', 'fw' ), + 'type' => 'text', + 'value' => __( 'Blog', 'fw' ) + ), + '404-title' => array( + 'label' => __( 'Text for 404 Page', 'fw' ), + 'desc' => __( 'The 404 anchor will have this text', 'fw' ), + 'type' => 'text', + 'value' => '404 Not Found' + ) + ), + ); + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'full'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $uri = fw()->extensions->get('breadcrumbs')->get_declared_URI('/includes/option-types/' . $this->get_type() . '/static/css/style.css'); + + wp_enqueue_style( + 'fw-option-' . $this->get_type(), + $uri, + array(), + fw()->extensions->get('breadcrumbs')->manifest->get_version() + ); + + $id = fw()->extensions->get('breadcrumbs')->get_option_id(); + + return fw()->backend->option_type('multi')->render($id, $this->internal_options, $data); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return fw()->backend->option_type('multi')->get_value_from_input($this->internal_options, $input_value); + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array() + ); + } +} + +FW_Option_Type::register('FW_Option_Type_Breadcrumbs'); diff --git a/scratch-parent/framework/extensions/breadcrumbs/includes/option-types/breadcrumbs/static/css/style.css b/scratch-parent/framework/extensions/breadcrumbs/includes/option-types/breadcrumbs/static/css/style.css new file mode 100644 index 00000000..6c7b22ad --- /dev/null +++ b/scratch-parent/framework/extensions/breadcrumbs/includes/option-types/breadcrumbs/static/css/style.css @@ -0,0 +1,3 @@ +.fw-backend-option-design-default.fw-backend-option-type-breadcrumbs { + padding: 0; +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/breadcrumbs/includes/sub-includes.php b/scratch-parent/framework/extensions/breadcrumbs/includes/sub-includes.php new file mode 100644 index 00000000..f9302f72 --- /dev/null +++ b/scratch-parent/framework/extensions/breadcrumbs/includes/sub-includes.php @@ -0,0 +1,5 @@ +id === fw()->extensions->get('slider')->get_post_type()) { + wp_enqueue_style('fw-selectize'); + wp_enqueue_script( + 'fw-population-method-categories', + $this->locate_js_URI($this->get_name()), + array('fw-selectize'), + $this->manifest->get_version() + ); + } + } + + public function get_population_methods($media_types) + { + $collector = array(); + foreach ($this->get_children() as $instance) { + $intersection = array_intersect($media_types, $instance->get_multimedia_types()); + + if (!empty($intersection)) { + $collector = array_merge($collector, $instance->get_population_method()); + } + } + + return $collector; + } + + public function get_population_options($population_method, $multimedia_types = array(), $options = array()) + { + $population_method_instance = $this->get_child('population-method-' . $population_method); + + if (empty($population_method)) { + FW_Flash_Messages::add( + 'fw-ext-'. $this->get_name() .'-wrong-method', + sprintf(__('Specified population method does not exists: %s', 'fw'), $population_method), + 'error' + ); + + return array(); + } + + return $population_method_instance->get_population_options($multimedia_types, $options); + } + + public function get_population_method($post_id) + { + $selected = fw_get_db_post_option($post_id, 'slider/selected'); + $population_method = fw_get_db_post_option($post_id, 'slider/'.$selected.'/population-method'); + + return $this->get_child('population-method-' . $population_method)->get_population_method(); + } + + public function get_number_of_images($post_id) + { + $selected = fw_get_db_post_option($post_id, 'slider/selected'); + $population_method = fw_get_db_post_option($post_id, 'slider/'.$selected.'/population-method'); + + return $this->get_child('population-method-' . $population_method)->get_number_of_images($post_id); + } + + public function get_frontend_data($post_id) + { + $selected = fw_get_db_post_option($post_id, 'slider/selected'); + $population_method = fw_get_db_post_option($post_id, 'slider/'.$selected.'/population-method'); + + return $this->get_child('population-method-' . $population_method)->get_frontend_data($post_id); + } + +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-categories/class-fw-extension-population-method-categories.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-categories/class-fw-extension-population-method-categories.php new file mode 100644 index 00000000..9fada05b --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-categories/class-fw-extension-population-method-categories.php @@ -0,0 +1,189 @@ +multimedia_types; + } + + public function get_population_method() + { + return array('categories' => __('Automatically, fetch images from categories')); + } + + public function get_population_options($multimedia_types, $custom_options) + { + $population_options = array(); + $post_categories = $this->get_post_categories(); + if (empty($post_categories)) { + $message = sprintf(__('%s extension needs configured categories in post types ', 'fw'), ucwords(str_replace('-', ' ', $this->get_name()))); + wp_die($message); + } else { + $population_options = array( + 'wrapper-population-method-categories' => array( + 'title' => __('Categories Population Method', 'fw'), + 'type' => 'box', + 'options' => array( + 'categories' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'selected' => array( + 'label' => __('Choose Category', 'fw'), + 'type' => 'select', + 'choices' => $this->get_post_categories() + ) + ), + 'choices' => $this->get_post_categories_sets() + ), + 'number_of_images' => array( + 'type' => 'text', + 'label' => __('Number of Images in the slider', 'fw') + ) + )) + ); + } + + return $population_options; + } + + public function get_post_categories() + { + $collector = array(); + $post_types = get_post_types(array('public' => true), 'objects'); + + foreach ($post_types as $key => $post_type) { + + $have_terms = $this->get_terms($key); + + if (!empty($have_terms)) { + $collector[$key] = empty($post_type->labels->name) ? $post_type->label : $post_type->labels->name; + } + } + + return $collector; + } + + private function get_terms($post_type) + { + $taxonomies = get_taxonomies(array('object_type' => array($post_type), 'hierarchical' => true)); + + return get_terms($taxonomies); + } + + private function get_post_categories_sets() + { + $post_types = get_post_types(array('public' => true)); + $terms_collector = array(); + + foreach ($post_types as $post_type) { + + $terms = $this->get_terms($post_type); + + if (!empty($terms) && !is_wp_error($terms)) { + $terms_collector = array(); + foreach ($terms as $term) { + $key = json_encode(array('term_id' => $term->term_id, 'taxonomy' => $term->taxonomy)); + $terms_collector[$key] = $term->name; + } + } + + $collector[$post_type] = array( + 'terms' => array( + 'type' => 'select-multiple', + 'attr' => array('class' => 'selectize fw-selectize'), + 'label' => __('Select Specific Categories', 'fw'), + 'choices' => $terms_collector, + ) + ); + } + return $collector; + } + + public function get_number_of_images($post_id) + { + return (int)fw_get_db_post_option($post_id, 'number_of_images'); + } + + public function get_frontend_data($post_id) + { + $collector = array(); + $meta = fw_get_db_post_option($post_id); + $post_status = get_post_status($post_id); + + if ('publish' === $post_status and isset($meta['populated'])) { + + $slider_name = $meta['slider']['selected']; + $population_method = $meta['slider'][$slider_name]['population-method']; + $number_of_images = (int)$meta['number_of_images']; + + $collector = array( + 'slides' => array(), + 'settings' => array( + 'title' => $meta['title'], + 'slider_type' => $slider_name, + 'population_method' => $population_method, + 'post_id' => $post_id, + 'extra' => array(), + ) + ); + + $query_data = array(); + $post_type = $meta['categories']['selected']; + $terms = $meta['categories'][$post_type]['terms']; + + $tax_query = array( + 'tax_query' => array( + 'relation' => 'OR' + ) + ); + + foreach ($terms as $term) { + $decoded_data = json_decode($term, true); + $query_data[$decoded_data['taxonomy']][] = $decoded_data['term_id']; + } + + foreach ($query_data as $taxonomy => $terms) { + $tax_query['tax_query'][] = array( + 'taxonomy' => $taxonomy, + 'field' => 'id', + 'terms' => $terms + ); + } + + $final_query = array_merge(array( + 'post_status' => 'publish', + 'posts_per_page' => $number_of_images, + 'post_type' => $post_type, + 'meta_key' => '_thumbnail_id', + ), $tax_query + ); + + $the_query = new WP_Query($final_query); + + while ($the_query->have_posts()) { + $the_query->the_post(); + array_push($collector['slides'], array( + 'title' => get_the_title(), + 'src' => wp_get_attachment_url(get_post_thumbnail_id(get_the_ID())), + 'desc' => get_the_excerpt(), + 'extra' => array() + )); + } + wp_reset_postdata(); + } + + return $collector; + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/class-fw-extension-population-method-custom.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/class-fw-extension-population-method-custom.php new file mode 100644 index 00000000..8fbb6403 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/class-fw-extension-population-method-custom.php @@ -0,0 +1,166 @@ +multimedia_types; + } + + + public function get_population_method() + { + return array('custom' => __('Manually, I\'ll upload the images myself')); + } + + public function get_population_options($multimedia_types, $custom_options) + { + $media_type_choices = $this->transform_multimedia_types_array($multimedia_types); + $media_type_values = array_keys($media_type_choices); + $media_type_values = array_shift($media_type_values); + + $options = array( + 'wrapper-population-method-custom' => array( + 'title' => __('Click to edit / Drag to reorder ', 'fw'), + 'type' => 'box', + 'options' => array( + 'custom-slides' => + array( + 'label' => false, + 'desc' => false, + 'type' => 'slides', + 'multimedia_type' => $media_type_values, + 'thumb_size' => array('height' => 75, 'width' => 138), + 'slides_options' => array( + 'multimedia' => array( + 'type' => 'multi-picker', + 'desc' => false, + 'label' => false, + 'hide_picker' => true, + 'picker' => array( + 'selected' => array( + 'type' => 'radio', + 'attr' => array('class' => 'multimedia-radio-controls'), + 'label' => __('Choose ', 'fw'), + 'choices' => $media_type_choices, + 'value' => $media_type_values + )), + 'choices' => $this->get_multimedia_types_sets($multimedia_types) + ), + 'title' => array( + 'type' => 'text', + 'label' => __('Title', 'fw'), + ), + 'desc' => array( + 'type' => 'textarea', + 'label' => __('Description', 'fw'), + 'value' => '' + ), + ) + ) + ) + ) + ); + + if (!empty($custom_options)) { + $options['wrapper-population-method-custom']['options']['custom-slides']['slides_options']['extra-options'] = + array( + 'type' => 'multi', + 'attr' => array('class' => 'fw-no-border'), + 'label' => false, + 'desc' => false, + 'inner-options' => $custom_options, + ); + } + + return $options; + } + + private function transform_multimedia_types_array($multimedia_types) + { + return array_combine( + array_values($multimedia_types), + array_map('ucfirst', $multimedia_types) + ); + } + + private function get_multimedia_types_sets($multimedia_types) + { + $options = array( + 'image' => array( + 'src' => array( + 'label' => __('Image', 'fw'), + 'type' => 'upload', + ) + ), + 'video' => array( + 'src' => array( + 'label' => __('Video', 'fw'), + 'type' => 'text' + ) + ), + ); + + $filtered_options = array(); + + $filtered_multimedia_types = array_intersect($this->multimedia_types, $multimedia_types); + + foreach ($filtered_multimedia_types as $multimedia_type) { + $filtered_options[$multimedia_type] = $options[$multimedia_type]; + } + + return $filtered_options; + } + + public function get_number_of_images($post_id) + { + return count(fw_get_db_post_option($post_id, 'custom-slides', array())); + } + + public function get_frontend_data($post_id) + { + $meta = fw_get_db_post_option($post_id); + $post_status = get_post_status($post_id); + + $collector = array(); + + if ('publish' === $post_status and isset($meta['populated'])) { + + $slider_name = $meta['slider']['selected']; + $population_method = $meta['slider'][$slider_name]['population-method']; + + $collector = array( + 'slides' => array(), + 'settings' => array( + 'title' => $meta['title'], + 'slider_type' => $slider_name, + 'population_method' => $population_method, + 'post_id' => $post_id, + 'extra' => isset($meta['custom-settings']) ? $meta['custom-settings'] : array(), + ) + ); + + foreach ($meta['custom-slides'] as $slide) { + array_push($collector['slides'], array( + 'title' => $slide['title'], + 'multimedia_type' => $slide['multimedia']['selected'], + 'src' => ($slide['multimedia']['selected'] === 'video') ? $slide['multimedia'][$slide['multimedia']['selected']]['src'] : $slide['multimedia'][$slide['multimedia']['selected']]['src']['url'], + 'desc' => $slide['desc'], + 'extra' => isset($slide['extra-options']) ? $slide['extra-options'] : array() + )); + } + } + + return $collector; + } + +} diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/bootstrap.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/bootstrap.php new file mode 100644 index 00000000..3ed22f21 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/bootstrap.php @@ -0,0 +1,2 @@ + fw_resize(FW_Request::POST('src'), $thumb_size['width'], $thumb_size['height'], true))); + } + + /** + * @internal + */ + public static function _action_ajax_cache_slide() + { + $output = ''; + $attr_data = json_decode(FW_Request::POST('option'), true); + + $option = $attr_data['option']; + $id = $attr_data['id']; + $data = $attr_data['data']; + + parse_str(FW_Request::POST('values'), $values); + + if (isset($values)) { + $options_values_cache = $values['fw_options']['custom-slides']; + $options_values = array_pop($options_values_cache); + $valid_values = fw_get_options_values_from_input( + $option['slides_options'], + $options_values + ); + + foreach ($values['fw_options']['custom-slides'] as $key => $value) { + $output .= "
    "; + + $output .= fw()->backend->render_options($option['slides_options'], $valid_values, array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $key . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . '][' . $key . ']' + )); + $output .= "
    "; + } + } + + wp_send_json($output); + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array(), + 'thumb_size' => array( + 'width' => 150, + 'height' => 150 + ), + 'slides_options' => array() + ); + } + + /** + * Generate option's html from option array + * @param string $id + * @param array $option + * @param array $data + * @return string HTML + * @internal + */ + protected function _render($id, $option, $data) + { + $js_path = fw()->extensions->get($this->extension_name)->get_declared_URI('/includes/slides/static/js/slides.js'); + $css_path = fw()->extensions->get($this->extension_name)->get_declared_URI('/includes/slides/static/css/slides.css'); + + $template_path = fw()->extensions->get($this->extension_name)->get_declared_path('/includes/slides/views/templates.php'); + + wp_enqueue_script( + 'fw-option-'. $this->get_type() .'-slides-js', + $js_path, + array('jquery-ui-sortable','qtip', 'fw'), + fw()->extensions->get($this->extension_name)->manifest->get_version() + ); + wp_enqueue_style( + 'fw-option-'. $this->get_type() .'-slides-css', + $css_path, + array('qtip'), + fw()->extensions->get($this->extension_name)->manifest->get_version() + ); + + $values = $data['value']; + $thumb_size = $option['thumb_size']; + $slides_options = $option['slides_options']; + $multimedia_type = (array) $option['multimedia_type']; + + $type = $this->get_type(); + $template = fw_render_view($template_path, compact('id', 'option', 'thumb_size', 'data', 'values', 'type', 'slides_options')); + + wp_localize_script( + 'fw-option-'. $this->get_type() .'-slides-js', + 'slides_templates', + $template + ); + + $path = fw()->extensions->get($this->extension_name)->get_declared_path('/includes/slides/views/slides.php'); + + return fw_render_view($path, compact('id', 'option', 'thumb_size', 'data', 'values', 'type', 'slides_options', 'multimedia_type')); + } + + /** + * Option's unique type, used in option array in 'type' key + * @return string + */ + public function get_type() + { + return 'slides'; + } + + /** + * Extract correct value for $option['value'] from input array + * If input value is empty, will be returned $option['value'] + * @param array $option + * @param array|string|null $input_value + * @return string|array|int|bool Correct value + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!is_array($input_value)) { + return $option['value']; + } + + //unset the last slide that is default for add + array_pop($input_value); + + $value = array(); + + $slides_options = fw_extract_only_options($option['slides_options']); + + foreach ($input_value as &$list_item_value) { + $current_value = array(); + + foreach ($slides_options as $id => $input_option) { + $current_value[$id] = fw()->backend->option_type($input_option['type'])->get_value_from_input( + $input_option, + isset($list_item_value[$id]) ? $list_item_value[$id] : null + ); + $current_value['thumb'] = isset($list_item_value['thumb']) ? $list_item_value['thumb'] : null; + } + + $value[] = $current_value; + } + return $value; + } +} + +FW_Option_Type::register('FW_Option_Type_Slides'); + +add_action('wp_ajax_cache_slide', array('FW_Option_Type_Slides', '_action_ajax_cache_slide')); +add_action('wp_ajax_resize_slide', array('FW_Option_Type_Slides', '_action_ajax_resize_slide')); \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/css/slides.css b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/css/slides.css new file mode 100644 index 00000000..b7b4a2bd --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/css/slides.css @@ -0,0 +1,136 @@ +.thumbs-wrapper { + margin: 20px auto; + padding-left: 25px; + padding-right: 25px; +} +.thumbs-wrapper .add-new-btn { + padding: 2px; + border: 3px solid transparent; +} +.thumbs-wrapper .add-new-btn div{ + width: 90px; + height:75px; + display: block; + background-color:#f2f2f2; + float:left; + font-size: 0px; + background-image: url(../images/icon.png); + background-repeat: no-repeat; + background-position: 50% 20px; +} +.thumbs-wrapper .add-new-btn p { + margin-top: 45px; + text-align: center; + font-style: italic; +} +.thumbs-wrapper .delete-btn { + display: none; + z-index: 999; + position: absolute; + border-width: 0px; + line-height: 0; + right: -5px; + top: -5px; + padding: 0px; + margin: 0px; + cursor: pointer; + border-radius: 100%; + background-color: #fff; +} +.thumbs-wrapper .delete-btn:hover { + color: #db382f; +} +.thumbs-wrapper .delete-btn:before { + content: '\f153'; + display: block !important; + font: 400 18px/1 dashicons; +} +.fw-option-type-slides .buttons-wrapper{ + padding: 15px 25px; + display : none; +} +.thumbs-wrapper li:hover .delete-btn { + display: block; +} +.thumbs-wrapper li { + margin-right: 4px; + margin-bottom: 0px; + position: relative; + display: block; + float: left; + cursor: pointer; + line-height: 0; + padding: 2px; + border-radius: 2px; + border: 3px solid transparent; +} +.thumbs-wrapper li.selected { + border: 3px solid #64bd1f; +} +.thumbs-wrapper li:hover{ + border: 3px solid #dddddd; +} +.thumbs-wrapper li.selected:hover{ + border: 3px solid #64bd1f; +} + +.thumbs-wrapper li.new-selected { + border: 3px solid #64bd1f; + margin-right: 40px; +} +.thumbs-wrapper li.selected:after, .thumbs-wrapper li.new-selected:after{ + content: "\f147"; + font-family: dashicons; + background-color: #64bd1f; + position: absolute; + right: 0px; + bottom: 0px; + border-top-left-radius: 2px; + color: #fff; + line-height: normal; + font-size: 20px; +} +.fw-slides-wrapper .fw-slide { + display :none; + border-top: 1px solid #eeeeee; +} +.fw-slides-wrapper .fw-slide.default{ + display: block; +} +.fw-backend-option-type-slides > .fw-backend-option-input > .fw-inner { + width: 100% !important; +} +.fw-backend-option-type-slides{ + padding: 0 !important; +} +.multimedia-radio-controls div { + display: inline-block; + margin-left: 15px; +} + +#fw-options-box-wrapper-population-method-custom .inside{ + margin-top: 0px !important; + padding-bottom: 0px !important; +} + +/* qtip */ + +.qtip-fw-slides { + padding: 5px 10px; + min-width: 0; +} + +.qtip-fw-slides .qtip-content { + text-align: center; +} + +/* end: qtip */ + +.fw-slide-spinner.spinner { + /*float: left;*/ + float: none; + display: inline-block !important; + margin-top: -3px; + visibility: hidden; + margin-right: 20px; +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/icon-bg.png b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/icon-bg.png new file mode 100644 index 00000000..3efd818e Binary files /dev/null and b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/icon-bg.png differ diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/icon.png b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/icon.png new file mode 100644 index 00000000..8ee8f122 Binary files /dev/null and b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/icon.png differ diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/no_img.jpg b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/no_img.jpg new file mode 100644 index 00000000..4fbd82a2 Binary files /dev/null and b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/no_img.jpg differ diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/no_video.jpg b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/no_video.jpg new file mode 100644 index 00000000..a96181a7 Binary files /dev/null and b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/no_video.jpg differ diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/js/slides.js b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/js/slides.js new file mode 100644 index 00000000..de1e7e5d --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/js/slides.js @@ -0,0 +1,416 @@ +/* + * Dependency jQuery Sortable + * */ + +(function ($) { + + $.fn.slides = function (options) { + var extensionPath =fw.FW_URI+'/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/static/images/'; + var defaults = { + 'mediaImg': extensionPath+'no_video.jpg', + 'noDataImg': extensionPath+'no_img.jpg', + 'imageExtensions': ['jpeg', 'jpg', 'png', 'gif', 'bmp'], + 'addSlideSelector': 'fw-add-slide', + 'editSlideSelector': '.fw-edit-slide', + 'addSlideEvent': 'fw:add:new:slide', + 'editSlideEvent': 'fw:edit:slide' + }, + settings = $.extend({}, defaults, options); + + return this.each(function () { + var $this = $(this), + elements = { + $optionWrappper: $this, + $addButton: $this.find('.fw-add-slide'), + $slidesWrapper: $this.find('.fw-slides-wrapper'), + $spinner :$this.parents('.postbox').find('.fw-slide-spinner') + }, + templates = { + settings: { + evaluate: /\{\{(.+?)\}\}/g, + interpolate: /\{\{=(.+?)\}\}/g, + escape: /\{\{-(.+?)\}\}/g + }, + thumb: $(slides_templates).filter('.default-thumb').html(), + slide: $(slides_templates).filter('.default-slide').html() + }, + utils = { + getSlideElement: function (slideNumber) { + return elements.$optionWrappper.find('.slide-' + slideNumber); + }, + initQtip: function ($elements) { + $elements.each(function () { + $(this).qtip({ + content: { + text :'Click to edit / Drag to reorder' + }, + position: { + at: 'top center', + my: 'bottom center', + viewport: jQuery('body') + }, + style: { + classes: 'qtip-fw qtip-fw-slides', + tip: { + width: 12, + height: 5 + } + } + }); + }); + + }, + appendDefaultSlide: function (slideNumber) { + var $compiled = $(_.template( + $.trim(templates.slide), + {i: slideNumber}, + templates.settings + )).hide(); + + $default = elements.$slidesWrapper.find('.default'); + + if ($default.length > 0) { + $default.slideUp(500, function () { + elements.$slidesWrapper.children().removeClass('default').hide(); + elements.$slidesWrapper.append($compiled); + fwEvents.trigger('fw:options:init', {$elements: $compiled}); + }); + } else { + elements.$slidesWrapper.append($compiled); + fwEvents.trigger('fw:options:init', {$elements: $compiled}); + } + }, + revealSlide: function (slideNumber) { + elements.$slidesWrapper.find('.fw-slide').hide(); + utils.getSlideElement(slideNumber).slideDown();//show(); + }, + replaceSlide: function (slideNumber) { + var $cachedSlide = cache.getCachedSlide(slideNumber).clone(); + + elements.$slidesWrapper.find('.slide-' + slideNumber).remove(); + elements.$slidesWrapper.append($cachedSlide); + fwEvents.trigger('fw:options:init', {$elements: $cachedSlide}); + }, + getDefaultThumb: function (data) { + var $defaultThumb = $( + _.template( + $.trim(templates.thumb), + {src: data['src'], i: data['order_id']}, + { + evaluate: /\{\{(.+?)\}\}/g, + interpolate: /\{\{=(.+?)\}\}/g, + escape: /\{\{-(.+?)\}\}/g + } + ) + ); + utils.initQtip($defaultThumb); + return $defaultThumb; + }, + cancelEditMode: function () { + this.hideControlButtons(); + this.deselectThumbs(); + this.deselectSlides(); + }, + hideControlButtons: function () { + elements.$optionWrappper.find('.buttons-wrapper').hide(); + }, + showControlButtons: function () { + $buttonsWrapper = elements.$optionWrappper.find('.buttons-wrapper'); + if ($buttonsWrapper.is(':hidden')) { + $buttonsWrapper.show(); + } + }, + showEditButtons: function () { + utils.showControlButtons(); + elements.$optionWrappper.find('.edit-buttons').show(); + elements.$addButton.hide(); + }, + showAddButton: function () { + utils.showControlButtons(); + elements.$addButton.show(); + elements.$optionWrappper.find('.edit-buttons').hide(); + }, + deselectThumbs: function () { + elements.$optionWrappper.find('li').removeClass('selected'); + elements.$optionWrappper.find('.add-new-btn').removeClass('new-selected'); + }, + deselectSlides: function () { + elements.$optionWrappper.find('.fw-slide').hide(); + }, + getThumbSrcFromOption: function ($option) { + + var $multimedia_type = $option.find('.picker-group :radio:checked').val(), + $group = $option.find('.choice-group.chosen'), + $inputValue = $group.find(':input').val(), + $thumbSrc = $group.find('.thumb[data-attid="' + $inputValue + '"] img'); + + if ($thumbSrc.length === 0) { + $thumbSrc = $inputValue; + } else { + $thumbSrc = $group.find('.thumb').attr('data-origsrc'); + } + + return {'src': $thumbSrc, 'multimedia_type': $multimedia_type}; + }, + initSortable: function () { + elements.$optionWrappper.find('.thumbs-wrapper').sortable({ + items: "li:not(.sortable-false)" + }); + }, + initSlides: function () { + utils.hideControlButtons(); + utils.appendDefaultSlide(slidesNumber); + utils.initSortable(); + + var thumbs = elements.$optionWrappper.find('.thumbs-wrapper li:not(.sortable-false)'); + utils.initQtip(thumbs); + $.each(thumbs, function () { + var slideNumber = $(this).data('order'); + $innerHtml = elements.$slidesWrapper.find('.slide-' + slideNumber).data('default-html'); + $outer = $('
    ' + $innerHtml + '
    '); + cache.slides['slide-' + slideNumber] = $outer; + }); + } + }, + validator = { + parseValidUrl: function (src) { + //REGEX FROM https://gist.github.com/dperini/729294 + var regex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i; + var regExp = new RegExp(regex); + return regExp.test(src); + }, + parseYouTubeSrc: function (src) { + // REGEX FROM http://stackoverflow.com/a/9102270 + var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/; + var matches = src.match(regex); + if (matches && matches[2].length == 11) { + return matches[2]; + } + return false; + }, + getYoutubeImgSrc: function (youtubeId) { + // http://stackoverflow.com/questions/2068344/how-do-i-get-a-youtube-video-thumbnail-from-the-youtube-api + return 'http://img.youtube.com/vi/' + youtubeId + '/mqdefault.jpg'; + }, + parseImgSrc: function (src) { + return (-1 !== $.inArray(src.split('.').pop().toLowerCase(), settings.imageExtensions)); + }, + parseVimeoSrc: function (src) { + //REGEX FROM http://stackoverflow.com/a/2916654 + var regex = /http:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/; + var regex = /https?:\/\/(?:www\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|)(\d+)(?:$|\/|\?)/ + + var matches = src.match(regex); + if (matches) { + return matches[3]; + } + return false; + }, + getVimeoImgSrc: function (eventName, data) { + + $.ajax({ + type: 'GET', + url: 'http://vimeo.com/api/v2/video/' + data['src'] + '.json', + jsonp: 'callback', + dataType: 'jsonp' + }).done(function (response) { + data['src'] = response[0].thumbnail_medium; + validator.triggerEvent(eventName, data); + }).fail(function () { + data['src'] = settings.mediaImg; + validator.triggerEvent(eventName, data); + }); + }, + triggerEvent: function (event, data) { + elements.$optionWrappper.trigger(event, data); + }, + validateSrc: function (eventName, data) { + var isMediaImg = true; + var src = data['src']; + if (data['multimedia_type'] === 'image' && data['src'] !== '') { + + var thumbSize = JSON.stringify(elements.$optionWrappper.data('option').option.thumb_size); + + $.ajax({ + type: "post", + dataType: "json", + url: ajaxurl, + data: { + 'action': 'resize_slide', + 'src': data['src'], + 'thumb_size': thumbSize + } + }).done(function (response) { + data['src'] = response.src; + validator.triggerEvent(eventName, data); + }).fail(function () { + data['src'] = settings.mediaImg; + validator.triggerEvent(eventName, data); + }); + + return; + } + if (data['src'] === '' || data['src'] === undefined) { + data['src'] = data.multimedia_type === 'image' ? settings.noDataImg : settings.mediaImg; + + this.triggerEvent(eventName, data); + return; + } + if (this.parseValidUrl(src)) { + if (this.parseYouTubeSrc(src) !== false) { + isMediaImg = false; + data['src'] = this.getYoutubeImgSrc(this.parseYouTubeSrc(data['src'])); + this.triggerEvent(eventName, data); + } + if (this.parseVimeoSrc(src) !== false) { + isMediaImg = false; + data['src'] = this.parseVimeoSrc(data['src']); + this.getVimeoImgSrc(eventName, data); + } + + if (this.parseImgSrc(src)) { + isMediaImg = false; + this.triggerEvent(eventName, data); + } + + if (isMediaImg) { + data['src'] = settings.mediaImg; + this.triggerEvent(eventName, data); + } + + } else { + data['src'] = settings.noDataImg; + this.triggerEvent(eventName, data); + } + } + }, + cache = { + slides: {}, + cacheSlide: function (slideNumber) { + + var serializedData = elements.$optionWrappper.find('.slide-' + slideNumber + ' :input').serialize(); + var optionSlides = JSON.stringify(elements.$optionWrappper.data('option')); + + $.ajax({ + type: "post", + dataType: "json", + url: ajaxurl, + data: { + 'action': 'cache_slide', + 'option': optionSlides, + 'values': serializedData + } + }).done(function (response) { + cache.slides['slide-' + slideNumber] = $(response); + }); + }, + getCachedSlide: function (slideNumber) { + return this.slides['slide-' + slideNumber]; + } + } + + slidesNumber = elements.$optionWrappper.find('.thumbs-wrapper li').length; + + utils.initSlides(); + + elements.$addButton.on('click', function (e) { + e.preventDefault(); + cache.cacheSlide(slidesNumber); + elements.$spinner.css({'visibility' : 'visible'}); + var mediaSrc = utils.getThumbSrcFromOption(utils.getSlideElement(slidesNumber)), + data = {src: mediaSrc['src'], order_id: slidesNumber, 'multimedia_type': mediaSrc['multimedia_type']}; + + slidesNumber++; + utils.appendDefaultSlide(slidesNumber); + utils.hideControlButtons(); + validator.validateSrc(settings.addSlideEvent, data); + }); + + elements.$optionWrappper.on(settings.addSlideEvent, function (e, data) { + elements.$optionWrappper.find('.thumbs-wrapper .add-new-btn').before(utils.getDefaultThumb(data)); + utils.deselectThumbs(); + elements.$spinner.css({visibility : 'hidden'}); + }); + + elements.$optionWrappper.on(settings.editSlideEvent, function (e, data) { + elements.$optionWrappper.find('.thumbs-wrapper li[data-order="' + data['order_id'] + '"]').replaceWith(utils.getDefaultThumb(data)); + elements.$spinner.css({visibility : 'hidden'}); + }); + + elements.$optionWrappper.on('click', '.thumbs-wrapper li:not(.sortable-false)', function (e) { + e.preventDefault(); + if (!$(this).hasClass('selected')) { + var lastSelectedThumb = elements.$optionWrappper.find('.thumbs-wrapper li.selected'); + + if (lastSelectedThumb.length > 0) { + utils.replaceSlide(lastSelectedThumb.data('order')); + } + + utils.deselectThumbs(); + utils.revealSlide($(this).data('order')); + $(this).addClass('selected'); + utils.showEditButtons(); + } + }); + + elements.$optionWrappper.on('click', '.fw-edit-slide', function (e) { + e.preventDefault(); + var slideNumber = elements.$optionWrappper.find('.thumbs-wrapper li.selected').data('order'), + mediaSrc = utils.getThumbSrcFromOption(utils.getSlideElement(slideNumber)); + + cache.cacheSlide(slideNumber); + elements.$spinner.css({'visibility' : 'visible'}); + utils.getSlideElement(slideNumber).slideUp(500, function () { + validator.validateSrc(settings.editSlideEvent, {'src': mediaSrc['src'], 'order_id': slideNumber, 'multimedia_type': mediaSrc['multimedia_type']}); + utils.cancelEditMode(); + }); + + }); + + elements.$optionWrappper.on('click', '.fw-cancel-edit', function (e) { + e.preventDefault(); + var slideNumber = elements.$optionWrappper.find('.thumbs-wrapper li.selected').data('order'); + + utils.getSlideElement(slideNumber).slideUp(500, function () { + utils.replaceSlide(slideNumber); + utils.cancelEditMode(); + utils.hideControlButtons(); + }); + + }); + + elements.$optionWrappper.on('click', '.delete-btn', function (e) { + var $selectedThumb = $(this).closest('li'), + slideNumber = $selectedThumb.data('order'); + + e.preventDefault(); + e.stopPropagation(); + utils.cancelEditMode(); + + $selectedThumb.qtip('destroy'); + $selectedThumb.remove(); + utils.getSlideElement(slideNumber).remove(); + }); + + elements.$optionWrappper.on('click', '.add-new-btn', function (e) { + if (!$(this).hasClass('new-selected')) { + utils.deselectSlides(); + elements.$optionWrappper.find('li').removeClass('selected'); + elements.$optionWrappper.find('.add-new-btn').addClass('new-selected'); + elements.$optionWrappper.find('.fw-slide.default').slideDown(); + utils.showAddButton(); + } + }) + }); + }; + +})(jQuery); + +jQuery(document).ready(function () { + fwEvents.on('fw:options:init', function (data) { + data.$elements + .find('.fw-option-type-slides:not(.fw-option-initialized)') + .slides() + .addClass('fw-option-initialized'); + }); +}); diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/views/slides.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/views/slides.php new file mode 100644 index 00000000..d62e11a5 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/views/slides.php @@ -0,0 +1,53 @@ + +
    +
      + + $value): ?> + +
    • +
      + + backend->option_type('hidden')->render('thumb', array('value' => $value['thumb']), array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $key . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . '][' . $key . ']', + ));?> +
    • + + +
    • +
      +

      Add New

      +
      +
    • + +
      +
    +
    +
    + + $value): ?> + + + backend->render_options($slides_options, $value, array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $key . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . '][' . $key . ']', + ));?> +
    + +
    + + + +
    +
    + + + +
    + +
    +
    diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/views/templates.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/views/templates.php new file mode 100644 index 00000000..e4681071 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-custom/includes/slides/views/templates.php @@ -0,0 +1,20 @@ + + + diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-posts/class-fw-extension-population-method-posts.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-posts/class-fw-extension-population-method-posts.php new file mode 100644 index 00000000..9107e201 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-posts/class-fw-extension-population-method-posts.php @@ -0,0 +1,157 @@ +multimedia_types; + } + + public function get_population_method() + { + return array('posts' => __('Automatically, fetch images from posts')); + } + + public function get_population_options($multimedia_types, $custom_options) + { + $population_options = array(); + $post_categories = $this->get_post_categories(); + if (empty($post_categories)) { + $message = sprintf(__('%s extension needs configured post categories in post types ', 'fw'), ucwords(str_replace('-', ' ', $this->get_name()))); + wp_die($message); + } else { + $population_options = array( + 'wrapper-population-method-posts' => array( + 'title' => __('Posts Population Method', 'fw'), + 'type' => 'box', + 'options' => array( + 'post_types' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'selected' => array( + 'label' => __('Choose Tag', 'fw'), + 'type' => 'select', + 'choices' => $this->get_post_categories() + ) + ), + 'choices' => $this->get_posts_sets() + ), + )) + ); + } + + return $population_options; + } + + public function get_post_categories() + { + $collector = array(); + $post_types = get_post_types(array('public' => true), 'objects'); + foreach ($post_types as $post_type => $post_type_obj) { + $have_posts = $this->get_posts($post_type); + if (!empty($have_posts)) { + $collector[$post_type] = empty($post_type_obj->labels->name) ? $post_type_obj->label : $post_type_obj->labels->name; + } + } + + return $collector; + } + + private function get_posts($post_type) + { + return get_posts( + array( + 'post_type' => $post_type, + 'post_status' => 'publish', + 'meta_key' => '_thumbnail_id', + )); + } + + private function get_posts_sets() + { + $post_types = get_post_types(array('public' => true)); + $collector = array(); + + foreach ($post_types as $post_type) { + $posts_collector = array(); + $posts = $this->get_posts($post_type); + + if (!empty($posts)) { + foreach ($posts as $post) { + $posts_collector[$post->ID] = empty($post->post_title) ? __('(no title)', 'fw') : $post->post_title; + } + + $collector[$post_type] = array( + 'posts_id' => array( + 'type' => 'select-multiple', + 'attr' => array('class' => 'selectize fw-selectize'), + 'label' => __('Select Specific posts', 'fw'), + 'choices' => $posts_collector, + ) + ); + } + + } + + return $collector; + } + + public function get_number_of_images($post_id) + { + return (int)fw_get_db_post_option($post_id, 'number_of_images'); + } + + public function get_frontend_data($post_id) + { + $collector = array(); + $meta = fw_get_db_post_option($post_id); + $post_status = get_post_status($post_id); + + if ('publish' === $post_status and isset($meta['populated'])) { + $slider_name = $meta['slider']['selected']; + $population_method = $meta['slider'][$slider_name]['population-method']; + $posts_id = $meta['post_types'][$meta['post_types']['selected']]['posts_id']; + + $collector = array( + 'slides' => array(), + 'settings' => array( + 'title' => $meta['title'], + 'slider_type' => $slider_name, + 'population_method' => $population_method, + 'post_id' => $post_id, + 'extra' => array(), + ) + ); + + $posts = get_posts(array( + 'post_in' => $posts_id + )); + + foreach ($posts as $post) { + setup_postdata($post); + array_push($collector['slides'], array( + 'title' => get_the_title(), + 'src' => wp_get_attachment_url(get_post_thumbnail_id($post->ID)), + 'desc' => get_the_excerpt(), + 'extra' => array( + 'post_id' => $post->ID + ) + )); + } + wp_reset_postdata(); + } + + return $collector; + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-tags/class-fw-extension-population-method-tags.php b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-tags/class-fw-extension-population-method-tags.php new file mode 100644 index 00000000..b4ad413c --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/extensions/population-method-tags/class-fw-extension-population-method-tags.php @@ -0,0 +1,189 @@ +multimedia_types; + } + + public function get_population_method() + { + return array('tags' => __('Automatically, fetch images from tags')); + } + + public function get_population_options($multimedia_types, $custom_options) + { + $population_options = array(); + $post_categories = $this->get_post_categories(); + if (empty($post_categories)) { + $message = sprintf(__('%s extension needs configured tags in post types ', 'fw'), ucwords(str_replace('-', ' ', $this->get_name()))); + wp_die($message); + } else { + $population_options = array( + 'wrapper-population-method-tags' => array( + 'title' => __('Tags Population Method', 'fw'), + 'type' => 'box', + 'options' => array( + 'tags' => array( + 'type' => 'multi-picker', + 'label' => false, + 'desc' => false, + 'picker' => array( + 'selected' => array( + 'label' => __('Choose Tag', 'fw'), + 'type' => 'select', + 'choices' => $this->get_post_categories() + ) + ), + 'choices' => $this->get_post_tags_sets() + ), + 'number_of_images' => array( + 'type' => 'text', + 'label' => __('Number of Images in the slider', 'fw') + ) + )) + ); + } + + return $population_options; + } + + public function get_post_categories() + { + $collector = array(); + $post_types = get_post_types(array('public' => true), 'objects'); + + foreach ($post_types as $key => $post_type) { + + $have_terms = $this->get_terms($key); + + if (!empty($have_terms)) { + $collector[$key] = empty($post_type->labels->name) ? $post_type->label : $post_type->labels->name; + } + } + + return $collector; + } + + private function get_terms($post_type) + { + $taxonomies = get_taxonomies(array('object_type' => array($post_type), 'hierarchical' => false)); + + return get_terms($taxonomies); + } + + private function get_post_tags_sets() + { + $post_types = get_post_types(array('public' => true)); + $terms_collector = array(); + + foreach ($post_types as $post_type) { + + $terms = $this->get_terms($post_type); + + if (!empty($terms) && !is_wp_error($terms)) { + $terms_collector = array(); + foreach ($terms as $term) { + $key = json_encode(array('term_id' => $term->term_id, 'taxonomy' => $term->taxonomy)); + $terms_collector[$key] = $term->name; + } + } + + $collector[$post_type] = array( + 'terms' => array( + 'type' => 'select-multiple', + 'attr' => array('class' => 'selectize fw-selectize'), + 'label' => __('Select Specific tags', 'fw'), + 'choices' => $terms_collector, + ) + ); + } + + return $collector; + } + + public function get_number_of_images($post_id) + { + return (int)fw_get_db_post_option($post_id, 'number_of_images'); + } + + public function get_frontend_data($post_id) + { + $collector = array(); + $meta = fw_get_db_post_option($post_id); + $post_status = get_post_status($post_id); + + if ('publish' === $post_status and isset($meta['populated'])) { + $slider_name = $meta['slider']['selected']; + $population_method = $meta['slider'][$slider_name]['population-method']; + $number_of_images = (int)$meta['number_of_images']; + + $collector = array( + 'slides' => array(), + 'settings' => array( + 'title' => $meta['title'], + 'slider_type' => $slider_name, + 'population_method' => $population_method, + 'post_id' => $post_id, + 'extra' => array(), + ) + ); + + $query_data = array(); + $post_type = $meta['tags']['selected']; + $terms = $meta['tags'][$post_type]['terms']; + + $tax_query = array( + 'tax_query' => array( + 'relation' => 'OR' + ) + ); + + foreach ($terms as $term) { + $decoded_data = json_decode($term, true); + $query_data[$decoded_data['taxonomy']][] = $decoded_data['term_id']; + } + + foreach ($query_data as $taxonomy => $terms) { + $tax_query['tax_query'][] = array( + 'taxonomy' => $taxonomy, + 'field' => 'id', + 'terms' => $terms + ); + } + + $final_query = array_merge(array( + 'post_status' => 'publish', + 'posts_per_page' => $number_of_images, + 'post_type' => $post_type, + 'meta_key' => '_thumbnail_id', + ), $tax_query + ); + + $the_query = new WP_Query($final_query); + + while ($the_query->have_posts()) { + $the_query->the_post(); + array_push($collector['slides'], array( + 'title' => get_the_title(), + 'src' => wp_get_attachment_url(get_post_thumbnail_id(get_the_ID())), + 'desc' => get_the_excerpt(), + 'extra' => array() + )); + } + wp_reset_postdata(); + } + + return $collector; + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/population-method/includes/extends/population-method-interface.php b/scratch-parent/framework/extensions/media/extensions/population-method/includes/extends/population-method-interface.php new file mode 100644 index 00000000..926729a0 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/population-method/includes/extends/population-method-interface.php @@ -0,0 +1,11 @@ +add_admin_filters(); + $this->add_admin_actions(); + } + } + + private function add_admin_filters() + { + add_filter('fw_post_options', array($this, '_admin_filter_load_options'), 10, 2); + add_filter('wp_insert_post_data', array($this, '_admin_filter_pre_save_slider_title'), 99, 2); + add_filter('post_updated_messages', array($this, '_admin_filter_change_updated_messages')); + add_filter('manage_' . $this->get_post_type() . '_posts_columns', array($this, '_admin_filter_add_columns'), 10, 1); + add_filter('post_row_actions', array($this, '_admin_filter_post_row_actions'), 10, 2); + add_filter('bulk_actions-edit-' . $this->get_post_type(), array($this, '_admin_filter_customize_bulk_actions')); + add_filter('post_updated_messages', array($this, '_admin_filter_remove_notices')); + add_filter('parent_file', array($this, '_set_active_submenu')); + } + + public function get_post_type() + { + return $this->post_type; + } + + private function add_admin_actions() + { + add_action('admin_enqueue_scripts', array($this, '_admin_action_enqueue_static')); + add_action('admin_menu', array($this, '_admin_action_replace_submit_meta_box')); + add_action('manage_' . $this->get_post_type() . '_posts_custom_column', array($this, '_admin_action_manage_custom_column'), 10, 2); + } + + function _set_active_submenu($parent_file) + { + global $submenu_file, $current_screen; + + // Set correct active/current submenu in the WordPress Admin menu + if ($current_screen->post_type == $this->post_type) { + $submenu_file = 'edit.php?post_type=' . $this->post_type; + } + return $parent_file; + } + + /** + * @internal + */ + public function _admin_filter_remove_notices($messages) + { + if (get_post_type() === $this->post_type) { + foreach ($messages[$this->post_type] as $key => $message) { + $messages[$this->post_type][$key] = preg_replace('/]*>([\s\S]*?)<\/a[^>]*>/', '', $message); + } + } + + return $messages; + } + + /*Hide edit bulk action from table*/ + + /** + * @internal + */ + public function _admin_action_manage_custom_column($column, $post_id) + { + switch ($column) { + case 'slider_design' : + $image = $this->get_slider_type($post_id); + $link = get_edit_post_link($post_id); + echo ''; + break; + case 'number_of_images' : + echo fw()->extensions->get('population-method')->get_number_of_images($post_id); + break; + case 'population_method' : + $population_method = fw()->extensions->get('population-method')->get_population_method($post_id); + echo '

    ' . array_shift($population_method) . '

    '; + break; + default : + break; + } + } + + /*Hide actions from rows in table (Quick Edit and View)*/ + + private function get_slider_type($post_id) + { + $slider_name = fw_get_db_post_option($post_id, $this->get_name() . '/selected'); + $sliders_types = $this->get_sliders_types(); + return isset($sliders_types[$slider_name]) ? $sliders_types[$slider_name] : array(); + } + + //TODO must return to normal method + private function get_sliders_types() + { + $choices = array(); + foreach ($this->get_active_sliders() as $instance_name) { + $choices[$instance_name] = $this->get_child($instance_name)->get_slider_type(); + } + return $choices; + } + + private function get_active_sliders() + { + $active_sliders = array(); + foreach ($this->get_children() as $slider_instance) { + $slider_population_methods = $slider_instance->get_population_methods(); + if (!empty($slider_population_methods)) { + $active_sliders[] = $slider_instance->get_name(); + } + } + return $active_sliders; + } + + /** + * @internal + */ + public function _admin_filter_customize_bulk_actions($actions) + { + unset($actions['edit']); + return $actions; + } + + /** + * @internal + */ + public function _admin_filter_post_row_actions($actions, $post) + { + if ($post->post_type === $this->get_post_type()) { + unset($actions['inline hide-if-no-js'], $actions['view']); + } + return $actions; + } + + /** + * @internal + */ + public function _admin_filter_add_columns($columns) + { + return array( + 'cb' => $columns['cb'], + 'slider_design' => __('Slider Design', 'fw'), + 'title' => $columns['title'], + 'number_of_images' => __('Number of Images', 'fw'), + 'population_method' => __('Population Method', 'fw'), + ); + } + + /** + * @internal + */ + function _admin_filter_change_updated_messages($messages) + { + global $post; + $post_type = get_post_type($post->ID); + + if ($post_type === $this->get_post_type()) { + $obj = get_post_type_object($post_type); + $singular = $obj->labels->singular_name; + + $messages[$post_type] = array( + 0 => '', // Unused. Messages start at index 1. + 1 => sprintf(__($singular . ' updated. View ' . strtolower($singular) . ''), esc_url(get_permalink($post->ID))), + 2 => __('Custom field updated.'), + 3 => __('Custom field deleted.'), + 4 => __($singular . ' updated.'), + 5 => isset($_GET['revision']) ? sprintf(__($singular . ' restored to revision from %s'), wp_post_revision_title((int)$_GET['revision'], false)) : false, + 6 => sprintf(__($singular . ' published. View ' . strtolower($singular) . ''), esc_url(get_permalink($post->ID))), + 7 => __('Page saved.'), + 8 => sprintf(__($singular . ' submitted. Preview ' . strtolower($singular) . ''), esc_url(add_query_arg('preview', 'true', get_permalink($post->ID)))), + 9 => sprintf(__($singular . ' scheduled for: %1$s. Preview ' . strtolower($singular) . ''), date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)), esc_url(get_permalink($post->ID))), + 10 => sprintf(__($singular . ' draft updated. Preview ' . strtolower($singular) . ''), esc_url(add_query_arg('preview', 'true', get_permalink($post->ID)))), + ); + } + + return $messages; + } + + /** + * @internal + */ + public function _admin_filter_pre_save_slider_title($data, $postarr) + { + if ($data['post_type'] === $this->get_post_type()) { + if (isset($postarr['fw_options']['slider']['selected'])) { + $active_slider = $postarr['fw_options']['slider']['selected']; + $data['post_title'] = $postarr['fw_options']['slider'][$active_slider]['title']; + } + + if (isset($postarr['fw_options']['title'])) { + $data['post_title'] = $postarr['fw_options']['title']; + } + } + + return $data; + } + + /** + * @internal + */ + public function _admin_action_replace_submit_meta_box() + { + remove_meta_box('submitdiv', $this->get_post_type(), 'core'); + add_meta_box('submitdiv', __('Publish', 'fw'), array($this, 'render_submit_meta_box'), $this->get_post_type(), 'side'); + } + + public function render_submit_meta_box($post, $args = array()) + { + // a modified version of post_submit_meta_box() (wp-admin/includes/meta-boxes.php, line 12) + $post_type = $post->post_type; + $post_type_object = get_post_type_object($post_type); + $can_publish = current_user_can($post_type_object->cap->publish_posts); + $meta = fw_get_db_post_option($post->ID); + + if (isset($_GET['action']) && $_GET['action'] === 'edit') { + $slider_name = $meta['slider']['selected']; + $population_method = $this->get_child($slider_name)->get_population_method($meta['slider'][$slider_name]['population-method']); + $slider_type = $this->get_slider_type($post->ID); + echo $this->render_view('backend/submit-box-edit', compact('post', 'population_method', 'meta', 'post_type', 'post_type_object', 'can_publish', 'slider_type')); + } else { + echo $this->render_view('backend/submit-box-raw', compact('post', 'meta', 'post_type', 'post_type_object', 'can_publish')); + } + } + + /** + * @internal + */ + public function _admin_filter_load_options($options, $post_type) + { + if ($post_type === $this->get_post_type()) { + if (fw_is_post_edit()) { + return $this->load_post_edit_options(); + } else { + return $this->load_post_new_options(); + } + } + + return $options; + } + + public function load_post_edit_options() + { + global $post; + $selected = fw_get_db_post_option($post->ID, $this->get_name().'/selected'); + $title_value = fw_get_db_post_option($post->ID, $this->get_name() . '/'.$selected.'/title'); + + $options = array_merge( + array( + 'slider-sidebar-metabox' => array( + 'context' => 'side', + 'title' => __(ucfirst($this->get_name()) . ' Configuration', 'fw'), + 'type' => 'box', + 'options' => array( + 'populated' => array( + 'type' => 'hidden', + 'value' => true + ), + 'title' => array( + 'type' => 'text', + 'label' => __(ucfirst($this->get_name()) . ' Title', 'fw'), + 'value' => $title_value, + 'desc' => 'Choose a title for your slider only for internal use: Ex: "Homepage".' + ) + ) + )), + $this->get_slider_population_method_options() + ); + + $custom_settings = $this->get_slider_options(); + + if (!empty($custom_settings)) { + $selected = fw_get_db_post_option($post->ID, $this->get_name() . '/selected'); + $custom_settings_value = fw_get_db_post_option($post->ID, $this->get_name() . '/'.$selected.'/custom-settings'); + $options['slider-sidebar-metabox']['options']['custom-settings'] = array( + 'label' => false, + 'desc' => false, + 'type' => 'multi', + 'value' => $custom_settings_value, + 'inner-options' => $this->get_slider_options() + ); + } + + return $options; + } + + private function get_slider_population_method_options() + { + global $post; + + $slider_name = fw_get_db_post_option($post->ID, $this->get_name() . '/selected'); + $population_method = fw_get_db_post_option($post->ID, $this->get_name() . '/'.$slider_name.'/population-method'); + $slider_instance = $this->get_child($slider_name); + $multimedia_types = $slider_instance->get_multimedia_types(); + $options = $slider_instance->get_population_method_options($population_method); + + return fw()->extensions->get('population-method')->get_population_options($population_method, $multimedia_types, $options); + + } + + private function get_slider_options() + { + global $post; + + $slider_type = fw_get_db_post_option($post->ID, $this->get_name() . '/selected'); + + return $this->get_child($slider_type)->get_slider_options(); + } + + public function load_post_new_options() + { + return array( + 'general' => array( + 'title' => __(ucfirst($this->get_name()) . ' Settings', 'fw'), + 'type' => 'box', + 'options' => array( + $this->get_name() => array( + 'type' => 'multi-picker', + 'value' => '', + 'show_borders' => true, + 'label' => false, + 'desc' => false, + 'picker' => array( + 'selected' => array( + 'label' => __('Type', 'fw'), + 'type' => 'image-picker', + 'choices' => $this->get_sliders_types() + ) + ), + 'choices' => $this->get_sliders_sets_options() + ) + ) + ) + ); + } + + private function get_sliders_sets_options() + { + $options = array(); + foreach ($this->get_active_sliders() as $instance_name) { + + $slider_options = $this->get_child($instance_name)->get_slider_options(); + + $options[$instance_name] = array( + 'population-method' => array( + 'type' => 'select', + 'label' => __('Population Method', 'fw'), + 'desc' => __('Choose the population method for your slider', 'fw'), + 'value' => '', + 'choices' => $this->get_child($instance_name)->get_population_methods() + ), + 'title' => array( + 'type' => 'text', + 'label' => __('Title', 'fw'), + 'value' => '', + 'desc' => 'Choose the ' . $this->get_name() . ' title (for internal use)' + ) + ); + + if (!empty($slider_options)) { + $options[$instance_name]['custom-settings'] = array( + 'label' => false, + 'desc' => false, + 'type' => 'multi', + 'inner-options' => $slider_options + ); + } + } + + return $options; + } + + public function render_slider($post_id, $dimensions) + { + $slider_name = fw_get_db_post_option($post_id, $this->get_name() . '/selected'); + + if (!is_null($slider_name)) { + return $this->get_child($slider_name)->render_slider($post_id, $dimensions); + } + } + + /** + * @internal + */ + public function _admin_action_enqueue_static() + { + $match_current_screen = fw_current_screen_match( + array( + 'only' => array( + array( + 'post_type' => $this->post_type, + ) + ) + )); + + if ($match_current_screen) { + wp_enqueue_style( + 'fw-extension-' . $this->get_name() . '-css', + $this->locate_css_URI('style'), + array(), + $this->manifest->get_version() + ); + } + } + + public function get_populated_sliders_choices() + { + $choices = array(); + + foreach ($this->get_populated_sliders() as $slider) { + + $choices[$slider->ID] = $slider->post_title; + } + + return $choices; + } + + public function get_populated_sliders() + { + $posts = get_posts(array( + 'post_type' => $this->post_type, + 'numberposts' => -1 + )); + + foreach ($posts as $key => $post) { + $meta = fw_get_db_post_option($post->ID); + if (!isset($meta['populated'])) { + unset($posts[$key]); + } + } + return $posts; + } + +} diff --git a/scratch-parent/framework/extensions/media/extensions/slider/includes/default/base/class-fw-slider.php b/scratch-parent/framework/extensions/media/extensions/slider/includes/default/base/class-fw-slider.php new file mode 100644 index 00000000..e89549a9 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/includes/default/base/class-fw-slider.php @@ -0,0 +1,104 @@ + $this->get_name(), + 'small' => array( + 'height' => 100, + 'src' => $this->get_declared_uri('/static/images/thumb.jpg'), + ), + 'large' => array( + 'height' => 208, + 'src' => $this->get_declared_uri('/static/images/preview.jpg') + ) + ); + } + + public function get_multimedia_types() + { + return $this->get_config('multimedia_types'); + } + + public function get_population_methods() + { + $population_methods = fw()->extensions->get('population-method')->get_population_methods($this->get_multimedia_types()); + $config_population_methods = $this->get_config('population_methods'); + $final = is_null($config_population_methods) ? $population_methods : array_intersect_key($population_methods, array_flip($config_population_methods)); + return $final; + + } + + public function get_population_method($type){ + $population_methods = $this->get_population_methods(); + return isset($population_methods[$type]) ? $population_methods[$type] : array(); + } + + private function get_frontend_data($post_id) + { + return fw()->extensions->get('population-method')->get_frontend_data($post_id); + } + + private function list_files($path, $ext){ + $suffix = '.'. trim($ext, '.'); + + if ($glob = glob($path .'/*'. $suffix)) { + return array_map('basename', $glob, array_fill_keys($glob, $suffix)); + } else { + return array(); + } + + + } + + private function add_static() + { + if ($js_path = $this->locate_path('/static/js')) { + foreach($this->list_files($js_path, 'js') as $js){ + wp_enqueue_script( + 'fw-ext-'. $this->get_name() .'-'. $js, + $this->locate_js_URI($js), + array(), + $this->manifest->get_version() + ); + } + } + + if ($js_path = $this->locate_path('/static/css')) { + foreach($this->list_files($js_path, 'css') as $css){ + wp_enqueue_style( + 'fw-ext-'. $this->get_name() .'-'. $css, + $this->locate_css_URI($css), + array(), + $this->manifest->get_version() + ); + } + } + } + + public function render_slider($post_id, $dimensions) + { + $this->add_static(); + $data = $this->get_frontend_data($post_id); + return $this->render_view($this->get_name(), compact('data', 'dimensions')); + } + + public function get_slider_options() + { + return $this->get_options('options'); + } + + public function get_population_method_options($population_method) + { + return $this->get_options($population_method); + } +} diff --git a/scratch-parent/framework/extensions/media/extensions/slider/includes/default/class-fw-extension-slider-default.php b/scratch-parent/framework/extensions/media/extensions/slider/includes/default/class-fw-extension-slider-default.php new file mode 100644 index 00000000..4e7ae628 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/includes/default/class-fw-extension-slider-default.php @@ -0,0 +1,13 @@ +extensions->get('slider')->get_post_type(), array( + 'labels' => array( + 'name' => __('Sliders', 'fw'), + 'singular_name' => __('Slider', 'fw'), + 'add_new' => __('Add New', 'fw'), + 'add_new_item' => __('Add New Slider', 'fw'), + 'edit_item' => __('Edit Slider', 'fw'), + 'new_item' => __('New Slider', 'fw'), + 'all_items' => __('Sliders', 'fw'), + 'view_item' => __('View Slider', 'fw'), + 'search_items' => __('Search Sliders', 'fw'), + 'not_found' => __('No Sliders found', 'fw'), + 'not_found_in_trash' => __('No Sliders found in Trash', 'fw'), + 'parent_item_colon' => '', + 'menu_name' => __('Sliders', 'fw') + ), + 'public' => false, + 'publicly_queryable' => true, + 'show_ui' => true, + 'show_in_nav_menus' => false, + 'query_var' => true, + 'rewrite' => array('slug' => fw()->extensions->get('slider')->get_post_type()), + 'has_archive' => true, + 'hierarchical' => false, + 'menu_position' => null, + 'supports' => array(''), + 'capabilities' => array( + 'edit_post' => 'edit_pages', + 'read_post' => 'edit_pages', + 'delete_post' => 'edit_pages', + 'edit_posts' => 'edit_pages', + 'edit_others_posts' => 'edit_pages', + 'publish_posts' => 'edit_pages', + 'read_private_posts'=> 'edit_pages', + + 'read' => 'edit_pages', + 'delete_posts' => 'edit_pages', + 'delete_private_posts' => 'edit_pages', + 'delete_published_posts'=> 'edit_pages', + 'delete_others_posts' => 'edit_pages', + 'edit_private_posts' => 'edit_pages', + 'edit_published_posts' => 'edit_pages', + ), + /** + * Show in menu only if user has access to the Appearance (Themes) menu + * else, the Sliders menu will appear, but when clicked on it + * users with smaller privileges that does not have access to Appearance menu (for e.g. 'edit_pages' capability) + * will see Access denied page + */ + 'show_in_menu' => current_user_can('switch_themes') ? 'themes.php' : null, +)); + diff --git a/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/class-fw-shortcode-slider.php b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/class-fw-shortcode-slider.php new file mode 100644 index 00000000..c3d02e9d --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/class-fw-shortcode-slider.php @@ -0,0 +1,14 @@ +extensions->get('slider')->render_slider($atts['slider_id'], + array( + 'width' => $atts['width'], + 'height' => $atts['height'] + ) + ); + } +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/config.php b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/config.php new file mode 100644 index 00000000..69b0d32a --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/config.php @@ -0,0 +1,11 @@ + array( + 'title' => __( 'Slider', 'fw' ), + 'description' => __( 'Slider', 'fw' ), + 'tab' => __( 'Media Elements', 'fw' ), + ) +); diff --git a/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/options.php b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/options.php new file mode 100644 index 00000000..bae7484a --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/options.php @@ -0,0 +1,33 @@ +extensions->get('slider')->get_populated_sliders_choices(); +if (!empty($choices)) { + $options = array( + 'slider_id' => array( + 'type' => 'select', + 'label' => __('Select Slider', 'fw'), + 'choices' => fw()->extensions->get('slider')->get_populated_sliders_choices() + ), + 'width' => array( + 'type' => 'text', + 'label' => __('Set width', 'fw'), + 'value' => 300 + ), + 'height' => array( + 'type' => 'text', + 'label' => __('Set height', 'fw'), + 'value' => 200 + ) + ); +} else { + $options = array( + 'no_sliders' => array( + 'type' => 'html', + 'attr' => array('style' => 'position: fixed; left: 50%; top: 50%; margin-left: -108px; margin-top: -50px;'), + 'label' => false, + 'desc' => false, + 'html' => '

    No Sliders Available

    '. + '

    '. __('No Sliders created yet. Please go to the
    Sliders page and create a new Slider

    ','fw') + + ) + ); +} diff --git a/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/static/css/styles.css b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/static/css/styles.css new file mode 100644 index 00000000..761a78bc --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/static/css/styles.css @@ -0,0 +1,5 @@ +.fw-shortcode-no-sliders { + margin: 0px auto; + background-color:#1f6f93 ; +} +.fw-backend-option-fw-edit-options-modal-no_sliders \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/static/img/layout_builder.png b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/static/img/layout_builder.png new file mode 100644 index 00000000..b72b843b Binary files /dev/null and b/scratch-parent/framework/extensions/media/extensions/slider/shortcodes/slider/static/img/layout_builder.png differ diff --git a/scratch-parent/framework/extensions/media/extensions/slider/static/css/style.css b/scratch-parent/framework/extensions/media/extensions/slider/static/css/style.css new file mode 100644 index 00000000..b95da4ec --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/static/css/style.css @@ -0,0 +1,29 @@ +/*.fw-option-type-image-picker ul.thumbnails.image_picker_selector li*/ +td.slider_design ul.thumbnails.image_picker_selector li { + margin-bottom: 0px; +} +.inside .submitbox ul.thumbnails.image_picker_selector li { + margin-bottom: 0px; +} +td.slider_design .fw-option-type-image-picker { + margin-bottom: 10px !important; + margin-top: 10px !important; +} +th.column-slider_design{ + width: 150px; +} +td.column-slider_design{ + line-height: 0 !important; +} +#submitdiv .inside{ + padding-bottom: 0px !important; +} +#submitdiv .fw-backend-options-last-border-hider{ + display: none; +} +#submitdiv #major-publishing-actions{ + border-top-width: 0px; +} +#submitdiv .fw-option-type-image-picker .thumbnail{ + cursor: auto; +} diff --git a/scratch-parent/framework/extensions/media/extensions/slider/views/backend/submit-box-edit.php b/scratch-parent/framework/extensions/media/extensions/slider/views/backend/submit-box-edit.php new file mode 100644 index 00000000..00aa73a7 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/views/backend/submit-box-edit.php @@ -0,0 +1,73 @@ + + + array( + 'label' => 'Type', + 'desc' => false, + 'type' => 'html', + 'html' => '' + ), + 'population-method' => array( + 'label' => __('Population Method', 'fw'), + 'type' => 'html', + 'attr' => array('disabled' => 'disabled','class'=>'fw-no-border'), + 'html' => ''.$population_method.'', + ) +);?> + +
    + $option){ + $out.=fw()->backend->render_option($key, $option); + } + echo $out; +// fw()->backend->render_options($options); + + ?> +
    +
    + ID)) { + if (!EMPTY_TRASH_DAYS) + $delete_text = __('Delete Permanently'); + else + $delete_text = __('Move to Trash'); + ?> + +
    + +
    + + post_status, array('publish', 'future', 'private')) || 0 == $post->ID) { + if ($can_publish) : + if (!empty($post->post_date_gmt) && time() < strtotime($post->post_date_gmt . ' +0000')) : ?> + + 'p')); ?> + + + 'p')); ?> + + + 'p')); ?> + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/scratch-parent/framework/extensions/media/extensions/slider/views/backend/submit-box-raw.php b/scratch-parent/framework/extensions/media/extensions/slider/views/backend/submit-box-raw.php new file mode 100644 index 00000000..302cc427 --- /dev/null +++ b/scratch-parent/framework/extensions/media/extensions/slider/views/backend/submit-box-raw.php @@ -0,0 +1,54 @@ + +
    +
    +

    + +

    +
    + +
    +
    + ID)) { + if (!EMPTY_TRASH_DAYS) + $delete_text = __('Delete Permanently'); + else + $delete_text = __('Move to Trash'); + ?> + +
    + +
    + + post_status, array('publish', 'future', 'private')) || 0 == $post->ID) { + if ($can_publish) : + if (!empty($post->post_date_gmt) && time() < strtotime($post->post_date_gmt . ' +0000')) : ?> + + 'p')); ?> + + + 'p')); ?> + + + 'p')); ?> + + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/scratch-parent/framework/extensions/megamenu/class-fw-extension-megamenu.php b/scratch-parent/framework/extensions/megamenu/class-fw-extension-megamenu.php new file mode 100644 index 00000000..28587802 --- /dev/null +++ b/scratch-parent/framework/extensions/megamenu/class-fw-extension-megamenu.php @@ -0,0 +1,225 @@ +add_admin_actions(); + $this->add_admin_filters(); + } + else { + $this->add_theme_actions(); + $this->add_theme_filters(); + } + } + + protected function add_admin_actions() + { + add_action('admin_enqueue_scripts', array($this, '_admin_action_admin_enqueue_scripts')); + add_action('wp_update_nav_menu_item', array($this, '_admin_action_wp_update_nav_menu_item'), 10, 3); + } + + protected function add_admin_filters() + { + add_filter('wp_edit_nav_menu_walker', array($this, '_admin_filter_wp_edit_nav_menu_walker')); + add_filter('manage_nav-menus_columns', array($this, '_admin_filter_manage_nav_menus_columns'), 20); + } + + protected function add_theme_actions() + { + add_action('wp_enqueue_scripts', array($this, '_theme_action_wp_enqueue_scripts')); + } + + protected function add_theme_filters() + { + add_filter('wp_page_menu_args', array($this, '_theme_filter_wp_page_menu_args')); + add_filter('wp_nav_menu_args', array($this, '_theme_filter_wp_nav_menu_args')); + add_filter('wp_nav_menu_objects', array($this, '_theme_filter_wp_nav_menu_objects'), 10, 2); + add_filter('nav_menu_link_attributes', array($this, '_theme_filter_nav_menu_link_attributes'), 10, 3); + add_filter('walker_nav_menu_start_el', array($this, '_theme_filter_walker_nav_menu_start_el'), 10, 4); + } + + /** + * @internal + */ + public function _admin_action_admin_enqueue_scripts($hook) + { + if ($hook == 'nav-menus.php') { + + wp_enqueue_media(); + wp_enqueue_style( + "fw-ext-{$this->get_name()}-admin", + $this->locate_URI('/static/css/admin.css'), + array(), + $this->manifest->get_version() + ); + wp_enqueue_script( + "fw-ext-{$this->get_name()}-admin", + $this->locate_URI('/static/js/admin.js'), + array('fw'), + $this->manifest->get_version() + ); + + // Enqueue all the necessary files for Icon dialog + $options = array( + 'hello' => array( + 'type' => 'icon', + 'label' => __('Select Icon', 'fw'), + ), + ); + fw()->backend->render_options($options); + + } + } + + /** + * @internal + */ + public function _admin_action_wp_update_nav_menu_item($menu_id, $menu_item_db_id, $args) + { + $flags = array('enabled', 'title-off', 'new-row'); + + $meta = request_mega_menu_meta($menu_item_db_id); + foreach ($flags as $flag) { + $meta[$flag] = isset($meta[$flag]); + } + + update_mega_menu_meta($menu_item_db_id, $meta); + } + + /** + * @internal + */ + public function _admin_filter_wp_edit_nav_menu_walker() + { + return 'FW_Admin_Menu_Walker'; + } + + /** + * @internal + */ + public function _admin_filter_manage_nav_menus_columns($columns) + { + $columns['icon'] = __('Icon', 'fw'); + return $columns; + } + + /** + * @internal + */ + public function _theme_action_wp_enqueue_scripts() + { + wp_enqueue_style('fw-font-awesome'); + } + + /** + * Just for removing FW_Theme_Menu_Walker set in the previous + * filter when fallback menu is in action. + * + * @internal + */ + public function _theme_filter_wp_page_menu_args($args) + { + if ($args['walker'] instanceof FW_Theme_Menu_Walker) { + $args['walker'] = ''; + } + return $args; + } + + /** + * @internal + */ + public function _theme_filter_wp_nav_menu_args($args) + { + // $args['menu'] = ... + // $args['menu_id'] = 'xxx-menu-id'; + // $args['menu_class'] = 'xxx-menu-class'; + // $args['container'] = 'xxx-container'; // should be in apply_filters('wp_nav_menu_container_allowedtags') + // $args['container_id'] = 'xxx-container-id'; + // $args['container_class'] = 'xxx-container-class'; + // $args['before'] = 'xxx-before'; + // $args['after'] = 'xxx-after'; + // $args['link_before'] = 'xxx-link-before'; + // $args['link_after'] = 'xxx-link-after'; + // $args['items_wrap'] = '
      %3$s
    '; + + $args['walker'] = new FW_Theme_Menu_Walker(); + return $args; + } + + /** + * @internal + */ + public function _theme_filter_wp_nav_menu_objects($sorted_menu_items, $args) + { + //
  • + // .... + //
  • + + $mega_menu = array(); + foreach ($sorted_menu_items as $item) { + if ($item->menu_item_parent == 0 && get_mega_menu_meta($item, 'enabled')) { + $mega_menu[$item->ID] = true; + } + } + + foreach ($sorted_menu_items as $item) { + if (isset($mega_menu[$item->ID])) { + $item->classes[] = 'menu-item-has-mega-menu'; + } + if (isset($mega_menu[$item->menu_item_parent])) { + $item->classes[] = 'mega-menu-col'; + } + if (get_mega_menu_meta($item, 'icon')) { + $item->classes[] = 'menu-item-has-icon'; + } + } + + return $sorted_menu_items; + } + + /** + * @internal + */ + public function _theme_filter_nav_menu_link_attributes($attr, $item, $args) + { + // item_output = {{before}}{{ link_before }}{% the_title %}{{ link_after }}{{ after }} + + $show_icon = !in_array('icon', (array) get_user_option('manage' . 'nav-menus' . 'columnshidden')); + + if ($show_icon) { + $fa_class = get_mega_menu_meta($item, 'icon'); + $attr['class'] = trim(@$attr['class'] . " $fa_class"); + } + + return $attr; + } + + /** + * @internal + */ + public function _theme_filter_walker_nav_menu_start_el($item_output, $item, $depth, $args) + { + //
  • + // {{ item_output }} + //

    {{ item.description }}

    + //
    + // + //
    + //
  • + + if ($depth > 0 && get_mega_menu_meta($item, 'title-off')) { + $item_output = ''; + } + + if ($depth > 0 && $a = trim($item->description)) { + $item_output .= '

    ' . esc_html($a) . '

    '; + } + + return $item_output; + } +} diff --git a/scratch-parent/framework/extensions/megamenu/includes/class-fw-admin-menu-walker.php b/scratch-parent/framework/extensions/megamenu/includes/class-fw-admin-menu-walker.php new file mode 100644 index 00000000..58c7a621 --- /dev/null +++ b/scratch-parent/framework/extensions/megamenu/includes/class-fw-admin-menu-walker.php @@ -0,0 +1,252 @@ + $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth; + + ob_start(); + $item_id = esc_attr( $item->ID ); + $removed_args = array( + 'action', + 'customlink-tab', + 'edit-menu-item', + 'menu-item', + 'page-tab', + '_wpnonce', + ); + + $original_title = ''; + if ( 'taxonomy' == $item->type ) { + $original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' ); + if ( is_wp_error( $original_title ) ) + $original_title = false; + } elseif ( 'post_type' == $item->type ) { + $original_object = get_post( $item->object_id ); + $original_title = get_the_title( $original_object->ID ); + } + + $classes = array( + 'menu-item menu-item-depth-' . $depth, + 'menu-item-' . esc_attr( $item->object ), + 'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'), + ); + + $title = $item->title; + + if ( ! empty( $item->_invalid ) ) { + $classes[] = 'menu-item-invalid'; + /* translators: %s: title of menu item which is invalid */ + $title = sprintf( __( '%s (Invalid)' ), $item->title ); + } elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) { + $classes[] = 'pending'; + /* translators: %s: title of menu item in draft status */ + $title = sprintf( __('%s (Pending)'), $item->title ); + } + + $title = ( ! isset( $item->label ) || '' == $item->label ) ? $title : $item->label; + + $submenu_text = ''; + if ( 0 == $depth ) + $submenu_text = 'style="display: none;"'; + + ?> +
    "); + }, + + /** + * Refresh location position on current active tab + */ + showPositions : function(){ + var $currentTab = fwSidebars.getCurrentTab(); + var possibleColors = $currentTab.find('.fw-ext-sidebars-positions select option:selected').data('extra-data'); + $currentTab.find('.placeholders') + .addClass('empty') + .find('.fw-ext-sidebars-location') + .addClass('empty'); + + if (possibleColors && possibleColors.colors) { + $currentTab.find('.placeholders') + .removeClass('empty') + .find('.fw-ext-sidebars-location') + .slice(0, possibleColors.colors) + .removeClass('empty'); + } + }, + + /** + * Create new sidebar ajax + */ + createNewSidebarAjax : function(sidebarName, $currentSelectize){ + if (!sidebarName) { + alert(PhpVar.missingSidebarName); + return false; + } + + var data = { + action:'add_new_sidebar_ajax', + name: sidebarName + }; + + var $spinner = $("[aria-selected='true']").find('.spinner'); + $spinner.show(); + $.post(ajaxurl, data, function(response) { + $spinner.hide(); + if (response.success) { + fwEvents.trigger('fw:sidebars:create:sidebar:success', {sidebar: response.data.sidebar, $currentSelectize: $currentSelectize}); + } else { + alert(response.data.message); + } + }).fail(function(){ + $spinner.hide(); + }); + return false; + }, + + /** + * Return current selected tab object + */ + getCurrentTab : function(){ + var currentActiveTab = $('.fw-sidebars-tabs-wrapper.fw-sidebars-tabs-initialized').tabs('option', 'active'); + return fwSidebars.getSidebarTab(currentActiveTab); + }, + + /** + * Return tab object by index + */ + getSidebarTab : function(index){ + return $('.fw-sidebars-tabs-wrapper.fw-sidebars-tabs-initialized').find('.ui-tabs-panel').eq(index).find('.fw-ext-sidebars-box-holder'); + }, + + /** + * Reset 'preset' settings at current tab + */ + resetSettings : function(){ + var $currentTab = fwSidebars.getCurrentTab(); + $currentTab.data('preset-id', ''); + //remove specific pages ids + $currentTab.find('.sidebars-specific-pages div').remove(); + + $currentTab.find('select.sidebar-selectize').each(function(){ + $(this).data('selectize').setDefaultValue(); + }); + + var defaultValue = $currentTab.find('.fw-ext-sidebars-positions select option:nth(0)').val(); + fwSidebars.changeImagePickerVal($currentTab, defaultValue); + }, + + /** + * Generate removable item on created tab + */ + renderCreatedTabPreset : function(slug, preset, label, description){ + var html = '
    ' + + '' + + '' + + '' + label + '' + + ' ' + description + '' + + '' + + '' + + '' + + '' + + ''+ + '
    ' + + $presetList = $('.fw-ext-sidebars-preset-list'); + + var $replaceItem = $presetList.find('div[data-type="' + slug + '"][data-preset-id="' + preset + '"]'); + if ($replaceItem.length){ + $replaceItem.data('type', slug) + .data('preset-id', preset) + .find('.fw-ext-sidebars-preset-edit') + .text(label); + //move $replaceItem down to list + $cloneItem = $replaceItem.clone(true, true); + $replaceItem.remove(); + $presetList.append($cloneItem); + $replaceItem = $cloneItem; + }else{ + $presetList.append(html); + //find just created object + $replaceItem = $presetList.find('div[data-type="' + slug + '"][data-preset-id="'+preset +'"]'); + } + + return $replaceItem; + }, + + /** + * Init error popup messages + */ + initQTip : function($elem) { + $elem.qtip({ + id: 'r'+ Math.random(), + position: { + at: 'top center', + my: 'bottom center', + viewport: $(document.body) + }, + style: { + classes: 'qtip-fw qtip-fw-info', + tip: { + width: 12, + height: 5 + } + }, + show: { + event: 'show_tip' + }, + hide: { + event: 'hide_tip' + } + }); + }, + + /** + * Show popup message on $elem with text + */ + showTip : function($elem, text){ + $elem.attr('title', text); + $elem.trigger('show_tip'); + setTimeout(function(){ + $elem.trigger('hide_tip'); + },5000) + }, + + selectizeInit : function(){ + fwEvents.on('fw:sidebars:create:sidebar:success', function(data){ + $('select.sidebar-selectize').each(function(){ + $(this).data('selectize').addOption({value: data.sidebar.id, text: data.sidebar.name}); + }); + + if (data.$currentSelectize) { + data.$currentSelectize.setValue(data.sidebar.id); + } + }); + + fwEvents.on('fw:sidebars:selectize:input', function(data){ + $('#'+data.event.target.id).focus(); + }); + + fwEvents.on('fw:sidebars:selectize:new-sidebar-submit', function(data){ + var name = $('#fw-ext-sidebars-new-sidebar-name').val(); + //hide selectize dropdown before submit + data.selectize.onBlur.apply(data.selectize, arguments); + fwSidebars.createNewSidebarAjax(name, data.selectize); + }) + + fwEvents.on('fw:sidebars:remove:sidebar:success', function(data){ + if (!data.sidebarId.length) return false; + + $('select.sidebar-selectize').each(function(){ + $(this).data('selectize').removeOption(data.sidebarId); + $(this).data('selectize').setDefaultValue(); + }); + + }); + + Selectize.define('fw_sidebars_selectize_plugin', function(options) { + var self = this; + this.setup = (function() { + var original = self.setup; + return function() { + original.apply(this, arguments); + var eventNS = self.eventNS; + this.$control_input.unbind('blur'); + $(document).unbind('mousedown' + eventNS ); + $(document).on('mousedown' + eventNS, function(e) { + if (self.isFocused) { + + if (e.target.id === 'fw-ext-sidebars-new-sidebar-name' || e.target.id === 'fw-ext-sidebars-new-sidebar-label'){ + fwEvents.trigger('fw:sidebars:selectize:input',{event: e, selectize: self}); + return false; + } + + if ( e.target.id === 'fw-ext-sidebars-new-sidebar-submit') { + fwEvents.trigger('fw:sidebars:selectize:new-sidebar-submit',{event: e, selectize: self}); + return false; + } + + if (e.target === self.$dropdown[0] || e.target.parentNode === self.$dropdown[0]) { + return false; + } + + if (!self.$control.has(e.target).length && e.target !== self.$control[0]) { + self.onBlur.apply(self, arguments); + } + } + }); + + }; + })(); + //method set default value + this.setDefaultValue = function() { + var $option = null; + var options = this.options; + + for (var i in options) { + if (options.hasOwnProperty(i)) { + $option = options[i]; + break; + } + } + + if ($option){ + this.setValue($option.value); + } else { + this.setValue(''); + } + } + + }); + + $('.sidebar-selectize').selectize({ + plugins: ['fw_sidebars_selectize_plugin'], + render: { + option: function(item){ + return '
    ' + item.text + '
    '; + } + }, + + onDropdownOpen: function($dropdown){ + var self = this; + var html = + '
    ' + + '
    '+ PhpVar.newSidebarLabel +'
    ' + + ''+ + ''+ + ''+ + '
    '+ + ''+ + ''+ + ''+ + '
    '+ + '
    '; + $dropdown.append(html); + + $('#fw-ext-sidebars-new-sidebar-name').on('keyup', function(event){ + if(event.keyCode == 13){ + fwEvents.trigger('fw:sidebars:selectize:new-sidebar-submit',{event: event, selectize: self}); + } + }); + + var selectOffset = parseInt($dropdown.closest('.selectize-control').offset().top - $(document).scrollTop(), 10), + selectHeight = $dropdown.closest('.selectize-control').height(), + dropdownHeight = $dropdown.height(); + + if(selectOffset + selectHeight + dropdownHeight > $(window).height()) { + $dropdown.addClass('dropdown-top'); + } + + return $dropdown; + }, + + onDropdownClose: function($dropdown){ + $dropdown.find('#fw-ext-sidebars-new-sidebar-container').remove(); + $dropdown.removeClass('dropdown-top'); + return $dropdown; + }, + + onChange: function(values) { + $(this.$control).removeClass('fw-ext-sidebars-error'); + } + }); + + }, + + onSidebarCreate : function(sidebar){ + var id = sidebar.id; + var name = sidebar.name; + var $col1 = $('.sidebars-column-1'); + var $col2 = $('.sidebars-column-2'); + + /** + * Empty sidebar html on widgets.php page + */ + var html = + '
    ' + + '
    ' + + '' + + '
    ' + + '
    '; + + var $newElement = $(html); + + if ($col2.length) { + if($col1.find('.widgets-holder-wrap').length > $col2.find('.widgets-holder-wrap').length ) { + $col2.append($newElement); + }else{ + $col1.append($newElement); + } + } else { + $col1.append($newElement); + } + + //FROM: /wp-admin/js/widgets.js + { + $newElement.find('.widgets-sortables').sortable({ + placeholder: 'widget-placeholder', + items: '> .widget', + handle: '> .widget-top > .widget-title', + cursor: 'move', + distance: 2, + containment: 'document', + start: function( event, ui ) { + var height, $this = $(this), + $wrap = $this.parent(), + inside = ui.item.children('.widget-inside'); + + if ( inside.css('display') === 'block' ) { + inside.hide(); + $(this).sortable('refreshPositions'); + } + + if ( ! $wrap.hasClass('closed') ) { + // Lock all open sidebars min-height when starting to drag. + // Prevents jumping when dragging a widget from an open sidebar to a closed sidebar below. + height = ui.item.hasClass('ui-draggable') ? $this.height() : 1 + $this.height(); + $this.css( 'min-height', height + 'px' ); + } + }, + + stop: function( event, ui ) { + var addNew, widgetNumber, $sidebar, $children, child, item, + $widget = ui.item, + id = fwSidebars.the_widget_id; + + if ( $widget.hasClass('deleting') ) { + wpWidgets.save( $widget, 1, 0, 1 ); // delete widget + $widget.remove(); + return; + } + + var addNew = $widget.find('input.add_new').val(); + var widgetNumber = $widget.find('input.multi_number').val(); + + $widget.attr( 'style', '' ).removeClass('ui-draggable'); + fwSidebars.the_widget_id = ''; + + if ( addNew ) { + if ( 'multi' === addNew ) { + $widget.html( + $widget.html().replace( /<[^<>]+>/g, function( tag ) { + return tag.replace( /__i__|%i%/g, widgetNumber ); + }) + ); + + $widget.attr( 'id', id.replace( '__i__', widgetNumber ) ); + widgetNumber++; + + $( 'div#' + id ).find( 'input.multi_number' ).val( widgetNumber ); + } else if ( 'single' === addNew ) { + $widget.attr( 'id', 'new-' + id ); + rem = 'div#' + id; + } + + wpWidgets.save( $widget, 0, 0, 1 ); + $widget.find('input.add_new').val(''); + } + + $sidebar = $widget.parent(); + + if ( $sidebar.parent().hasClass('closed') ) { + $sidebar.parent().removeClass('closed'); + $children = $sidebar.children('.widget'); + + // Make sure the dropped widget is at the top + if ( $children.length > 1 ) { + child = $children.get(0); + item = $widget.get(0); + + if ( child.id && item.id && child.id !== item.id ) { + $( child ).before( $widget ); + } + } + } + + if ( addNew ) { + $widget.find( 'a.widget-action' ).trigger('click'); + } else { + wpWidgets.saveOrder( $sidebar.attr('id') ); + } + }, + + activate: function() { + $(this).parent().addClass( 'widget-hover' ); + }, + + deactivate: function() { + // Remove all min-height added on "start" + $(this).css( 'min-height', '' ).parent().removeClass( 'widget-hover' ); + }, + + receive: function( event, ui ) { + var $sender = $( ui.sender ); + + // Don't add more widgets to orphaned sidebars + if ( this.id.indexOf('orphaned_widgets') > -1 ) { + $sender.sortable('cancel'); + return; + } + + // If the last widget was moved out of an orphaned sidebar, close and remove it. + if ( $sender.attr('id').indexOf('orphaned_widgets') > -1 && ! $sender.children('.widget').length ) { + $sender.parents('.orphan-sidebar').slideUp( 400, function(){ $(this).remove(); } ); + } + } + }).sortable( 'option', 'connectWith', 'div.widgets-sortables' ); + } + + $widgetChooser = $('#wpbody-content').find('.widgets-chooser'); + if($widgetChooser.find()) + $widgetChooser.find('.widgets-chooser-sidebars').append($('
  • '+name+'
  • ').data('sidebarId',sidebar.id)); + + $newElement.find('.sidebar-name').on('click', function(event){ + $newElement.toggleClass('closed'); + }); + + fwSidebars.initQTip($newElement.find('.fw-ext-sidebars-delete-button')); + + $newElement.find('.fw-ext-sidebars-delete-button').on('click', function(e){ + fwEvents.trigger('fw:sidebars:remove:sidebar:click', { $this: $(this), event: e }); + return false; + }); + + } + + }; + + $(document).ready(function() { + fwSidebars.init(); + }); + +})(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework/extensions/sidebars/views/backend-main-view.php b/scratch-parent/framework/extensions/sidebars/views/backend-main-view.php new file mode 100644 index 00000000..55bf003b --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/backend-main-view.php @@ -0,0 +1,60 @@ + + + +
    +
    + +

    + +

    +
    + +
    +
    +
      + +
    • +
    • + +
    • >
    • +
    +
    +
    + +
    +
    + + +
    + extensions->get('sidebars')->get_declared_path('/views/backend-tab-grouped.php'), array( + 'grouped_options' => $grouped_options, + 'data_positions_options' => $data_positions_options, + 'id' => 'grouped', + 'sidebars' => $sidebars, + )); ?> +
    + +
    + extensions->get('sidebars')->get_declared_path('/views/backend-tab-specific.php'), array( + 'specific_options' => $specific_options, + 'data_positions_options' => $data_positions_options, + 'id' => 'specific', + 'sidebars' => $sidebars, + )); ?> +
    + + +
    > + extensions->get('sidebars')->get_declared_path('/views/backend-tab-created-sidebars.php'), array( + 'created_sidebars' => $created_sidebars, + )); ?> +
    + +
    +
    +
    +
    + +
    +
    + diff --git a/scratch-parent/framework/extensions/sidebars/views/backend-select-sidebar.php b/scratch-parent/framework/extensions/sidebars/views/backend-select-sidebar.php new file mode 100644 index 00000000..916e2d93 --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/backend-select-sidebar.php @@ -0,0 +1,11 @@ + +
    + +
    + diff --git a/scratch-parent/framework/extensions/sidebars/views/backend-sidebars-positions.php b/scratch-parent/framework/extensions/sidebars/views/backend-sidebars-positions.php new file mode 100644 index 00000000..81b88a33 --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/backend-sidebars-positions.php @@ -0,0 +1,43 @@ + +
    +
    +
    + +
    +
    +
    + +
    +
    + backend->option_type('image-picker')->render('positions', $data_positions_options, array('value' => '')); ?> +
    +
    +
    + +
    + +
    +
    + +
    + + + +
    + + extensions->get('sidebars')->get_declared_path('/views/backend-select-sidebar.php'), array( + 'id' => $id , + 'color' => $color, + 'sidebars' => $sidebars, + )); ?> + +
    + +
    + +
    + + +
    + +
    \ No newline at end of file diff --git a/scratch-parent/framework/extensions/sidebars/views/backend-tab-created-sidebars.php b/scratch-parent/framework/extensions/sidebars/views/backend-tab-created-sidebars.php new file mode 100644 index 00000000..dc0b8213 --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/backend-tab-created-sidebars.php @@ -0,0 +1,30 @@ + +
    + +
    + +
    + + +
    + + + + + + +  () + + + + + + +
    + + +
    + +
    + + diff --git a/scratch-parent/framework/extensions/sidebars/views/backend-tab-grouped.php b/scratch-parent/framework/extensions/sidebars/views/backend-tab-grouped.php new file mode 100644 index 00000000..a5e5a504 --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/backend-tab-grouped.php @@ -0,0 +1,36 @@ + +
    + +
    +
    + +
    +
    +
    + +
    +
    + backend->option_type('select')->render($id, $grouped_options, array( + 'id_prefix' => 'fw-option-sidebars-for-', + 'value' => '' + )); + ?> +
    +
    + +
    + +
    +
    +
    + +
    + + extensions->get('sidebars')->get_declared_path('/views/backend-sidebars-positions.php'), array( + 'data_positions_options' => $data_positions_options, + 'id' => $id. '-positions', + 'sidebars' => $sidebars, + )); ?> + +
    diff --git a/scratch-parent/framework/extensions/sidebars/views/backend-tab-specific.php b/scratch-parent/framework/extensions/sidebars/views/backend-tab-specific.php new file mode 100644 index 00000000..ecd5d52e --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/backend-tab-specific.php @@ -0,0 +1,42 @@ + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + backend->option_type('select')->render($id, $specific_options, array( + 'id_prefix' => 'fw-option-sidebars-for-', + 'value' => '' + )); + ?> +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    + + extensions->get('sidebars')->get_declared_path('/views/backend-sidebars-positions.php'), array( + 'data_positions_options' => $data_positions_options, + 'id' => $id. '-positions', + 'sidebars' => $sidebars, + )); ?> +
    diff --git a/scratch-parent/framework/extensions/sidebars/views/frontend-no-widgets.php b/scratch-parent/framework/extensions/sidebars/views/frontend-no-widgets.php new file mode 100644 index 00000000..daa99fe5 --- /dev/null +++ b/scratch-parent/framework/extensions/sidebars/views/frontend-no-widgets.php @@ -0,0 +1,7 @@ + + diff --git a/scratch-parent/framework/extensions/styling/class-fw-extension-styling.php b/scratch-parent/framework/extensions/styling/class-fw-extension-styling.php new file mode 100644 index 00000000..07f0b90d --- /dev/null +++ b/scratch-parent/framework/extensions/styling/class-fw-extension-styling.php @@ -0,0 +1,170 @@ +get_settings_options(); + + if (!empty(self::$user_options)) { + if ( is_admin() ) { + $this->form = new FW_Form( $this->get_name(), array( + 'render' => array( $this, '_form_render' ), + 'validate' => array( $this, '_form_validate' ), + 'save' => array( $this, '_form_save' ) + ) ); + + $this->add_admin_actions(); + } else { + $this->add_theme_actions(); + } + } + + } + + protected function add_admin_actions() { + add_action( 'fw_' . $this->get_name() . '_form_save', array( $this, '_admin_action_generate_css' ) ); + + add_action( 'admin_menu', array( $this, '_admin_action_add_menu' ), 20 ); + } + + protected function add_theme_actions() { + add_action( 'wp_head', array( $this, '_theme_action_print_css' ), 99 ); + } + + /** + * @internal + */ + public function _admin_action_add_menu() { + + $default_args = array( + 'page_title' => __( 'Styling', 'fw' ), + 'menu_title' => __( 'Styling', 'fw' ), + 'menu_slug' => 'fw-styling' + ); + $filtered_args = apply_filters( 'fw_ext_' . $this->get_name() . '_page_' . $default_args['menu_slug'], $default_args ); + $args = array_merge( $default_args, $filtered_args ); + add_theme_page( + $args['page_title'], + $args['menu_title'], + 'manage_options', + $args['menu_slug'], + array( $this, 'render_styling_settings_page' ) + ); + return true; + } + + public function render_styling_settings_page() { + echo '
    '; + echo '

    ' . __( 'Styling', 'fw' ) . '

    '; + $this->form->render(); + echo '
    '; + } + + /** + * @internal + */ + public function _form_render( $data ) { + + $this->add_admin_static(); + + $options = array( + array( + 'custom_css' => array( + 'title' => false, + 'type' => 'box', + 'options' => self::$user_options + ) + ) + ); + + $values = FW_Request::POST( FW_Option_Type::get_default_name_prefix(), fw_get_db_extension_data( $this->get_name(), 'options' ) ); + + echo fw()->backend->render_options( $options, $values ); + + $data['submit']['html'] = ''; + + unset( $options ); + + return $data; + } + + /** + * @internal + * @param $errors + * @return array + */ + public function _form_validate( $errors ) { + if (!current_user_can('manage_options')) { + $errors[] = __('You have no permission to change Styling options', 'fw'); + } + + return $errors; + } + + /** + * @internal + */ + public function _form_save( $data ) { + fw_set_db_extension_data( $this->get_name(), 'options', fw_get_options_values_from_input( $this->get_settings_options() ) ); + + do_action( 'fw_' . $this->get_name() . '_form_save' ); + + $data['redirect'] = fw_current_url(); + + return $data; + } + + /* + * @internal + */ + private function add_admin_static() { + wp_enqueue_style( + 'fw-extension-' . $this->get_name() . '-styles', + $this->locate_css_URI( 'styles' ), + array(), + $this->manifest->get_version() + ); + wp_enqueue_script( + 'fw-extension-' . $this->get_name(), + $this->locate_js_URI('scripts'), + array('jquery'), + $this->manifest->get_version(), + true + ); + } + + /** + * Triggers when the framework settings are saved, + * it generates css from the styling settings and stores it + * @internal + */ + public function _admin_action_generate_css() { + $theme_options = fw_extract_only_options( $this->get_settings_options() ); + $saved_data = fw_get_db_extension_data( $this->get_name(), 'options' ); + $css_for_style_options = FW_Styling_Css_Generator::get_css( $theme_options, $saved_data ); + fw_set_db_extension_data( $this->get_name(), 'css', $css_for_style_options ); + } + + /** + * Prints the css generated from the styling settings + * @internal + */ + public function _theme_action_print_css() { + $css = fw_get_db_extension_data( $this->get_name(), 'css' ); + if ( ! empty( $css ) ) { + echo $css; + } + } +} diff --git a/scratch-parent/framework/extensions/styling/helpers.php b/scratch-parent/framework/extensions/styling/helpers.php new file mode 100644 index 00000000..c1c05b4e --- /dev/null +++ b/scratch-parent/framework/extensions/styling/helpers.php @@ -0,0 +1,24 @@ + array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p' ), + 'links' => array( + 'links' => 'a', + 'links_hover' => 'a:hover' + ), + ); + + private static $initialized = false; + + private static $google_fonts; + + private static $remote_fonts = array(); + + static public function get_css( $theme_options, $saved_data ) { + + if ( ! self::$initialized ) { + self::$google_fonts = fw_get_google_fonts(); + self::$initialized = true; + } + + //generate css + $css = ''; + foreach ( $theme_options as $option_name => $option_settings ) { + if ( $option_settings['type'] !== 'style' ) { + unset ( $theme_options[ $option_name ] ); + continue; + } + + $css .= self::generate_option_css( $option_settings['blocks'], $saved_data[$option_name] ); + break; + } + + if ( ! empty( $css ) ) { + $css = ""; + $css .= self::get_remote_fonts() . $css; + } + + return $css; + } + + private static function generate_option_css( $blocks, $saved_settings ) { + + $css = ''; + + foreach ( $blocks as $block_id => $block_settings ) { + if ( empty( $block_settings['css_selector'] ) ) { + continue; + } + $css_selectors = (array) $block_settings['css_selector']; + $block_elements = (array) $block_settings['elements']; + + //Typography + $css .= self::generate_typography_css( $css_selectors, $block_elements, $saved_settings['blocks'][ $block_id ] ); + + //Links + $links = array_intersect( $block_elements, array_keys( self::$tags['links'] ) ); + foreach ( $links as $link ) { + foreach ( $css_selectors as $selector ) { + $css .= $selector . ' ' . self::$tags['links'][ $link ] . "{ color: " . $saved_settings['blocks'][ $block_id ][ $link ] . ";}\n"; + } + } + + //Background + $css .= self::generate_background_css( $css_selectors, $block_elements, $saved_settings['blocks'][ $block_id ] ); + } + + return $css; + } + + private static function generate_typography_css( $css_selectors, $elements, $settings ) { + $css = ''; + + $typography_tags = array_intersect( (array) $elements, self::$tags['typography'] ); + foreach ( $typography_tags as $tag ) { + + $current_family = $settings[ $tag ]['family']; + + $current_style = $settings[ $tag ]['style']; + + if ( $current_style === 'regular' ) { + $current_style = '400'; + } + if ( $current_style == 'italic' ) { + $current_style = '400italic'; + } + + $font_style = ( strpos( $current_style, 'italic' ) ) ? 'font-style: italic;' : ''; + $font_weight = 'font-weight: ' . intval( $current_style ) . ';'; + + self::insert_remote_font( $current_family, $current_style ); + + foreach ( $css_selectors as $selector ) { + $css .= $selector . ' ' . $tag . "{ + color: " . $settings[ $tag ]['color'] . "; + font-size: " . $settings[ $tag ]['size'] . "px; + font-family: '" . $current_family . "';" + . $font_style . "" . $font_weight . " + + }\n"; + } + } + + return $css; + } + + private static function insert_remote_font( $font, $style ) { + + if ( ! isset( self::$google_fonts[ $font ] ) ) { + return false; + } + + if ( ! isset( self::$remote_fonts[ $font ] ) ) { + self::$remote_fonts[ $font ] = array(); + } + + if ( ! in_array( $style, self::$remote_fonts[ $font ] ) ) { + self::$remote_fonts[ $font ][] = $style; + } + + return true; + } + + private static function generate_background_css( $css_selectors, $elements, $settings ) { + + $css = ''; + if ( ! in_array( 'background', $elements ) ) { + return $css; + } + + $bgImageCss = ''; + if ( ! empty( $settings['background']['background-image']['data']['css']['background-image'] ) ) { + $bgImageCss .= $settings['background']['background-image']['data']['css']['background-image']; + if ( ! empty( $settings['background']['background-image']['data']['css']['background-repeat'] ) ) { + $bgImageCss .= ' ' . $settings['background']['background-image']['data']['css']['background-repeat']; + } + $bgImageCss .= ', '; + } + $fallback = 'background-color: ' . $settings['background']['background-color']['primary'] . ';'; + $fallback .= ( ! empty( $settings['background']['background-image']['data']['css']['background-image'] ) ) ? 'background-image: ' . $settings['background']['background-image']['data']['css']['background-image'] . ';' : ''; + $fallback .= ( ! empty( $settings['background']['background-image']['data']['css']['background-repeat'] ) ) ? 'background-repeat: ' . $settings['background']['background-image']['data']['css']['background-repeat'] . ';' : ''; + + foreach ( $css_selectors as $selector ) { + //Gradient http://css-tricks.com/examples/CSS3Gradient/ + $css .= $selector . ' ' . '{ + /* fallback */ + ' . $fallback . ' + /* Safari 4-5, Chrome 1-9 */ + background: ' . $bgImageCss . '-webkit-gradient(linear, left top, right top, from(' . $settings['background']['background-color']['primary'] . '), to(' . $settings['background']['background-color']['secondary'] . ')); + + /* Safari 5.1, Chrome 10+ */ + background: ' . $bgImageCss . '-webkit-linear-gradient(left, ' . $settings['background']['background-color']['primary'] . ', ' . $settings['background']['background-color']['secondary'] . '); + + /* Firefox 3.6+ */ + background: ' . $bgImageCss . '-moz-linear-gradient(left, ' . $settings['background']['background-color']['primary'] . ', ' . $settings['background']['background-color']['secondary'] . '); + + /* IE 10 */ + background: ' . $bgImageCss . '-ms-linear-gradient(left, ' . $settings['background']['background-color']['primary'] . ', ' . $settings['background']['background-color']['secondary'] . '); + + /* Opera 11.10+ */ + background: ' . $bgImageCss . '-o-linear-gradient(left, ' . $settings['background']['background-color']['primary'] . ', ' . $settings['background']['background-color']['secondary'] . '); + }'; + + //Background-image + unset( $settings['background']['background-image']['data']['css']['background-image'] ); + unset( $settings['background']['background-image']['data']['css']['background-repeat'] ); + if ( sizeof( $settings['background']['background-image']['data']['css'] ) ) { + $css .= $selector . ' ' . '{'; + foreach ( $settings['background']['background-image']['data']['css'] as $css_property => $css_value ) { + $css .= $css_property . ': ' . $css_value . ';'; + } + $css .= '}'; + } + } + + + return $css; + } + + private static function get_remote_fonts() { + if ( ! sizeof( self::$remote_fonts ) ) { + return ''; + } + + $html = " array( + 'h1' => 'Titles (H1)', + 'h2' => 'Subtitles (H2)', + 'h3' => 'Subtitles (H3)', + 'h4' => 'Subtitles (H4)', + 'h5' => 'Subtitles (H5)', + 'h6' => 'Subtitles (H6)', + 'p' => 'Body (p)' + ), + 'links' => array( + 'links' => 'Links', + 'links_hover' => 'Links Hover' + ), + 'default_values' => array( + 'typography' => array( + 'h1' => array( + 'size' => 32, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + 'h2' => array( + 'size' => 24, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + 'h3' => array( + 'size' => 18, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + 'h4' => array( + 'size' => 16, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + 'h5' => array( + 'size' => 13, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + 'h6' => array( + 'size' => 11, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + 'p' => array( + 'size' => 13, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ), + ), + 'links' => array( + 'links' => '#0000ff', + 'links_hover' => '#ff0000', + ), + 'background' => array( + 'background-color' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff', + ) + ) + ) + ); + + $ext = fw()->extensions->get( 'styling' ); + + self::$extension = array( + 'path' => $ext->get_declared_path(), + 'URI' => $ext->get_declared_URI() + ); + } + + /** + * @internal + */ + public function _get_backend_width_type() { + return 'full'; + } + + /** + * @internal + */ + protected function _get_defaults() { + return array( + 'value' => array(), + 'blocks' => array() + ); + } + + /** + * @internal + */ + protected function _render( $id, $option, $data ) { + $this->add_static( $option ); + + $option = $this->prepare_options( $option ); + + return fw_render_view( self::$extension['path'] . '/includes/option-types/' . $this->get_type() . '/views/main.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + 'settings' => self::$settings, + 'extension' => self::$extension + ) ); + } + + private function add_static( $option ) { + + $version = fw()->extensions->get('styling')->manifest->get_version(); + + wp_enqueue_style( + 'fw-option-' . $this->get_type(), + self::$extension['URI'] . '/includes/option-types/' . $this->get_type() . '/static/css/styles.css' , + array('fw-jscrollpane'), + $version + ); + + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + self::$extension['URI'] . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js', + array('jquery', 'underscore', 'fw-jscrollpane'), + $version + ); + + wp_localize_script( 'fw-option-' . $this->get_type(), 'styleOptionTypeSettings', array( 'preview' => ( ! isset( $option['preview'] ) || $option['preview'] !== false ) ? true : false ) ); + } + + public function get_type() { + return 'style'; + } + + private function prepare_options( $option ) { + + if ( empty( $option['blocks'] ) ) { + $option['blocks'] = array(); + } + + if ( empty( $option['value'] ) || ! is_array( $option['value'] ) ) { + if ( ! empty( $option['predefined'] ) && is_array( $option['predefined'] ) ) { + reset( $option['predefined'] ); + $first_key = key( $option['predefined'] ); + $option['value'] = ( ! empty( $option['predefined'][ $first_key ]['blocks'] ) && is_array( $option['predefined'][ $first_key ]['blocks'] ) ) ? $option['predefined'][ $first_key ]['blocks'] : array(); + } else { + $option['value'] = array(); + } + } + + foreach ( $option['blocks'] as $block_id => $block_settings ) { + //Typography + foreach ( array_intersect( array_values( $block_settings['elements'] ), array_keys( self::$settings['typography_tags'] ) ) as $element ) { + $option['value'][ $block_id ][ $element ] = array_merge( + self::$settings['default_values']['typography'][ $element ], + ( ! empty( $option['value'][ $block_id ][ $element ] ) && is_array( $option['value'][ $block_id ][ $element ] ) ) ? $option['value'][ $block_id ][ $element ] : array() + ); + } + //Links + foreach ( array_intersect( array_values( $block_settings['elements'] ), array_keys( self::$settings['links'] ) ) as $element ) { + $option['value'][ $block_id ][ $element ] = ( ! empty( $option['value'][ $block_id ][ $element ] ) && preg_match( '/^#[a-f0-9]{6}$/i', $option['value'][ $block_id ][ $element ] ) ) ? $option['value'][ $block_id ][ $element ] : self::$settings['default_values']['links'][ $element ]; + } + if ( in_array( 'background', $block_settings['elements'] ) ) { + $option['value'][ $block_id ]['background']['background-color']['primary'] = ( ! empty( $option['value'][ $block_id ]['background']['background-color']['primary'] ) && preg_match( '/^#[a-f0-9]{6}$/i', $option['value'][ $block_id ]['background']['background-color']['primary'] ) ) ? $option['value'][ $block_id ]['background']['background-color']['primary'] : self::$settings['default_values']['background']['background-color']['primary']; + $option['value'][ $block_id ]['background']['background-color']['secondary'] = ( ! empty( $option['value'][ $block_id ]['background']['background-color']['secondary'] ) && preg_match( '/^#[a-f0-9]{6}$/i', $option['value'][ $block_id ]['background']['background-color']['secondary'] ) ) ? $option['value'][ $block_id ]['background']['background-color']['secondary'] : self::$settings['default_values']['background']['background-color']['secondary']; + $option['value'][ $block_id ]['background']['background-image']['value'] = ( ! empty( $option['value'][ $block_id ]['background']['background-image']['value'] ) ) ? $option['value'][ $block_id ]['background']['background-image']['value'] : null; + $option['value'][ $block_id ]['background']['background-image']['choices'] = ( ! empty( $option['value'][ $block_id ]['background']['background-image']['choices'] ) ) ? (array) $option['value'][ $block_id ]['background']['background-image']['choices'] : array(); + } + } + + return $option; + } + + /** + * @internal + */ + protected function _get_value_from_input( $option, $input_value ) { + + if (!is_array($input_value)) { + $input_value = $option['value']; + } + + $saved = array(); + $saved['predefined'] = ( ! empty( $input_value['predefined'] ) ) ? $input_value['predefined'] : ''; + + $option = $this->prepare_options( $option ); + + foreach ( $input_value as $block_id => $block_settings ) { + + if ( ! is_array( $block_settings ) ) { + unset( $input_value[ $block_id ] ); + continue; + } + + foreach ( $block_settings as $tag => $tag_settings ) { + + if ( in_array( $tag, array_keys( self::$settings['typography_tags'] ) ) ) { //Typography + $tag_settings = fw()->backend->option_type( 'typography' )->get_value_from_input( array( + 'value' => $option['value'][ $block_id ][ $tag ] + ), $tag_settings ); + } elseif ( in_array( $tag, array_keys( self::$settings['links'] ) ) ) { //Links + $tag_settings = fw()->backend->option_type( 'color-picker' )->get_value_from_input( array( + 'value' => $option['value'][ $block_id ][ $tag ] + ), $tag_settings ); + } elseif ( $tag === 'background' && ! empty( $tag_settings ) ) { //Background + $tag_settings['background-color'] ['primary'] = fw()->backend->option_type( 'color-picker' )->get_value_from_input( array( + 'value' => $option['value'][ $block_id ]['background']['background-color']['primary'] + ), $tag_settings['background-color']['primary'] ); + + $tag_settings['background-image'] = fw()->backend->option_type( 'background-image' )->get_value_from_input( + json_decode( $tag_settings['background-image']['data'], true ), + $tag_settings['background-image'] + ); + + $block_settings[ $tag ] = $tag_settings; + } elseif ( ( $tag === 'before' || $tag === 'after' ) && ! empty( $option['blocks'][ $block_id ][ $tag ] ) ) { + $tag_settings = fw_get_options_values_from_input( + $option['blocks'][ $block_id ][ $tag ], + $input_value[ $block_id ][ $tag ] + ); + } + + $block_settings[ $tag ] = $tag_settings; + } + + $input_value[ $block_id ] = $block_settings; + + } + + $saved['blocks'] = $input_value; + + return $saved; + } +} + +FW_Option_Type::register('FW_Option_Type_Style'); diff --git a/scratch-parent/framework/extensions/styling/includes/option-types/style/static/css/styles.css b/scratch-parent/framework/extensions/styling/includes/option-types/style/static/css/styles.css new file mode 100644 index 00000000..eee712f3 --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/option-types/style/static/css/styles.css @@ -0,0 +1,238 @@ +.fw-backend-option-type-style { + padding-left: 0; + padding-top: 0; + padding-right: 0; +} + + +.fw-option-type-style .settings .tabs ul.tabs-titles li { + display: inline-block; +} + +.fw-option-type-style .settings .tabs .block-tab { + width: 800px; + height: 200px; + background-color: #ffffff; + border: 1px solid red; +} + + +/* Typography */ + +.fw-option-type-style .tabs .block-tab select.fw-option-type-typography-option-size { + width: 62px; +} + +.fw-option-type-style .tabs .block-tab select.fw-option-typography-option-style { + width: 90px; +} + +.fw-option-type-style .tabs .block-tab input.fw-option-type-color-picker { + width: 80px; +} + +.fw-option-type-style .tabs .block-tab .iris-picker.iris-border { + left: 349px +} + + +/* Settings */ + +.fw-option-type-style .fw-option-type-style-option .fw-backend-option { + border-width: 0; + padding: 15px 25px 0; +} + +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li a.nav-tab { + padding: 6px 10px; + font-weight: 600; + font-size: 15px; + line-height: 24px; + text-decoration: none; + color: #000000; + background: #f1f1f1; + margin: -4px 4px -1px 0; + border: 1px solid #ccc; +} + +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li:after { + content: none; +} + +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li.ui-state-active a.nav-tab, +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li.ui-state-focus a.nav-tab { + color: #222; + background: 0 0; + border-bottom: 1px solid #fff; + outline: none; +} + +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li.ui-state-hover a.nav-tab { + background-color: #f8f8f8; +} + +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li.ui-state-active a.nav-tab, +.fw-option-type-style .fw-options-tabs-first-level.fw-option-type-style-settings > .fw-options-tabs-list ul li.ui-state-focus a.nav-tab { + background-color: #ffffff; +} + +.fw-option-type-style .settings, +.fw-option-type-style .preview { + display: none; +} + +.fw-option-type-style .style-preview { + position: fixed; + right: 0; + width: 560px; + height: 500px; + border: 1px solid #cccccc; + background-color: red; + display: none; +} + + +/* New */ + +.fw-option-type-style .fw-option-type-style-settings .fw-options-tab .background-image .fw-inner { + width: inherit; +} + +.fw-option-type-style .predefined_styles { + margin-bottom: 32px; +} + +.fw-option-type-style .fw-option-type-style-settings-tabs.fw-options-tabs-list ul li a.nav-tab { + padding: 1px 14px !important; + font-size: 12px !important; + margin: -4px -2px -1px 0 !important; +} + +.fw-option-type-style .fw-option-type-style-settings-tabs.fw-options-tabs-list ul li.ui-state-active a.nav-tab, +.fw-option-type-style .fw-option-type-style-settings-tabs.fw-options-tabs-list ul li.ui-state-focus a.nav-tab { + color: #2ea2cc; +} + + +/* Preview CSS */ + +.fw-option-type-style .style-preview { + position: fixed; + display: none; + top: 50px; + left: 820px; + right: auto; + z-index: 1; + width: 402px; + height: 50%; + background-color: #fff; + border: 1px solid #cccccc; + margin: 50px 0 0; +} + +.fw-option-type-style .preview-block { + border-top: 1px solid #ccc; +} + +.fw-option-type-style .preview-block:first-child { + border-top: none; +} + +.fw-option-type-style .preview-block > div { + padding: 20px; + position: relative; +} + +.fw-option-type-style .preview-block h1, +.fw-option-type-style .preview-block h2, +.fw-option-type-style .preview-block h3, +.fw-option-type-style .preview-block h4, +.fw-option-type-style .preview-block h5, +.fw-option-type-style .preview-block h6 { + padding: 0; + margin: 0 0 .3em; + line-height: normal; +} + +.fw-option-type-style .preview-block p { + margin: 0 100px 0 0; +} + +.fw-option-type-style .preview-block .bl-links { + position: absolute; + right: 15px; + bottom: 20px; +} + +.fw-option-type-style .preview-block .bl-links a { + font-size: 12px; + display: inline-block; + margin-right: 5px; +} + +.fw-option-type-style .preview-block .bl-links a:hover, +.fw-option-type-style .preview-block .bl-links a.links_hover { + text-decoration: none; +} + +.fw-option-type-style .style-preview .description { + position: absolute; + bottom: -40px; +} + +.fw-option-type-style .style-preview .description p { + font-size: 13px; + font-family: 'Open Sans', sans-serif; + font-style: italic; + color: #999; +} + +.fw-option-type-style .style-preview .inner { + overflow: auto; + height: 100%; +} + +.fw-option-type-style .style-preview .jspPane { + width: 100% !important; +} + +.fw-option-type-style .style-preview .jspVerticalBar { + width: 6px; + background: transparent; + right: 5px; +} + +.fw-option-type-style .style-preview .jspTrack { + background: transparent; +} + +.fw-option-type-style .style-preview .jspDrag { + background: none; +} + +.fw-option-type-style .style-preview .jspDrag:before { + content: ''; + position: absolute; + top: 5px; + bottom: 5px; + width: 100%; + background: #000; + border-radius: 3px; +} + +.fw-option-type-style .style-preview h3 { + cursor: text !important; + border: none; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.fw-option-type-style .fw-inner-option { + max-width: 428px; +} + +.fw-option-type-style .predefined_styles .fw-option-type-image-picker ul.thumbnails.image_picker_selector li { + margin: 0 8px 1px 0; + } \ No newline at end of file diff --git a/scratch-parent/framework/extensions/styling/includes/option-types/style/static/js/scripts.js b/scratch-parent/framework/extensions/styling/includes/option-types/style/static/js/scripts.js new file mode 100644 index 00000000..8264fe0d --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/option-types/style/static/js/scripts.js @@ -0,0 +1,455 @@ +/*global styleOptionTypeSettings, googleFonts */ + +(function ($) { + + var fwOptionTypeStyle, fwOptionTypeStylePreview; + + fwOptionTypeStyle = { + + previewEnabled: styleOptionTypeSettings.preview, + + deselectPredefined: function ($options) { + $(document).find('.fw-option-type-style-option.predefined_styles .fw-option-type-image-picker ul li .thumbnail.selected').trigger('click'); + }, + + initialize: function () { + + fwEvents.on('fw:options:init', function (data) { + var $options = data.$elements.find('.fw-option-type-style:not(.fw-option-initialized)'); + + $options.find('.settings .tabs').tabs(); + + $options.addClass('fw-option-initialized'); + + $options.find('.fw-option-type-style-option.predefined_styles .fw-option-type-image-picker') + .on('fw:option-type:image-picker:clicked', function (e, data) { + if (_.isBoolean(data.data) || !_.isObject(data.data['settings']['blocks'])) { + return; + } + + var $style = $(this).closest('.fw-option-type-style'); + $options.off('fw:color:picker:changed', 'input.fw-option-type-color-picker', fwOptionTypeStylePreview.fireColorChange); + _.each(data.data['settings']['blocks'], function (blockSettings, blockId) { + + var $blockContainer = $style.find('.fw-options-tabs-wrapper.fw-option-type-style-settings .fw-options-tab[data-block="' + blockId + '"]'); + + fwOptionTypeStyle.setBlockOptions($blockContainer, blockSettings); + }); + $options.on('fw:color:picker:changed', 'input.fw-option-type-color-picker', fwOptionTypeStylePreview.fireColorChange); + }); + + if (fwOptionTypeStyle.previewEnabled) { + + setTimeout(function () { + fwOptionTypeStylePreview.initialize($options); + }, 0); + + } + }); + }, + + setBlockOptions: function ($container, data) { + + fwEvents.off('fw:options:style:setBlockPreview', fwOptionTypeStylePreview.setBlockPreview); + + var typography = { + h1: '.h1', + h2: '.h2', + h3: '.h3', + h4: '.h4', + h5: '.heading_5', + h6: '.heading_6', + p: 'p.block-paragraph' + }; + + var links = { + links: '.links', + links_hover: '.links_hover' + }; + + _.each(data, function (item, index) { + var $element = $container.find('.fw-option-type-style-option.' + index); + + if (index === 'background') { + fwOptionTypeStyle.setBackgroundOption($container, item); + } + else if ($element.length == 1) { + if (typography.hasOwnProperty(index)) { + fwOptionTypeStyle.setTypographyOptions($element, item); + } + else if (links.hasOwnProperty(index)) { + $element.find('input.fw-option-type-color-picker.initialized').iris('color', item) + } + } + + }); + + fwEvents.on('fw:options:style:setBlockPreview', fwOptionTypeStylePreview.setBlockPreview); + + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $container, + needTimeOut: true + }); + }, + + setBackgroundOption: function ($container, data) { + + //Color + $container.find('.fw-option-type-style-option.background-color .primary-color input.fw-option-type-color-picker.initialized').iris('color', + data['background-color']['primary']); + $container.find('.fw-option-type-style-option.background-color .secondary-color input.fw-option-type-color-picker.initialized').iris('color', + data['background-color']['secondary']); + + //Image + if (data['background-image'].hasOwnProperty('choices')) { + + var settings, smallImgAttr, selectHtml = ''; + _.each(data['background-image']['choices'], function (item, index) { + settings = {css: item['css']}; + smallImgAttr = {src: item['icon'], height: 50}; + selectHtml += ''; + }); + $container.find('.fw-option-type-style-option.background.background-image .fw-option-type-image-picker select:first').html(selectHtml).val(data['background-image']['value']); + $container.find('input.background-image-data[type="hidden"]').val(JSON.stringify(data['background-image'])); + + $container.find('.fw-option-type-style-option.background.background-image').find('.fw-option.fw-option-type-background-image').removeClass('initialized'); + $container.find('.fw-option-type-style-option.background.background-image').find('.fw-option.fw-option-type-image-picker').removeClass('fw-option-initialized'); + $container.find('.fw-option-type-style-option.background.background-image').find('.fw-option.fw-option-type-image-picker ul.thumbnails').remove(); + $container.find('.fw-option-type-style-option.background.background-image').find('.fw-option.fw-option-type-image-picker select:first').removeAttr('style'); + + fwEvents.trigger('fw:options:init', {$elements: $container.find('.fw-option-type-style-option.background.background-image')}); + + $container.find('.fw-option-type-style-option.background.background-image .type input[value="predefined"]').attr('checked', 'checked'); + + $container.find('.fw-option-type-style-option.background.background-image .type').show(); + $container.find('.fw-option-type-style-option.background.background-image .custom').hide(); + $container.find('.fw-option-type-style-option.background.background-image .predefined').show(); + + } else { + $container.find('.fw-option-type-style-option.background.background-image .type input[value="custom"]').attr('checked', 'checked'); + + $container.find('.fw-option-type-style-option.background.background-image .type').hide(); + $container.find('.fw-option-type-style-option.background.background-image .predefined').hide(); + } + }, + + setTypographyOptions: function ($element, data) { + var $typography = $('.fw-option-type-style .fw-option-type-style-option.typo'); + var $sizeElement = $element.find('.fw-option-typography-option-size select[data-type="size"]'); + var $familyElement = $element.find('.fw-option-typography-option-family select[data-type="family"]'); + var $styleElement = $element.find('.fw-option-typography-option-style select[data-type="style"]'); + var $colorElement = $element.find('.fw-option-typography-option-color .fw-option-type-color-picker.initialized'); + + //Size + $sizeElement.val(data.size); + + //Family + $typography.off('change', 'select[data-type="family"]', fwOptionTypeStylePreview.fireTypographyChange); + $familyElement[0].selectize.setValue(data.family); + $typography.on('change', 'select[data-type="family"]', fwOptionTypeStylePreview.fireTypographyChange); + + var html = ''; + if (googleFonts.hasOwnProperty(data.family)) { + var font = googleFonts[data.family]; + _.each(font['variants'], function (variant) { + html += ''; + }); + } + else { + html += ''; + } + $styleElement.html(html).val(data.style); + + //Color + $colorElement.iris('color', data.color); + } + }; + + fwOptionTypeStylePreview = { + + loadedGoogleFonts: [], + + initialize: function ($options) { + + $options.find('.style-preview').each(function () { + var $this = $(this); + var $scrollpane = $this.find('.inner:first'); + + $scrollpane.jScrollPane(); + $this.show(); + + setTimeout(function () { + + $scrollpane.trigger('fw:option:style:fix-preview'); + }, 100); + + var scrollAPI = $scrollpane.data('jsp'); + + // fix preview position and size + $(window).on('resize scroll fw:option:style:fix-preview', function () { + if (!$this.is(':visible')) { + return; + } + + // select any input with fixed size (here we chose textarea) + var $leftProvider = $('.fw-backend-option-type-textarea:first textarea:first'); + var $topProvider = $this.closest('.fw-postbox'); + + if (!$leftProvider.length || !$topProvider.length) { + return; + } + + var adminBarHeight = $('#wpadminbar').height(); + var previewWidth = $this.width(); + var contentHeight = $this.find('.inner .jspPane:first').height(); + + var left = $leftProvider.offset().left + $leftProvider.width() + 40; + + var top = $topProvider.offset().top - adminBarHeight + 12; + top -= $(window).scrollTop(); + top = top < 0 ? 0 : top; + + var height = $(window).height() - top - parseInt($('#wpbody-content').css('padding-bottom')) * 2; + height = height < previewWidth ? previewWidth : height; + height = height > contentHeight ? contentHeight : height; + + $this.css({ + 'left': left + 'px', + 'top': top + 'px', + 'height': height + 'px' + }); + + scrollAPI.reinitialise(); + }); + + $this.addClass('fw-hidden-xs'); + }); + + $(window).trigger('fw:option:style:fix-preview'); + + $options.on('fw:option-type:upload:change fw:option-type:upload:clear', function (event) { + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $(event.target).closest('.fw-options-tab'), + needTimeOut: false + }); + }); + + $options.find('.fw-option-type-style-option.background-image .fw-option-type-background-image') + .on('fw:option-type:background-image:clicked', function (e, data) { + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $(this).closest('.fw-options-tab'), + needTimeOut: true + }); + fwOptionTypeStyle.deselectPredefined(); + }); + + //Typography changed + $('.fw-option-type-style .fw-option-type-style-option.typo').on('change', + 'select[data-type="size"], select[data-type="style"]', function () { + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $(this).closest('.fw-options-tab'), + needTimeOut: false + }); + fwOptionTypeStyle.deselectPredefined(); + }).on('change', 'select[data-type="family"]', fwOptionTypeStylePreview.fireTypographyChange); + + //Background Image changed + $('.fw-option-type-style .fw-option-type-style-settings .fw-option-type-style-option.background-image').on('click', + '.type div label', fwOptionTypeStylePreview.fireBackgroundImageTypeChange); + + //Color Picker changed + $options.on('fw:color:picker:changed', 'input.fw-option-type-color-picker', fwOptionTypeStylePreview.fireColorChange); + + fwEvents.on('fw:options:style:setBlockPreview', fwOptionTypeStylePreview.setBlockPreview); + + $options.find('.fw-options-tab').each(function () { + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $(this), + needTimeOut: false + }); + }); + }, + + setBlockPreview: function (data) { + + var $block = data.$block, + typoSettings, + css = ''; + + //Typography + $block.find('.fw-option-type-style-option.typo').each(function () { + typoSettings = fwOptionTypeStylePreview.collectTypographyOptionSettings($(this)); + css += fwOptionTypeStylePreview.generateTypographyOptionCss('.preview-block .' + $block.data('block') + ' ' + $(this).data('css-selector'), + typoSettings); + }); + + //Links + $block.find('.fw-option-type-style-option.link').each(function () { + css += fwOptionTypeStylePreview.generateLinkOptionCss('.preview-block .' + $block.data('block') + ' .bl-links a.' + $(this).data('css-selector'), + fwOptionTypeStylePreview.collectLinkOptionSettings($(this))); + }); + + //Background + css += fwOptionTypeStylePreview.generateBackgroundCss('.preview-block .' + $block.data('block'), + fwOptionTypeStylePreview.collectBackgroundSettings($block)); + + //Apply Changes + if (data.needTimeOut) { + setTimeout(function () { + $('.fw-option-type-style style[data-block-id="' + $block.data('block') + '"]').replaceWith(''); + }, 600); + setTimeout(function () { + $(window).trigger('fw:option:style:fix-preview'); + }, 800); + } + else { + $('.fw-option-type-style style[data-block-id="' + $block.data('block') + '"]').replaceWith(''); + $(window).trigger('fw:option:style:fix-preview'); + } + return true; + }, + + collectBackgroundSettings: function ($block) { + var type = $block.find('.fw-option-type-style-option.background-image .fw-option-type-radio input:checked:first').val(), + imageData = {}; + + if (type !== 'predefined') { + if ($block.find('.fw-option-type-style-option.background-image .thumb:first').attr('data-origsrc')) { + imageData['background-image'] = 'url("' + $block.find('.fw-option-type-style-option.background-image .thumb:first').attr('data-origsrc') + '")'; + } + } + else { + imageData = JSON.parse($block.find('.fw-option-type-style-option.background-image select:first option:selected').attr('data-extra-data')); + imageData = imageData['css']; + } + var bgImage = { + type: type, + css: (typeof imageData === 'object') ? imageData : {} + }; + + var bgColor = { + primary: ($block.find('.fw-option-type-style-option.background-color .primary-color input.fw-option-type-color-picker.initialized').length === 1) ? $block.find('.fw-option-type-style-option.background-color .primary-color input.fw-option-type-color-picker.initialized').iris('color') : $block.find('.primary-color input.fw-option-type-color-picker').val(), + secondary: ($block.find('.fw-option-type-style-option.background-color .secondary-color input.fw-option-type-color-picker.initialized').length === 1) ? $block.find('.fw-option-type-style-option.background-color .secondary-color input.fw-option-type-color-picker.initialized').iris('color') : $block.find('.secondary-color input.fw-option-type-color-picker').val() + }; + + return { + bgColor: bgColor, + bgImage: bgImage + } + }, + + generateBackgroundCss: function (cssSelector, settings) { + var css, fallback = '', bgImageCss = ''; + + css = cssSelector + '{'; + + if (settings.bgImage.css.hasOwnProperty('background-image')) { + bgImageCss += settings.bgImage.css['background-image']; + fallback += 'background-image: ' + settings.bgImage.css['background-image'] + ';'; + if (settings.bgImage.css.hasOwnProperty('background-repeat')) { + bgImageCss += ' ' + settings.bgImage.css['background-repeat']; + fallback += 'background-repeat: ' + settings.bgImage.css['background-repeat'] + ';'; + } + bgImageCss += ', '; + } + + css += 'background-color: ' + settings.bgColor.primary + ';' + fallback; + css += 'background: ' + bgImageCss + '-webkit-gradient(linear, left top, right top, from(' + settings.bgColor.primary + '), to(' + settings.bgColor.secondary + '));'; + css += 'background: ' + bgImageCss + '-webkit-linear-gradient(left, ' + settings.bgColor.primary + ', ' + settings.bgColor.secondary + '); '; + css += 'background: ' + bgImageCss + '-moz-linear-gradient(left, ' + settings.bgColor.primary + ', ' + settings.bgColor.secondary + ');'; + css += 'background: ' + bgImageCss + '-ms-linear-gradient(left, ' + settings.bgColor.primary + ', ' + settings.bgColor.secondary + ');'; + css += 'background: ' + bgImageCss + '-o-linear-gradient(left, ' + settings.bgColor.primary + ', ' + settings.bgColor.secondary + ');'; + _.each(settings.bgImage.css, function (item, index) { + if (index != 'background-image' && index != 'background-repeat') { + css += index + ': ' + item + ';'; + } + }); + css += '}'; + return css; + }, + + collectLinkOptionSettings: function ($element) { + return { + color: ($element.find('input.fw-option-type-color-picker.initialized').length === 1) ? $element.find('input.fw-option-type-color-picker.initialized').iris('color') : $element.find('input.fw-option-type-color-picker').val() + } + }, + + generateLinkOptionCss: function (cssSelector, settings) { + var css; + + css = cssSelector + '{color: ' + settings.color + '}'; + + return css; + }, + + collectTypographyOptionSettings: function ($element) { + var style = $element.find('select[data-type="style"]').val(); + + var settings = { + size: $element.find('select[data-type="size"]').val(), + family: ($element.find('.fw-option-typography-option select[data-type="family"]').val()) ? $element.find('.fw-option-typography-option select[data-type="family"]').val() : $element.find('.fw-option-typography-option select[data-type="family"]').attr('data-value'), + style: (/italic/i.test(style)) ? 'italic' : 'normal', + weight: (parseInt(style)) ? parseInt(style) : 400, + color: ($element.find('input.fw-option-type-color-picker.initialized').length === 1) ? $element.find('input.fw-option-type-color-picker.initialized').iris('color') : $element.find('input.fw-option-type-color-picker').val() + }; + + if (googleFonts.hasOwnProperty(settings.family) && $.inArray(settings.family, + fwOptionTypeStylePreview.loadedGoogleFonts) === -1) { + var variants = googleFonts[settings.family]['variants'].join(','); + $('head').append(''); + fwOptionTypeStylePreview.loadedGoogleFonts.push(settings.family); + } + + return settings; + }, + + generateTypographyOptionCss: function (cssSelector, settings) { + var css, cssProperties = { + size: {property: 'font-size', unit: 'px'}, + family: {property: 'font-family', unit: ''}, + style: {property: 'font-style', unit: ''}, + weight: {property: 'font-weight', unit: ''}, + color: {property: 'color', unit: ''} + }; + + css = cssSelector + '{'; + _.each(settings, function (item, index) { + css += cssProperties[index].property + ': ' + item + cssProperties[index].unit + ';'; + }); + css += '}'; + + return css; + }, + + fireTypographyChange: function (e) { + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $(this).closest('.fw-options-tab'), + needTimeOut: true + }); + fwOptionTypeStyle.deselectPredefined(); + }, + + fireBackgroundImageTypeChange: function () { + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: $(this).closest('.fw-options-tab'), + needTimeOut: false + }); + fwOptionTypeStyle.deselectPredefined(); + }, + + fireColorChange: function (event, data) { + if (data.$element.closest('.before-options').length === 1 || data.$element.closest('.after-options').length === 1) return false; + fwEvents.trigger('fw:options:style:setBlockPreview', { + $block: data.$element.closest('.fw-options-tab'), + needTimeOut: false + }); + fwOptionTypeStyle.deselectPredefined(); + return true; + } + }; + + $(document).ready(function () { + fwOptionTypeStyle.initialize(); + }); + +})(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework/extensions/styling/includes/option-types/style/views/main.php b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/main.php new file mode 100644 index 00000000..df4945dd --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/main.php @@ -0,0 +1,40 @@ +'; + if ( ! empty( $option['predefined'] ) ) { + echo fw_render_view( $extension['path'] . '/includes/option-types/style/views/predefined.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data + ) ); + } + if ( ! isset( $option['preview'] ) || $option['preview'] !== false ) { + echo fw_render_view( $extension['path'] . '/includes/option-types/style/views/preview.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data + ) ); + } + echo fw_render_view( $extension['path'] . '/includes/option-types/style/views/settings.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + 'settings' => $settings + ) ); +echo '
    '; \ No newline at end of file diff --git a/scratch-parent/framework/extensions/styling/includes/option-types/style/views/predefined.php b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/predefined.php new file mode 100644 index 00000000..8e3b03bb --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/predefined.php @@ -0,0 +1,54 @@ + $style_data ) { + $choices[ $style_key ] = array( + 'small' => array( + 'src' => $style_data['icon'], + 'height' => 46 + ), + 'data' => array( + 'settings' => $style_data + ) + ); +} + +$tmp_options = array( + 'predefined' => array( + 'type' => 'image-picker', + 'value' => 'default', + 'label' => __('Predefined Styles', 'fw'), + 'choices' => $choices, + 'blank' => true + ) +); + +unset($choices); + +$tmp_values = array( + 'predefined' => ( ! empty( $data['value']['predefined'] ) ) + ? $data['value']['predefined'] + : key( $option['predefined'] ) +); + +?> +
    + backend->render_options( + $tmp_options, + $tmp_values, + array( + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ); + + unset($tmp_options, $tmp_values); + ?> +
    \ No newline at end of file diff --git a/scratch-parent/framework/extensions/styling/includes/option-types/style/views/preview.php b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/preview.php new file mode 100644 index 00000000..89aa856d --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/preview.php @@ -0,0 +1,48 @@ + +
    +
    + $block ) : + if ( empty( $block['elements'] ) ) { + continue; + } ?> +
    +
    + ' . $block['title'] . '(H' . $i . ')' . ''; + endfor; ?> + +

    Mauris iaculis portititor posuef Praesent id metus massa, ut.

    + + +
    +
    + +
    + +
    +

    +
    +
    + $block ) { + echo ''; +} +?> diff --git a/scratch-parent/framework/extensions/styling/includes/option-types/style/views/settings.php b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/settings.php new file mode 100644 index 00000000..42f20b9b --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/option-types/style/views/settings.php @@ -0,0 +1,221 @@ + +
    +
    +
      + $block ): ?> +
    • + +
    +
    +
    + +
    + $block ): ?> + +
    + backend->render_options( $block['before'], $before_block_values, array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $block_id . '-style-option-before-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']' . '[' . $block_id . '][before]', + ) ); + endif; + + // Typography Tags + foreach ( array_intersect( array_values( $elements ), array_keys( $settings['typography_tags'] ) ) as $tag ): ?> +
    + array( + 'type' => 'typography', + 'label' => $settings['typography_tags'][ $tag ], + 'desc' => false, + ) + ); + + $tmp_values = array( + $tag => array_merge( + $settings['default_values']['typography'][ $tag ], + ( ! empty( $option['value'][ $block_id ][ $tag ] ) ) + ? $option['value'][ $block_id ][ $tag ] + : array(), + ( ! empty( $data['value']['blocks'][ $block_id ][ $tag ] ) ) + ? $data['value']['blocks'][ $block_id ][ $tag ] + : array() + ) + ); + + echo fw()->backend->render_options( + $tmp_options, + $tmp_values, + array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $block_id . '-typography-option-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']' . '[' . $block_id . ']', + ) + ); + + unset($tmp_options, $tmp_values); + ?> +
    + + + +
    + array( + 'type' => 'gradient', + 'label' => __( 'Background', 'fw' ), + 'desc' => false, + 'value' => array( + 'primary' => '#ffffff', + 'secondary' => '#ffffff', + ) + ) + ); + + $tmp_values = array( + 'background-color' => array( + 'primary' => ( ! empty( $data['value']['blocks'][ $block_id ]['background']['background-color']['primary'] ) ) + ? $data['value']['blocks'][ $block_id ]['background']['background-color']['primary'] + : $option['value'][ $block_id ]['background']['background-color']['primary'], + 'secondary' => ( ! empty( $data['value']['blocks'][ $block_id ]['background']['background-color']['secondary'] ) ) + ? $data['value']['blocks'][ $block_id ]['background']['background-color']['secondary'] + : $option['value'][ $block_id ]['background']['background-color']['secondary'] + ) + ); + + echo fw()->backend->render_options( + $tmp_options, + $tmp_values, + array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $block_id . '-background-color-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']' . '[' . $block_id . '][background]', + ) + ); + + unset($tmp_options, $tmp_values); + ?> +
    + +
    + + + array_merge( + $background_image_option, + array( + 'label' => ' ', + 'type' => 'background-image' + ) + ) + ); + + $tmp_values = array( + 'background-image' => ( ! empty( $data['value']['blocks'][ $block_id ]['background']['background-image'] ) ) + ? $data['value']['blocks'][ $block_id ]['background']['background-image'] + : $option['value'][ $block_id ]['background']['background-image'] + ); + + echo fw()->backend->render_options( + $tmp_options, + $tmp_values, + array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $block_id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']' . '[' . $block_id . '][background]', + ) + ); + + unset($tmp_options, $tmp_values); + ?> +
    + backend->render_options( $block['after'], $after_block_values, array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $block_id . '-styling-option-after-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']' . '[' . $block_id . '][after]', + ) ); + } + ?> +
    + +
    +
    +
    diff --git a/scratch-parent/framework/extensions/styling/includes/sub-includes.php b/scratch-parent/framework/extensions/styling/includes/sub-includes.php new file mode 100644 index 00000000..a665b4a6 --- /dev/null +++ b/scratch-parent/framework/extensions/styling/includes/sub-includes.php @@ -0,0 +1,5 @@ +add_actions(); + $this->add_filters(); + } + + private function add_actions() + { + add_action('core_upgrade_preamble', array($this, '_action_updates_page_footer')); + + add_action('update-core-custom_'. 'fw-update-framework', array($this, '_action_update_framework')); + add_action('update-core-custom_'. 'fw-update-theme', array($this, '_action_update_theme')); + add_action('update-core-custom_'. 'fw-update-extensions', array($this, '_action_update_extensions')); + } + + private function add_filters() + { + add_filter('wp_get_update_data', array($this, '_filter_update_data'), 10, 2); + } + + /** + * @internal + */ + public function _action_updates_page_footer() + { + echo $this->render_view('updates-list', array( + 'updates' => $this->get_updates(!empty($_GET['force-check'])) + )); + } + + /** + * @internal + */ + public function _filter_update_data($data, $titles) + { + $updates = $this->get_updates(!empty($_GET['force-check'])); + + if ($updates['framework'] && !is_wp_error($updates['framework'])) { + $data['counts']['total']++; + } + + if ($updates['theme'] && !is_wp_error($updates['theme'])) { + $data['counts']['total']++; + } + + if (!empty($updates['extensions'])) { + foreach ($updates['extensions'] as $ext_name => $ext_update) { + if (is_wp_error($ext_update)) { + continue; + } + + $data['counts']['total']++; + } + } + + return $data; + } + + private function get_updates($force_check = false) + { + $cache_key = 'fw_ext_update/updates'; + + // use cache because this method may be called multiple times (to prevent useless requests to update servers) + + try { + return FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $updates = array( + 'framework' => $this->get_framework_update($force_check), + 'theme' => $this->get_theme_update($force_check), + 'extensions' => $this->get_extensions_with_updates($force_check) + ); + + FW_Cache::set($cache_key, $updates); + + return $updates; + } + } + + /** + * Collect extensions that has new versions available + */ + private function get_extensions_with_updates($force_check = false) + { + $updates = array(); + + $services = $this->get_children(); + + foreach (fw()->extensions->get_all() as $ext_name => $extension) { + /** @var FW_Extension $extension */ + + if ($extension->get_declared_source() !== 'child') { + /** + * Only extensions from child theme are standalone and can have updates. + * Extensions from framework comes with framework. + * Extensions from parent theme comes with parent theme. + */ + continue; + } + + /** + * Ask each service if it knows how to update the extension + */ + foreach ($services as $service_name => $service) { + /** @var $service FW_Ext_Update_Service */ + + $latest_version = $service->_get_extension_latest_version($extension, $force_check); + + if ($latest_version === false) { + // It said that it doesn't know how to update it + continue; + } + + if (is_wp_error($latest_version)) { + $updates[$ext_name] = $latest_version; + break; + } + + $fixed_latest_version = preg_replace('/^[^0-9]+/i', '', $latest_version); + + if (!version_compare($latest_version, $extension->manifest->get_version(), '>')) { + // we already have latest version + continue; + } + + $updates[$ext_name] = array( + 'service' => $service_name, + 'latest_version' => $latest_version, + 'fixed_latest_version' => $fixed_latest_version + ); + + break; + } + } + + return $updates; + } + + /** + * @param bool $force_check + * @return array|false|WP_Error + */ + private function get_framework_update($force_check = false) + { + /** + * Ask each service if it knows how to update the framework + */ + foreach ($this->get_children() as $service_name => $service) { + /** @var $service FW_Ext_Update_Service */ + + $latest_version = $service->_get_framework_latest_version($force_check); + + if ($latest_version === false) { + // It said that it doesn't know how to update it + continue; + } + + if (is_wp_error($latest_version)) { + return $latest_version; + } + + $fixed_latest_version = preg_replace('/^[^0-9]+/i', '', $latest_version); + + if (!version_compare($fixed_latest_version, fw()->manifest->get_version(), '>')) { + // we already have latest version + continue; + } + + return array( + 'service' => $service_name, + 'latest_version' => $latest_version, + 'fixed_latest_version' => $fixed_latest_version + ); + } + + return false; + } + + /** + * @param bool $force_check + * @return array|false|WP_Error + */ + private function get_theme_update($force_check = false) + { + /** + * Ask each service if it knows how to update the theme + */ + foreach ($this->get_children() as $service_name => $service) { + /** @var $service FW_Ext_Update_Service */ + + $latest_version = $service->_get_theme_latest_version($force_check); + + if ($latest_version === false) { + // It said that it doesn't know how to update it + continue; + } + + if (is_wp_error($latest_version)) { + return $latest_version; + } + + $fixed_latest_version = preg_replace('/^[^0-9]+/i', '', $latest_version); + + if (!version_compare($fixed_latest_version, fw()->theme->manifest->get_version(), '>')) { + // we already have latest version + continue; + } + + return array( + 'service' => $service_name, + 'latest_version' => $latest_version, + 'fixed_latest_version' => $fixed_latest_version + ); + } + + return false; + } + + private function maintenance_mode($enable = false) + { + global $wp_filesystem; + + if (!$wp_filesystem) { + return; + } + + $file = $wp_filesystem->abspath() . '.maintenance'; + + if ($enable) { + // Create maintenance file to signal that we are upgrading + $maintenance_string = ''; + $wp_filesystem->delete($file); + $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE); + } else if ( !$enable && $wp_filesystem->exists($file) ) { + $wp_filesystem->delete($file); + } + } + + /** + * @internal + */ + public function _action_update_framework() + { + $nonce_name = '_nonce_fw_ext_update_framework'; + if (!isset($_POST[$nonce_name]) || !wp_verify_nonce($_POST[$nonce_name])) { + wp_die(__('Invalid nonce.', 'fw')); + } + + { + if (!class_exists('_FW_Ext_Update_Framework_Upgrader_Skin')) { + fw_include_file_isolated( + $this->get_declared_path('/includes/classes/class--fw-ext-update-framework-upgrader-skin.php') + ); + } + + $skin = new _FW_Ext_Update_Framework_Upgrader_Skin(array( + 'title' => __('Update Framework', 'fw'), + )); + } + + require_once ABSPATH . 'wp-admin/admin-header.php'; + + $skin->header(); + + $update = $this->get_framework_update(true); + + do { + if ($update === false) { + $skin->error(__('Failed to get framework latest version.', 'fw')); + break; + } elseif (is_wp_error($update)) { + $skin->error($update); + break; + } + + $context = $this->context; + + if (!FW_WP_Filesystem::request_access($context, fw_current_url(), array($nonce_name))) { + break; + } + + $this->maintenance_mode(true); + + /** @var WP_Filesystem_Base $wp_filesystem */ + global $wp_filesystem; + + // create temporary directory for files to be downloaded in it + { + $tmp_download_dir = FW_WP_Filesystem::real_path_to_filesystem_path(FW_CACHE_DIR .'/update'); + + // just in case it already exists, clear everything, it may contain broken/old files + $wp_filesystem->rmdir($tmp_download_dir, true); + + if (!FW_WP_Filesystem::mkdir_recursive($tmp_download_dir)) { + $skin->error(__('Cannot create directory: '. $tmp_download_dir, 'fw')); + break; + } + } + + $skin->feedback(__('Downloading framework...', 'fw')); + { + /** @var FW_Ext_Update_Service $service */ + $service = $this->get_child($update['service']); + + $downloaded_files_dir = $service->_download_framework($update['latest_version'], $tmp_download_dir); + + if (!$downloaded_files_dir) { + $skin->error(__('Failed to download framework.', 'fw')); + break; + } elseif (is_wp_error($downloaded_files_dir)) { + $skin->error($downloaded_files_dir); + break; + } + } + + $skin->feedback(__('Installing framework...', 'fw')); + { + $framework_dir = FW_WP_Filesystem::real_path_to_filesystem_path(FW_DIR); + + // remove entire framework directory + $wp_filesystem->rmdir($framework_dir, true); + + // move downloaded directory as new framework directory + $wp_filesystem->move($downloaded_files_dir, $framework_dir); + } + + $skin->feedback(__('Framework updated.', 'fw')); + + $wp_filesystem->delete($tmp_download_dir, true, 'd'); + + $skin->set_result(true); + $skin->after(); + } while(false); + + $this->maintenance_mode(false); + + $skin->footer(); + + require_once(ABSPATH . 'wp-admin/admin-footer.php'); + } + + /** + * @internal + */ + public function _action_update_theme() + { + $nonce_name = '_nonce_fw_ext_update_theme'; + if (!isset($_POST[$nonce_name]) || !wp_verify_nonce($_POST[$nonce_name])) { + wp_die(__('Invalid nonce.', 'fw')); + } + + require_once(ABSPATH . 'wp-admin/admin-header.php'); + + fw_print('Hello'); + + require_once(ABSPATH . 'wp-admin/admin-footer.php'); + } + + /** + * @internal + */ + public function _action_update_extensions() + { + $nonce_name = '_nonce_fw_ext_update_extensions'; + if (!isset($_POST[$nonce_name]) || !wp_verify_nonce($_POST[$nonce_name])) { + wp_die(__('Invalid nonce.', 'fw')); + } + + require_once(ABSPATH . 'wp-admin/admin-header.php'); + + fw_print('Hello'); + + require_once(ABSPATH . 'wp-admin/admin-footer.php'); + } +} diff --git a/scratch-parent/framework/extensions/update/extensions/github-update/class-fw-extension-github-update.php b/scratch-parent/framework/extensions/update/extensions/github-update/class-fw-extension-github-update.php new file mode 100644 index 00000000..92555eb6 --- /dev/null +++ b/scratch-parent/framework/extensions/update/extensions/github-update/class-fw-extension-github-update.php @@ -0,0 +1,183 @@ + 'user/repo'} to your manifest and this extension will handle it + */ +class FW_Extension_Github_Update extends FW_Ext_Update_Service +{ + private $manifest_key = 'github_update'; + private $manifest_key_regex = '/^([^\s\/]+)\/([^\s\/]+)$/'; + + private $transient_expiration = 3600; + + private $download_timeout = 300; + + /** + * @internal + */ + protected function _init() + { + } + + private function fetch_latest_version($user_slash_repo) + { + $http = new WP_Http(); + + $response = $http->get('https://api.github.com/repos/'. $user_slash_repo .'/releases'); + + unset($http); + + if (wp_remote_retrieve_response_code($response) !== 200) { + return new WP_Error('fw_ext_update_github_fetch_failed', __('Failed to contact Github.', 'fw')); + } + + $releases = json_decode($response['body'], true); + + unset($response); + + if (empty($releases)) { + return new WP_Error( + 'fw_ext_update_github_fetch_no_releases', + sprintf(__('No releases found in repository "%s".', 'fw'), $user_slash_repo) + ); + } + + return $releases[0]['tag_name']; + } + + /** + * {@inheritdoc} + * @internal + */ + public function _get_framework_latest_version($force_check) + { + $user_slash_repo = fw()->manifest->get($this->manifest_key); + + if (empty($user_slash_repo)) { + return false; + } + + if (!preg_match($this->manifest_key_regex, $user_slash_repo)) { + return new WP_Error('fw_ext_update_github_framework_manifest_invalid', + __('Framework manifest has invalid "github_update" parameter. Please use "user/repo" format.', 'fw') + ); + } + + $theme_id = preg_replace('[^a-z0-9_]', '_', fw()->theme->manifest->get_id()); + $transient_id = 'fw_ext_update_gh_'. $theme_id .'_fw'; // this should be 45 characters or less + + if ($force_check) { + delete_site_transient($transient_id); + } else { + $cache = get_site_transient($transient_id); + + if ($cache !== false && isset($cache[$user_slash_repo])) { + return $cache[$user_slash_repo]; + } + } + + $latest_version = $this->fetch_latest_version($user_slash_repo); + + if (empty($latest_version)) { + return new WP_Error( + sprintf(__('Failed to fetch framework latest version from github "%s".', 'fw'), $user_slash_repo) + ); + } + + if (is_wp_error($latest_version)) { + return $latest_version; + } + + set_site_transient( + $transient_id, + array($user_slash_repo => $latest_version), + $this->transient_expiration + ); + + return $latest_version; + } + + /** + * {@inheritdoc} + * @internal + */ + public function _download_framework($version, $wp_filesystem_download_directory) + { + /** @var WP_Filesystem_Base $wp_filesystem */ + global $wp_filesystem; + + $user_slash_repo = fw()->manifest->get($this->manifest_key); + + $http = new WP_Http(); + + $response = $http->get('https://api.github.com/repos/'. $user_slash_repo .'/releases'); + + unset($http); + + if (wp_remote_retrieve_response_code($response) !== 200) { + return new WP_Error('fw_ext_update_github_framework_download_releases_failed', + __('Failed to access Github repository releases.', 'fw') + ); + } + + $releases = json_decode($response['body'], true); + + unset($response); + + if (empty($releases)) { + return new WP_Error('fw_ext_update_github_framework_download_no_releases', + __('Github repository has no releases.', 'fw') + ); + } + + $release = false; + + foreach ($releases as $_release) { + if ($_release['tag_name'] === $version) { + $release = $_release; + } + } + + if (empty($release)) { + return new WP_Error('fw_ext_update_github_framework_download_not_existing_release', + sprintf(__('Requested version (release) for download does not exists "%s".', 'fw'), $version) + ); + } + + $http = new WP_Http(); + + $response = $http->request($release['zipball_url'], array( + 'timeout' => $this->download_timeout, + )); + + unset($http); + + if (wp_remote_retrieve_response_code($response) !== 200) { + return new WP_Error('fw_ext_update_github_framework_download_failed', + __('Failed to download framework zip.', 'fw') + ); + } + + $zip_path = $wp_filesystem_download_directory .'/temp.zip'; + + // save zip to file + $wp_filesystem->put_contents($zip_path, $response['body']); + + unset($response); + + unzip_file(FW_WP_Filesystem::filesystem_path_to_real_path($zip_path), $wp_filesystem_download_directory); + + // remove zip file + $wp_filesystem->delete($zip_path, false, 'f'); + + // in this directory, sure exists only one directory, get it + { + $unzipped_dir = $wp_filesystem->dirlist($wp_filesystem_download_directory); + $unzipped_dir = $wp_filesystem_download_directory .'/'. key($unzipped_dir); + } + + return $unzipped_dir; + } +} diff --git a/scratch-parent/framework/extensions/update/includes/classes/class--fw-ext-update-extensions-list-table.php b/scratch-parent/framework/extensions/update/includes/classes/class--fw-ext-update-extensions-list-table.php new file mode 100644 index 00000000..db1933e7 --- /dev/null +++ b/scratch-parent/framework/extensions/update/includes/classes/class--fw-ext-update-extensions-list-table.php @@ -0,0 +1,126 @@ + 'fw-ext-update-extensions-update' + )); + + $this->_extensions = $args['extensions']; + + $this->_table_columns = array( + 'cb' => '', + 'details' => fw_html_tag( + 'a', + array( + 'href' => '#', + 'onclick' => "jQuery(this).closest('tr').find('input[type=\"checkbox\"]:first').trigger('click'); return false;" + ), + __('Select All', 'fw') + ), + ); + $this->_table_columns_count = count($this->_table_columns); + } + + public function get_columns() + { + return $this->_table_columns; + } + + public function prepare_items() + { + if ($this->total_items !== null) { + return; + } + + $this->total_items = count($this->_extensions); + + $this->set_pagination_args(array( + 'total_items' => $this->total_items, + 'per_page' => $this->items_pre_page, + )); + + $page_num = $this->get_pagenum(); + $offset = ($page_num - 1) * $this->items_pre_page; + + /** + * Prepare items for output + */ + foreach ($this->_extensions as $ext_name => $ext_update) { + $extension = fw()->extensions->get($ext_name); + + if (is_wp_error($ext_update)) { + $this->items[] = array( + 'cb' => '', + 'details' => + '

    '. + ''. fw_htmlspecialchars($extension->manifest->get_name()) .''. + '
    '. + ''. $ext_update->get_error_message() .''. + '

    ', + ); + } else { + $this->items[] = array( + 'cb' => '', + 'details' => + '

    '. + ''. fw_htmlspecialchars($extension->manifest->get_name()) .''. + '
    '. + 'You have version '. $extension->manifest->get_version() .' installed. '. + 'Update to '. fw_htmlspecialchars($ext_update['fixed_latest_version']) .'.'. + '

    ', + ); + } + } + } + + public function has_items() + { + $this->prepare_items(); + + return $this->total_items; + } + + /** + * (override parent) + */ + function single_row($item) + { + static $row_class = ''; + + $row_class = ( $row_class == '' ? ' class="alternate"' : '' ); + + echo ''; + echo $this->single_row_columns( $item ); + echo ''; + } + + protected function column_cb($item) + { + echo $item['cb']; + } + + protected function column_default($item, $column_name) + { + echo $item[$column_name]; + } + + function no_items() + { + _e('No Extensions for update.', 'fw'); + } +} diff --git a/scratch-parent/framework/extensions/update/includes/classes/class--fw-ext-update-framework-upgrader-skin.php b/scratch-parent/framework/extensions/update/includes/classes/class--fw-ext-update-framework-upgrader-skin.php new file mode 100644 index 00000000..eb9059ed --- /dev/null +++ b/scratch-parent/framework/extensions/update/includes/classes/class--fw-ext-update-framework-upgrader-skin.php @@ -0,0 +1,33 @@ +decrement_update_count('framework'); + + $update_actions = array( + 'updates_page' => fw_html_tag( + 'a', + array( + 'href' => self_admin_url('update-core.php'), + 'title' => esc_attr__('Go to updates page'), + 'target' => '_parent', + ), + __('Return to Updates page') + ) + ); + + /** + * Filter the list of action links available following framework update. + * @param array $update_actions Array of plugin action links. + */ + $update_actions = apply_filters('fw_ext_update_framework_complete_actions', $update_actions); + + if (!empty($update_actions)) { + $this->feedback(implode(' | ', (array)$update_actions)); + } + } +} diff --git a/scratch-parent/framework/extensions/update/includes/extends/class-fw-ext-update-service.php b/scratch-parent/framework/extensions/update/includes/extends/class-fw-ext-update-service.php new file mode 100644 index 00000000..0d1e7f49 --- /dev/null +++ b/scratch-parent/framework/extensions/update/includes/extends/class-fw-ext-update-service.php @@ -0,0 +1,104 @@ +extensions->get('update'); + +if (fw_current_screen_match(array('only' => array(array('id' => 'update-core'))))) { + // Include only on update page + + wp_enqueue_style( + 'fw-ext-'. $extension->get_name() .'-update-page', + $extension->get_declared_URI('/static/css/admin-update-page.css'), + array(), + $extension->manifest->get_version() + ); +} diff --git a/scratch-parent/framework/extensions/update/static/css/admin-update-page.css b/scratch-parent/framework/extensions/update/static/css/admin-update-page.css new file mode 100644 index 00000000..2ca7e70d --- /dev/null +++ b/scratch-parent/framework/extensions/update/static/css/admin-update-page.css @@ -0,0 +1,3 @@ +#fw-ext-update-extensions .tablenav { + display: none; +} \ No newline at end of file diff --git a/scratch-parent/framework/extensions/update/views/updates-list.php b/scratch-parent/framework/extensions/update/views/updates-list.php new file mode 100644 index 00000000..a3d526d8 --- /dev/null +++ b/scratch-parent/framework/extensions/update/views/updates-list.php @@ -0,0 +1,64 @@ + + + + +

    + +

    get_error_message() ?>

    + +
    +

    manifest->get_version(), + $updates['framework']['fixed_latest_version'] + ), 'fw') + ?>

    + +

    +
    + + + + + +

    theme->manifest->get_name()), 'fw') ?>

    + +

    get_error_message() ?>

    + +
    +

    theme->manifest->get_version(), + $updates['theme']['fixed_latest_version'] + ), 'fw') + ?>

    + +

    +
    + + + + + +

    +
    +

    + extensions->get('update')->get_declared_path('/includes/classes/class--fw-ext-update-extensions-list-table.php') + ); + } + + $list_table = new _FW_Ext_Update_Extensions_List_Table(array( + 'extensions' => $updates['extensions'] + )); + + $list_table->display(); + ?> + +

    +
    + diff --git a/scratch-parent/framework/helpers/class-fw-access-key.php b/scratch-parent/framework/helpers/class-fw-access-key.php new file mode 100644 index 00000000..f99f73df --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-access-key.php @@ -0,0 +1,43 @@ +get_key() !== 'whatever') { + * trigger_error('Call denied', E_USER_ERROR); + * } + * + * //... + * } + */ +class FW_Access_Key +{ + private static $created_keys = array(); + + private $key; + + public function get_key() + { + return $this->key; + } + + /** + * @param string $unique_key unique + */ + final public function __construct($unique_key) + { + if (isset(self::$created_keys[$unique_key])) { + trigger_error('Key "'. $unique_key .'" already defined', E_USER_ERROR); + } + + self::$created_keys[$unique_key] = true; + + $this->key = $unique_key; + } +} diff --git a/scratch-parent/framework/helpers/class-fw-cache.php b/scratch-parent/framework/helpers/class-fw-cache.php new file mode 100644 index 00000000..1b06c9d2 --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-cache.php @@ -0,0 +1,180 @@ + nnn MB + } else if ($matches[2] == 'K') { + $memory_limit = $matches[1] * 1024; // nnn_k -> nnn KB + } + } + + self::$memory_limit = $memory_limit; + } + + return self::$memory_limit; + } + + protected static function memory_exceeded() + { + return memory_get_usage() >= self::get_memory_limit() - self::$min_free_memory; + } + + /** + * @internal + */ + public static function _init() + { + self::$not_found_value = new FW_Cache_Not_Found_Exception(); + } + + public static function free_memory() + { + while (self::memory_exceeded() && !empty(self::$cache)) { + reset(self::$cache); + + $key = key(self::$cache); + + unset(self::$cache[$key]); + } + } + + /** + * @param $keys + * @param $value + * @param $keys_delimiter + */ + public static function set($keys, $value, $keys_delimiter = '/') + { + fw_aks($keys, $value, self::$cache, $keys_delimiter); + + self::free_memory(); // call it every time to take care about memory + } + + /** + * Unset key from cache + * @param $keys + * @param $keys_delimiter + */ + public static function del($keys, $keys_delimiter = '/') + { + fw_aku($keys, self::$cache, $keys_delimiter); + + self::free_memory(); // call it every time to take care about memory + } + + /** + * @param $keys + * @param $keys_delimiter + * @param $load_callback + * @return mixed + * @throws FW_Cache_Not_Found_Exception + */ + public static function get($keys, $load_callback = null, $keys_delimiter = '/') + { + $keys = (string)$keys; + $keys_arr = explode($keys_delimiter, $keys); + + $key = $keys_arr; + $key = array_shift($key); + + if ($key === '' || $key === null) { + trigger_error('First key must not be empty', E_USER_ERROR); + } + + $value = fw_akg($keys, self::$cache, self::$not_found_value, $keys_delimiter); + + self::free_memory(); // call it every time to take care about memory + + if ($value === self::$not_found_value) { + // others can load values for keys with TFC::set() + { + $parameters = array( + 'key' => $key, + 'keys' => $keys, + 'keys_arr' => $keys_arr, + ); + + if (is_callable($load_callback)) { + call_user_func_array($load_callback, array($parameters)); + } else { + do_action('fw_cache_load', $parameters); + } + + unset($parameters); + } + + // try again to get value (maybe someone loaded it) + $value = fw_akg($keys, self::$cache, self::$not_found_value, $keys_delimiter); + + if ($value === self::$not_found_value) { + throw new FW_Cache_Not_Found_Exception('Cache key not found: '. $keys); + } + } + + return $value; + } + + /** + * Empty the cache + */ + public static function clear() + { + self::$cache = array(); + } +} +FW_Cache::_init(); + +class FW_Cache_Not_Found_Exception extends Exception {} + +// auto free_memory() every X ticks +{ + /** + * 3000: ~15 times + */ + declare(ticks=3000); + + register_tick_function(array('FW_Cache', 'free_memory')); +} diff --git a/scratch-parent/framework/helpers/class-fw-dumper.php b/scratch-parent/framework/helpers/class-fw-dumper.php new file mode 100644 index 00000000..9b709df6 --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-dumper.php @@ -0,0 +1,124 @@ + + * echo TVar_dumper::dump($var); + * + * + * @author Qiang Xue + * @version $Id$ + * @package System.Util + * @since 3.0 + */ +class FW_Dumper +{ + private static $_objects; + private static $_output; + private static $_depth; + + /** + * Converts a variable into a string representation. + * This method achieves the similar functionality as var_dump and print_r + * but is more robust when handling complex objects such as PRADO controls. + * @param mixed $var Variable to be dumped + * @param integer $depth Maximum depth that the dumper should go into the variable. Defaults to 10. + * @return string the string representation of the variable + */ + public static function dump($var, $depth=10) + { + self::reset_internals(); + + self::$_depth=$depth; + self::dump_internal($var,0); + + $output = self::$_output; + + self::reset_internals(); + + return $output; + } + + private static function reset_internals() + { + self::$_output=''; + self::$_objects=array(); + self::$_depth=10; + } + + private static function dump_internal($var,$level) + { + switch(gettype($var)) { + case 'boolean': + self::$_output.=$var?'true':'false'; + break; + case 'integer': + self::$_output.="$var"; + break; + case 'double': + self::$_output.="$var"; + break; + case 'string': + self::$_output.="'$var'"; + break; + case 'resource': + self::$_output.='{resource}'; + break; + case 'NULL': + self::$_output.="null"; + break; + case 'unknown type': + self::$_output.='{unknown}'; + break; + case 'array': + if(self::$_depth<=$level) + self::$_output.='array(...)'; + else if(empty($var)) + self::$_output.='array()'; + else + { + $keys=array_keys($var); + $spaces=str_repeat(' ',$level*4); + self::$_output.="array\n".$spaces.'('; + foreach($keys as $key) + { + self::$_output.="\n".$spaces." [$key] => "; + self::$_output.=self::dump_internal($var[$key],$level+1); + } + self::$_output.="\n".$spaces.')'; + } + break; + case 'object': + if(($id=array_search($var,self::$_objects,true))!==false) + self::$_output.=get_class($var).'(...)'; + else if(self::$_depth<=$level) + self::$_output.=get_class($var).'(...)'; + else + { + $id=array_push(self::$_objects,$var); + $class_name=get_class($var); + $members=(array)$var; + $keys=array_keys($members); + $spaces=str_repeat(' ',$level*4); + self::$_output.="$class_name\n".$spaces.'('; + foreach($keys as $key) + { + $key_display=strtr(trim($key),array("\0"=>':')); + self::$_output.="\n".$spaces." [$key_display] => "; + self::$_output.=self::dump_internal($members[$key],$level+1); + } + self::$_output.="\n".$spaces.')'; + } + break; + } + } +} \ No newline at end of file diff --git a/scratch-parent/framework/helpers/class-fw-flash-messages.php b/scratch-parent/framework/helpers/class-fw-flash-messages.php new file mode 100644 index 00000000..755d9d32 --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-flash-messages.php @@ -0,0 +1,167 @@ + 'backend class/type' (only 2 backend types exists: error and updated) + 'error' => 'error', + 'warning' => 'update-nag', + 'info' => 'updated', + 'success' => 'updated' + ); + + private static $session_key = 'fw_flash_messages'; + + private static function get_messages() + { + $messages = FW_Session::get(self::$session_key); + + if (!is_array($messages)) { + $messages = array_fill_keys(array_keys(self::$available_types), array()); + } + + return $messages; + } + + private static function set_messages(array $messages) + { + FW_Session::set(self::$session_key, $messages); + } + + /** + * Remove messages with ids from pending remove + */ + private static function process_pending_remove_ids() + { + $pending_remove = array(); + + foreach (self::get_messages() as $messages) { + if (empty($messages)) + continue; + + foreach ($messages as $message) { + if (empty($message['remove_ids'])) + continue; + + foreach ($message['remove_ids'] as $remove_id) { + $pending_remove[$remove_id] = true; + } + } + } + + $types = self::get_messages(); + + foreach ($types as $type => $messages) { + if (empty($messages)) + continue; + + foreach ($messages as $id => $message) { + if (isset($pending_remove[$id])) { + unset($types[$type][$id]); + } + } + } + + self::set_messages($types); + } + + /** + * Add flash message + ** + * @param string $id Unique id of the message + * @param string $message Message (can be html) + * @param string $type Type from $available_types + * @param array $removed_ids Remove flashes with this id(s) + * (For e.g. your message is success and some known error messages ids needs to be removed + * because they are not relevant anymore, your success message suppress/cancels them) + */ + public static function add($id, $message, $type = 'info', array $removed_ids = array()) + { + if (!isset(self::$available_types[$type])) { + trigger_error(sprintf(__('Invalid flash message type: %s', 'tfuse'), $type), E_USER_WARNING); + $type = 'info'; + } + + $messages = self::get_messages(); + + $messages[$type][$id] = array( + 'message' => $message, + 'remove_ids' => $removed_ids, + ); + + self::set_messages($messages); + } + + /** + * Use this method to print messages html in backend + * (used in action at the end of the file) + * @internal + */ + public static function _print_backend() + { + self::process_pending_remove_ids(); + + $html = array_fill_keys(array_keys(self::$available_types), ''); + + $all_messages = self::get_messages(); + + foreach ($all_messages as $type => $messages) { + if (!empty($messages)) { + foreach ($messages as $id => $data) { + $html[$type] .= '

    '. $data['message'] .'

    '; + + unset($all_messages[$type][$id]); + } + + $html[$type] = '
    '. $html[$type] .'
    '; + } + } + + echo '
    '. implode("\n\n", $html) .'
    '; + + unset($success, $error, $info); + + self::set_messages($all_messages); + } + + /** + * Use this method to print messages html in frontend + * @internal + */ + public static function _print_frontend() + { + self::process_pending_remove_ids(); + + $html = array_fill_keys(array_keys(self::$available_types), ''); + + $all_messages = self::get_messages(); + + foreach ($all_messages as $type => $messages) { + if (!empty($messages)) { + foreach ($messages as $id => $data) { + $html[$type] .= '

    '. nl2br($data['message']) .'

    '; + + unset($all_messages[$type][$id]); + } + + $html[$type] = '
    '. $html[$type] .'
    '; + } + } + + self::set_messages($all_messages); + + echo '
    '; + echo implode("\n\n", $html); + echo '
    '; + } +} + +/** + * Display flash messages in backend as notices + */ +add_action('admin_notices', array('FW_Flash_Messages', '_print_backend')); diff --git a/scratch-parent/framework/helpers/class-fw-form.php b/scratch-parent/framework/helpers/class-fw-form.php new file mode 100644 index 00000000..74762af7 --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-form.php @@ -0,0 +1,417 @@ + instance} + */ + protected static $forms = array(); + + /** + * The id of the submitted form id + * @var string + */ + protected static $submitted_id; + + /** + * Hidden input name that stores the form id + * @var string + */ + protected static $id_input_name = 'fwf'; + + /** + * Form id + * @var string + */ + protected $id; + + /** + * Html attributes for
    tag + * @var array + */ + protected $attr; + + /** + * Found validation errors + * @var array + */ + protected $errors; + + /** + * If current request is the submit of this form + * @var bool + */ + protected $is_submitted; + + /** + * @var bool + */ + protected $validate_and_save_called = false; + + protected $callbacks = array( + 'render' => false, + 'validate' => false, + 'save' => false + ); + + /** + * @param string $id Unique + * @param array $data (optional) + * array( + * 'render' => callback // The callback that will render the form's html + * 'validate' => callback // The callback that will validate user input + * 'save' => callback // The callback that will save successfully validated user input + * 'attr' => array() // Custom attributes + * ) + */ + public function __construct($id, $data = array()) + { + if (isset(self::$forms[$id])) { + trigger_error(sprintf(__('Form with id "%s" was already defined', 'fw'), $id), E_USER_ERROR); + } + + $this->id = $id; + + self::$forms[$this->id] =& $this; + + // prepare $this->attr + { + if (!isset($data['attr']) || !is_array($data['attr'])) { + $data['attr'] = array(); + } + + $data['attr']['id'] = 'fw_form_'. $this->id; + + if (isset($data['attr']['method'])) { + $data['attr']['method'] = strtolower($data['attr']['method']); + + $data['attr']['method'] = in_array($data['attr']['method'], array('get', 'post')) + ? $data['attr']['method'] + : 'post'; + } else { + $data['attr']['method'] = 'post'; + } + + if (!isset($data['attr']['action'])) { + $data['attr']['action'] = ''; + } + + $this->attr = $data['attr']; + } + + // prepare $this->callbacks + { + $this->callbacks = array( + 'render' => empty($data['render']) ? false : $data['render'], + 'validate' => empty($data['validate']) ? false : $data['validate'], + 'save' => empty($data['save']) ? false : $data['save'], + ); + } + + if (did_action('wp_loaded')) { + // in case if form instance was created after action + $this->_validate_and_save(); + } else { + // attach to an action before 'send_headers' action, to be able to do redirects + add_action('wp_loaded', array($this, '_validate_and_save'), 101); + } + } + + protected function validate() + { + if (is_array($this->errors)) { + trigger_error(__METHOD__ .' already called', E_USER_WARNING); + return; + } + + /** + * Errors array {'input[name]' => 'Error message'} + */ + $errors = array(); + + /** + * Call validate callback + * + * Callback must 'manually' extract input values from $_POST (or $_GET) + */ + if ($this->callbacks['validate']) { + $errors = call_user_func_array($this->callbacks['validate'], array($errors)); + + if (!is_array($errors)) { + + $errors = array(); + } + } + + /** + * check nonce + */ + if ($this->attr['method'] == 'post') { + $nonce_name = '_nonce_'. md5($this->id); + + if (!isset($_REQUEST[$nonce_name]) || wp_verify_nonce($_REQUEST[$nonce_name], 'submit_fwf') === false) { + $errors[$nonce_name] = __('Nonce verification failed', 'fw'); + } + } + + $this->errors = $errors; + } + + protected function save() + { + $save_data = array( + // you can set here a url for redirect after save + 'redirect' => null + ); + + /** + * Call save callback + * + * Callback must 'manually' extract input values from $_POST (or $_GET) + */ + if ($this->callbacks['save']) { + $data = call_user_func_array($this->callbacks['save'], array($save_data)); + + if (!is_array($data)) { + // fix if returned wrong data from callback + $data = $save_data; + } + + $save_data = $data; + + unset($data); + } + + if (isset($save_data['redirect'])) { + wp_redirect($save_data['redirect']); + exit; + } + } + + /** + * If current form was submitted, validate and save it + * + * Note: This callback can abort script execution if save does redirect + * + * @return bool|null + * @internal + */ + public function _validate_and_save() + { + if ($this->validate_and_save_called) { + trigger_error(__METHOD__ .' already called', E_USER_WARNING); + return null; + } else { + $this->validate_and_save_called = true; + } + + if (!$this->is_submitted()) { + return; + } + + $this->validate(); + + if (!$this->is_valid()) { + return false; + } + + $this->save(); + + return true; + } + + /** + * @return string + */ + public function get_id() + { + return $this->id; + } + + /** + * Get html attribute(s) + * + * @param null|string $name + * @return array|string + */ + public function attr($name = null) + { + if ($name) { + return isset($this->attr[$name]) ? $this->attr[$name] : null; + } else { + return $this->attr; + } + } + + /** + * Render form's html + */ + public function render($data = array()) + { + echo fw_html_tag('form', $this->attr); + + if (!empty($this->attr['action']) && $this->attr['method'] == 'get') { + /** + * Add query vars from action attribute url to hidden inputs to not loose them + * For cases when get_search_link() will return '.../?s=~', + * the 's' will be lost after submit and no search page will be shown + */ + + parse_str(parse_url($this->attr['action'], PHP_URL_QUERY), $query_vars); + + if (!empty($query_vars)) { + foreach ($query_vars as $var_name => $var_value) { + ?>attr['method'] == 'post') { + wp_nonce_field('submit_fwf', '_nonce_'. md5($this->id)); + } + + $render_data = array( + 'submit' => array( + 'value' => __('Submit', 'fw'), + /** + * you can set here custom submit button html + * and the 'value' parameter will not be used + */ + 'html' => null, + ), + 'data' => $data, + 'attr' => $this->attr, + ); + + unset($data); + + if ($this->callbacks['render']) { + $data = call_user_func_array($this->callbacks['render'], array($render_data)); + + if (empty($data)) { + // fix if returned wrong data from callback + $data = $render_data; + } + + $render_data = $data; + + unset($data); + } + + // In filter can be defined custom html for submit button + if (isset($render_data['submit']['html'])): + print $render_data['submit']['html']; + else: + ?>
    is_submitted)) { + $method = strtoupper($this->attr('method')); + + if ($method === 'POST') { + $this->is_submitted = ( + isset($_POST[self::$id_input_name]) + && + FW_Request::POST(self::$id_input_name) === $this->id + ); + } elseif ($method === 'GET') { + $this->is_submitted = ( + isset($_GET[self::$id_input_name]) + && + FW_Request::GET(self::$id_input_name) === $this->id + ); + } else { + $this->is_submitted = false; + } + } + + return $this->is_submitted; + } + + /** + * @return bool + */ + public function is_valid() + { + if (!$this->validate_and_save_called) { + trigger_error(__METHOD__ .' called before validation', E_USER_WARNING); + return null; + } + + return empty($this->errors); + } + + /** + * Get validation errors + * @return array + */ + public function get_errors() + { + if (!$this->validate_and_save_called) { + trigger_error(__METHOD__ .' called before validation', E_USER_WARNING); + return array('~' => true); + } + + return $this->errors; + } + + /** + * Get submitted form instance (or false if no form is currently submitted) + * @return FW_Form|false + */ + public static function get_submitted() + { + if (is_null(self::$submitted_id)) { + // method called first time, search for submitted form + do { + foreach (self::$forms as $form) { + if ($form->is_submitted()) { + self::$submitted_id = $form->get_id(); + break 2; + } + } + + self::$submitted_id = false; + } while(false); + } + + if (is_string(self::$submitted_id)) { + return self::$forms[ self::$submitted_id ]; + } else { + return false; + } + } +} + +if (is_admin()) { + /** + * Display form errors in admin side + */ + function _action_show_fw_form_errors_in_admin() { + $form = FW_Form::get_submitted(); + + if (!$form || $form->is_valid()) { + return; + } + + foreach ($form->get_errors() as $input_name => $error_message) { + FW_Flash_Messages::add('fw-form-admin-'. $input_name, $error_message, 'error'); + } + } + add_action('wp_loaded', '_action_show_fw_form_errors_in_admin', 111); +} \ No newline at end of file diff --git a/scratch-parent/framework/helpers/class-fw-request.php b/scratch-parent/framework/helpers/class-fw-request.php new file mode 100644 index 00000000..96ca61dd --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-request.php @@ -0,0 +1,88 @@ + key1][key2][key3] ) + $multikey = str_replace('/', '][', $multikey) . ']'; + + // removes the first closed square bracket ( key1][key2][key3] => key1[key2][key3] ) + $multikey = preg_replace('/\]/', '', $multikey, 1); + + setcookie($multikey, $set_value, $expire, $path); + } else { + return self::get_set_key($multikey, $set_value, $_COOKIE); + } + } + + public static function REQUEST($multikey = null, $default_value = null) + { + return fw_stripslashes_deep_keys( + $multikey === null + ? $_REQUEST + : fw_akg($multikey, $_REQUEST, $default_value) + ); + } +} diff --git a/scratch-parent/framework/helpers/class-fw-resize.php b/scratch-parent/framework/helpers/class-fw-resize.php new file mode 100644 index 00000000..a5ee62d5 --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-resize.php @@ -0,0 +1,155 @@ +get_attachment( $attachment ); + $path = get_attached_file( $row['ID'] ); + + return ( ! isset( $row ) || ! $path ) ? false : array( + 'id' => intval( $row['ID'] ), + 'path' => $path, + 'url' => $row['guid'] + ); + } + + private function get_attachment( $attachment ) { + global $wpdb; + + if ( is_numeric( $attachment ) ) { + return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID=%d", $attachment ), ARRAY_A ); + } else { + $attachment = str_replace( array( 'http:', 'https:' ), '', $attachment ); + + return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE guid LIKE %s", '%' . $attachment ), ARRAY_A ); + } + } + + public function process( $attachment, $width, $height, $crop = false ) { + + $attachment_info = $this->get_attachment_info( $attachment ); + + if ( ! $attachment_info ) { + return new WP_Error( 'invalid_attachment', 'Invalid Attachment', $attachment ); + } + + $file_path = $attachment_info['path']; + + $info = pathinfo( $file_path ); + $dir = $info['dirname']; + $ext = ( isset( $info['extension'] ) ) ? $info['extension'] : 'jpg'; + $name = wp_basename( $file_path, ".$ext" ); + $name = preg_replace( '/(.+)(\-\d+x\d+)$/', '$1', $name ); + + // Suffix applied to filename + $suffix = "{$width}x{$height}"; + + // Get the destination file name + $destination_file_name = "{$dir}/{$name}-{$suffix}.{$ext}"; + + // No need to resize & create a new image if it already exists + if ( ! file_exists( $destination_file_name ) ) { + //Image Resize + $editor = wp_get_image_editor( $file_path ); + + if ( is_wp_error( $editor ) ) { + return new WP_Error( 'wp_image_editor', 'WP Image editor can\'t resize this attachment', $attachment ); + } + + // Get the original image size + $size = $editor->get_size(); + $orig_width = $size['width']; + $orig_height = $size['height']; + + $src_x = $src_y = 0; + $src_w = $orig_width; + $src_h = $orig_height; + + if ( $crop ) { + + $cmp_x = $orig_width / $width; + $cmp_y = $orig_height / $height; + + // Calculate x or y coordinate, and width or height of source + if ( $cmp_x > $cmp_y ) { + $src_w = round( $orig_width / $cmp_x * $cmp_y ); + $src_x = round( ( $orig_width - ( $orig_width / $cmp_x * $cmp_y ) ) / 2 ); + } else if ( $cmp_y > $cmp_x ) { + $src_h = round( $orig_height / $cmp_y * $cmp_x ); + $src_y = round( ( $orig_height - ( $orig_height / $cmp_y * $cmp_x ) ) / 2 ); + } + + } + + $editor->crop( $src_x, $src_y, $src_w, $src_h, $width, $height ); + + $saved = $editor->save( $destination_file_name ); + + $images = wp_get_attachment_metadata( $attachment_info['id'] ); + if ( ! empty( $images['resizes'] ) && is_array( $images['resizes'] ) ) { + foreach ( $images['resizes'] as $image_size => $image_path ) { + $images['resizes'][ $image_size ] = addslashes( $image_path ); + } + } + $images['resizes'][ $suffix ] = addslashes( $saved['path'] ); + wp_update_attachment_metadata( $attachment_info['id'], $images ); + + } + + return array( + 'id' => $attachment_info['id'], + 'src' => str_replace( basename( $attachment_info['url'] ), basename( $destination_file_name ), $attachment_info['url'] ) + ); + } + } +} + +if ( ! function_exists( 'fw_resize' ) ) { + function fw_resize( $url, $width, $height, $crop = false ) { + $fw_resize = FW_Resize::getInstance(); + $response = $fw_resize->process( $url, $width, $height, $crop ); + + return ( ! is_wp_error( $response ) && ! empty( $response['src'] ) ) ? $response['src'] : $url; + } +} + +if ( ! function_exists( 'fw_delete_resized_thumbnails' ) ) { + function fw_delete_resized_thumbnails( $id ) { + $images = wp_get_attachment_metadata( $id ); + if ( ! empty( $images['resizes'] ) ) { + foreach ( $images['resizes'] as $image ) { + @unlink( $image ); + } + } + } + + add_action( 'delete_attachment', 'fw_delete_resized_thumbnails' ); +} diff --git a/scratch-parent/framework/helpers/class-fw-session.php b/scratch-parent/framework/helpers/class-fw-session.php new file mode 100644 index 00000000..fd78db9e --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-session.php @@ -0,0 +1,30 @@ +errors) && $wp_filesystem->errors->get_error_code() ) { + return false; + } + + if ( + $wp_filesystem->abspath() + && + $wp_filesystem->wp_content_dir() + && + $wp_filesystem->wp_plugins_dir() + && + $wp_filesystem->wp_themes_dir() + && + $wp_filesystem->find_folder($context) + ) { + // ok + } else { + return false; + } + + return true; + } + + /** + * Convert real file path to WP Filesystem path + * @param string $path + * @return string + */ + final public static function real_path_to_filesystem_path($path) { + /** @var WP_Filesystem_Base $wp_filesystem */ + global $wp_filesystem; + + if (!$wp_filesystem) { + trigger_error('Filesystem is not available', E_USER_WARNING); + return false; + } + + $path = fw_fix_path($path); + + $real_abspath = untrailingslashit(fw_fix_path(ABSPATH)); + $wp_filesystem_abspath = untrailingslashit($wp_filesystem->abspath()); + $relative_path = preg_replace('/^'. preg_quote($real_abspath, '/') .'/', '', $path); + + return $wp_filesystem_abspath . $relative_path; + } + + /** + * Convert WP Filesystem path to real file path + * @param string $wp_filesystem_path + * @return string + */ + final public static function filesystem_path_to_real_path($wp_filesystem_path) { + /** @var WP_Filesystem_Base $wp_filesystem */ + global $wp_filesystem; + + if (!$wp_filesystem) { + trigger_error('Filesystem is not available', E_USER_WARNING); + return false; + } + + $wp_filesystem_path = fw_fix_path($wp_filesystem_path); + + $real_abspath = untrailingslashit(fw_fix_path(ABSPATH)); + $wp_filesystem_abspath = untrailingslashit($wp_filesystem->abspath()); + $relative_path = preg_replace('/^'. preg_quote($wp_filesystem_abspath, '/') .'/', '', $wp_filesystem_path); + + return $real_abspath . $relative_path; + } + + /** + * Create wp filesystem directory recursive + * @param string $wp_filesystem_dir_path + * @return bool + */ + final public static function mkdir_recursive($wp_filesystem_dir_path) { + /** @var WP_Filesystem_Base $wp_filesystem */ + global $wp_filesystem; + + if (!$wp_filesystem) { + trigger_error('Filesystem is not available', E_USER_WARNING); + return false; + } + + $wp_filesystem_dir_path = fw_fix_path($wp_filesystem_dir_path); + + $path = ''; + $check_if_exists = true; + $firs_loop = true; + foreach (explode('/', $wp_filesystem_dir_path) as $dir_name) { + if (empty($dir_name)) { + if ($firs_loop) { + // in first loop $dir_name can be empty because it's starting with + } else { + trigger_error('Invalid path: '. $wp_filesystem_dir_path, E_USER_WARNING); + return false; + } + } + + $firs_loop = false; + + $path .= '/'. $dir_name; + if ($check_if_exists) { + if ($wp_filesystem->is_dir($path)) { + // do nothing if exists + continue; + } else { + // do not check anymore, next directories sure does not exists + $check_if_exists = false; + } + } + + $wp_filesystem->mkdir($path, FS_CHMOD_DIR); + } + + return true; + } +} diff --git a/scratch-parent/framework/helpers/class-fw-wp-option.php b/scratch-parent/framework/helpers/class-fw-wp-option.php new file mode 100644 index 00000000..4306f2af --- /dev/null +++ b/scratch-parent/framework/helpers/class-fw-wp-option.php @@ -0,0 +1,83 @@ +extensions->get($extension_name)) { + trigger_error('Invalid extension: '. $extension_name, E_USER_WARNING); + return; + } + + if ($multi_key) { + $multi_key = $extension_name .'/'. $multi_key; + } else { + $multi_key = $extension_name; + } + + return FW_WP_Option::get('fw_extensions', $multi_key, $get_original_value); + } + + /** + * Set some extension's data in database + * + * @param string $extension_name Name of the extension that owns the data + * @param string|null $multi_key The key of the data you want to set. null - all data + * @param mixed $value + */ + function fw_set_db_extension_data($extension_name, $multi_key = null, $value) { + if (!fw()->extensions->get($extension_name)) { + trigger_error('Invalid extension: '. $extension_name, E_USER_WARNING); + return; + } + + if ($multi_key) { + $multi_key = $extension_name .'/'. $multi_key; + } else { + $multi_key = $extension_name; + } + + FW_WP_Option::set('fw_extensions', $multi_key, $value); + } +} diff --git a/scratch-parent/framework/helpers/fw-google-fonts.json b/scratch-parent/framework/helpers/fw-google-fonts.json new file mode 100644 index 00000000..05e9f742 --- /dev/null +++ b/scratch-parent/framework/helpers/fw-google-fonts.json @@ -0,0 +1 @@ +{"ABeeZee":{"family":"ABeeZee","variants":["regular","italic"],"position":0},"Abel":{"family":"Abel","variants":["regular"],"position":28},"Abril Fatface":{"family":"Abril Fatface","variants":["regular"],"position":58},"Aclonica":{"family":"Aclonica","variants":["regular"],"position":88},"Acme":{"family":"Acme","variants":["regular"],"position":118},"Actor":{"family":"Actor","variants":["regular"],"position":148},"Adamina":{"family":"Adamina","variants":["regular"],"position":178},"Advent Pro":{"family":"Advent Pro","variants":["100","200","300","regular","500","600","700"],"position":208},"Aguafina Script":{"family":"Aguafina Script","variants":["regular"],"position":238},"Akronim":{"family":"Akronim","variants":["regular"],"position":268},"Aladin":{"family":"Aladin","variants":["regular"],"position":298},"Aldrich":{"family":"Aldrich","variants":["regular"],"position":328},"Alegreya":{"family":"Alegreya","variants":["regular","italic","700","700italic","900","900italic"],"position":358},"Alegreya SC":{"family":"Alegreya SC","variants":["regular","italic","700","700italic","900","900italic"],"position":388},"Alex Brush":{"family":"Alex Brush","variants":["regular"],"position":418},"Alfa Slab One":{"family":"Alfa Slab One","variants":["regular"],"position":448},"Alice":{"family":"Alice","variants":["regular"],"position":478},"Alike":{"family":"Alike","variants":["regular"],"position":508},"Alike Angular":{"family":"Alike Angular","variants":["regular"],"position":538},"Allan":{"family":"Allan","variants":["regular","700"],"position":568},"Allerta":{"family":"Allerta","variants":["regular"],"position":598},"Allerta Stencil":{"family":"Allerta Stencil","variants":["regular"],"position":628},"Allura":{"family":"Allura","variants":["regular"],"position":658},"Almendra":{"family":"Almendra","variants":["regular","italic","700","700italic"],"position":688},"Almendra Display":{"family":"Almendra Display","variants":["regular"],"position":718},"Almendra SC":{"family":"Almendra SC","variants":["regular"],"position":748},"Amarante":{"family":"Amarante","variants":["regular"],"position":778},"Amaranth":{"family":"Amaranth","variants":["regular","italic","700","700italic"],"position":808},"Amatic SC":{"family":"Amatic SC","variants":["regular","700"],"position":838},"Amethysta":{"family":"Amethysta","variants":["regular"],"position":868},"Anaheim":{"family":"Anaheim","variants":["regular"],"position":898},"Andada":{"family":"Andada","variants":["regular"],"position":928},"Andika":{"family":"Andika","variants":["regular"],"position":958},"Angkor":{"family":"Angkor","variants":["regular"],"position":988},"Annie Use Your Telescope":{"family":"Annie Use Your Telescope","variants":["regular"],"position":1018},"Anonymous Pro":{"family":"Anonymous Pro","variants":["regular","italic","700","700italic"],"position":1048},"Antic":{"family":"Antic","variants":["regular"],"position":1078},"Antic Didone":{"family":"Antic Didone","variants":["regular"],"position":1108},"Antic Slab":{"family":"Antic Slab","variants":["regular"],"position":1138},"Anton":{"family":"Anton","variants":["regular"],"position":1168},"Arapey":{"family":"Arapey","variants":["regular","italic"],"position":1198},"Arbutus":{"family":"Arbutus","variants":["regular"],"position":1228},"Arbutus Slab":{"family":"Arbutus Slab","variants":["regular"],"position":1258},"Architects Daughter":{"family":"Architects Daughter","variants":["regular"],"position":1288},"Archivo Black":{"family":"Archivo Black","variants":["regular"],"position":1318},"Archivo Narrow":{"family":"Archivo Narrow","variants":["regular","italic","700","700italic"],"position":1348},"Arimo":{"family":"Arimo","variants":["regular","italic","700","700italic"],"position":1378},"Arizonia":{"family":"Arizonia","variants":["regular"],"position":1408},"Armata":{"family":"Armata","variants":["regular"],"position":1438},"Artifika":{"family":"Artifika","variants":["regular"],"position":1468},"Arvo":{"family":"Arvo","variants":["regular","italic","700","700italic"],"position":1498},"Asap":{"family":"Asap","variants":["regular","italic","700","700italic"],"position":1528},"Asset":{"family":"Asset","variants":["regular"],"position":1558},"Astloch":{"family":"Astloch","variants":["regular","700"],"position":1588},"Asul":{"family":"Asul","variants":["regular","700"],"position":1618},"Atomic Age":{"family":"Atomic Age","variants":["regular"],"position":1648},"Aubrey":{"family":"Aubrey","variants":["regular"],"position":1678},"Audiowide":{"family":"Audiowide","variants":["regular"],"position":1708},"Autour One":{"family":"Autour One","variants":["regular"],"position":1738},"Average":{"family":"Average","variants":["regular"],"position":1768},"Average Sans":{"family":"Average Sans","variants":["regular"],"position":1798},"Averia Gruesa Libre":{"family":"Averia Gruesa Libre","variants":["regular"],"position":1828},"Averia Libre":{"family":"Averia Libre","variants":["300","300italic","regular","italic","700","700italic"],"position":1858},"Averia Sans Libre":{"family":"Averia Sans Libre","variants":["300","300italic","regular","italic","700","700italic"],"position":1888},"Averia Serif Libre":{"family":"Averia Serif Libre","variants":["300","300italic","regular","italic","700","700italic"],"position":1918},"Bad Script":{"family":"Bad Script","variants":["regular"],"position":1948},"Balthazar":{"family":"Balthazar","variants":["regular"],"position":1978},"Bangers":{"family":"Bangers","variants":["regular"],"position":2008},"Basic":{"family":"Basic","variants":["regular"],"position":2038},"Battambang":{"family":"Battambang","variants":["regular","700"],"position":2068},"Baumans":{"family":"Baumans","variants":["regular"],"position":2098},"Bayon":{"family":"Bayon","variants":["regular"],"position":2128},"Belgrano":{"family":"Belgrano","variants":["regular"],"position":2158},"Belleza":{"family":"Belleza","variants":["regular"],"position":2188},"BenchNine":{"family":"BenchNine","variants":["300","regular","700"],"position":2218},"Bentham":{"family":"Bentham","variants":["regular"],"position":2248},"Berkshire Swash":{"family":"Berkshire Swash","variants":["regular"],"position":2278},"Bevan":{"family":"Bevan","variants":["regular"],"position":2308},"Bigelow Rules":{"family":"Bigelow Rules","variants":["regular"],"position":2338},"Bigshot One":{"family":"Bigshot One","variants":["regular"],"position":2368},"Bilbo":{"family":"Bilbo","variants":["regular"],"position":2398},"Bilbo Swash Caps":{"family":"Bilbo Swash Caps","variants":["regular"],"position":2428},"Bitter":{"family":"Bitter","variants":["regular","italic","700"],"position":2458},"Black Ops One":{"family":"Black Ops One","variants":["regular"],"position":2488},"Bokor":{"family":"Bokor","variants":["regular"],"position":2518},"Bonbon":{"family":"Bonbon","variants":["regular"],"position":2548},"Boogaloo":{"family":"Boogaloo","variants":["regular"],"position":2578},"Bowlby One":{"family":"Bowlby One","variants":["regular"],"position":2608},"Bowlby One SC":{"family":"Bowlby One SC","variants":["regular"],"position":2638},"Brawler":{"family":"Brawler","variants":["regular"],"position":2668},"Bree Serif":{"family":"Bree Serif","variants":["regular"],"position":2698},"Bubblegum Sans":{"family":"Bubblegum Sans","variants":["regular"],"position":2728},"Bubbler One":{"family":"Bubbler One","variants":["regular"],"position":2758},"Buda":{"family":"Buda","variants":["300"],"position":2788},"Buenard":{"family":"Buenard","variants":["regular","700"],"position":2818},"Butcherman":{"family":"Butcherman","variants":["regular"],"position":2848},"Butterfly Kids":{"family":"Butterfly Kids","variants":["regular"],"position":2878},"Cabin":{"family":"Cabin","variants":["regular","italic","500","500italic","600","600italic","700","700italic"],"position":2908},"Cabin Condensed":{"family":"Cabin Condensed","variants":["regular","500","600","700"],"position":2938},"Cabin Sketch":{"family":"Cabin Sketch","variants":["regular","700"],"position":2968},"Caesar Dressing":{"family":"Caesar Dressing","variants":["regular"],"position":2998},"Cagliostro":{"family":"Cagliostro","variants":["regular"],"position":3028},"Calligraffitti":{"family":"Calligraffitti","variants":["regular"],"position":3058},"Cambo":{"family":"Cambo","variants":["regular"],"position":3088},"Candal":{"family":"Candal","variants":["regular"],"position":3118},"Cantarell":{"family":"Cantarell","variants":["regular","italic","700","700italic"],"position":3148},"Cantata One":{"family":"Cantata One","variants":["regular"],"position":3178},"Cantora One":{"family":"Cantora One","variants":["regular"],"position":3208},"Capriola":{"family":"Capriola","variants":["regular"],"position":3238},"Cardo":{"family":"Cardo","variants":["regular","italic","700"],"position":3268},"Carme":{"family":"Carme","variants":["regular"],"position":3298},"Carrois Gothic":{"family":"Carrois Gothic","variants":["regular"],"position":3328},"Carrois Gothic SC":{"family":"Carrois Gothic SC","variants":["regular"],"position":3358},"Carter One":{"family":"Carter One","variants":["regular"],"position":3388},"Caudex":{"family":"Caudex","variants":["regular","italic","700","700italic"],"position":3418},"Cedarville Cursive":{"family":"Cedarville Cursive","variants":["regular"],"position":3448},"Ceviche One":{"family":"Ceviche One","variants":["regular"],"position":3478},"Changa One":{"family":"Changa One","variants":["regular","italic"],"position":3508},"Chango":{"family":"Chango","variants":["regular"],"position":3538},"Chau Philomene One":{"family":"Chau Philomene One","variants":["regular","italic"],"position":3568},"Chela One":{"family":"Chela One","variants":["regular"],"position":3598},"Chelsea Market":{"family":"Chelsea Market","variants":["regular"],"position":3628},"Chenla":{"family":"Chenla","variants":["regular"],"position":3658},"Cherry Cream Soda":{"family":"Cherry Cream Soda","variants":["regular"],"position":3688},"Cherry Swash":{"family":"Cherry Swash","variants":["regular","700"],"position":3718},"Chewy":{"family":"Chewy","variants":["regular"],"position":3748},"Chicle":{"family":"Chicle","variants":["regular"],"position":3778},"Chivo":{"family":"Chivo","variants":["regular","italic","900","900italic"],"position":3808},"Cinzel":{"family":"Cinzel","variants":["regular","700","900"],"position":3838},"Cinzel Decorative":{"family":"Cinzel Decorative","variants":["regular","700","900"],"position":3868},"Clicker Script":{"family":"Clicker Script","variants":["regular"],"position":3898},"Coda":{"family":"Coda","variants":["regular","800"],"position":3928},"Coda Caption":{"family":"Coda Caption","variants":["800"],"position":3958},"Codystar":{"family":"Codystar","variants":["300","regular"],"position":3988},"Combo":{"family":"Combo","variants":["regular"],"position":4018},"Comfortaa":{"family":"Comfortaa","variants":["300","regular","700"],"position":4048},"Coming Soon":{"family":"Coming Soon","variants":["regular"],"position":4078},"Concert One":{"family":"Concert One","variants":["regular"],"position":4108},"Condiment":{"family":"Condiment","variants":["regular"],"position":4138},"Content":{"family":"Content","variants":["regular","700"],"position":4168},"Contrail One":{"family":"Contrail One","variants":["regular"],"position":4198},"Convergence":{"family":"Convergence","variants":["regular"],"position":4228},"Cookie":{"family":"Cookie","variants":["regular"],"position":4258},"Copse":{"family":"Copse","variants":["regular"],"position":4288},"Corben":{"family":"Corben","variants":["regular","700"],"position":4318},"Courgette":{"family":"Courgette","variants":["regular"],"position":4348},"Cousine":{"family":"Cousine","variants":["regular","italic","700","700italic"],"position":4378},"Coustard":{"family":"Coustard","variants":["regular","900"],"position":4408},"Covered By Your Grace":{"family":"Covered By Your Grace","variants":["regular"],"position":4438},"Crafty Girls":{"family":"Crafty Girls","variants":["regular"],"position":4468},"Creepster":{"family":"Creepster","variants":["regular"],"position":4498},"Crete Round":{"family":"Crete Round","variants":["regular","italic"],"position":4528},"Crimson Text":{"family":"Crimson Text","variants":["regular","italic","600","600italic","700","700italic"],"position":4558},"Croissant One":{"family":"Croissant One","variants":["regular"],"position":4588},"Crushed":{"family":"Crushed","variants":["regular"],"position":4618},"Cuprum":{"family":"Cuprum","variants":["regular","italic","700","700italic"],"position":4648},"Cutive":{"family":"Cutive","variants":["regular"],"position":4678},"Cutive Mono":{"family":"Cutive Mono","variants":["regular"],"position":4708},"Damion":{"family":"Damion","variants":["regular"],"position":4738},"Dancing Script":{"family":"Dancing Script","variants":["regular","700"],"position":4768},"Dangrek":{"family":"Dangrek","variants":["regular"],"position":4798},"Dawning of a New Day":{"family":"Dawning of a New Day","variants":["regular"],"position":4828},"Days One":{"family":"Days One","variants":["regular"],"position":4858},"Delius":{"family":"Delius","variants":["regular"],"position":4888},"Delius Swash Caps":{"family":"Delius Swash Caps","variants":["regular"],"position":4918},"Delius Unicase":{"family":"Delius Unicase","variants":["regular","700"],"position":4948},"Della Respira":{"family":"Della Respira","variants":["regular"],"position":4978},"Devonshire":{"family":"Devonshire","variants":["regular"],"position":5008},"Didact Gothic":{"family":"Didact Gothic","variants":["regular"],"position":5038},"Diplomata":{"family":"Diplomata","variants":["regular"],"position":5068},"Diplomata SC":{"family":"Diplomata SC","variants":["regular"],"position":5098},"Doppio One":{"family":"Doppio One","variants":["regular"],"position":5128},"Dorsa":{"family":"Dorsa","variants":["regular"],"position":5158},"Dosis":{"family":"Dosis","variants":["200","300","regular","500","600","700","800"],"position":5188},"Dr Sugiyama":{"family":"Dr Sugiyama","variants":["regular"],"position":5218},"Droid Sans":{"family":"Droid Sans","variants":["regular","700"],"position":5248},"Droid Sans Mono":{"family":"Droid Sans Mono","variants":["regular"],"position":5278},"Droid Serif":{"family":"Droid Serif","variants":["regular","italic","700","700italic"],"position":5308},"Duru Sans":{"family":"Duru Sans","variants":["regular"],"position":5338},"Dynalight":{"family":"Dynalight","variants":["regular"],"position":5368},"EB Garamond":{"family":"EB Garamond","variants":["regular"],"position":5398},"Eagle Lake":{"family":"Eagle Lake","variants":["regular"],"position":5428},"Eater":{"family":"Eater","variants":["regular"],"position":5458},"Economica":{"family":"Economica","variants":["regular","italic","700","700italic"],"position":5488},"Electrolize":{"family":"Electrolize","variants":["regular"],"position":5518},"Emblema One":{"family":"Emblema One","variants":["regular"],"position":5548},"Emilys Candy":{"family":"Emilys Candy","variants":["regular"],"position":5578},"Engagement":{"family":"Engagement","variants":["regular"],"position":5608},"Englebert":{"family":"Englebert","variants":["regular"],"position":5638},"Enriqueta":{"family":"Enriqueta","variants":["regular","700"],"position":5668},"Erica One":{"family":"Erica One","variants":["regular"],"position":5698},"Esteban":{"family":"Esteban","variants":["regular"],"position":5728},"Euphoria Script":{"family":"Euphoria Script","variants":["regular"],"position":5758},"Ewert":{"family":"Ewert","variants":["regular"],"position":5788},"Exo":{"family":"Exo","variants":["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],"position":5818},"Expletus Sans":{"family":"Expletus Sans","variants":["regular","italic","500","500italic","600","600italic","700","700italic"],"position":5848},"Fanwood Text":{"family":"Fanwood Text","variants":["regular","italic"],"position":5878},"Fascinate":{"family":"Fascinate","variants":["regular"],"position":5908},"Fascinate Inline":{"family":"Fascinate Inline","variants":["regular"],"position":5938},"Faster One":{"family":"Faster One","variants":["regular"],"position":5968},"Fasthand":{"family":"Fasthand","variants":["regular"],"position":5998},"Federant":{"family":"Federant","variants":["regular"],"position":6028},"Federo":{"family":"Federo","variants":["regular"],"position":6058},"Felipa":{"family":"Felipa","variants":["regular"],"position":6088},"Fenix":{"family":"Fenix","variants":["regular"],"position":6118},"Finger Paint":{"family":"Finger Paint","variants":["regular"],"position":6148},"Fjord One":{"family":"Fjord One","variants":["regular"],"position":6178},"Flamenco":{"family":"Flamenco","variants":["300","regular"],"position":6208},"Flavors":{"family":"Flavors","variants":["regular"],"position":6238},"Fondamento":{"family":"Fondamento","variants":["regular","italic"],"position":6268},"Fontdiner Swanky":{"family":"Fontdiner Swanky","variants":["regular"],"position":6298},"Forum":{"family":"Forum","variants":["regular"],"position":6328},"Francois One":{"family":"Francois One","variants":["regular"],"position":6358},"Freckle Face":{"family":"Freckle Face","variants":["regular"],"position":6388},"Fredericka the Great":{"family":"Fredericka the Great","variants":["regular"],"position":6418},"Fredoka One":{"family":"Fredoka One","variants":["regular"],"position":6448},"Freehand":{"family":"Freehand","variants":["regular"],"position":6478},"Fresca":{"family":"Fresca","variants":["regular"],"position":6508},"Frijole":{"family":"Frijole","variants":["regular"],"position":6538},"Fugaz One":{"family":"Fugaz One","variants":["regular"],"position":6568},"GFS Didot":{"family":"GFS Didot","variants":["regular"],"position":6598},"GFS Neohellenic":{"family":"GFS Neohellenic","variants":["regular","italic","700","700italic"],"position":6628},"Gafata":{"family":"Gafata","variants":["regular"],"position":6658},"Galdeano":{"family":"Galdeano","variants":["regular"],"position":6688},"Galindo":{"family":"Galindo","variants":["regular"],"position":6718},"Gentium Basic":{"family":"Gentium Basic","variants":["regular","italic","700","700italic"],"position":6748},"Gentium Book Basic":{"family":"Gentium Book Basic","variants":["regular","italic","700","700italic"],"position":6778},"Geo":{"family":"Geo","variants":["regular","italic"],"position":6808},"Geostar":{"family":"Geostar","variants":["regular"],"position":6838},"Geostar Fill":{"family":"Geostar Fill","variants":["regular"],"position":6868},"Germania One":{"family":"Germania One","variants":["regular"],"position":6898},"Gilda Display":{"family":"Gilda Display","variants":["regular"],"position":6928},"Give You Glory":{"family":"Give You Glory","variants":["regular"],"position":6958},"Glass Antiqua":{"family":"Glass Antiqua","variants":["regular"],"position":6988},"Glegoo":{"family":"Glegoo","variants":["regular"],"position":7018},"Gloria Hallelujah":{"family":"Gloria Hallelujah","variants":["regular"],"position":7048},"Goblin One":{"family":"Goblin One","variants":["regular"],"position":7078},"Gochi Hand":{"family":"Gochi Hand","variants":["regular"],"position":7108},"Gorditas":{"family":"Gorditas","variants":["regular","700"],"position":7138},"Goudy Bookletter 1911":{"family":"Goudy Bookletter 1911","variants":["regular"],"position":7168},"Graduate":{"family":"Graduate","variants":["regular"],"position":7198},"Gravitas One":{"family":"Gravitas One","variants":["regular"],"position":7228},"Great Vibes":{"family":"Great Vibes","variants":["regular"],"position":7258},"Griffy":{"family":"Griffy","variants":["regular"],"position":7288},"Gruppo":{"family":"Gruppo","variants":["regular"],"position":7318},"Gudea":{"family":"Gudea","variants":["regular","italic","700"],"position":7348},"Habibi":{"family":"Habibi","variants":["regular"],"position":7378},"Hammersmith One":{"family":"Hammersmith One","variants":["regular"],"position":7408},"Hanalei":{"family":"Hanalei","variants":["regular"],"position":7438},"Hanalei Fill":{"family":"Hanalei Fill","variants":["regular"],"position":7468},"Handlee":{"family":"Handlee","variants":["regular"],"position":7498},"Hanuman":{"family":"Hanuman","variants":["regular","700"],"position":7528},"Happy Monkey":{"family":"Happy Monkey","variants":["regular"],"position":7558},"Headland One":{"family":"Headland One","variants":["regular"],"position":7588},"Henny Penny":{"family":"Henny Penny","variants":["regular"],"position":7618},"Herr Von Muellerhoff":{"family":"Herr Von Muellerhoff","variants":["regular"],"position":7648},"Holtwood One SC":{"family":"Holtwood One SC","variants":["regular"],"position":7678},"Homemade Apple":{"family":"Homemade Apple","variants":["regular"],"position":7708},"Homenaje":{"family":"Homenaje","variants":["regular"],"position":7738},"IM Fell DW Pica":{"family":"IM Fell DW Pica","variants":["regular","italic"],"position":7768},"IM Fell DW Pica SC":{"family":"IM Fell DW Pica SC","variants":["regular"],"position":7798},"IM Fell Double Pica":{"family":"IM Fell Double Pica","variants":["regular","italic"],"position":7828},"IM Fell Double Pica SC":{"family":"IM Fell Double Pica SC","variants":["regular"],"position":7858},"IM Fell English":{"family":"IM Fell English","variants":["regular","italic"],"position":7888},"IM Fell English SC":{"family":"IM Fell English SC","variants":["regular"],"position":7918},"IM Fell French Canon":{"family":"IM Fell French Canon","variants":["regular","italic"],"position":7948},"IM Fell French Canon SC":{"family":"IM Fell French Canon SC","variants":["regular"],"position":7978},"IM Fell Great Primer":{"family":"IM Fell Great Primer","variants":["regular","italic"],"position":8008},"IM Fell Great Primer SC":{"family":"IM Fell Great Primer SC","variants":["regular"],"position":8038},"Iceberg":{"family":"Iceberg","variants":["regular"],"position":8068},"Iceland":{"family":"Iceland","variants":["regular"],"position":8098},"Imprima":{"family":"Imprima","variants":["regular"],"position":8128},"Inconsolata":{"family":"Inconsolata","variants":["regular","700"],"position":8158},"Inder":{"family":"Inder","variants":["regular"],"position":8188},"Indie Flower":{"family":"Indie Flower","variants":["regular"],"position":8218},"Inika":{"family":"Inika","variants":["regular","700"],"position":8248},"Irish Grover":{"family":"Irish Grover","variants":["regular"],"position":8278},"Istok Web":{"family":"Istok Web","variants":["regular","italic","700","700italic"],"position":8308},"Italiana":{"family":"Italiana","variants":["regular"],"position":8338},"Italianno":{"family":"Italianno","variants":["regular"],"position":8368},"Jacques Francois":{"family":"Jacques Francois","variants":["regular"],"position":8398},"Jacques Francois Shadow":{"family":"Jacques Francois Shadow","variants":["regular"],"position":8428},"Jim Nightshade":{"family":"Jim Nightshade","variants":["regular"],"position":8458},"Jockey One":{"family":"Jockey One","variants":["regular"],"position":8488},"Jolly Lodger":{"family":"Jolly Lodger","variants":["regular"],"position":8518},"Josefin Sans":{"family":"Josefin Sans","variants":["100","100italic","300","300italic","regular","italic","600","600italic","700","700italic"],"position":8548},"Josefin Slab":{"family":"Josefin Slab","variants":["100","100italic","300","300italic","regular","italic","600","600italic","700","700italic"],"position":8578},"Joti One":{"family":"Joti One","variants":["regular"],"position":8608},"Judson":{"family":"Judson","variants":["regular","italic","700"],"position":8638},"Julee":{"family":"Julee","variants":["regular"],"position":8668},"Julius Sans One":{"family":"Julius Sans One","variants":["regular"],"position":8698},"Junge":{"family":"Junge","variants":["regular"],"position":8728},"Jura":{"family":"Jura","variants":["300","regular","500","600"],"position":8758},"Just Another Hand":{"family":"Just Another Hand","variants":["regular"],"position":8788},"Just Me Again Down Here":{"family":"Just Me Again Down Here","variants":["regular"],"position":8818},"Kameron":{"family":"Kameron","variants":["regular","700"],"position":8848},"Karla":{"family":"Karla","variants":["regular","italic","700","700italic"],"position":8878},"Kaushan Script":{"family":"Kaushan Script","variants":["regular"],"position":8908},"Keania One":{"family":"Keania One","variants":["regular"],"position":8938},"Kelly Slab":{"family":"Kelly Slab","variants":["regular"],"position":8968},"Kenia":{"family":"Kenia","variants":["regular"],"position":8998},"Khmer":{"family":"Khmer","variants":["regular"],"position":9028},"Kite One":{"family":"Kite One","variants":["regular"],"position":9058},"Knewave":{"family":"Knewave","variants":["regular"],"position":9088},"Kotta One":{"family":"Kotta One","variants":["regular"],"position":9118},"Koulen":{"family":"Koulen","variants":["regular"],"position":9148},"Kranky":{"family":"Kranky","variants":["regular"],"position":9178},"Kreon":{"family":"Kreon","variants":["300","regular","700"],"position":9208},"Kristi":{"family":"Kristi","variants":["regular"],"position":9238},"Krona One":{"family":"Krona One","variants":["regular"],"position":9268},"La Belle Aurore":{"family":"La Belle Aurore","variants":["regular"],"position":9298},"Lancelot":{"family":"Lancelot","variants":["regular"],"position":9328},"Lato":{"family":"Lato","variants":["100","100italic","300","300italic","regular","italic","700","700italic","900","900italic"],"position":9358},"League Script":{"family":"League Script","variants":["regular"],"position":9388},"Leckerli One":{"family":"Leckerli One","variants":["regular"],"position":9418},"Ledger":{"family":"Ledger","variants":["regular"],"position":9448},"Lekton":{"family":"Lekton","variants":["regular","italic","700"],"position":9478},"Lemon":{"family":"Lemon","variants":["regular"],"position":9508},"Life Savers":{"family":"Life Savers","variants":["regular","700"],"position":9538},"Lilita One":{"family":"Lilita One","variants":["regular"],"position":9568},"Limelight":{"family":"Limelight","variants":["regular"],"position":9598},"Linden Hill":{"family":"Linden Hill","variants":["regular","italic"],"position":9628},"Lobster":{"family":"Lobster","variants":["regular"],"position":9658},"Lobster Two":{"family":"Lobster Two","variants":["regular","italic","700","700italic"],"position":9688},"Londrina Outline":{"family":"Londrina Outline","variants":["regular"],"position":9718},"Londrina Shadow":{"family":"Londrina Shadow","variants":["regular"],"position":9748},"Londrina Sketch":{"family":"Londrina Sketch","variants":["regular"],"position":9778},"Londrina Solid":{"family":"Londrina Solid","variants":["regular"],"position":9808},"Lora":{"family":"Lora","variants":["regular","italic","700","700italic"],"position":9838},"Love Ya Like A Sister":{"family":"Love Ya Like A Sister","variants":["regular"],"position":9868},"Loved by the King":{"family":"Loved by the King","variants":["regular"],"position":9898},"Lovers Quarrel":{"family":"Lovers Quarrel","variants":["regular"],"position":9928},"Luckiest Guy":{"family":"Luckiest Guy","variants":["regular"],"position":9958},"Lusitana":{"family":"Lusitana","variants":["regular","700"],"position":9988},"Lustria":{"family":"Lustria","variants":["regular"],"position":10018},"Macondo":{"family":"Macondo","variants":["regular"],"position":10048},"Macondo Swash Caps":{"family":"Macondo Swash Caps","variants":["regular"],"position":10078},"Magra":{"family":"Magra","variants":["regular","700"],"position":10108},"Maiden Orange":{"family":"Maiden Orange","variants":["regular"],"position":10138},"Mako":{"family":"Mako","variants":["regular"],"position":10168},"Marcellus":{"family":"Marcellus","variants":["regular"],"position":10198},"Marcellus SC":{"family":"Marcellus SC","variants":["regular"],"position":10228},"Marck Script":{"family":"Marck Script","variants":["regular"],"position":10258},"Margarine":{"family":"Margarine","variants":["regular"],"position":10288},"Marko One":{"family":"Marko One","variants":["regular"],"position":10318},"Marmelad":{"family":"Marmelad","variants":["regular"],"position":10348},"Marvel":{"family":"Marvel","variants":["regular","italic","700","700italic"],"position":10378},"Mate":{"family":"Mate","variants":["regular","italic"],"position":10408},"Mate SC":{"family":"Mate SC","variants":["regular"],"position":10438},"Maven Pro":{"family":"Maven Pro","variants":["regular","500","700","900"],"position":10468},"McLaren":{"family":"McLaren","variants":["regular"],"position":10498},"Meddon":{"family":"Meddon","variants":["regular"],"position":10528},"MedievalSharp":{"family":"MedievalSharp","variants":["regular"],"position":10558},"Medula One":{"family":"Medula One","variants":["regular"],"position":10588},"Megrim":{"family":"Megrim","variants":["regular"],"position":10618},"Meie Script":{"family":"Meie Script","variants":["regular"],"position":10648},"Merienda":{"family":"Merienda","variants":["regular","700"],"position":10678},"Merienda One":{"family":"Merienda One","variants":["regular"],"position":10708},"Merriweather":{"family":"Merriweather","variants":["300","300italic","regular","italic","700","700italic","900","900italic"],"position":10738},"Metal":{"family":"Metal","variants":["regular"],"position":10768},"Metal Mania":{"family":"Metal Mania","variants":["regular"],"position":10798},"Metamorphous":{"family":"Metamorphous","variants":["regular"],"position":10828},"Metrophobic":{"family":"Metrophobic","variants":["regular"],"position":10858},"Michroma":{"family":"Michroma","variants":["regular"],"position":10888},"Miltonian":{"family":"Miltonian","variants":["regular"],"position":10918},"Miltonian Tattoo":{"family":"Miltonian Tattoo","variants":["regular"],"position":10948},"Miniver":{"family":"Miniver","variants":["regular"],"position":10978},"Miss Fajardose":{"family":"Miss Fajardose","variants":["regular"],"position":11008},"Modern Antiqua":{"family":"Modern Antiqua","variants":["regular"],"position":11038},"Molengo":{"family":"Molengo","variants":["regular"],"position":11068},"Molle":{"family":"Molle","variants":["italic"],"position":11098},"Monofett":{"family":"Monofett","variants":["regular"],"position":11128},"Monoton":{"family":"Monoton","variants":["regular"],"position":11158},"Monsieur La Doulaise":{"family":"Monsieur La Doulaise","variants":["regular"],"position":11188},"Montaga":{"family":"Montaga","variants":["regular"],"position":11218},"Montez":{"family":"Montez","variants":["regular"],"position":11248},"Montserrat":{"family":"Montserrat","variants":["regular","700"],"position":11278},"Montserrat Alternates":{"family":"Montserrat Alternates","variants":["regular","700"],"position":11308},"Montserrat Subrayada":{"family":"Montserrat Subrayada","variants":["regular","700"],"position":11338},"Moul":{"family":"Moul","variants":["regular"],"position":11368},"Moulpali":{"family":"Moulpali","variants":["regular"],"position":11398},"Mountains of Christmas":{"family":"Mountains of Christmas","variants":["regular","700"],"position":11428},"Mouse Memoirs":{"family":"Mouse Memoirs","variants":["regular"],"position":11458},"Mr Bedfort":{"family":"Mr Bedfort","variants":["regular"],"position":11488},"Mr Dafoe":{"family":"Mr Dafoe","variants":["regular"],"position":11518},"Mr De Haviland":{"family":"Mr De Haviland","variants":["regular"],"position":11548},"Mrs Saint Delafield":{"family":"Mrs Saint Delafield","variants":["regular"],"position":11578},"Mrs Sheppards":{"family":"Mrs Sheppards","variants":["regular"],"position":11608},"Muli":{"family":"Muli","variants":["300","300italic","regular","italic"],"position":11638},"Mystery Quest":{"family":"Mystery Quest","variants":["regular"],"position":11668},"Neucha":{"family":"Neucha","variants":["regular"],"position":11698},"Neuton":{"family":"Neuton","variants":["200","300","regular","italic","700","800"],"position":11728},"News Cycle":{"family":"News Cycle","variants":["regular","700"],"position":11758},"Niconne":{"family":"Niconne","variants":["regular"],"position":11788},"Nixie One":{"family":"Nixie One","variants":["regular"],"position":11818},"Nobile":{"family":"Nobile","variants":["regular","italic","700","700italic"],"position":11848},"Nokora":{"family":"Nokora","variants":["regular","700"],"position":11878},"Norican":{"family":"Norican","variants":["regular"],"position":11908},"Nosifer":{"family":"Nosifer","variants":["regular"],"position":11938},"Nothing You Could Do":{"family":"Nothing You Could Do","variants":["regular"],"position":11968},"Noticia Text":{"family":"Noticia Text","variants":["regular","italic","700","700italic"],"position":11998},"Nova Cut":{"family":"Nova Cut","variants":["regular"],"position":12028},"Nova Flat":{"family":"Nova Flat","variants":["regular"],"position":12058},"Nova Mono":{"family":"Nova Mono","variants":["regular"],"position":12088},"Nova Oval":{"family":"Nova Oval","variants":["regular"],"position":12118},"Nova Round":{"family":"Nova Round","variants":["regular"],"position":12148},"Nova Script":{"family":"Nova Script","variants":["regular"],"position":12178},"Nova Slim":{"family":"Nova Slim","variants":["regular"],"position":12208},"Nova Square":{"family":"Nova Square","variants":["regular"],"position":12238},"Numans":{"family":"Numans","variants":["regular"],"position":12268},"Nunito":{"family":"Nunito","variants":["300","regular","700"],"position":12298},"Odor Mean Chey":{"family":"Odor Mean Chey","variants":["regular"],"position":12328},"Offside":{"family":"Offside","variants":["regular"],"position":12358},"Old Standard TT":{"family":"Old Standard TT","variants":["regular","italic","700"],"position":12388},"Oldenburg":{"family":"Oldenburg","variants":["regular"],"position":12418},"Oleo Script":{"family":"Oleo Script","variants":["regular","700"],"position":12448},"Oleo Script Swash Caps":{"family":"Oleo Script Swash Caps","variants":["regular","700"],"position":12478},"Open Sans":{"family":"Open Sans","variants":["300","300italic","regular","italic","600","600italic","700","700italic","800","800italic"],"position":12508},"Open Sans Condensed":{"family":"Open Sans Condensed","variants":["300","300italic","700"],"position":12538},"Oranienbaum":{"family":"Oranienbaum","variants":["regular"],"position":12568},"Orbitron":{"family":"Orbitron","variants":["regular","500","700","900"],"position":12598},"Oregano":{"family":"Oregano","variants":["regular","italic"],"position":12628},"Orienta":{"family":"Orienta","variants":["regular"],"position":12658},"Original Surfer":{"family":"Original Surfer","variants":["regular"],"position":12688},"Oswald":{"family":"Oswald","variants":["300","regular","700"],"position":12718},"Over the Rainbow":{"family":"Over the Rainbow","variants":["regular"],"position":12748},"Overlock":{"family":"Overlock","variants":["regular","italic","700","700italic","900","900italic"],"position":12778},"Overlock SC":{"family":"Overlock SC","variants":["regular"],"position":12808},"Ovo":{"family":"Ovo","variants":["regular"],"position":12838},"Oxygen":{"family":"Oxygen","variants":["300","regular","700"],"position":12868},"Oxygen Mono":{"family":"Oxygen Mono","variants":["regular"],"position":12898},"PT Mono":{"family":"PT Mono","variants":["regular"],"position":12928},"PT Sans":{"family":"PT Sans","variants":["regular","italic","700","700italic"],"position":12958},"PT Sans Caption":{"family":"PT Sans Caption","variants":["regular","700"],"position":12988},"PT Sans Narrow":{"family":"PT Sans Narrow","variants":["regular","700"],"position":13018},"PT Serif":{"family":"PT Serif","variants":["regular","italic","700","700italic"],"position":13048},"PT Serif Caption":{"family":"PT Serif Caption","variants":["regular","italic"],"position":13078},"Pacifico":{"family":"Pacifico","variants":["regular"],"position":13108},"Paprika":{"family":"Paprika","variants":["regular"],"position":13138},"Parisienne":{"family":"Parisienne","variants":["regular"],"position":13168},"Passero One":{"family":"Passero One","variants":["regular"],"position":13198},"Passion One":{"family":"Passion One","variants":["regular","700","900"],"position":13228},"Patrick Hand":{"family":"Patrick Hand","variants":["regular"],"position":13258},"Patua One":{"family":"Patua One","variants":["regular"],"position":13288},"Paytone One":{"family":"Paytone One","variants":["regular"],"position":13318},"Peralta":{"family":"Peralta","variants":["regular"],"position":13348},"Permanent Marker":{"family":"Permanent Marker","variants":["regular"],"position":13378},"Petit Formal Script":{"family":"Petit Formal Script","variants":["regular"],"position":13408},"Petrona":{"family":"Petrona","variants":["regular"],"position":13438},"Philosopher":{"family":"Philosopher","variants":["regular","italic","700","700italic"],"position":13468},"Piedra":{"family":"Piedra","variants":["regular"],"position":13498},"Pinyon Script":{"family":"Pinyon Script","variants":["regular"],"position":13528},"Pirata One":{"family":"Pirata One","variants":["regular"],"position":13558},"Plaster":{"family":"Plaster","variants":["regular"],"position":13588},"Play":{"family":"Play","variants":["regular","700"],"position":13618},"Playball":{"family":"Playball","variants":["regular"],"position":13648},"Playfair Display":{"family":"Playfair Display","variants":["regular","italic","700","700italic","900","900italic"],"position":13678},"Playfair Display SC":{"family":"Playfair Display SC","variants":["regular","italic","700","700italic","900","900italic"],"position":13708},"Podkova":{"family":"Podkova","variants":["regular","700"],"position":13738},"Poiret One":{"family":"Poiret One","variants":["regular"],"position":13768},"Poller One":{"family":"Poller One","variants":["regular"],"position":13798},"Poly":{"family":"Poly","variants":["regular","italic"],"position":13828},"Pompiere":{"family":"Pompiere","variants":["regular"],"position":13858},"Pontano Sans":{"family":"Pontano Sans","variants":["regular"],"position":13888},"Port Lligat Sans":{"family":"Port Lligat Sans","variants":["regular"],"position":13918},"Port Lligat Slab":{"family":"Port Lligat Slab","variants":["regular"],"position":13948},"Prata":{"family":"Prata","variants":["regular"],"position":13978},"Preahvihear":{"family":"Preahvihear","variants":["regular"],"position":14008},"Press Start 2P":{"family":"Press Start 2P","variants":["regular"],"position":14038},"Princess Sofia":{"family":"Princess Sofia","variants":["regular"],"position":14068},"Prociono":{"family":"Prociono","variants":["regular"],"position":14098},"Prosto One":{"family":"Prosto One","variants":["regular"],"position":14128},"Puritan":{"family":"Puritan","variants":["regular","italic","700","700italic"],"position":14158},"Purple Purse":{"family":"Purple Purse","variants":["regular"],"position":14188},"Quando":{"family":"Quando","variants":["regular"],"position":14218},"Quantico":{"family":"Quantico","variants":["regular","italic","700","700italic"],"position":14248},"Quattrocento":{"family":"Quattrocento","variants":["regular","700"],"position":14278},"Quattrocento Sans":{"family":"Quattrocento Sans","variants":["regular","italic","700","700italic"],"position":14308},"Questrial":{"family":"Questrial","variants":["regular"],"position":14338},"Quicksand":{"family":"Quicksand","variants":["300","regular","700"],"position":14368},"Quintessential":{"family":"Quintessential","variants":["regular"],"position":14398},"Qwigley":{"family":"Qwigley","variants":["regular"],"position":14428},"Racing Sans One":{"family":"Racing Sans One","variants":["regular"],"position":14458},"Radley":{"family":"Radley","variants":["regular","italic"],"position":14488},"Raleway":{"family":"Raleway","variants":["100","200","300","regular","500","600","700","800","900"],"position":14518},"Raleway Dots":{"family":"Raleway Dots","variants":["regular"],"position":14548},"Rambla":{"family":"Rambla","variants":["regular","italic","700","700italic"],"position":14578},"Rammetto One":{"family":"Rammetto One","variants":["regular"],"position":14608},"Ranchers":{"family":"Ranchers","variants":["regular"],"position":14638},"Rancho":{"family":"Rancho","variants":["regular"],"position":14668},"Rationale":{"family":"Rationale","variants":["regular"],"position":14698},"Redressed":{"family":"Redressed","variants":["regular"],"position":14728},"Reenie Beanie":{"family":"Reenie Beanie","variants":["regular"],"position":14758},"Revalia":{"family":"Revalia","variants":["regular"],"position":14788},"Ribeye":{"family":"Ribeye","variants":["regular"],"position":14818},"Ribeye Marrow":{"family":"Ribeye Marrow","variants":["regular"],"position":14848},"Righteous":{"family":"Righteous","variants":["regular"],"position":14878},"Risque":{"family":"Risque","variants":["regular"],"position":14908},"Rochester":{"family":"Rochester","variants":["regular"],"position":14938},"Rock Salt":{"family":"Rock Salt","variants":["regular"],"position":14968},"Rokkitt":{"family":"Rokkitt","variants":["regular","700"],"position":14998},"Romanesco":{"family":"Romanesco","variants":["regular"],"position":15028},"Ropa Sans":{"family":"Ropa Sans","variants":["regular","italic"],"position":15058},"Rosario":{"family":"Rosario","variants":["regular","italic","700","700italic"],"position":15088},"Rosarivo":{"family":"Rosarivo","variants":["regular","italic"],"position":15118},"Rouge Script":{"family":"Rouge Script","variants":["regular"],"position":15148},"Ruda":{"family":"Ruda","variants":["regular","700","900"],"position":15178},"Rufina":{"family":"Rufina","variants":["regular","700"],"position":15208},"Ruge Boogie":{"family":"Ruge Boogie","variants":["regular"],"position":15238},"Ruluko":{"family":"Ruluko","variants":["regular"],"position":15268},"Rum Raisin":{"family":"Rum Raisin","variants":["regular"],"position":15298},"Ruslan Display":{"family":"Ruslan Display","variants":["regular"],"position":15328},"Russo One":{"family":"Russo One","variants":["regular"],"position":15358},"Ruthie":{"family":"Ruthie","variants":["regular"],"position":15388},"Rye":{"family":"Rye","variants":["regular"],"position":15418},"Sacramento":{"family":"Sacramento","variants":["regular"],"position":15448},"Sail":{"family":"Sail","variants":["regular"],"position":15478},"Salsa":{"family":"Salsa","variants":["regular"],"position":15508},"Sanchez":{"family":"Sanchez","variants":["regular","italic"],"position":15538},"Sancreek":{"family":"Sancreek","variants":["regular"],"position":15568},"Sansita One":{"family":"Sansita One","variants":["regular"],"position":15598},"Sarina":{"family":"Sarina","variants":["regular"],"position":15628},"Satisfy":{"family":"Satisfy","variants":["regular"],"position":15658},"Scada":{"family":"Scada","variants":["regular","italic","700","700italic"],"position":15688},"Schoolbell":{"family":"Schoolbell","variants":["regular"],"position":15718},"Seaweed Script":{"family":"Seaweed Script","variants":["regular"],"position":15748},"Sevillana":{"family":"Sevillana","variants":["regular"],"position":15778},"Seymour One":{"family":"Seymour One","variants":["regular"],"position":15808},"Shadows Into Light":{"family":"Shadows Into Light","variants":["regular"],"position":15838},"Shadows Into Light Two":{"family":"Shadows Into Light Two","variants":["regular"],"position":15868},"Shanti":{"family":"Shanti","variants":["regular"],"position":15898},"Share":{"family":"Share","variants":["regular","italic","700","700italic"],"position":15928},"Share Tech":{"family":"Share Tech","variants":["regular"],"position":15958},"Share Tech Mono":{"family":"Share Tech Mono","variants":["regular"],"position":15988},"Shojumaru":{"family":"Shojumaru","variants":["regular"],"position":16018},"Short Stack":{"family":"Short Stack","variants":["regular"],"position":16048},"Siemreap":{"family":"Siemreap","variants":["regular"],"position":16078},"Sigmar One":{"family":"Sigmar One","variants":["regular"],"position":16108},"Signika":{"family":"Signika","variants":["300","regular","600","700"],"position":16138},"Signika Negative":{"family":"Signika Negative","variants":["300","regular","600","700"],"position":16168},"Simonetta":{"family":"Simonetta","variants":["regular","italic","900","900italic"],"position":16198},"Sirin Stencil":{"family":"Sirin Stencil","variants":["regular"],"position":16228},"Six Caps":{"family":"Six Caps","variants":["regular"],"position":16258},"Skranji":{"family":"Skranji","variants":["regular","700"],"position":16288},"Slackey":{"family":"Slackey","variants":["regular"],"position":16318},"Smokum":{"family":"Smokum","variants":["regular"],"position":16348},"Smythe":{"family":"Smythe","variants":["regular"],"position":16378},"Sniglet":{"family":"Sniglet","variants":["regular","800"],"position":16408},"Snippet":{"family":"Snippet","variants":["regular"],"position":16438},"Snowburst One":{"family":"Snowburst One","variants":["regular"],"position":16468},"Sofadi One":{"family":"Sofadi One","variants":["regular"],"position":16498},"Sofia":{"family":"Sofia","variants":["regular"],"position":16528},"Sonsie One":{"family":"Sonsie One","variants":["regular"],"position":16558},"Sorts Mill Goudy":{"family":"Sorts Mill Goudy","variants":["regular","italic"],"position":16588},"Source Code Pro":{"family":"Source Code Pro","variants":["200","300","regular","500","600","700","900"],"position":16618},"Source Sans Pro":{"family":"Source Sans Pro","variants":["200","200italic","300","300italic","regular","italic","600","600italic","700","700italic","900","900italic"],"position":16648},"Special Elite":{"family":"Special Elite","variants":["regular"],"position":16678},"Spicy Rice":{"family":"Spicy Rice","variants":["regular"],"position":16708},"Spinnaker":{"family":"Spinnaker","variants":["regular"],"position":16738},"Spirax":{"family":"Spirax","variants":["regular"],"position":16768},"Squada One":{"family":"Squada One","variants":["regular"],"position":16798},"Stalemate":{"family":"Stalemate","variants":["regular"],"position":16828},"Stalinist One":{"family":"Stalinist One","variants":["regular"],"position":16858},"Stardos Stencil":{"family":"Stardos Stencil","variants":["regular","700"],"position":16888},"Stint Ultra Condensed":{"family":"Stint Ultra Condensed","variants":["regular"],"position":16918},"Stint Ultra Expanded":{"family":"Stint Ultra Expanded","variants":["regular"],"position":16948},"Stoke":{"family":"Stoke","variants":["300","regular"],"position":16978},"Strait":{"family":"Strait","variants":["regular"],"position":17008},"Sue Ellen Francisco":{"family":"Sue Ellen Francisco","variants":["regular"],"position":17038},"Sunshiney":{"family":"Sunshiney","variants":["regular"],"position":17068},"Supermercado One":{"family":"Supermercado One","variants":["regular"],"position":17098},"Suwannaphum":{"family":"Suwannaphum","variants":["regular"],"position":17128},"Swanky and Moo Moo":{"family":"Swanky and Moo Moo","variants":["regular"],"position":17158},"Syncopate":{"family":"Syncopate","variants":["regular","700"],"position":17188},"Tangerine":{"family":"Tangerine","variants":["regular","700"],"position":17218},"Taprom":{"family":"Taprom","variants":["regular"],"position":17248},"Telex":{"family":"Telex","variants":["regular"],"position":17278},"Tenor Sans":{"family":"Tenor Sans","variants":["regular"],"position":17308},"Text Me One":{"family":"Text Me One","variants":["regular"],"position":17338},"The Girl Next Door":{"family":"The Girl Next Door","variants":["regular"],"position":17368},"Tienne":{"family":"Tienne","variants":["regular","700","900"],"position":17398},"Tinos":{"family":"Tinos","variants":["regular","italic","700","700italic"],"position":17428},"Titan One":{"family":"Titan One","variants":["regular"],"position":17458},"Titillium Web":{"family":"Titillium Web","variants":["200","200italic","300","300italic","regular","italic","600","600italic","700","700italic","900"],"position":17488},"Trade Winds":{"family":"Trade Winds","variants":["regular"],"position":17518},"Trocchi":{"family":"Trocchi","variants":["regular"],"position":17548},"Trochut":{"family":"Trochut","variants":["regular","italic","700"],"position":17578},"Trykker":{"family":"Trykker","variants":["regular"],"position":17608},"Tulpen One":{"family":"Tulpen One","variants":["regular"],"position":17638},"Ubuntu":{"family":"Ubuntu","variants":["300","300italic","regular","italic","500","500italic","700","700italic"],"position":17668},"Ubuntu Condensed":{"family":"Ubuntu Condensed","variants":["regular"],"position":17698},"Ubuntu Mono":{"family":"Ubuntu Mono","variants":["regular","italic","700","700italic"],"position":17728},"Ultra":{"family":"Ultra","variants":["regular"],"position":17758},"Uncial Antiqua":{"family":"Uncial Antiqua","variants":["regular"],"position":17788},"Underdog":{"family":"Underdog","variants":["regular"],"position":17818},"Unica One":{"family":"Unica One","variants":["regular"],"position":17848},"UnifrakturCook":{"family":"UnifrakturCook","variants":["700"],"position":17878},"UnifrakturMaguntia":{"family":"UnifrakturMaguntia","variants":["regular"],"position":17908},"Unkempt":{"family":"Unkempt","variants":["regular","700"],"position":17938},"Unlock":{"family":"Unlock","variants":["regular"],"position":17968},"Unna":{"family":"Unna","variants":["regular"],"position":17998},"VT323":{"family":"VT323","variants":["regular"],"position":18028},"Vampiro One":{"family":"Vampiro One","variants":["regular"],"position":18058},"Varela":{"family":"Varela","variants":["regular"],"position":18088},"Varela Round":{"family":"Varela Round","variants":["regular"],"position":18118},"Vast Shadow":{"family":"Vast Shadow","variants":["regular"],"position":18148},"Vibur":{"family":"Vibur","variants":["regular"],"position":18178},"Vidaloka":{"family":"Vidaloka","variants":["regular"],"position":18208},"Viga":{"family":"Viga","variants":["regular"],"position":18238},"Voces":{"family":"Voces","variants":["regular"],"position":18268},"Volkhov":{"family":"Volkhov","variants":["regular","italic","700","700italic"],"position":18298},"Vollkorn":{"family":"Vollkorn","variants":["regular","italic","700","700italic"],"position":18328},"Voltaire":{"family":"Voltaire","variants":["regular"],"position":18358},"Waiting for the Sunrise":{"family":"Waiting for the Sunrise","variants":["regular"],"position":18388},"Wallpoet":{"family":"Wallpoet","variants":["regular"],"position":18418},"Walter Turncoat":{"family":"Walter Turncoat","variants":["regular"],"position":18448},"Warnes":{"family":"Warnes","variants":["regular"],"position":18478},"Wellfleet":{"family":"Wellfleet","variants":["regular"],"position":18508},"Wire One":{"family":"Wire One","variants":["regular"],"position":18538},"Yanone Kaffeesatz":{"family":"Yanone Kaffeesatz","variants":["200","300","regular","700"],"position":18568},"Yellowtail":{"family":"Yellowtail","variants":["regular"],"position":18598},"Yeseva One":{"family":"Yeseva One","variants":["regular"],"position":18628},"Yesteryear":{"family":"Yesteryear","variants":["regular"],"position":18658},"Zeyada":{"family":"Zeyada","variants":["regular"],"position":18688}} \ No newline at end of file diff --git a/scratch-parent/framework/helpers/general.php b/scratch-parent/framework/helpers/general.php new file mode 100644 index 00000000..e1585f02 --- /dev/null +++ b/scratch-parent/framework/helpers/general.php @@ -0,0 +1,1056 @@ +{$key_or_property}, $default_value); + } else { + return fw_akg($keys, $array_or_object[$key_or_property], $default_value); + } + } else { + if ($is_object) { + return $array_or_object->{$key_or_property}; + } else { + return $array_or_object[$key_or_property]; + } + } +} + +/** + * Set (or create if not exists) value for specified key in some array level + * + * @param string $keys 'a/b/c', or 'a/b/c/' equivalent to: $arr['a']['b']['c'][] = $val; + * @param mixed $value + * @param array|object $array_or_object + * @param string $keys_delimiter + */ +function fw_aks($keys, $value, &$array_or_object, $keys_delimiter = '/') { + if (!is_array($keys)) { + $keys = explode($keys_delimiter, (string)$keys); + } + + $key_or_property = array_shift($keys); + if ($key_or_property === null) { + return; + } + + $is_object = is_object($array_or_object); + + if ($is_object) { + if (!property_exists($array_or_object, $key_or_property) + || !(is_array($array_or_object->{$key_or_property}) || is_object($array_or_object->{$key_or_property})) + ) { + if ($key_or_property === '') { + // this happens when use 'empty keys' like: abc/d/e////i/j//foo/ + trigger_error('Cannot push value to object like in array ($arr[] = $val)', E_USER_WARNING); + } else { + $array_or_object->{$key_or_property} = array(); + } + } + } else { + if (!is_array($array_or_object)) { + $array_or_object = array(); + } + + if (!array_key_exists($key_or_property, $array_or_object) || !is_array($array_or_object[$key_or_property])) { + if ($key_or_property === '') { + // this happens when use 'empty keys' like: abc.d.e....i.j..foo. + $array_or_object[] = array(); + + // get auto created key (last) + end($array_or_object); + $key_or_property = key($array_or_object); + } else { + $array_or_object[$key_or_property] = array(); + } + } + } + + if (isset($keys[0])) { // not used count() for performance reasons + if ($is_object) { + fw_aks($keys, $value, $array_or_object->{$key_or_property}); + } else { + fw_aks($keys, $value, $array_or_object[$key_or_property]); + } + } else { + if ($is_object) { + $array_or_object->{$key_or_property} = $value; + } else { + $array_or_object[$key_or_property] = $value; + } + } +} + +/** + * Unset specified key in some array level + * + * @param string $keys 'a/b/c' -> unset($arr['a']['b']['c']); + * @param array|object $array_or_object + * @param string $keys_delimiter + */ +function fw_aku($keys, &$array_or_object, $keys_delimiter = '/') { + if (!is_array($keys)) { + $keys = explode($keys_delimiter, (string)$keys); + } + + $key_or_property = array_shift($keys); + if ($key_or_property === null || $key_or_property === '') { + return; + } + + $is_object = is_object($array_or_object); + + if ($is_object) { + if (!property_exists($array_or_object, $key_or_property)) { + return; + } + } else { + if (!is_array($array_or_object) || !array_key_exists($key_or_property, $array_or_object)) { + return; + } + } + + if (isset($keys[0])) { // not used count() for performance reasons + if ($is_object) { + fw_aku($keys, $array_or_object->{$key_or_property}); + } else { + fw_aku($keys, $array_or_object[$key_or_property]); + } + } else { + if ($is_object) { + unset($array_or_object->{$key_or_property}); + } else { + unset($array_or_object[$key_or_property]); + } + + return; + } +} + +/** + * Generate random unique md5 + */ +function fw_rand_md5() { + return md5(time() .'-'. uniqid(rand(), true) .'-'. mt_rand(1, 1000)); +} + +/** + * Return last + 1 + */ +function fw_unique_increment() { + static $i = null; + + if ($i === null) + $i = mt_rand(0, 9370); + + return $i++; +} + +/** + * Nice displayed print_r alternative + * + * @param mixed $value Value to debug + * @param bool $die Stop script after print + */ +function fw_print($value, $die = false) { + static $first_time = true; + + if ($first_time) { + ob_start(); + echo ''; + echo str_replace(array(' ', "\n"), '', ob_get_clean()); + } + + echo '
    ';
    +
    +	echo fw_htmlspecialchars(FW_Dumper::dump($value));
    +
    +	echo '
    '; + + $first_time = false; + + if ($die) { + die(); + } +} + +/** + * Generate html tag + * + * @param string $tag Tag name + * @param array $attr Tag attributes + * @param bool|string $end Append closing tag. Also accepts body content + * @return string The tag's html + */ +function fw_html_tag($tag, $attr = array(), $end = false) { + $html = '<'. $tag .' '. fw_attr_to_html($attr); + + if ($end === true) { + # + $html .= '>'; + } else if ($end === false || empty($end)) { + #
    + $html .= '/>'; + } else { + #
    content
    + $html .= '>'. $end .''; + } + + return $html; +} + +/** + * Generate attributes string for html tag + * @param array $attr_array array('href' => '/', 'title' => 'Test') + * @return string 'href="/" title="Test"' + */ +function fw_attr_to_html(array $attr_array) { + $html_attr = ''; + + foreach ($attr_array as $attr_name => $attr_val) { + if ($attr_val === false) { + continue; + } + + $html_attr .= $attr_name .'="'. esc_attr($attr_val) .'" '; + } + + return $html_attr; +} + +/** + * Strip slashes from values, and from keys if magic_quotes_gpc = On + */ +function fw_stripslashes_deep_keys($value) { + static $magic_quotes = null; + if ($magic_quotes === null) { + $magic_quotes = get_magic_quotes_gpc(); + } + + if (is_array($value)) { + if ($magic_quotes) { + $new_value = array(); + foreach ($value as $key => $val) { + $new_value[ is_string($key) ? stripslashes($key) : $key ] = fw_stripslashes_deep_keys($val); + } + $value = $new_value; + unset($new_value); + } else { + $value = array_map('fw_stripslashes_deep_keys', $value); + } + } elseif (is_object($value)) { + $vars = get_object_vars($value); + foreach ($vars as $key=>$data) { + $value->{$key} = fw_stripslashes_deep_keys($data); + } + } elseif (is_string($value)) { + $value = stripslashes($value); + } + + return $value; +} + +/** + * Add slashes to values, and to keys if magic_quotes_gpc = On + */ +function fw_addslashes_deep_keys($value) { + static $magic_quotes = null; + if ($magic_quotes === null) { + $magic_quotes = get_magic_quotes_gpc(); + } + + if (is_array($value)) { + if ($magic_quotes) { + $new_value = array(); + foreach ($value as $key=>$value) { + $new_value[ is_string($key) ? addslashes($key) : $key ] = fw_addslashes_deep_keys($value); + } + $value = $new_value; + unset($new_value); + } else { + $value = array_map('fw_addslashes_deep_keys', $value); + } + } elseif (is_object($value)) { + $vars = get_object_vars($value); + foreach ($vars as $key=>$data) { + $value->{$key} = fw_addslashes_deep_keys($data); + } + } elseif (is_string($value)) { + $value = addslashes($value); + } + + return $value; +} + +/** + * Check if current screen pass/match give rules + * @param array $rules Rules for current screen + * @return bool + */ +function fw_current_screen_match(array $rules) { + $available_options = array( + 'action' => true, + 'base' => true, + 'id' => true, + 'is_network' => true, + 'is_user' => true, + 'parent_base' => true, + 'parent_file' => true, + 'post_type' => true, + 'taxonomy' => true, + ); + + if (empty($rules)) { + return true; + } + + $rules = array_merge( + array( + 'exclude' => array(), // array of arrays or array with keys from $available_options + 'only' => array(), // same as in 'exclude' + ), + $rules + ); + + if (empty($rules['exclude']) && empty($rules['only'])) { + return true; + } + + global $current_screen; + + if (gettype($current_screen) != 'object') { + return false; + } + + // check if current screen passes the "only" rules + do { + $only = $rules['only']; + + if (empty($only)) { + break; + } + + if (!isset($only[0])) { // if not array of arrays + $only = array($only); + } + + $found_one = false; + $counter = 0; + foreach ($only as $rule) { + if (!count($rule)) { + continue; + } + + $match = true; + + foreach ($rule as $r_key => $r_val) { + if (!isset($available_options[$r_key])) { + continue; + } + + if (gettype($r_val) != 'array') { + $r_val = array($r_val); + } + + $counter++; + + if (!in_array($current_screen->{$r_key}, $r_val)) { + $match = false; + break; + } + } + + if ($match) { + $found_one = true; + break; + } + } + + if (!$found_one && $counter) { + return false; + } + } while(false); + + // check if current screen passes the "exclude" rules + do { + $exclude = $rules['exclude']; + + if (empty($exclude)) { + break; + } + + if (!isset($exclude[0])) { // if not array of arrays + $exclude = array($exclude); + } + + foreach ($exclude as $rule) { + if (!count($rule)) { + continue; + } + + $match = true; + $counter = 0; + + foreach ($rule as $r_key => $r_val) { + if (!isset($available_options[$r_key])) { + continue; + } + + if (gettype($r_val) != 'array') { + $r_val = array($r_val); + } + + $counter++; + + if (!in_array($current_screen->{$r_key}, $r_val)) { + $match = false; + break; + } + } + + if ($match && $counter) { + return false; + } + } + } while(false); + + return true; +} + +/** + * Search relative path in child then in parent theme directory and return URI + * + * @param string $rel_path '/some/path_to_dir' or '/some/path_to_file.php' + * @return string URI + */ +function fw_locate_theme_path_uri($rel_path) { + if (FW_CT && file_exists(FW_CT_DIR . $rel_path)) { + return FW_CT_URI . $rel_path; + } + + if (file_exists(FW_PT_DIR . $rel_path)) { + return FW_PT_URI . $rel_path; + } + + return 'about:blank#theme-file-not-found:'. $rel_path; +} + +/** + * Search relative path in child then in parent theme directory and return full path + * + * @param string $rel_path '/some/path_to_dir' or '/some/path_to_file.php' + * @return string URI + */ +function fw_locate_theme_path($rel_path) { + if (FW_CT && file_exists(FW_CT_DIR . $rel_path)) { + return FW_CT_DIR . $rel_path; + } + + if (file_exists(FW_PT_DIR . $rel_path)) { + return FW_PT_DIR . $rel_path; + } + + return false; +} + +/** + * Safe render a view and return html + * In view will be accessible only passed variables + * Use this function to not include files directly and to not give access to current context variables (like $this) + * @param string $file_path + * @param array $view_variables + * @return string HTML + */ +function fw_render_view($file_path, $view_variables = array()) { + extract($view_variables, EXTR_REFS); + + ob_start(); + + require $file_path; + + return ob_get_clean(); +} + +/** + * Safe load variables from an file + * Use this function to not include files directly and to not give access to current context variables (like $this) + * @param string $file_path + * @param array $variables array('variable_name' => 'default_value') + * @return array + */ +function fw_get_variables_from_file($file_path, array $variables) { + require $file_path; + + foreach ($variables as $variable_name => $default_value) { + if (isset($$variable_name)) { + $variables[$variable_name] = $$variable_name; + } + } + + return $variables; +} + +/** + * Use this function to not include files directly and to not give access to current context variables (like $this) + * @param string $file_path + */ +function fw_include_file_isolated($file_path) { + if (file_exists($file_path)) { + include $file_path; + } +} + +/** + * Extract only input options from array with: tabs, boxes, options + * @param array $options + * @param array $_recursion_options Do not use this parameter + * @return array + */ +function fw_extract_only_options(array $options, &$_recursion_options = array()) { + static $recursion = null; + + if ($recursion === null) { + $recursion = array( + 'level' => 0, + 'result' => array(), + ); + + $_recursion_options =& $options; + } + + foreach ($_recursion_options as $id => &$option) { + if (isset($option['options'])) { + // this is container with options + $recursion['level']++; + fw_extract_only_options(array(), $option['options']); + $recursion['level']--; + } elseif (isset($option['type']) && is_string($option['type'])) { + $recursion['result'][$id] =& $option; + } elseif (is_int($id) && is_array($option)) { + // this is array with options + $recursion['level']++; + fw_extract_only_options(array(), $option); + $recursion['level']--; + } + } + + if ($recursion['level'] == 0) { + $result =& $recursion['result']; + + $recursion = null; + + return $result; + } +} + +/** + * Collect correct options from first level on the array and group them + * @param array $collected Will be filled with found correct options + * @param array $options + */ +function fw_collect_first_level_options(&$collected, &$options) { + if (empty($options)) + return; + + if (empty($collected)) { + $collected['tabs'] = array(); + $collected['boxes'] = array(); + $collected['groups'] = array(); + + $collected['options'] = array(); + + $collected['groups_and_options'] = array(); + } + + foreach ($options as $option_id => &$option) { + if (isset($option['options'])) { + // this is container for other options + + switch ($option['type']) { + case 'tab': + $collected['tabs'][$option_id] =& $option; + break; + case 'box': + $collected['boxes'][$option_id] =& $option; + break; + case 'group': + $collected['groups'][$option_id] =& $option; + + $collected['groups_and_options'][$option_id] =& $option; + break; + default: + trigger_error('Invalid option container type: '. $option['type'], E_USER_WARNING); + } + } elseif (is_int($option_id) && is_array($option)) { + // array with options + fw_collect_first_level_options($collected, $option); + } elseif (isset($option['type'])) { + // simple option, last possible level in options array + $collected['options'][$option_id] =& $option; + + $collected['groups_and_options'][$option_id] =& $option; + } else { + trigger_error('Invalid option: '. $option_id, E_USER_WARNING); + } + } +} + +/** + * Get correct values from input (POST) for given options + * This values can be saved in db then replaced with $option['value'] for each option + * @param array $options + * @param array $input_array + * @return array Values + */ +function fw_get_options_values_from_input(array $options, $input_array = null) { + if (!is_array($input_array)) { + $input_array = FW_Request::POST(FW_Option_Type::get_default_name_prefix()); + } + + $values = array(); + + foreach (fw_extract_only_options($options) as $id => $option) { + $values[$id] = fw()->backend->option_type($option['type'])->get_value_from_input( + $option, + isset($input_array[$id]) ? $input_array[$id] : null + ); + } + + return $values; +} + +/** + * 'abc[def][xyz]' -> 'abc/def/xyz' + * 'abc[def][xyz][]' -> 'abc/def/xyz' + */ +function fw_html_attr_name_to_array_multi_key($attr_name) { + $attr_name = str_replace('[]', '', $attr_name); + $attr_name = str_replace('][', '/', $attr_name); + $attr_name = str_replace('[', '/', $attr_name); + $attr_name = str_replace(']', '', $attr_name); + + return $attr_name; +} + +/** + * Used when getting some option value from serialized array saved in a custom place + * and that option is unreachable for standard WordPress filters by other plugins + * For e.g. that option cannot be translated by plugins, so we pass it's value through this function and do the fixes + * @param $value + * @return array + */ +function fw_prepare_option_value($value) { + if (empty($value)) { + return $value; + } + + if (function_exists('qtrans_use_current_language_if_not_found_use_default_language')) { + if (is_array($value)) { + array_walk_recursive($value, 'qtrans_use_current_language_if_not_found_use_default_language'); + } else { + $value = qtrans_use_current_language_if_not_found_use_default_language($value); + } + } + + return $value; +} + +/** + * This function is used in 'save_post' action + * + * @param $post_id + * @return bool + */ +function fw_is_real_post_save($post_id) +{ + return !( + wp_is_post_revision($post_id) + || wp_is_post_autosave($post_id) + || (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) + || (defined('DOING_AJAX') && DOING_AJAX) + || empty($_POST) + || empty($_POST['post_ID']) + ); +} + +/** + * @return Array with Google fonts + */ +function fw_get_google_fonts() { + $cache_key = 'fw_google_fonts'; + + try { + return FW_Cache::get($cache_key); + } catch (FW_Cache_Not_Found_Exception $e) { + $fonts = apply_filters('fw_google_fonts', + json_decode( + file_get_contents(dirname(__FILE__) .'/fw-google-fonts.json'), + true + ) + ); + + FW_Cache::set($cache_key, $fonts); + + return $fonts; + } +} + +/** + * @return string Current url + */ +function fw_current_url() { + static $cache = null; + if ($cache !== null) + return $cache; + + $pageURL = 'http'; + + if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') + $pageURL .= 's'; + + $pageURL .= '://'; + + if ($_SERVER['SERVER_PORT'] != '80') + $pageURL .= $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['REQUEST_URI']; + else + $pageURL .= $_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']; + + $cache = $pageURL; + + return $cache; +} + +function fw_is_valid_domain_name($domain_name) { + return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) // valid chars check + && preg_match("/^.{1,253}$/", $domain_name) // overall length check + && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); // length of each label +} + +/** + * Use this id do not want to enter every time same last two parameters + * Info: Cannot use default parameters because in php 5.2 encoding is not UTF-8 by default + * + * @param string $string + * @return string + */ +function fw_htmlspecialchars($string) { + return htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); +} + +/** + * Check if current user has one capability from the given list + * + * @param array $capabilities list of capabilities to check + * @param mixed $default_value + * @return string|bool|mixed + * Return first capability that user can. + * Else, return default value if it is not null, else return first capability from list. + * Use default value false to check if user can some of the capabilities + */ +function fw_current_user_can($capabilities, $default_value = null) +{ + if (is_user_logged_in()) { + foreach ($capabilities as $capability) { + if (current_user_can($capability)) + return $capability; + } + } + + return ($default_value !== null ? $default_value : array_shift($capabilities)); +} + +/** + * Convert number of seconds to 'X {units}' + * + * E.g. 123 => '2 minutes' + * then you can use this string how you want, for e.g. append ' ago' => '2 minutes ago' + * + * @param int $seconds + * @return string + */ +function fw_human_time($seconds) +{ + static $translations = null; + if ($translations === null) { + $translations = array( + 'year' => __('year', 'tfuse'), + 'years' => __('years', 'tfuse'), + + 'month' => __('month', 'tfuse'), + 'months' => __('months', 'tfuse'), + + 'week' => __('week', 'tfuse'), + 'weeks' => __('weeks', 'tfuse'), + + 'day' => __('day', 'tfuse'), + 'days' => __('days', 'tfuse'), + + 'hour' => __('hour', 'tfuse'), + 'hours' => __('hours', 'tfuse'), + + 'minute' => __('minute', 'tfuse'), + 'minutes' => __('minutes', 'tfuse'), + + 'second' => __('second', 'tfuse'), + 'seconds' => __('seconds', 'tfuse'), + ); + } + + $tokens = array ( + 31536000 => 'year', + 2592000 => 'month', + 604800 => 'week', + 86400 => 'day', + 3600 => 'hour', + 60 => 'minute', + 1 => 'second' + ); + + foreach ($tokens as $unit => $translation_key) { + if ($seconds < $unit) + continue; + + $number_of_units = floor($seconds / $unit); + + return $number_of_units .' '. $translations[ $translation_key . ($number_of_units != 1 ? 's' : '') ]; + } +} + +function fw_strlen($string) { + return mb_strlen($string, 'UTF-8'); +} + +/** + * If currently is a Post Edit page display/submit + * @return bool + */ +function fw_is_post_edit() { + static $result = null; + + if ($result === null) { + $result = false; + + if (is_admin()) { + if ( + empty($_POST) + && + isset($_GET['action']) + && + $_GET['action'] === 'edit' + && + isset($_GET['post']) + ) { + // Display Edit Post page + $result = true; + } elseif ( + isset($_POST['action']) + && + $_POST['action'] === 'editpost' + && + isset($_POST['post_type']) + && + isset($_POST['post_ID']) + && + strpos(wp_get_referer(), 'action=edit') !== false + ) { + // Submit Edit Post page + $result = true; + } + } + } + + return $result; +} + +/** + * @param string $dirname 'foo-bar' + * @return string 'Foo_Bar' + */ +function fw_dirname_to_classname($dirname) { + $class_name = explode('-', $dirname); + $class_name = array_map('ucfirst', $class_name); + $class_name = implode('_', $class_name); + + return $class_name; +} + +/** + * This function is a wrapper function that set correct width and height for iframes from wp_oembed_get() function + * + * @param $url + * @param array $args + * @return bool|string + */ +function fw_oembed_get($url, $args = array()) { + $html = wp_oembed_get($url, $args); + + if (!empty($args['width']) and !empty($args['height']) and class_exists('DOMDocument') and !empty($html)) { + $dom_element = new DOMDocument(); + $dom_element->loadHTML($html); + $obj = $dom_element->getElementsByTagName('iframe')->item(0); + $obj->setAttribute('width', $args['width']); + $obj->setAttribute('height', $args['height']); + //saveXml instead of SaveHTML for php version compatibility + $html = $dom_element->saveXML($obj, LIBXML_NOEMPTYTAG); + } + + return $html; +} + +/** + * Try everything to create and make a path (file or directory) writable + * Works only within /wp-content dir, cannot make writable something outside it + * @param string $path + * @return bool + * @deprecated It's not safe to make files writable or create files as php user. Use http://codex.wordpress.org/Filesystem_API + */ +function fw_try_make_writable($path) { + static $root_dir = null; + + if ($root_dir === null) { + $root_dir = fw_fix_path(WP_CONTENT_DIR); + } + + $chmod_writable_dir = 0777; + $chmod_writable_file = 0666; + + do { + if (is_writable($path)) + return true; + + $path = fw_fix_path($path); + + // Extract relative path: '/root/dir' . $relPath + { + $rel_path = explode($root_dir, $path); + + if (!empty($rel_path[0])) + break; // is not located in root dir + + array_shift($rel_path); // remove first empty element + + $rel_path = implode($root_dir, $rel_path); + } + + $rel_path_arr = explode('/', $rel_path); + array_shift($rel_path_arr); // remove first empty element + + if (empty($rel_path_arr)) + break; + + $file_name = ''; + if (!is_dir($path)) { + if (file_exists($path)) { + // file exists, we can only try to make it writable + if (@chmod($path, $chmod_writable_file)) { + true; + } else { + break; + } + } + + $file_name = array_pop($rel_path_arr); + } + + if (!empty($rel_path_arr)) { + // check if parent directories exists, if not, create and make writable + + $dir_path = $root_dir .'/'. implode('/', $rel_path_arr); + + if (!file_exists($dir_path)) { + $created = @mkdir( + $dir_path, + $chmod_writable_dir, + true + ); + + if (!$created) { + break; + } + } + + if (!is_writable($dir_path)) { + if (@chmod($dir_path, $chmod_writable_dir)) { + true; + } else { + break; + } + } + } + + if ($file_name) { + // file not exists, need to create + if (false === file_put_contents($path, '')) { + break; + } + + if (is_writable($path)) { + return true; + } + + if (@chmod($path, $chmod_writable_file)) { + true; + } else { + break; + } + } + + return true; + } while(false); + + return false; +} diff --git a/scratch-parent/framework/helpers/post-meta.php b/scratch-parent/framework/helpers/post-meta.php new file mode 100644 index 00000000..f3f88c4f --- /dev/null +++ b/scratch-parent/framework/helpers/post-meta.php @@ -0,0 +1,215 @@ +get_var( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ) ) + return fw_add_post_meta($object_id, $meta_key, $passed_value); + + $_meta_value = $meta_value; + $meta_value = maybe_serialize( $meta_value ); + + $data = compact( 'meta_value' ); + $where = array( $column => $object_id, 'meta_key' => $meta_key ); + + if ( !empty( $prev_value ) ) { + $prev_value = maybe_serialize($prev_value); + $where['meta_value'] = $prev_value; + } + + do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); + + if ( 'post' == $meta_type ) + do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); + + $wpdb->update( $table, $data, $where ); + + wp_cache_delete($object_id, $meta_type . '_meta'); + + do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); + + if ( 'post' == $meta_type ) + do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value ); + + return true; +} + +function fw_add_post_meta($post_id, $meta_key, $meta_value, $unique = false) { + // make sure meta is added to the post, not a revision + if ( $the_post = wp_is_post_revision($post_id) ) + $post_id = $the_post; + + $meta_type = 'post'; + $object_id = $post_id; + + if ( !$meta_type || !$meta_key ) + return false; + + if ( !$object_id = absint($object_id) ) + return false; + + if ( ! $table = _get_meta_table($meta_type) ) + return false; + + global $wpdb; + + $column = esc_sql($meta_type . '_id'); + + // expected_slashed ($meta_key) + // $meta_key = stripslashes($meta_key); // this was the trouble ! + // $meta_value = stripslashes_deep($meta_value); // this was the trouble ! + $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type ); + + $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique ); + if ( null !== $check ) + return $check; + + if ( $unique && $wpdb->get_var( $wpdb->prepare( + "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d", + $meta_key, $object_id ) ) ) + return false; + + $_meta_value = $meta_value; + $meta_value = maybe_serialize( $meta_value ); + + do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value ); + + $result = $wpdb->insert( $table, array( + $column => $object_id, + 'meta_key' => $meta_key, + 'meta_value' => $meta_value + ) ); + + if ( ! $result ) + return false; + + $mid = (int) $wpdb->insert_id; + + wp_cache_delete($object_id, $meta_type . '_meta'); + + do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value ); + + return $mid; +} + +function fw_delete_post_meta($post_id, $meta_key, $meta_value = '') { + // make sure meta is added to the post, not a revision + if ( $the_post = wp_is_post_revision($post_id) ) + $post_id = $the_post; + + $meta_type = 'post'; + $object_id = $post_id; + $delete_all = false; + + if ( !$meta_type || !$meta_key ) + return false; + + if ( (!$object_id = absint($object_id)) && !$delete_all ) + return false; + + if ( ! $table = _get_meta_table($meta_type) ) + return false; + + global $wpdb; + + $type_column = esc_sql($meta_type . '_id'); + $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; + // expected_slashed ($meta_key) + // $meta_key = stripslashes($meta_key); // this was the trouble ! + // $meta_value = stripslashes_deep($meta_value); // this was the trouble ! + + $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all ); + if ( null !== $check ) + return (bool) $check; + + $_meta_value = $meta_value; + $meta_value = maybe_serialize( $meta_value ); + + $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key ); + + if ( !$delete_all ) + $query .= $wpdb->prepare(" AND $type_column = %d", $object_id ); + + if ( $meta_value ) + $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value ); + + $meta_ids = $wpdb->get_col( $query ); + if ( !count( $meta_ids ) ) + return false; + + if ( $delete_all ) + $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) ); + + do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); + + // Old-style action. + if ( 'post' == $meta_type ) + do_action( 'delete_postmeta', $meta_ids ); + + $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )"; + + $count = $wpdb->query($query); + + if ( !$count ) + return false; + + if ( $delete_all ) { + foreach ( (array) $object_ids as $o_id ) { + wp_cache_delete($o_id, $meta_type . '_meta'); + } + } else { + wp_cache_delete($object_id, $meta_type . '_meta'); + } + + do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value ); + + // Old-style action. + if ( 'post' == $meta_type ) + do_action( 'deleted_postmeta', $meta_ids ); + + return true; +} diff --git a/scratch-parent/framework/includes/hooks.php b/scratch-parent/framework/includes/hooks.php new file mode 100644 index 00000000..28989b92 --- /dev/null +++ b/scratch-parent/framework/includes/hooks.php @@ -0,0 +1,4 @@ +'; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return (string)(is_null($input_value) ? $option['value'] : $input_value); + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '' + ); + } +} +FW_Option_Type::register('FW_Option_Type_Hidden'); + +class FW_Option_Type_Text extends FW_Option_Type +{ + public function get_type() + { + return 'text'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['attr']['value'] = (string)$data['value']; + + return ''; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return (string)(is_null($input_value) ? $option['value'] : $input_value); + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '' + ); + } +} +FW_Option_Type::register('FW_Option_Type_Text'); + +class FW_Option_Type_Password extends FW_Option_Type +{ + public function get_type() + { + return 'password'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['attr']['value'] = (string)$data['value']; + + return ''; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return (string)(is_null($input_value) ? $option['value'] : $input_value); + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '' + ); + } +} +FW_Option_Type::register('FW_Option_Type_Password'); + +class FW_Option_Type_Textarea extends FW_Option_Type +{ + public function get_type() + { + return 'textarea'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['value'] = (string)$data['value']; + + unset($option['attr']['value']); // be sure to remove value from attributes + + $option['attr'] = array_merge(array('rows' => '6'), $option['attr']); + $option['attr']['class'] .= ' code'; + + return ''; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return (string)(is_null($input_value) ? $option['value'] : $input_value); + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '' + ); + } +} +FW_Option_Type::register('FW_Option_Type_Textarea'); + +/** + * Required keys: + * 'html' => '
    ...
    ' + */ +class FW_Option_Type_Html extends FW_Option_Type +{ + public function get_type() + { + return 'html'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['attr']['value'] = (string)$data['value']; + + $div_attr = $option['attr']; + unset($div_attr['name']); + unset($div_attr['value']); + + return '
    '. + fw()->backend->option_type('hidden')->render($id, array( + 'attr' => array( + 'class' => 'fw-option-html-value', + ), + 'value' => $option['attr']['value'], + ), + array( + 'id_prefix' => $data['id_prefix'], + 'name_prefix' => $data['name_prefix'] + ) + ). + '
    '. $option['html'] .'
    '. + '
    '; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return (string)(is_null($input_value) ? $option['value'] : $input_value); + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '', + 'html' => 'default html', + ); + } +} +FW_Option_Type::register('FW_Option_Type_Html'); + +/** + * Same html but displayed in fixed width + */ +class FW_Option_Type_Html_Fixed extends FW_Option_Type_Html +{ + public function get_type() + { + return 'html-fixed'; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'fixed'; + } +} +FW_Option_Type::register('FW_Option_Type_Html_Fixed'); + +/** + * Same html but displayed in full width + */ +class FW_Option_Type_Html_Full extends FW_Option_Type_Html +{ + public function get_type() + { + return 'html-full'; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'full'; + } +} +FW_Option_Type::register('FW_Option_Type_Html_Full'); + +class FW_Option_Type_Checkbox extends FW_Option_Type +{ + public function get_type() + { + return 'checkbox'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['value'] = (bool)$data['value']; + + unset($option['attr']['value']); + + return ''. + ''. + ''. + ''; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + return (bool)$input_value; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => false, + 'text' => __('Yes', 'fw'), + ); + } +} +FW_Option_Type::register('FW_Option_Type_Checkbox'); + +/** + * Checkboxes list + * + * Required keys: + * * 'choices' => array( + * 'value' => 'Text', + * ... + * ) + */ +class FW_Option_Type_Checkboxes extends FW_Option_Type +{ + public function get_type() + { + return 'checkboxes'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['value'] = is_array($data['value']) ? $data['value'] : array(); + + $div_attr = $option['attr']; + unset($div_attr['name']); + unset($div_attr['value']); + + $html = '
    '; + + $html .= ''. + ''; + + foreach ($option['choices'] as $value => $text) { + $choice_id = $option['attr']['id'] .'-'. $value; + + $html .= '
    '. + ''. + '
    '; + } + + $html .= '
    '; + + return $html; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (is_array($input_value)) { + $value = array(); + + foreach ($input_value as $choice => $val) { + if ($val === '') + continue; + + if (!isset($option['choices'][$choice])) + continue; + + $value[$choice] = true; + } + } else { + $value = $option['value']; + } + + return $value; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array(), + 'choices' => array() + ); + } +} +FW_Option_Type::register('FW_Option_Type_Checkboxes'); + +/** + * Radio list + * + * Required option keys: + * * 'choices' => array( + * 'value' => 'Text', + * ... + * ) + */ +class FW_Option_Type_Radio extends FW_Option_Type +{ + public function get_type() + { + return 'radio'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['value'] = (string)$data['value']; + + $div_attr = $option['attr']; + unset($div_attr['name']); + unset($div_attr['value']); + + $html = '
    '; + + /*$html .= ''. + '';*/ + + foreach ($option['choices'] as $value => $text) { + $choice_id = $option['attr']['id'] .'-'. $value; + + $html .= '
    '. + ''. + '
    '; + } + + $html .= '
    '; + + return $html; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!isset($option['choices'][$input_value])) { + if ( + empty($option['choices']) || + isset($option['choices'][ $option['value'] ]) + ) { + $input_value = $option['value']; + } else { + reset($option['choices']); + $input_value = key($option['choices']); + } + } + + return (string)$input_value; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '', + 'choices' => array() + ); + } +} +FW_Option_Type::register('FW_Option_Type_Radio'); + +/** + * Select + * + * Required keys: + * * 'choices' => array( + * 'value' => 'Text', + * ... + * ) + */ +class FW_Option_Type_Select extends FW_Option_Type +{ + public function get_type() + { + return 'select'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['value'] = $data['value']; + + $option['attr']['data-saved-value'] = $data['value']; + unset( + $option['attr']['value'], + $option['attr']['multiple'] + ); + + if (!isset($option['choices'])) { + $option['choices'] = array(); + } + + $html = ''; + + return $html; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (empty($option['no-validate'])) { + $all_choices = $this->get_choices($option['choices']); + + if (!isset($all_choices[$input_value])) { + if ( + empty($all_choices) || + isset($all_choices[ $option['value'] ]) + ) { + $input_value = $option['value']; + } else { + reset($all_choices); + $input_value = key($all_choices); + } + } + + unset($all_choices); + } + + return (string)$input_value; + } + + /** + * Extract recursive from optgroups all choices as one level array + */ + protected function get_choices($choices) + { + $result = array(); + + foreach ($choices as $cid => $choice) { + if (is_array($choice) && isset($choice['choices'])) { + // optgroup + $result += $this->get_choices($choice['choices']); + } else { + $result[$cid] = $choice; + } + } + + return $result; + } + + protected function render_choices(&$choices, &$value) + { + if (empty($choices) || !is_array($choices)) + return ''; + + $html = ''; + + foreach ($choices as $c_value => $choice) { + if (is_array($choice)) { + if (!isset($choice['attr'])) { + $choice['attr'] = array(); + } + + if (isset($choice['choices'])) { // optgroup + $html .= ''. + $this->render_choices($choice['choices'], $value). + ''; + } else { // choice as array (with custom attributes) + $choice['attr']['value'] = $c_value; + + unset($choice['attr']['selected']); // this is not allowed + + $html .= ''; + } + } else { // simple choice + $html .= ''; + } + } + + return $html; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '', + 'choices' => array() + ); + } +} +FW_Option_Type::register('FW_Option_Type_Select'); + +/** + * Select Multiple + * + * Required keys: + * * 'choices' => array( + * 'value' => 'Text', + * ... + * ) + */ +class FW_Option_Type_Select_Multiple extends FW_Option_Type_Select +{ + public function get_type() + { + return 'select-multiple'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $option['value'] = $data['value']; + + unset($option['attr']['value']); + + $option['attr']['name'] .= '[]'; + $option['attr']['multiple'] = 'multiple'; + + if (!isset($option['attr']['size'])) { + $option['attr']['size'] = '7'; + } + + $html = ''; + + return $html; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!is_array($input_value)) { + $input_value = $option['value']; + } + + if (empty($option['no-validate'])) { + $all_choices = $this->get_choices($option['choices']); + + foreach ($input_value as $key => $value) { + if (!isset($all_choices[$value])) { + unset($input_value[$key]); + } + } + + unset($all_choices); + } + + return $input_value; + } + + protected function render_choices(&$choices, &$value) + { + if (empty($choices) || !is_array($choices)) + return ''; + + $html = ''; + + foreach ($choices as $c_value => $choice) { + if (is_array($choice)) { + if (!isset($choice['attr'])) { + $choice['attr'] = array(); + } + + if (isset($choice['choices'])) { // optgroup + $html .= ''. + $this->render_choices($choice['choices'], $value). + ''; + } else { // choice as array (with custom attributes) + $choice['attr']['value'] = $c_value; + + unset($choice['attr']['selected']); // this is not allowed + + $html .= ''; + } + } else { // simple choice + $html .= ''; + } + } + + return $html; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array(), + 'choices' => array() + ); + } +} +FW_Option_Type::register('FW_Option_Type_Select_Multiple'); + + +$dir = dirname(__FILE__); + +require $dir .'/option-types/icon/class-fw-option-type-icon.php'; +require $dir .'/option-types/image-picker/class-fw-option-type-image-picker.php'; +require $dir .'/option-types/upload/class-fw-option-type-upload.php'; +require $dir .'/option-types/color-picker/class-fw-option-type-color-picker.php'; +require $dir .'/option-types/gradient/class-fw-option-type-gradient.php'; +require $dir .'/option-types/background-image/class-fw-option-type-background-image.php'; +require $dir .'/option-types/multi/class-fw-option-type-multi.php'; +require $dir .'/option-types/switch/class-fw-option-type-switch.php'; +require $dir .'/option-types/typography/class-fw-option-type-typography.php'; +require $dir .'/option-types/builder/class-fw-option-type-builder.php'; +require $dir .'/option-types/multi-upload/class-fw-option-type-multi-upload.php'; +require $dir .'/option-types/multi-picker/class-fw-option-type-multi-picker.php'; +require $dir .'/option-types/wp-editor/class-fw-option-type-wp-editor.php'; +require $dir .'/option-types/date-picker/class-fw-option-type-wp-date-picker.php'; +require $dir .'/option-types/addable-option/class-fw-option-type-addable-option.php'; +require $dir .'/option-types/addable-box/class-fw-option-type-addable-box.php'; +require $dir .'/option-types/addable-popup/class-fw-option-type-addable-popup.php'; +require $dir .'/option-types/multi-select/class-fw-option-type-multi-select.php'; diff --git a/scratch-parent/framework/includes/option-types/addable-box/class-fw-option-type-addable-box.php b/scratch-parent/framework/includes/option-types/addable-box/class-fw-option-type-addable-box.php new file mode 100644 index 00000000..6675cddd --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-box/class-fw-option-type-addable-box.php @@ -0,0 +1,109 @@ +get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/css/styles.css', + array(), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-'. $this->get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/js/scripts.js', + array('fw-events', 'jquery-ui-sortable'), + fw()->manifest->get_version(), + true + ); + } + + if (empty($data['value']) || !is_array($data['value'])) { + $data['value'] = array(); + } + + /** Prepare controls */ + { + $controls = array_merge( + array( + 'delete' => '' + ), + $option['box-controls'] + ); + + // move 'delete' control to end + { + if (isset($controls['delete'])) { + $_delete = $controls['delete']; + unset($controls['delete']); + $controls['delete'] = $_delete; + unset($_delete); + } + } + } + + return fw_render_view(FW_DIR .'/includes/option-types/'. $this->get_type() .'/view.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + 'controls' => $controls, + )); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!is_array($input_value)) { + return $option['value']; + } + + $value = array(); + + $box_options = fw_extract_only_options($option['box-options']); + + foreach ($input_value as &$list_item_value) { + $current_value = array(); + + foreach ($box_options as $id => $input_option) { + $current_value[$id] = fw()->backend->option_type($input_option['type'])->get_value_from_input( + $input_option, + isset($list_item_value[$id]) ? $list_item_value[$id] : null + ); + } + + $value[] = $current_value; + } + + return $value; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array(), + 'box-controls' => array(), + 'box-options' => array() + ); + } +} +FW_Option_Type::register('FW_Option_Type_Addable_Box'); diff --git a/scratch-parent/framework/includes/option-types/addable-box/static/css/styles.css b/scratch-parent/framework/includes/option-types/addable-box/static/css/styles.css new file mode 100644 index 00000000..cfa01070 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-box/static/css/styles.css @@ -0,0 +1,32 @@ +.fw-option-type-addable-box > .fw-option-boxes.ui-sortable > .fw-option-box > .fw-postbox { + min-width: 100%; +} + +.fw-option-type-addable-box > .fw-option-boxes.ui-sortable > .fw-option-box > .fw-postbox > h3.hndle { + cursor: move !important; /* to rewrite .fw-postbox h3.hndle */ +} + +.fw-option-type-addable-box > .fw-option-boxes > .fw-option-box { + margin-bottom: 20px; +} + +.fw-option-type-addable-box > .fw-option-boxes.ui-sortable > .fw-option-box > .fw-postbox > h3.hndle span:after { + content: '\00a0'; /*   - when title is empty, box has too small (broken) height */ +} + + +/* Controls */ + +.fw-option-type-addable-box > .fw-option-boxes > .fw-option-box h3.hndle .fw-html-after-title { + float: right; + position: relative; /* fix .handlediv::before padding that goes on top of the content from .fw-html-after-title */ + padding-right: 3px; +} + +.fw-option-type-addable-box > .fw-option-boxes > .fw-option-box h3.hndle .fw-option-box-controls .fw-option-box-control { + text-decoration: none; +} + +.fw-option-type-addable-box > .fw-option-boxes > .fw-option-box h3.hndle .fw-option-box-controls .fw-option-box-control-wrapper { + color: #cccccc; +} diff --git a/scratch-parent/framework/includes/option-types/addable-box/static/js/scripts.js b/scratch-parent/framework/includes/option-types/addable-box/static/js/scripts.js new file mode 100644 index 00000000..5975a2cc --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-box/static/js/scripts.js @@ -0,0 +1,141 @@ +jQuery(document).ready(function ($) { + var methods = { + /** Make full/prefixed event name from short name */ + makeEventName: function(shortName) { + return 'fw:option-type:addable-box:'+ shortName; + }, + /** Create object with useful data about box for event data */ + getBoxDataForEvent: function($box) { + var data = {}; + + data.$box = $box; + data.$controls = $box.find('.fw-option-box-controls:first'); + data.$options = $box.find('.fw-option-box-options:first'); + + data.$box = $box.find('.fw-postbox:first'); + data.$title = data.$box.find('> h3.hndle:first'); + data.$titleText = data.$title.find('> span:first'); + + return data; + }, + /** Make boxes to be sortable */ + reInitSortable: function ($boxes) { + try { + $boxes.sortable('destroy'); + } catch (e) { + // happens when sortable was not initialized before + } + + var isMobile = $(document.body).hasClass('mobile'); + + $boxes.sortable({ + items: '> .fw-option-box', + handle: '.hndle:first', + cursor: 'move', + placeholder: 'sortable-placeholder', + delay: ( isMobile ? 200 : 0 ), + distance: 2, + tolerance: 'pointer', + forcePlaceholderSize: true, + axis: 'y', + start: function(e, ui){ + // Update the height of the placeholder to match the moving item. + { + var height = ui.item.outerHeight(); + + height -= 2; // Subtract 2 for borders + + ui.placeholder.height(height); + } + } + }); + }, + /** Init boxes controls */ + initControls: function ($boxes) { + $boxes + .find('.fw-option-box-controls:not(.initialized)') + .on('click', '.fw-option-box-control', function(e){ + e.preventDefault(); + e.stopPropagation(); // prevent open/close of the box (when the link is in box title bar) + + var $control = $(this); + var controlId = $control.attr('data-control-id'); + + switch (controlId) { + case 'delete': + $control.closest('.fw-option-box').remove(); + break; + default: + // custom control. trigger event for others to handle this + $control.closest('.fw-option-type-addable-box').trigger( + methods.makeEventName('.fw-options-tabs-wrapper .fw-options-tabs-contents'), { + controlId: controlId, + $control: $control, + box: methods.getBoxDataForEvent($control.closest('.box')) + } + ); + } + }) + .addClass('initialized') + .find('.fw-option-box-control').off('click'); // remove e.stopPropagation() added by /wp-admin/js/postbox.min.js + } + }; + + fwEvents.on('fw:options:init', function (data) { + var $elements = data.$elements.find('.fw-option-type-addable-box:not(.fw-option-initialized)'); + + /** Init Add button */ + $elements.on('click', '.fw-option-boxes-controls .fw-option-boxes-add-button', function(){ + var $button = $(this); + var $option = $button.closest('.fw-option-type-addable-box'); + var $boxes = $option.find('.fw-option-boxes:first'); + var increment = parseInt($button.attr('data-increment')); + + var $newBox = $( + $option.find('.default-box-template:first').attr('data-template') + .split('###-addable-box-increment-###').join(String(increment)) + ); + + $button.attr('data-increment', increment + 1); + + $boxes.append( + $newBox + ); + + methods.initControls($newBox); + methods.reInitSortable($boxes); + + // remove focus form "Add" button to prevent pressing space/enter to add easy many boxes + $newBox.find('input,select,textarea').first().focus(); + + fwEvents.trigger('fw:options:init', {$elements: $newBox}); + + var box = methods.getBoxDataForEvent($newBox); + + $option.trigger(methods.makeEventName('box:init'), {box: box}); + }); + + // close postboxes and attach event listener + $elements.find('> .fw-option-boxes > .fw-option-box > .fw-postbox').addClass('closed'); + + methods.initControls($elements); + + $elements.addClass('fw-option-initialized'); + + setTimeout(function(){ + // executed later, after .sortable('destroy') from backend-options.js + methods.reInitSortable($elements.find('.fw-option-boxes')); + + // execute box:init event for existing boxes + $elements.each(function(){ + var $option = $(this); + + $option.find('> .fw-option-boxes > .fw-option-box').each(function(){ + $option.trigger(methods.makeEventName('box:init'), { + box: methods.getBoxDataForEvent($(this)) + }); + }) + }); + }, 100); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-box/view.php b/scratch-parent/framework/includes/option-types/addable-box/view.php new file mode 100644 index 00000000..a62b6904 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-box/view.php @@ -0,0 +1,99 @@ + + + $control): ?> + + + + +
    > + +
    + &$values): ?> + +
    + +
    + backend->render_options($box_options, $values, array( + 'id_prefix' => $data['id_prefix'] . $id .'-'. $i .'-', + 'name_prefix' => $data['name_prefix'] .'['. $id .']['. $i .']', + )) ?> +
    + backend->render_box( + $data['id_prefix'] . $id .'-'. $i .'-box', + '͏ ', + ob_get_clean(), + array( + 'html_after_title' => $controls_html + ) + ); + ?> +
    + +
    +
    '. + fw()->backend->render_box( + $data['id_prefix'] . $id .'-'. $increment_template .'-box', + '͏ ', + '
    '. + fw()->backend->render_options($box_options, $values, array( + 'id_prefix' => $data['id_prefix'] . $id .'-'. $increment_template .'-', + 'name_prefix' => $data['name_prefix'] .'['. $id .']['. $increment_template .']', + )). + '
    ', + array( + 'html_after_title' => $controls_html + ) + ). + '
    ' + ); + ?>"> +
    + +
    +
    \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-option/class-fw-option-type-addable-option.php b/scratch-parent/framework/includes/option-types/addable-option/class-fw-option-type-addable-option.php new file mode 100644 index 00000000..feca1c36 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-option/class-fw-option-type-addable-option.php @@ -0,0 +1,77 @@ + array(), + 'option' => array( + 'type' => 'text', + ) + ); + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + // static + { + wp_enqueue_style( + 'fw-option-'. $this->get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/css/styles.css', + array(), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-'. $this->get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/js/scripts.js', + array('fw-events', 'jquery-ui-sortable'), + fw()->manifest->get_version(), + true + ); + } + + return fw_render_view(FW_DIR .'/includes/option-types/'. $this->get_type() .'/view.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + 'move_img_src' => FW_URI .'/static/img/sort-vertically.png', + )); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!is_array($input_value)) { + return $option['value']; + } + + $option_type = fw()->backend->option_type($option['option']['type']); + + $value = array(); + + foreach ($input_value as $option_input_value) { + $value[] = $option_type->get_value_from_input( + $option['option'], + $option_input_value + ); + } + + return $value; + } +} +FW_Option_Type::register('FW_Option_Type_Addable_Option'); diff --git a/scratch-parent/framework/includes/option-types/addable-option/static/css/styles.css b/scratch-parent/framework/includes/option-types/addable-option/static/css/styles.css new file mode 100644 index 00000000..8ca7c187 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-option/static/css/styles.css @@ -0,0 +1,58 @@ +.fw-option-type-addable-option .fw-option-type-addable-option-option td, +#edittag .form-table .fw-option-type-addable-option .fw-option-type-addable-option-option td, +#edittag .form-table .fw-option-type-addable-option tr.sortable-placeholder td { + padding: 0 0 15px 0; + vertical-align: top; +} + +.fw-option-type-addable-option .fw-option-type-addable-option-option td.td-option, +#edittag .form-table .fw-option-type-addable-option .fw-option-type-addable-option-option td.td-option { + padding-right: 10px; +} + +.fw-option-type-addable-option .fw-option-type-addable-option-option td.td-remove, +#edittag .form-table .fw-option-type-addable-option .fw-option-type-addable-option-option td.td-remove { + width: 10px; + padding-top: 4px; +} + +.fw-option-type-addable-option .fw-option-type-addable-option-option td.td-remove .dashicons { + font-size: 16px; + line-height: 1.3; + color: #AAAAAA; +} + +.fw-option-type-addable-option .fw-option-type-addable-option-option td.td-remove .dashicons:hover { + color: #CC0000; +} + +.fw-option-type-addable-option .fw-option-type-addable-option-option td.td-move, +#edittag .form-table .fw-option-type-addable-option .fw-option-type-addable-option-option td.td-move { + cursor: move; + width: 15px; + padding-top: 4px; +} + + +.fw-option-type-addable-option tr.fw-option-type-addable-option-option.ui-sortable-helper { + display: block; +} + +.fw-option-type-addable-option tr.fw-option-type-addable-option-option.ui-sortable-helper:before, +.fw-option-type-addable-option tr.fw-option-type-addable-option-option.ui-sortable-helper:after { + display: table; + content: " "; +} + +.fw-option-type-addable-option tr.fw-option-type-addable-option-option.ui-sortable-helper > td { + display: block; + float: left; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.fw-option-type-addable-option tr.fw-option-type-addable-option-option.ui-sortable-helper td.td-option { + width: calc(100% - 35px); +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-option/static/js/scripts.js b/scratch-parent/framework/includes/option-types/addable-option/static/js/scripts.js new file mode 100644 index 00000000..09cc9b7d --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-option/static/js/scripts.js @@ -0,0 +1,70 @@ +jQuery(document).ready(function ($) { + function initSortable ($options) { + try { + $options.sortable('destroy'); + } catch (e) { + // happens when sortable was not initialized before + } + + var isMobile = $(document.body).hasClass('mobile'); + + $options.sortable({ + items: '> tbody > tr', + handle: 'td:first', + cursor: 'move', + placeholder: 'sortable-placeholder', + delay: ( isMobile ? 200 : 0 ), + distance: 2, + tolerance: 'pointer', + forcePlaceholderSize: true, + axis: 'y', + start: function(e, ui){ + // Update the height of the placeholder to match the moving item. + { + var height = ui.item.outerHeight(); + + ui.placeholder.height(height); + } + } + }); + } + + fwEvents.on('fw:options:init', function (data) { + var $elements = data.$elements.find('.fw-option-type-addable-option:not(.fw-option-initialized)'); + + /** Init Add button */ + $elements.on('click', '.fw-option-type-addable-option-add', function(){ + var $button = $(this); + var $option = $button.closest('.fw-option-type-addable-option'); + var $options = $option.find('.fw-option-type-addable-option-options:first'); + var increment = parseInt($button.attr('data-increment')); + + var $newOption = $( + $option.find('.default-addable-option-template:first').attr('data-template') + .split('###-addable-option-increment-###').join(String(increment)) + ); + + $button.attr('data-increment', increment + 1); + + $options.append( + $newOption + ); + + // remove focus form "Add" button to prevent pressing space/enter to add easy many options + $newOption.find('input,select,textarea').first().focus(); + + fwEvents.trigger('fw:options:init', {$elements: $newOption}); + }); + + /** Init Remove button */ + $elements.on('click', '.fw-option-type-addable-option-remove', function(){ + $(this).closest('.fw-option-type-addable-option-option').remove(); + }); + + $elements.each(function(){ + initSortable($elements.find('.fw-option-type-addable-option-options:first')); + }); + + $elements.addClass('fw-option-initialized'); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-option/view.php b/scratch-parent/framework/includes/option-types/addable-option/view.php new file mode 100644 index 00000000..51b3aead --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-option/view.php @@ -0,0 +1,88 @@ + +
    > + + + + + + + + + +
    + + + backend->option_type($option['option']['type'])->render( + $i, + $option['option'], + array( + 'value' => $option_value, + 'id_prefix' => $data['id_prefix'] . $id .'--option-', + 'name_prefix' => $data['name_prefix'] .'['. $id .']', + ) + ); + + $i++; + ?> + + +
    +
    + + + + '. + fw()->backend->option_type($option['option']['type'])->render( + $increment_template, + $option['option'], + array( + 'id_prefix' => $data['id_prefix'] . $id .'--option-', + 'name_prefix' => $data['name_prefix'] .'['. $id .']', + ) + ). + ' + + + + ' + ); + ?>"> +
    + +
    +
    \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-popup/class-fw-option-type-addable-popup.php b/scratch-parent/framework/includes/option-types/addable-popup/class-fw-option-type-addable-popup.php new file mode 100644 index 00000000..93512acb --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-popup/class-fw-option-type-addable-popup.php @@ -0,0 +1,132 @@ +get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/styles.css', + array('fw'), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/' . $this->get_type() . '.js', + array('underscore', 'fw-events', 'jquery-ui-sortable', 'fw'), + fw()->manifest->get_version(), + true + ); + + { + $transformed_options = $this->transform_options($option['popup-options']); + $localize_var_name = 'fw_option_type_' . str_replace('-', '_', $this->get_type()) . '_localize_' . + // this way prevents undefined variable errors when addable popup is used inside another addable popup + md5(json_encode($transformed_options)); + + wp_localize_script( + 'fw-option-' . $this->get_type(), + $localize_var_name, + array( + 'title' => empty($option['popup-title']) ? $option['label'] : $option['popup-title'], + 'options' => $this->transform_options($option['popup-options']), + 'template' => $option['template'] + ) + ); + + $option['attr']['data-localize-var-name'] = $localize_var_name; + } + + fw()->backend->render_options($option['popup-options']); // This makes sure that the option's static is enqueued + + $sortable_image = FW_URI . '/static/img/sort-vertically.png'; + + return fw_render_view(FW_DIR . '/includes/option-types/' . $this->get_type() . '/views/view.php', compact('id', 'option', 'data', 'sortable_image')); + } + + /* + * Puts each option into a separate array + * to keep it's order inside the modal dialog + */ + private function transform_options($options) + { + $new_options = array(); + foreach ($options as $id => $option) { + $new_options[] = array($id => $option); + } + return $new_options; + } + + /** + * Option's unique type, used in option array in 'type' key + * @return string + */ + public function get_type() + { + return 'addable-popup'; + } + + /** + * Extract correct value for $option['value'] from input array + * If input value is empty, will be returned $option['value'] + * @param array $option + * @param array|string|null $input_value + * @return string|array|int|bool Correct value + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!is_array($input_value)) { + return $option['value']; + } + + $values = array_map('json_decode', $input_value, array_fill(0, count($input_value), true)); + + return $values; + } + + /** + * Default option array + * + * This makes possible an option array to have required only one parameter: array('type' => '...') + * Other parameters are merged with array returned from this method + * + * @return array + * + * array( + * 'value' => '', + * ... + * ) + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array(), + 'popup-options' => array( + 'default' => array('type' => 'text'), + ), + 'template' => '', + 'popup-title' => null, + ); + } + +} + +FW_Option_Type::register('FW_Option_Type_Addable_Popup'); diff --git a/scratch-parent/framework/includes/option-types/addable-popup/static/css/styles.css b/scratch-parent/framework/includes/option-types/addable-popup/static/css/styles.css new file mode 100644 index 00000000..79ed3e88 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-popup/static/css/styles.css @@ -0,0 +1,38 @@ +.fw-option-type-addable-popup .item{ + position: relative; + background-color: #fff; + min-height: 40px; + cursor: pointer; +} + +.fw-option-type-addable-popup .item .content{ + padding: 12px 30px; +} + +.fw-option-type-addable-popup .item:not(.default) + .item:not(.default){ + border-top: 1px dashed #E1E1E1; +} + +.fw-option-type-addable-popup .items-wrapper{ + border: 1px solid #e1e1e1; + margin-bottom: 20px; +} + +.fw-option-type-addable-popup .delete-item{ + position: absolute; + right: 7px; + top:50%; + margin-top: -10px; +} + +.fw-option-type-addable-popup .sort-item{ + position: absolute; + left: 11px; + top:50%; + margin-top: -4px; + width: 7px; +} + +.fw-option-type-addable-popup .item.default{ + display: none; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-popup/static/js/addable-popup.js b/scratch-parent/framework/includes/option-types/addable-popup/static/js/addable-popup.js new file mode 100644 index 00000000..ea9ef5ae --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-popup/static/js/addable-popup.js @@ -0,0 +1,137 @@ +(function ($, _, fwEvents, window) { + + addablePopup = function () { + var $this = $(this), + $defaultItem = $this.find('.item.default'), + nodes = { + $optionWrapper: $this, + $addButton: $this.find('.add-new-item'), + $itemsWrapper: $this.find('.items-wrapper'), + getDefaultItem: function () { + return $defaultItem.clone().removeClass('default'); + } + }, + data = window[nodes.$optionWrapper.attr('data-localize-var-name')], + utils = { + modal: new fw.OptionsModal({ + title: data.title, + options: data.options + }), + countItems: function () { + return nodes.$itemsWrapper.find('.item:not(.default)').length; + }, + removeDefaultItem: function () { + nodes.$itemsWrapper.find('.item.default').remove(); + }, + toogleItemsWrapper: function () { + + if (utils.countItems() === 0) { + nodes.$itemsWrapper.hide(); + } else { + nodes.$itemsWrapper.show(); + } + }, + init: function () { + utils.initItemsTemplates(); + utils.toogleItemsWrapper(); + utils.removeDefaultItem(); + utils.initSortable(); + }, + initSortable: function () { + nodes.$itemsWrapper.sortable({ + items: '.item:not(.default)', + cursor: 'move', + distance: 2, + tolerance: 'pointer', + axis: 'y' + }); + }, + initItemsTemplates: function () { + var $items = nodes.$itemsWrapper.find('.item:not(.default)'); + if ($items.length > 0) { + $items.each(function () { + utils.editItem($(this), JSON.parse($(this).find('input').val())); + }); + } + }, + createItem: function (values) { + var $clonedItem = nodes.getDefaultItem(), + $clonedInput = $clonedItem.find('.input-wrapper'), + $inputTemplate = $(_.template( + $.trim($clonedInput.html()), + {json: JSON.stringify(values), i: utils.countItems()}, + { + evaluate: /\{\{(.+?)\}\}/g, + interpolate: /\{\{=(.+?)\}\}/g, + escape: /\{\{-(.+?)\}\}/g + } + )), + $itemTemplate = _.template( + $.trim(data.template), + values, + { + evaluate: /\{\{(.+?)\}\}/g, + interpolate: /\{\{=(.+?)\}\}/g, + escape: /\{\{-(.+?)\}\}/g + } + ); + $clonedInput.find('input').replaceWith($inputTemplate); + $clonedItem.find('.content').html($itemTemplate); + return $clonedItem; + }, + addNewItem: function (values) { + nodes.$itemsWrapper.append(utils.createItem(values)); + }, + editItem: function (item, values) { + item.replaceWith(utils.createItem(values)); + } + }; + + nodes.$itemsWrapper.on('click', '.delete-item', function (e) { + e.stopPropagation(); + e.preventDefault(); + $(this).closest('.item').remove(); + utils.toogleItemsWrapper(); + }); + + nodes.$itemsWrapper.on('click', '.item', function (e) { + e.preventDefault(); + + var values = {}; + var $input = $(this).find('input'); + + if ($input.length) { + values = JSON.parse($input.val()); + } + + utils.modal.set('edit', true); + utils.modal.set('values', values, {silent: true}); + utils.modal.set('itemRef', $(this)); + utils.modal.open(); + }); + + nodes.$addButton.on('click', function () { + utils.modal.set('edit', false); + utils.modal.set('values', {}, {silent: true}); + utils.modal.open(); + }); + + utils.modal.on('change:values', function (modal, values) { + if (!modal.get('edit')) { + utils.addNewItem(values); + utils.toogleItemsWrapper(); + } else { + utils.editItem(utils.modal.get('itemRef'), values); + } + }); + + utils.init(); + }; + + fwEvents.on('fw:options:init', function (data) { + data.$elements + .find('.fw-option-type-addable-popup:not(.fw-option-initialized)').each(addablePopup) + .addClass('fw-option-initialized'); + }); + +})(jQuery, _, fwEvents, window); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/addable-popup/views/templates.php b/scratch-parent/framework/includes/option-types/addable-popup/views/templates.php new file mode 100644 index 00000000..e1c81881 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-popup/views/templates.php @@ -0,0 +1,10 @@ + + diff --git a/scratch-parent/framework/includes/option-types/addable-popup/views/view.php b/scratch-parent/framework/includes/option-types/addable-popup/views/view.php new file mode 100644 index 00000000..88bffe69 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/addable-popup/views/view.php @@ -0,0 +1,37 @@ + +
    > + +
    +
    +
    + backend->option_type('hidden')->render('', array('value' => '{{-json}}'), array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . '{{=i}}' . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ));?> +
    + + +
    + +
    + $value): ?> +
    +
    + backend->option_type('hidden')->render('', array('value' => esc_attr(json_encode($value))), array( + 'id_prefix' => $data['id_prefix'] . $id . '-' . $key . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ));?> +
    + + +
    tmp
    + +
    + +
    + + +
    + diff --git a/scratch-parent/framework/includes/option-types/background-image/class-fw-option-type-background-image.php b/scratch-parent/framework/includes/option-types/background-image/class-fw-option-type-background-image.php new file mode 100644 index 00000000..95f3e733 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/background-image/class-fw-option-type-background-image.php @@ -0,0 +1,126 @@ + '', + 'choices' => array() + ); + } + + /** + * @internal + */ + protected function _render( $id, $option, $data ) { + // add static + { + wp_enqueue_style( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/styles.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js', + array( 'jquery', 'fw-events' ), + fw()->manifest->get_version(), + true + ); + } + + $option = $this->check_parameters( $option ); + $data = $this->check_data( $option, $data ); + + return fw_render_view( FW_DIR . '/includes/option-types/' . $this->get_type() . '/view.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data + ) ); + } + + private function check_parameters( $option ) { + + if ( empty( $option['choices'] ) || ! is_array( $option['choices'] ) ) { + $option['choices'] = array(); + } + if ( empty( $option['value'] ) || ! in_array( $option['value'], array_keys( $option['choices'] ) ) ) { + $option['value'] = ''; + } + + return $option; + } + + private function check_data( $option, $data ) { + + $value = ( ! empty( $option['value'] ) ) ? $option['value'] : ''; + unset( $option['value'] ); + + $data['value'] = array_merge( + array( + 'type' => ( ! empty( $value ) ) ? 'predefined' : 'custom', + 'predefined' => $value, + 'custom' => '', + 'data' => ( ! empty( $option['choices'][ $value ]['css'] ) ) ? $option['choices'][ $value ]['css'] : array() + ), + (array) $data['value'] + ); + + return $data; + } + + /** + * @internal + */ + protected function _get_value_from_input( $option, $input_value ) + { + if (is_array($input_value)) { + if ( empty( $input_value['type'] ) ) { + $input_value['type'] = ( ! empty( $option['choices'] ) ) ? 'predefined' : 'custom'; + } + + if ( $input_value['type'] === 'custom') { + if( $attachment_id = intval($input_value['custom']) ) { + $input_value['predefined'] = $option['value']; + $attachment_url = wp_get_attachment_url($attachment_id); + $input_value['data'] = array( + 'icon' => $attachment_url, + 'css' => array( + 'background-image' => 'url("' . $attachment_url . '")' + ) + ); + } else { + $input_value['predefined'] = $option['value']; + $input_value['data'] = array( + 'icon' => '', + 'css' => array() + ); + } + + } else { + $input_value['predefined'] = ( isset( $input_value['predefined'] ) ) ? $input_value['predefined'] : $option['value']; + $input_value['custom'] = ''; + $input_value['data'] = ( ! empty( $option['choices'][ $input_value['predefined'] ] ) ) ? $option['choices'][ $input_value['predefined'] ] : array(); + } + } else { + $input_value = $option['value']; + } + + return $input_value; + } +} + +FW_Option_Type::register('FW_Option_Type_Background_Image'); diff --git a/scratch-parent/framework/includes/option-types/background-image/static/css/styles.css b/scratch-parent/framework/includes/option-types/background-image/static/css/styles.css new file mode 100644 index 00000000..f219cc90 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/background-image/static/css/styles.css @@ -0,0 +1,14 @@ +.fw-option-type-background-image .type .fw-option-type-radio div { + display: inline-block; + margin-left: 15px; +} + +.fw-option-type-background-image .predefined, +.fw-option-type-background-image .custom { + margin-top: 15px; +} + +.fw-option-type-background-image div.fw-option-type-radio { + margin: 0 0 9px -15px; + font-size: 14px; +} diff --git a/scratch-parent/framework/includes/option-types/background-image/static/js/scripts.js b/scratch-parent/framework/includes/option-types/background-image/static/js/scripts.js new file mode 100644 index 00000000..d65e79f5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/background-image/static/js/scripts.js @@ -0,0 +1,35 @@ +jQuery(document).ready(function ($) { + var optionTypeClass = 'fw-option-type-background-image'; + var eventNamePrefix = 'fw:option-type:background-image:'; + + fwEvents.on('fw:options:init', function (data) { + var $options = data.$elements.find('.'+ optionTypeClass +':not(.initialized)'); + + $options.find('.fw-option-type-radio').on('change', function (e) { + var $predefined = jQuery(this).closest('.fw-inner').find('.predefined'); + var $custom = jQuery(this).closest('.fw-inner').find('.custom'); + + if (e.target.value === 'custom') { + $predefined.hide(); + $custom.show(); + } else { + $predefined.show(); + $custom.hide(); + } + }); + + // route inner image-picker events as this option events + { + $options.on('fw:option-type:image-picker:clicked', '.fw-option-type-image-picker', function(e, data) { + jQuery(this).trigger(eventNamePrefix +'clicked', data); + }); + + $options.on('fw:option-type:image-picker:changed', '.fw-option-type-image-picker', function(e, data) { + jQuery(this).trigger(eventNamePrefix +'changed', data); + }); + } + + $options.addClass('initialized'); + }); + +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/background-image/view.php b/scratch-parent/framework/includes/option-types/background-image/view.php new file mode 100644 index 00000000..b2bf7df0 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/background-image/view.php @@ -0,0 +1,95 @@ + +
    > +
    style="display: none;"> + backend->option_type( 'radio' )->render( + 'type', + array( + 'type' => 'radio', + 'value' => 'predefined', + 'choices' => array( + 'predefined' => __( 'Predefined images', 'fw' ), + 'custom' => __( 'Custom image', 'fw' ) + ), + ), + array( + 'value' => $data['value']['type'], + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ); + ?> +
    + + $choice_value ) { + $choices[ $choice_key ] = array( + 'small' => array( + 'src' => $choice_value['icon'], + 'height' => 50 + ), + 'data' => array( + 'css' => $choice_value['css'] + ) + ); + } + ?> +
    style="display: none;"> + backend->option_type( 'image-picker' )->render( + 'predefined', + array( + 'type' => 'image-picker', + 'value' => $option['value'], + 'choices' => $choices + ), + array( + 'value' => ( $data['value']['type'] === 'predefined' ) ? $data['value']['predefined'] : $option['value'], + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ); + ?> +
    + +
    style="display: none;"> + backend->option_type( 'upload' )->render( + 'custom', + array( + 'type' => 'upload', + 'value' => ( $data['value']['type'] === 'custom' ) ? $data['value']['custom'] : '', + ), + array( + 'value' => ( $data['value']['type'] === 'custom' ) ? $data['value']['custom'] : '', + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ); + ?> +
    +
    \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/builder/README.md b/scratch-parent/framework/includes/option-types/builder/README.md new file mode 100644 index 00000000..3fc3b12a --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/README.md @@ -0,0 +1,138 @@ +## Create builder + +#### In PHP + +* Create class for items + +```php +abstract class FW_Option_Type_Builder_Foo_Item extends FW_Option_Type_Builder_Item +{ + final public function get_builder_type() + { + return 'builder-foo'; + } + + // ... +} +``` + +* Create builder option type + +```php +class FW_Option_Type_Builder_Foo extends FW_Option_Type_Builder +{ + final public function get_type() + { + return 'builder-foo'; + } + + final public function item_type_is_valid($item_type_instance) + { + if (!is_subclass_of($item_type_instance, 'FW_Option_Type_Builder_Foo_Item')) { + return false; + } + + return true; + } + + // ... +} + +FW_Option_Type::register('FW_Option_Type_Builder_Foo'); +``` + +#### In Javascript + +```javascript +// If you want to change Builder class for your type, attach to the event +fwEvents.trigger('fw-builder:'+ 'builder-foo' +':before-create', function(data){ + var MyBuilder = data.Builder.extend({ + // ... + }); + + data.Builder = MyBuilder; +}); +``` + +## Register item to builder + +#### In PHP + +```php +class FW_Option_Type_Builder_Foo_Item_Bar extends FW_Option_Type_Builder_Foo_Item +{ + public function get_builder_type() + { + return 'builder-foo'; + } + + public function get_type() + { + return 'bar'; + } + + public function enqueue_static() + { + wp_enqueue_style( + 'fw-builder-'. $this->get_builder_type() .'-item-'. $this->get_type(), + FW_URI .'/.../items/'. $this->get_type() .'/static/css/styles.css' + ); + + wp_enqueue_script( + 'fw-builder-'. $this->get_builder_type() .'-item-'. $this->get_type(), + FW_URI .'/.../items/'. $this->get_type() .'/static/js/scripts.js', + array( + 'fw-events', + ), + false, + true + ); + + // ... + } + + // ... +} + +FW_Option_Type_Builder::register_item_type('FW_Option_Type_Builder_Foo_Item_Bar'); +``` + +#### In JavaScript + +Attach to event and register your item __class__ (not instance!) + +```javascript +fwEvents.one('fw-builder:'+ 'builder-foo' +':register-items', function(builder){ + /** Minimal example: only required parameters */ + { + var MyItem = builder.classes.Item.extend({ + defaults: { + // required: unique type of the item (within the builder) + type: 'my-unique-item-type' + } + }); + } + + /** Full example: all possibilities */ + { + var MyItem = builder.classes.Item.extend({ + defaults: { + type: 'my-unique-item-type' + // other item data ... + }, + initialize: function(){ + this.defaultInitialize(); + + this.view = new builder.classes.ItemView({ + id: 'fw-visual-builder-item-'+ this.cid, + model: this, + template: _.template('
    ...
    ') + }); + // Also you can extend builder.classes.ItemView and create a view with more advanced functionality + } + }); + } + + builder.registerItemClass(MyItem); +}); +``` \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/builder/class-fw-option-type-builder.php b/scratch-parent/framework/includes/option-types/builder/class-fw-option-type-builder.php new file mode 100644 index 00000000..01d1cb05 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/class-fw-option-type-builder.php @@ -0,0 +1,4 @@ + '

    Item Title

    ', + * ), + * array( + * 'tab' => __('Tab Title', 'fw'), + * 'html' => '

    Item Title

    ', + * ), + * ... + * ) + */ + abstract public function get_thumbnails(); + + /** + * Called when builder is rendered + */ + abstract public function enqueue_static(); + + final public function __construct() + { + // Maybe in the future this method will have some functionality + + if (method_exists($this, '_init')) { + $this->_init(); + } + } + + /** + * Overwrite this method if you want to change/fix attributes that comes from js + * @param $attributes array Backbone Item (Model) attributes + * @return mixed + */ + public function get_value_from_attributes($attributes) + { + return $attributes; + } +} diff --git a/scratch-parent/framework/includes/option-types/builder/extends/class-fw-option-type-builder.php b/scratch-parent/framework/includes/option-types/builder/extends/class-fw-option-type-builder.php new file mode 100644 index 00000000..d5f36337 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/extends/class-fw-option-type-builder.php @@ -0,0 +1,298 @@ + item-instance} + */ + private $item_types = array(); + + /** + * @param string|FW_Option_Type_Builder_Item $item_type_class + */ + final public static function register_item_type($item_type_class) + { + if (is_array(self::$item_types_pending_registration)) { + // Item types never requested. Continue adding to pending + self::$item_types_pending_registration[] = $item_type_class; + } else { + self::$item_types_pending_registration = array($item_type_class); + + self::register_pending_item_types(); + } + } + + private static function register_pending_item_types() + { + if (!is_array(self::$item_types_pending_registration)) { + // all pending item types already registered + return; + } + + foreach (self::$item_types_pending_registration as $item_type_class) { + if (is_string($item_type_class)) { + $item_type_instance = new $item_type_class; + } else { + $item_type_instance = $item_type_class; + } + + unset($item_type_class); + + if (!is_subclass_of($item_type_instance, 'FW_Option_Type_Builder_Item')) { + trigger_error('Invalid builder item type class '. get_class($item_type_instance), E_USER_WARNING); + return; + } + + $builder_type = $item_type_instance->get_builder_type(); + + /** + * @var FW_Option_Type_Builder $builder_type_instance + */ + $builder_type_instance = fw()->backend->option_type($builder_type); + + if (!$builder_type_instance->item_type_is_valid($item_type_instance)) { + trigger_error('Invalid builder item. (type: '. $item_type_instance->get_type() .')', E_USER_WARNING); + return; + } + + $builder_type_instance->_register_item_type($item_type_instance); + } + + self::$item_types_pending_registration = false; + } + + /** + * @param FW_Option_Type_Builder_Item $item_type_instance + */ + private function _register_item_type($item_type_instance) + { + if (isset($this->item_types[$item_type_instance->get_type()])) { + trigger_error('Builder item already registered (type: '. $item_type_instance->get_type() .')', E_USER_ERROR); + return; + } + + $this->item_types[$item_type_instance->get_type()] = $item_type_instance; + } + + /** + * @return FW_Option_Type_Builder_Item[] + */ + final protected function get_item_types() + { + if (is_array(self::$item_types_pending_registration)) { + /** + * Item types requested first time. + * Register pending item types. + */ + self::register_pending_item_types(); + } + + return $this->item_types; + } + + /** + * Overwrite this method to force your builder type items to extend custom class or to have custom requirements + * @param FW_Option_Type_Builder_Item $item_type_instance + * @return bool + */ + protected function item_type_is_valid($item_type_instance) + { + return is_subclass_of($item_type_instance, 'FW_Option_Type_Builder_Item'); + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array( + 'json' => '[]' + ) + ); + } + + /** + * @internal + */ + final protected function _render($id, $option, $data) + { + { + wp_enqueue_style( + 'fw-option-builder', + FW_URI .'/includes/option-types/builder/static/css/builder.css', + array('fw'), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-builder', + FW_URI .'/includes/option-types/builder/static/js/builder.js', + array( + 'jquery-ui-draggable', + 'jquery-ui-sortable', + 'fw', + 'fw-events', + 'backbone', + 'backbone-relational' + ), + fw()->manifest->get_version(), + true + ); + } + + { + wp_enqueue_style( + 'fw-option-builder-helpers', + FW_URI .'/includes/option-types/builder/static/css/helpers.css', + array('fw-option-builder'), + fw()->manifest->get_version() + ); + + wp_enqueue_media(); + + wp_enqueue_script( + 'fw-option-builder-helpers', + FW_URI .'/includes/option-types/builder/static/js/helpers.js', + array('fw-option-builder',), + fw()->manifest->get_version(), + true + ); + + wp_localize_script( + 'fw-option-builder-helpers', + 'fw_option_type_builder_helpers', + array( + 'l10n' => array( + 'save' => __('Save', 'fw') + ) + ) + ); + } + + if (method_exists($this, 'enqueue_static')) { + $this->enqueue_static($id, $option, $data); + } + + /** + * array( + * 'Tab title' => array( + * '', + * '', + * '', + * ), + * 'Tab title' => array( + * '', + * ) + * ) + */ + $thumbnails = array(); + + foreach ($this->get_item_types() as $item) { + /** @var FW_Option_Type_Builder_Item $item */ + + $item->enqueue_static(); + + foreach ($item->get_thumbnails() as $thumbnail) { + if (!isset($thumbnail['tab'])) { + $tab_title = '~'; + } else { + $tab_title = $thumbnail['tab']; + } + + if (!isset($thumbnails[$tab_title])) { + $thumbnails[$tab_title] = array(); + } + + $thumbnails[$tab_title][] = + '
    '. + $thumbnail['html']. + '
    '; + } + } + + if (method_exists($this, 'sort_thumbnails')) { + $this->sort_thumbnails($thumbnails); + } + + return fw_render_view(dirname(__FILE__) .'/../view.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + 'thumbnails' => $thumbnails, + 'option_type'=> $this->get_type() + )); + } + + /** + * {@inheritdoc} + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (empty($input_value)) { + $input_value = $option['value']['json']; + } + + $items = json_decode($input_value, true); + + if (!$items) { + $items = array(); + } + + return array( + 'json' => json_encode( + $this->get_value_from_items($items) + ), + ); + } + + /** + * Get correct value from items + * @param array $items + * @return array + */ + public function get_value_from_items($items) + { + /** + * @var FW_Option_Type_Builder_Item[] $item_types + */ + $item_types = $this->get_item_types(); + + $fixed_items = array(); + + foreach ($items as $item_attributes) { + if (!isset($item_attributes['type']) || !isset($item_types[ $item_attributes['type'] ])) { + // invalid item type + continue; + } + + $fixed_item_attributes = $item_types[ $item_attributes['type'] ]->get_value_from_attributes($item_attributes); + + if (isset($fixed_item_attributes['_items'])) { + $fixed_item_attributes['_items'] = $this->get_value_from_items($fixed_item_attributes['_items']); + } + + $fixed_items[] = $fixed_item_attributes; + } + + return $fixed_items; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'full'; + } +} diff --git a/scratch-parent/framework/includes/option-types/builder/static/css/builder.css b/scratch-parent/framework/includes/option-types/builder/static/css/builder.css new file mode 100644 index 00000000..f40c00c5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/static/css/builder.css @@ -0,0 +1,130 @@ +.fw-option-type-builder .builder-items-types { + padding: 0; +} + + +/* builder-item-type */ + +.fw-option-type-builder .builder-item-type { + width: 70px; + height: 70px; + border: 1px solid #e1e1e1; + font-size: 11px; + margin: 0 5px 5px 0; + background-color: #ffffff; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.fw-option-type-builder .builder-item-type:hover, +.fw-option-type-builder .builder-item-type.ui-draggable-dragging { + border-color: #8f8f8f; + cursor: move; + z-index: 9999; +} + +.fw-option-type-builder .builder-item-type .builder-item-type-icon-title { + padding: 5px; +} + +.fw-option-type-builder .builder-item-type .item-type-icon-title .item-type-icon { + text-align: center; +} + +.fw-option-type-builder .builder-item-type .item-type-icon-title .item-type-icon .dashicons { + font-size: 30px; + display: inline-table; +} + +.fw-option-type-builder .builder-item-type .item-type-icon-title .item-type-title { + text-align: center; +} + +/* end: builder-item-type */ + + +.fw-option-type-builder .builder-root-items { + padding-top: 15px; + border-top: 1px solid #eeeeee; +} + +.fw-option-type-builder .builder-items { + padding: 10px; +} + +.fw-option-type-builder .builder-items .builder-item { + float: none; + display: inline-block; + vertical-align: top; + padding: 10px; + cursor: move; +} + +.fw-option-type-builder .builder-items .builder-item.new-item { + animation: fwGrowIn .3s ease-in-out; + animation-iteration-count: 1; + + -webkit-animation: fwGrowIn .3s ease-in-out; + -webkit-animation-iteration-count: 1; + + -moz-animation: fwGrowIn .3s ease-in-out; + -moz-animation-iteration-count: 1; + + -o-animation: fwGrowIn .3s ease-in-out; + -o-animation-iteration-count: 1; + + -ms-animation: fwGrowIn .3s ease-in-out; + -ms-animation-iteration-count: 1; +} + +.fw-option-type-builder .builder-root-items .builder-item-type.ui-sortable-placeholder { + display: inline-block; + float: none; +} + + +/* allow/deny items in _items */ + +.fw-option-type-builder .builder-items .builder-item.fw-builder-item-allow-incoming-type > div { +} + +.fw-option-type-builder .builder-items .builder-item.fw-builder-item-deny-incoming-type > div { +} + +/* end: allow/deny*/ + + +/* backend fixes */ + +.fw-backend-option-type-builder { + padding-left: 0; + padding-top: 0; + padding-right: 0; +} + +.fw-backend-option-type-builder > .fw-backend-option-desc { + padding: 15px 25px 0; +} + +.fw-option-type-builder .fw-backend-option-type-html { + padding-top: 0; + border-bottom: 0; +} + +/* end: backend fixes */ + + +/* qtip */ + +.qtip-fw-builder { + padding: 5px 10px; + min-width: 0; +} + +.qtip-fw-builder .qtip-content { + text-align: center; +} + +/* end: qtip */ \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/builder/static/css/helpers.css b/scratch-parent/framework/includes/option-types/builder/static/css/helpers.css new file mode 100644 index 00000000..c31df22b --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/static/css/helpers.css @@ -0,0 +1,20 @@ +/* Width Changer */ + +.fw-builder-item-width-changer { + white-space: nowrap; + font-weight: bold; +} + +.fw-builder-item-width-changer a { + font-size: 13px; + font-weight: bold; + line-height: 18px; + width: 18px; + height: 18px; + outline: 0; +} + +.fw-builder-item-width-changer.is-first a.decrease-width, +.fw-builder-item-width-changer.is-last a.increase-width { + color: #b2b2b2; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/builder/static/js/builder.js b/scratch-parent/framework/includes/option-types/builder/static/js/builder.js new file mode 100644 index 00000000..e765d756 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/static/js/builder.js @@ -0,0 +1,1007 @@ +jQuery(document).ready(function($){ + /** Some functions */ + { + /** + * Loop recursive through all items in given collection + */ + function forEachItemRecursive(collection, callback) { + collection.each(function(item){ + callback(item); + + forEachItemRecursive(item.get('_items'), callback); + }); + } + } + + var Builder = Backbone.Model.extend({ + defaults: { + type: null // required + }, + /** + * Extract item type from class + * @param {this.classes.Item} ItemClass + * @returns {String} + */ + getItemClassType: function(ItemClass) { + return (typeof ItemClass.prototype.defaults === 'function') + ? ItemClass.prototype.defaults().type + : ItemClass.prototype.defaults.type; + }, + /** + * @param {String} type + * @returns {this.classes.Item} + */ + getRegisteredItemClassByType: function(type) { + return this.registeredItemsClasses[type]; + }, + /** + * Register Item Class (with unique type) + * @param {this.classes.Item} ItemClass + * @returns {boolean} + */ + registerItemClass: function(ItemClass) { + if (!(ItemClass.prototype instanceof this.classes.Item)) { + console.error('Tried to register Item Type Class that does not extend this.classes.Item', ItemClass); + return false; + } + + var type = this.getItemClassType(ItemClass); + + if (typeof type != 'string') { + console.error('Invalid Builder Item type: '+ type, ItemClass); + return false; + } + + if (typeof this.registeredItemsClasses[type] != 'undefined') { + console.error('Builder Item type "'+ type +'" already registered', ItemClass); + return false; + } + + this.registeredItemsClasses[type] = ItemClass; + + return true; + }, + /** + * ! Do not rewrite this (it's final) + * @private + * + * Properties created in initialize(): + * + * Classes to extend + * - classes.Item + * - classes.ItemView + * - classes.Items + * - classes.ItemsView + * + * From this classes will be created items instances + * { 'type' => Class } + * - registeredItemsClasses + * + * Reference to root this.classes.Items Collection instance that contains all items + * - rootItems + * + * Hidden input that stores JSON.stringify(this.rootItems) + * - $input + */ + initialize: function(attributes, options) { + var builder = this; + + /** + * todo: To be able to extend and customize for e.g. only Item class. To not rewrite entire .initialize() + * this.__definePrivateMethods() + * this.__defineItem() + * this.__defineItemView() + * this.__defineItems() + * this.__defineItemsView() + */ + + /** + * Assign a value to define this property inside this, not in prototype + * Instances of Builder should not share items + */ + this.registeredItemsClasses = {}; + + /** Define private functions accessible only within this method */ + { + /** + * Find Item instance recursive in Items collection + * @param {this.classes.Items} collection + * @param {Object} itemAttr + * @return {this.classes.Item|null} + */ + function findItemRecursive(items, itemAttr) { + var item = items.get(itemAttr); + + if (item) { + return item; + } + + items.each(function(_item){ + if (item) { + // stop search if item found + return false; + } + + /** @var {builder.classes.Item} _item */ + item = findItemRecursive( + _item.get('_items'), + itemAttr + ); + }); + + return item; + } + + /** + * (Re)Create Items from json + * + * Used on collection.reset([...]) to create nested items + * + * @param {this.classes.Item} item + * @param {Array} _items + * @returns {boolean} + * @private + */ + function createItemsFromJSON(item, _items) { + if (!_items) { + return false; + } + + _.each(_items, function(_item) { + var ItemClass = builder.getRegisteredItemClassByType(_item['type']); + + if (!ItemClass) { + return; + } + + var __items = _item['_items']; + + delete _item['_items']; + + var subItem = new ItemClass(_item); + + item.get('_items').add(subItem); + + createItemsFromJSON(subItem, __items); + }); + + return true; + } + + // Mark new added items with special class, to be able to add css effects to it + { + var markItemAsNew; + + (function(){ + var lastNewItem = false; + + var rootItemsInitialized = false; + + var removeClassTimeout; + var removeClassAfter = 700; + + markItemAsNew = function (item) { + clearTimeout(removeClassTimeout); + + if (lastNewItem) { + lastNewItem.view.$el.removeClass('new-item'); + } + + item.view.$el.addClass('new-item'); + + lastNewItem = item; + + removeClassTimeout = setTimeout(function(){ + if (lastNewItem) { + lastNewItem.view.$el.removeClass('new-item'); + } + }, removeClassAfter); + + if (!rootItemsInitialized) { + builder.rootItems.on('builder:change', function(){ + if (lastNewItem) { + lastNewItem.view.$el.removeClass('new-item'); + } + + lastNewItem = false; + }); + + rootItemsInitialized = true; + } + } + })(); + } + } + + /** Define classes */ + { + this.classes = {}; + + /** Items */ + { + this.classes.Items = Backbone.Collection.extend({ + /** + * Guess which item type to create from json + * (usually called on .reset()) + */ + model: function(attrs, options) { + do { + if (typeof attrs == 'function') { + // It's a class. Check if has correct type + if (builder.getItemClassType(attrs)) { + return attrs; + } else { + break; + } + } else if (typeof attrs == 'object') { + /** + * it's an object with attributes for new instance + * check if has correct type in it (get registered class with this type) + */ + + var ItemClass = builder.getRegisteredItemClassByType(attrs['type']); + + if (!ItemClass) { + break; + } + + var _items = attrs['_items']; + + delete attrs['_items']; + + var item = new ItemClass(attrs); + + createItemsFromJSON(item, _items); + + return item; + } + } while(false); + + console.error('Cannot detect Item type', attrs, options); + + return new builder.classes.Item; + }, + /** + * View that contains sortable with items views + */ + view: null, + initialize: function() { + this.defaultInitialize(); + + this.view = new builder.classes.ItemsView({ + collection: this + }); + }, + /** + * It is required to call this method in .initialize() + */ + defaultInitialize: function() { + this.on('add', function(item) { + // trigger custom event on rootItems to update input value + builder.rootItems.trigger('builder:change'); + + markItemAsNew(item); + }); + + this.on('remove', function(item) { + // trigger custom event on rootItems to update input value + builder.rootItems.trigger('builder:change'); + }); + } + }); + + this.classes.ItemsView = Backbone.View.extend({ + // required + + collection: null, + + // end: required + + tagName: 'div', + className: 'builder-items fw-row fw-border-box-sizing', + template: _.template(''), + events: {}, + initSortableTimeout: 0, + initialize: function() { + this.defaultInitialize(); + }, + /** + * It is required to call this method in .initialize() + */ + defaultInitialize: function() { + this.listenTo(this.collection, 'add change remove reset', this.render); + + this.render(); + }, + render: function() { + /** + * First .detach() elements + * to prevent them to be removed (reset) on .html('...') replace + */ + { + this.collection.each(function(item) { + item.view.$el.detach(); + }); + } + + if (this.$el.hasClass('ui-sortable')) { + this.$el.sortable('destroy'); + } + + this.$el.html(this.template({ + items: this.collection + })); + + var that = this; + + this.collection.each(function(item) { + that.$el.append(item.view.$el); + }); + + /** + * init sortable with delay, after element added to DOM + * fixes bug: sortable sometimes not initialized if element is not in DOM + */ + { + clearTimeout(this.initSortableTimeout); + + this.initSortableTimeout = setTimeout(function(){ + that.initSortable(); + }, 12); + } + + return this; + }, + initSortable: function(){ + if (this.$el.hasClass('ui-sortable')) { + // already initialized + return false; + } + + // remove "allowed" and "denied" classes from all items + function itemsRemoveAllowedDeniedClasses() { + builder.rootItems.view.$el.removeClass( + 'fw-builder-item-allow-incoming-type fw-builder-item-deny-incoming-type' + ); + + forEachItemRecursive(builder.rootItems, function(item){ + item.view.$el.removeClass( + 'fw-builder-item-allow-incoming-type fw-builder-item-deny-incoming-type' + ); + }); + } + + this.$el.sortable({ + items: '> .builder-item', + connectWith: '#'+ builder.$input.closest('.fw-option-type-builder').attr('id') +' .builder-root-items .builder-items', + distance: 10, + opacity: 0.6, + start: function(event, ui) { + // check if it is an exiting item (and create variables) + { + // extract cid from view id + var movedItemCid = ui.item.attr('id'); + + if (!movedItemCid) { + // not an existing item, it's a thumbnail from draggable + return; + } + + movedItemCid = movedItemCid.split('-').pop(); + + if (!movedItemCid) { + // not an existing item, it's a thumbnail from draggable + return; + } + + var movedItem = findItemRecursive( + builder.rootItems, + {cid: movedItemCid} + ); + + if (!movedItem) { + console.warn('Item not found (cid: "'+ movedItemCid +'")'); + return; + } + } + + var movedItemType = movedItem.get('type'); + + /** + * add "allowed" classes to items vies where allowIncomingType(movedItemType) returned true + * else add "denied" class + */ + { + { + if (movedItem.allowDestinationType(null)) { + builder.rootItems.view.$el.addClass('fw-builder-item-allow-incoming-type'); + } else { + builder.rootItems.view.$el.addClass('fw-builder-item-deny-incoming-type'); + } + } + + forEachItemRecursive(builder.rootItems, function(item){ + if (item.cid === movedItemCid) { + // this is current moved item + return; + } + + if ( + item.allowIncomingType(movedItemType) + && + movedItem.allowDestinationType(item.get('type')) + ) { + item.view.$el.addClass('fw-builder-item-allow-incoming-type'); + } else { + item.view.$el.addClass('fw-builder-item-deny-incoming-type'); + } + }); + } + }, + stop: function() { + itemsRemoveAllowedDeniedClasses(); + }, + receive: function(event, ui) { + // sometimes the "stop" event is not triggered and classes remains + itemsRemoveAllowedDeniedClasses(); + + { + var currentItemType = null; // will remain null if it is root collection + var currentItem; + + if (this.collection._item) { + currentItemType = this.collection._item.get('type'); + currentItem = this.collection._item; + } + } + + var incomingItemType = ui.item.attr('data-builder-item-type'); + + if (incomingItemType) { + // received item type from draggable + + var IncomingItemClass = builder.getRegisteredItemClassByType(incomingItemType); + + if (IncomingItemClass) { + if ( + IncomingItemClass.prototype.allowDestinationType(currentItemType) + && + ( + !currentItemType + || + currentItem.allowIncomingType(incomingItemType) + ) + ) { + this.collection.add( + new IncomingItemClass({}, { + $thumb: ui.item + }), + { + at: this.$el.find('> .builder-item-type').index() + } + ); + } else { + // replace all html, so dragged element will be removed + this.render(); + } + } else { + console.error('Invalid item type: '+ incomingItemType); + + this.render(); + } + } else { + // received existing item from another sortable + + if (!ui.item.attr('id')) { + console.warn('Invalid view id', ui.item); + return; + } + + // extract cid from view id + var incomingItemCid = ui.item.attr('id').split('-').pop(); + + var incomingItem = findItemRecursive( + builder.rootItems, + {cid: incomingItemCid} + ); + + if (!incomingItem) { + console.warn('Item not found (cid: "'+ incomingItemCid +'")'); + return; + } + + var incomingItemType = incomingItem.get('type'); + var IncomingItemClass = builder.getRegisteredItemClassByType(incomingItemType); + + if ( + IncomingItemClass.prototype.allowDestinationType(currentItemType) + && + ( + !currentItemType + || + currentItem.allowIncomingType(incomingItemType) + ) + ) { + // move item from one collection to another + { + var at = ui.item.index(); + + // prevent 'remove', that will remove all events from the element + incomingItem.view.$el.detach(); + + incomingItem.collection.remove(incomingItem); + + this.collection.add(incomingItem, { + at: at + }); + } + } else { + console.log('[Builder] Item move denied'); + ui.sender.sortable('cancel'); + } + } + }.bind(this), + update: function (event, ui) { + if (ui.item.attr('data-ignore-update-once')) { + ui.item.removeAttr('data-ignore-update-once'); + return; + } + + if (ui.item.attr('data-builder-item-type')) { + // element just received from draggable, it is not builder item yet, do nothing + return; + } + + if (!ui.item.attr('id')) { + console.warn('Invalid item, no id'); + return; + } + + if (!$(this).find('> #'+ ui.item.attr('id') +':first').length) { + // Item not in sortable, probably moved to another sortable, do nothing + + /** + * Right after this event, is expected to be next 'update' for on same item. + * But between this two 'update' is a 'receive' that takes care about item move from + * one collection to another and place ar right index position in destination model, + * so it is better to ignore next coming 'update'. + * Set a special attribute to ignore 'update' once + */ + ui.item.attr('data-ignore-update-once', 'true'); + + return; + } + + // extract cid from view id + var itemCid = ui.item.attr('id').split('-').pop(); + + var item = findItemRecursive( + builder.rootItems, + {cid: itemCid} + ); + + if (!item) { + console.warn('Item not found (cid: "'+ itemCid +'")'); + return; + } + + var index = ui.item.index(); + + // change item position in collection + { + var collection = item.collection; + + // prevent 'remove', that will remove all events from the element + item.view.$el.detach(); + + collection.remove(item); + + collection.add(item, {at: index}); + } + } + }); + + return true; + } + }); + } + + /** Item */ + { + this.classes.Item = Backbone.RelationalModel.extend({ + // required + + defaults: { + /** @type {String} Your item unique type (withing the builder) */ + type: null + }, + + /** @type {builder.classes.ItemView} */ + view: null, + + // end: required + + /** ! Do not overwrite this property */ + relations: [ + { + type: Backbone.HasMany, + key: '_items', + //relatedModel: builder.classes.Item, // class does not exists at this point, initialized below + collectionType: builder.classes.Items, + collectionKey: '_item' + } + ], + initialize: function(){ + this.view = new builder.classes.ItemView({ + id: 'fw-builder-item-'+ this.cid, + model: this + }); + + this.defaultInitialize(); + }, + /** + * It is required to call this method in .initialize() + */ + defaultInitialize: function() { + // trigger custom event on rootItems to update input value + this.on('change', function() { + builder.rootItems.trigger('builder:change'); + }); + }, + /** + * Item decide if allows an incoming item type to be placed inside it's _items + * + * @param {String} type + * @returns {boolean} + */ + allowIncomingType: function(type) { + return false; + }, + /** + * Item decide if allows to be placed into _items of another item type + * + * ! Do not use "this" in this method, it will be called without an instance via Class.prototype.allowDestinationType() + * + * @param {String|null} type String - item type; null - root items + * @returns {boolean} + */ + allowDestinationType: function(type) { + return true; + } + }); + + { + this.classes.Item.prototype.relations[0].relatedModel = this.classes.Item; + } + + this.classes.ItemView = Backbone.View.extend({ + // required + + /** @type {builder.classes.Item} */ + model: null, + /** @type {String} 'any-string-'+ this.model.cid */ + id: null, + + // end: required + + tagName: 'div', + className: 'builder-item fw-border-box-sizing fw-col-xs-12', + template: _.template('
    Default View
    '), + initialize: function(){ + this.defaultInitialize(); + this.render(); + }, + /** + * It is required to call this method in .initialize() + */ + defaultInitialize: function() { + this.listenTo(this.model, 'change', this.render); + }, + render: function() { + this.defaultRender(); + }, + defaultRender: function(templateData) { + var _items = this.model.get('_items'); + + /** + * First .detach() elements + * to prevent them to be removed (reset) on .html('...') replace + */ + _items.view.$el.detach(); + + this.$el.html( + this.template( + templateData || {} + ) + ); + + /** + * Sometimes sub items sortable view is not initialized or (destroyed if was initialized) + * Tell it to render and maybe it will fix itself + */ + if (!_items.view.$el.hasClass('ui-sortable')) { + _items.view.render(); + } + + /** + * replace
    with builder.classes.ItemsView.$el + */ + this.$el.find('.builder-items:first').replaceWith( + _items.view.$el + ); + + return this; + } + }); + } + } + + this.rootItems = new this.classes.Items; + + fwEvents.trigger('fw-builder:'+ this.get('type') +':register-items', this); + + // prepare this.$input + { + if (typeof options.$input == 'undefined') { + console.warn('$input not specified. Items will no be saved'); + + this.$input = $(''); + } else { + this.$input = options.$input; + } + + // recover saved items from input + { + var savedItems = []; + + try { + savedItems = JSON.parse(this.$input.val()); + } catch (e) { + console.error('Failed to recover items from input', e); + } + + this.rootItems.reset(savedItems); + + delete savedItems; + } + + // listen to items changes and update input + { + // use timeout to not load browser/cpu when there are many changes at once (for e.g. on .reset()) + var saveTimeout = 0; + + this.listenTo(this.rootItems, 'builder:change', function(){ + clearTimeout(saveTimeout); + + saveTimeout = setTimeout(function(){ + builder.$input.val( + JSON.stringify(builder.rootItems) + ); + }, 100); + }); + } + } + } + }); + + /** + * Create qTips for elements with data-hover-tip="Tip Text" attribute + */ + var RootItemsTips = (function(rootItems){ + /** + * Store all created qTip instances APIs + */ + this.tipsAPIs = []; + + this.resetTimeout = 0; + + this.resetTips = function() { + _.each(this.tipsAPIs, function(api) { + api.destroy(true); + }); + + this.tipsAPIs = []; + + var that = this; + + rootItems.view.$el.find('[data-hover-tip]').each(function(){ + $(this).qtip({ + position: { + at: 'top center', + my: 'bottom center', + viewport: rootItems.view.$el.parent() + }, + style: { + classes: 'qtip-fw qtip-fw-builder', + tip: { + width: 12, + height: 5 + } + }, + content: { + text: $(this).attr('data-hover-tip') + } + }); + + that.tipsAPIs.push( + $(this).qtip('api') + ); + }); + }; + + // initialize + { + this.resetTips(); + + var that = this; + + rootItems.on('builder:change', function(){ + clearTimeout(that.resetTimeout); + + that.resetTimeout = setTimeout(function(){ + that.resetTips(); + }, 100); + }); + } + }); + + fwEvents.on('fw:options:init', function (data) { + var $options = data.$elements.find('.fw-option-type-builder:not(.initialized)'); + + $options.closest('.fw-backend-option').addClass('fw-backend-option-type-builder'); + + $options.each(function(){ + var $this = $(this); + var id = $this.attr('id'); + var type = $this.attr('data-builder-option-type'); + + /** + * Create instance of Builder + */ + { + var data = { + type: type, + $option: $this, + $input: $this.find('> input:first'), + $types: $this.find('.builder-items-types:first'), + $rootItems: $this.find('.builder-root-items:first') + }; + + var eventData = $.extend(data, { + /** + * In event you can extend (customize/change) and replace this (property) class + */ + Builder: Builder + }); + + fwEvents.trigger('fw-builder:'+ type +':before-create', eventData); + + var builder = new eventData.Builder( + { + type: data.type + }, + { + $input: data.$input + } + ); + + builder.rootItems.view.$el.appendTo(data.$rootItems); + + new RootItemsTips(builder.rootItems); + } + + /** + * Init draggable thumbnails + */ + $this.find('.builder-items-types .builder-item-type').draggable({ + connectToSortable: '#'+ id +' .builder-root-items .builder-items', + helper: 'clone', + distance: 10, + start: function(event, ui) { + var movedType = ui.helper.attr('data-builder-item-type'); + + if (!movedType) { + return; + } + + var MovedTypeClass = builder.getRegisteredItemClassByType(movedType); + + if (!MovedTypeClass) { + return; + } + + /** + * add "allowed" classes to items vies where allowIncomingType(movedType) returned true + * else add "denied" class + */ + { + { + if (MovedTypeClass.prototype.allowDestinationType(null)) { + builder.rootItems.view.$el.addClass('fw-builder-item-allow-incoming-type'); + } else { + builder.rootItems.view.$el.addClass('fw-builder-item-deny-incoming-type'); + } + } + + forEachItemRecursive(builder.rootItems, function(item){ + if ( + item.allowIncomingType(movedType) + && + MovedTypeClass.prototype.allowDestinationType(item.get('type')) + ) { + item.view.$el.addClass('fw-builder-item-allow-incoming-type'); + } else { + item.view.$el.addClass('fw-builder-item-deny-incoming-type'); + } + }); + } + }, + stop: function() { + // remove "allowed" and "denied" classes from all items + { + builder.rootItems.view.$el.removeClass( + 'fw-builder-item-allow-incoming-type fw-builder-item-deny-incoming-type' + ); + + forEachItemRecursive(builder.rootItems, function(item){ + item.view.$el.removeClass( + 'fw-builder-item-allow-incoming-type fw-builder-item-deny-incoming-type' + ); + }); + } + } + }); + + /** + * Add item on thumbnail click + */ + $this.find('.builder-items-types').on('click', '.builder-item-type', function(){ + var $itemType = $(this); + + var itemType = $itemType.attr('data-builder-item-type'); + + if (itemType) { + var ItemTypeClass = builder.getRegisteredItemClassByType(itemType); + + if (ItemTypeClass) { + if (ItemTypeClass.prototype.allowDestinationType(null)) { + builder.rootItems.add( + new ItemTypeClass({}, { + $thumb: $itemType + }) + ); + } + } else { + console.error('Invalid item type: '+ itemType); + } + } else { + console.error('Cannot extract item type from clicked thumbnail'); + } + }); + + /** + * Add tips to thumbnails + */ + $this.find('.builder-items-types .builder-item-type [data-hover-tip]').each(function(){ + $(this).qtip({ + position: { + at: 'top center', + my: 'bottom center' + }, + style: { + classes: 'qtip-fw qtip-fw-builder', + tip: { + width: 12, + height: 5 + } + }, + content: { + text: $(this).attr('data-hover-tip') + } + }); + }); + }); + + $options.addClass('initialized'); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/builder/static/js/helpers.js b/scratch-parent/framework/includes/option-types/builder/static/js/helpers.js new file mode 100644 index 00000000..93c417e4 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/static/js/helpers.js @@ -0,0 +1,312 @@ +var FwBuilderComponents = { + Item: {}, + ItemView: {}, + Items: {}, + ItemsView: {} +}; + +/** + * Change item width + * + * Usage: + * + * // in ItemView.initialize() + * + * this.widthChangerView = new FwBuilderComponents.ItemView.WidthChanger({ + * model: this.model, + * view: this, + * widths: [ + * { + * text: '1/12', + * value: 1, // or 8.33333333 as % + * itemViewClass: 'fw-col-sm-1' + * }, + * //... + * { + * text: '1/1', + * value: 12, // or 100 as % + * itemViewClass: 'fw-col-sm-12' + * } + * ], + * modelAttribute: 'width', + * }); + * + * // in ItemView.render() + * + * this.$('.some-class').append( this.widthChangerView.$el ); + * + * this.widthChangerView.delegateEvents(); // rebind events after element "remove" happened + */ +FwBuilderComponents.ItemView.WidthChanger = Backbone.View.extend({ + tagName: 'div', + className: 'fw-builder-item-width-changer', + template: _.template( + ''+ + ' <%- width %> '+ + '' + ), + events: { + 'click .decrease-width': 'decreaseWidth', + 'click .increase-width': 'increaseWidth' + }, + widths: [ + { + 'text': '1/12', + 'value': 1, + 'itemViewClass': 'fw-col-sm-1' + }, + { + 'text': '2/12', + 'value': 2, + 'itemViewClass': 'fw-col-sm-2' + }, + { + 'text': '3/12', + 'value': 3, + 'itemViewClass': 'fw-col-sm-3' + }, + { + 'text': '4/12', + 'value': 4, + 'itemViewClass': 'fw-col-sm-4' + }, + { + 'text': '5/12', + 'value': 5, + 'itemViewClass': 'fw-col-sm-5' + }, + { + 'text': '6/12', + 'value': 6, + 'itemViewClass': 'fw-col-sm-6' + }, + { + 'text': '7/12', + 'value': 7, + 'itemViewClass': 'fw-col-sm-7' + }, + { + 'text': '8/12', + 'value': 8, + 'itemViewClass': 'fw-col-sm-8' + }, + { + 'text': '9/12', + 'value': 9, + 'itemViewClass': 'fw-col-sm-9' + }, + { + 'text': '10/12', + 'value': 10, + 'itemViewClass': 'fw-col-sm-10' + }, + { + 'text': '11/12', + 'value': 11, + 'itemViewClass': 'fw-col-sm-11' + }, + { + 'text': '12/12', + 'value': 12, + 'itemViewClass': 'fw-col-sm-12' + } + ], + /** + * The attribute name that will be changed in item on width changes + * this.model.set(this.modelAttribute, this.widths[N].value) + */ + modelAttribute: 'width', + initialize: function(options) { + _.extend(this, _.pick(options, + 'view', + 'widths', + 'modelAttribute' + )); + + // set special properties for first and last width + { + this.widths[0].first = true; + this.widths[ this.widths.length - 1 ].last = true; + } + + this.listenTo(this.model, 'change:' + this.modelAttribute, this.render); + + this.render(); + }, + render: function() { + this.updateWidth(); + + var widthValue = this.model.get(this.modelAttribute); + var width = _.findWhere(this.widths, {value: widthValue}); + var widthText = '?'; + + if (width) { + widthText = width.text; + } + + { + this.$el.removeClass('is-first is-last'); + + if (!!width.first) { + this.$el.addClass('is-first'); + } + + if (!!width.last) { + this.$el.addClass('is-last'); + } + } + + this.$el.html( + this.template({ + width: widthText + }) + ); + }, + decreaseWidth: function() { + var widthValue = this.model.get(this.modelAttribute); + var widthsValues = _.pluck(this.widths, 'value'); + var currentWidthIndex = _.indexOf(widthsValues, widthValue); + + if (currentWidthIndex == -1) { + // Current value does not exists (invalid) set first width + widthValue = widthsValues[0]; + } else if (currentWidthIndex == 0) { + // Do nothing, this is the smallest width + } else { + // Set smaller width + widthValue = widthsValues[currentWidthIndex - 1]; + } + + this.updateWidth(widthValue); + }, + increaseWidth: function() { + var widthValue = this.model.get(this.modelAttribute); + var widthsValues = _.pluck(this.widths, 'value'); + var currentWidthIndex = _.indexOf(widthsValues, widthValue); + + if (currentWidthIndex == -1) { + // Current value does not exists (invalid) set last width + widthValue = widthsValues[ widthsValues.length - 1 ]; + } else if (currentWidthIndex == widthsValues.length - 1) { + // Do nothing, this is the biggest width + } else { + // Set bigger width + widthValue = widthsValues[currentWidthIndex + 1]; + } + + this.updateWidth(widthValue); + }, + updateWidth: function(widthValue) { + if (typeof widthValue == 'undefined') { + widthValue = this.model.get(this.modelAttribute); + } + + var widthsValues = _.pluck(this.widths, 'value'); + + // check if correct + if (-1 == _.indexOf(widthsValues, widthValue)) { + // set default + widthValue = widthsValues[0]; + } + + if (widthValue != this.model.get(this.modelAttribute)) { + // set only when is different, to prevent trigger actions on those who listens to model 'change' + this.model.set(this.modelAttribute, widthValue); + } + + var itemViewClass = _.findWhere(this.widths, {value: widthValue}).itemViewClass; + + this.view.$el + .removeClass( + _.pluck(this.widths, 'itemViewClass').join(' ') + ) + .addClass(itemViewClass); + } +}); + +/** + * Usage: + * + * // in ItemView.initialize() + * + * this.inlineEditor = new FwBuilderComponents.ItemView.InlineTextEditor({ + * model: item, + * editAttribute: 'model_attr_name' // also is available nested attribute property notation: 'a/b/c' will do {a: {b: {c: 'value'}}} + * }) + * + * // in ItemView.render() + * + * this.$('.some-class').append( this.inlineEditor.$el ); + * + * this.inlineEditor.delegateEvents(); // rebind events after element "remove" happened + */ +FwBuilderComponents.ItemView.InlineTextEditor = Backbone.View.extend({ + tagName: 'div', + className: 'fw-builder-item-width-changer', + template: _.template( + ' ' + ), + events: { + 'change input': 'update', + 'focusout input': 'hide' + }, + render: function() { + var localized = fw_option_type_builder_helpers; + + this.$el.html( + this.template({ + value: this.editAttributeWitoutRoot + ? fw.opg(this.editAttributeWitoutRoot, this.model.get(this.editAttributeRoot)) + : this.model.get(this.editAttributeRoot), + save: localized.l10n.save + }) + ); + + this.$el.addClass('fw-hidden'); + }, + initialize: function(options) { + _.extend(this, _.pick(options, + 'editAttribute' + )); + + this.delimiter = '/'; + + /** + * From 'a/b/c', extract: 'a' and 'b/c' + */ + { + var editAttributeSplit = this.editAttribute.split(this.delimiter); + + this.editAttributeRoot = editAttributeSplit.shift(); + this.editAttributeWitoutRoot = editAttributeSplit.join(this.delimiter); + } + + this.listenTo(this.model, 'change:'+ this.editAttributeRoot, this.render); + + this.render(); + }, + update: function() { + var value = this.$el.find('input').val(); + + if (!jQuery.trim(value).length) { + value = ' '; + } + + var value = this.editAttributeWitoutRoot + ? fw.ops(this.editAttributeWitoutRoot, value, + // clone to not change by reference, else values will be equal and model.set() will not trigger 'change' + _.clone(this.model.get(this.editAttributeRoot))) + : value; + + this.model.set(this.editAttributeRoot, value); + }, + hide: function() { + this.$el.addClass('fw-hidden'); + + this.trigger('hide'); + }, + show: function() { + this.$el.removeClass('fw-hidden'); + this.$el.find('input').focus(); + } +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/builder/view.php b/scratch-parent/framework/includes/option-types/builder/view.php new file mode 100644 index 00000000..d136a92a --- /dev/null +++ b/scratch-parent/framework/includes/option-types/builder/view.php @@ -0,0 +1,61 @@ + &$thumbnails_tab_thumbnails) { + $tabs_options[ 'random-'. fw_unique_increment() ] = array( + 'type' => 'tab', + 'title' => $thumbnails_tab_title, + 'attr' => array( + 'class' => 'fw-option-type-builder-thumbnails-tab', + ), + 'options' => array( + 'random-'. fw_unique_increment() => array( + 'type' => 'html', + 'label' => false, + 'desc' => false, + 'html' => implode("\n", $thumbnails_tab_thumbnails), + ), + ), + ); + } +} +?> +
    > + backend->option_type('hidden')->render( + $id, + array(), + array( + 'value' => $data['value']['json'], + 'id_prefix' => $data['id_prefix'] .'input--', + 'name_prefix' => $data['name_prefix'] + ) + ); + ?> +
    + backend->render_options($tabs_options) ?> +
    +
    +
    diff --git a/scratch-parent/framework/includes/option-types/color-picker/class-fw-option-type-color-picker.php b/scratch-parent/framework/includes/option-types/color-picker/class-fw-option-type-color-picker.php new file mode 100644 index 00000000..bb033c49 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/color-picker/class-fw-option-type-color-picker.php @@ -0,0 +1,77 @@ +get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/css/styles.css', + array(), + fw()->manifest->get_version() + ); + + wp_enqueue_script('wp-color-picker'); + + wp_enqueue_script( + 'fw-option-'. $this->get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/js/scripts.js', + array('fw-events'), + fw()->manifest->get_version(), + true + ); + } + + $option['attr']['value'] = (string)$data['value']; + $option['attr']['class'] .= ' code'; + $option['attr']['size'] = '7'; + $option['attr']['maxlength'] = '7'; + $option['attr']['onclick'] = 'this.select()'; + + return ''; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!isset($input_value) || !preg_match('/^#[a-f0-9]{6}$/i', $input_value)) { + $input_value = $option['value']; + } + + return (string)$input_value; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '' + ); + } +} +FW_Option_Type::register('FW_Option_Type_Color_Picker'); diff --git a/scratch-parent/framework/includes/option-types/color-picker/static/css/styles.css b/scratch-parent/framework/includes/option-types/color-picker/static/css/styles.css new file mode 100644 index 00000000..3b9fec08 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/color-picker/static/css/styles.css @@ -0,0 +1,25 @@ +input.fw-option-type-color-picker { + width: 70px !important; +} + +@media (max-width: 782px) { + input.fw-option-type-color-picker { + width: 100px !important; + } +} + +input.fw-option-type-color-picker.iris-error { + background-color: #ffebe8; + border-left: none; + border-color: #c00; + color: #000; +} + +.fw-inner .iris-picker.iris-border { + z-index: 999; + position: absolute; +} + +.fw-backend-option-input-type-color-picker .fw-option-help-in-input { + top: 4px !important; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/color-picker/static/js/scripts.js b/scratch-parent/framework/includes/option-types/color-picker/static/js/scripts.js new file mode 100644 index 00000000..55912893 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/color-picker/static/js/scripts.js @@ -0,0 +1,69 @@ +jQuery(document).ready(function($){ + jQuery(document.body).click(function (e) { + if (!$(e.target).is('.fw-option-type-color-picker, .iris-picker, .iris-picker-inner, .iris-palette')) { + $('.fw-option-type-color-picker.initialized').iris('hide'); + } + }); + + /** + * Return true if color is dark + * @param {string} color Accept only correct color format, e.g. #123456 + */ + function isColorDark(color) { + color = color.substring(1); // remove # + + /** @link http://24ways.org/2010/calculating-color-contrast/ */ + { + var r = parseInt(color.substr(0,2),16); + var g = parseInt(color.substr(2,2),16); + var b = parseInt(color.substr(4,2),16); + var yiq = ((r*299)+(g*587)+(b*114))/1000; + } + + return yiq < 128; + } + + fwEvents.on('fw:options:init', function (data) { + data.$elements.find('input.fw-option-type-color-picker:not(.initialized)').each(function(){ + var $input = jQuery(this); + + $input.iris({ + hide: false, + defaultColor: false, + clear: function(){}, + change: function(event, ui){ + var color = ui.color.toString(); + + $input.css('background-color', color); + $input.css('color', isColorDark(color) ? '#FFFFFF' : '#000000'); + + $input.trigger('fw:color:picker:changed', { + $element: $input, + event : event, + ui : ui + }); + }, + palettes: true + }); + + $input.addClass('initialized'); + + $input.iris('hide'); + + var color = $input.val(); + + if (/^#[a-f0-9]{6}$/.test(color)) { + $input.iris('color', color); + } + }); + + jQuery('.fw-inner').on('click', '.fw-option-type-color-picker', function () { + $('.fw-option-type-color-picker.initialized').iris('hide'); + + $(this).iris('show'); + + return false; + }); + + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/date-picker/class-fw-option-type-wp-date-picker.php b/scratch-parent/framework/includes/option-types/date-picker/class-fw-option-type-wp-date-picker.php new file mode 100644 index 00000000..596fc5c2 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/class-fw-option-type-wp-date-picker.php @@ -0,0 +1,110 @@ +internal_options = array( + 'label' => false, + 'type' => 'text', + 'value' => '' + ); + } + + /** + * @internal + */ + public function _get_backend_width_type() { + return 'fixed'; + } + + /** + * @internal + */ + protected function _get_defaults() { + return array( + 'value' => '', + 'monday-first' => true, // The week will begin with Monday; for Sunday, set to false + 'min-date' => date('d-m-Y'), // Minimum date will be current day, set a date in format d-m-Y as a start date, or set null for no minimum date + 'max-date' => null, // There will not be set the maximum date by default, set a date in format d-m-Y as a start date + ); + } + + /** + * @internal + */ + protected function _render( $id, $option, $data ) { + $language = substr(get_locale(), 0, 2); + $css_uri = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/datepicker.css'; + $js_uri = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js'; + $date_picker_js_uri = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/bootstrap-datepicker.js'; + + + + $properties = array( + 'language' => $language, + 'weekStart' => ( $option['monday-first'] == true ) ? 1 : 0, + 'minDate' => ( $option['min-date'] !== null ) ? $option['min-date'] : null, + 'maxDate' => ( $option['max-date'] !== null ) ? $option['max-date'] : null, + ); + + $option['attr']['readonly'] = 'readonly'; + $option['attr']['data-fw-option-date-picker-opts'] = json_encode( $properties ); + + wp_enqueue_style( + 'fw-option-' . $this->get_type(), + $css_uri, + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + $js_uri, + array('jquery', 'fw-events'), + fw()->manifest->get_version(), + true + ); + wp_enqueue_script( + 'fw-option-' . $this->get_type() . '-date-picker', + $date_picker_js_uri, + array('jquery', 'fw-events'), + fw()->manifest->get_version(), + true + ); + + if( $language != 'en' ) { + $locale_uri = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/locales/bootstrap-datepicker.' . $language . '.js'; + wp_enqueue_script( + 'fw-option-' . $this->get_type() . '-date-picker-locale', + $locale_uri, + array('fw-option-' . $this->get_type() . '-date-picker'), + fw()->manifest->get_version(), + true + ); + } + + return fw()->backend->option_type( 'text' )->render( $id, $option, $data ); + } + + /** + * @internal + */ + protected function _get_value_from_input( $option, $input_value ) { + if (is_null($input_value)) { + $input_value = $option['value']; + } + + return (string)$input_value; + } +} + +FW_Option_Type::register('FW_Option_Type_Date_Picker'); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/css/datepicker.css b/scratch-parent/framework/includes/option-types/date-picker/static/css/datepicker.css new file mode 100644 index 00000000..6f061df8 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/css/datepicker.css @@ -0,0 +1,514 @@ +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-top: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-top: 0; + position: absolute; +} +.datepicker-dropdown.datepicker-orient-left:before { + left: 6px; +} +.datepicker-dropdown.datepicker-orient-left:after { + left: 7px; +} +.datepicker-dropdown.datepicker-orient-right:before { + right: 6px; +} +.datepicker-dropdown.datepicker-orient-right:after { + right: 7px; +} +.datepicker-dropdown.datepicker-orient-top:before { + top: -7px; +} +.datepicker-dropdown.datepicker-orient-top:after { + top: -6px; +} +.datepicker-dropdown.datepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; +} +.datepicker-dropdown.datepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid #ffffff; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.datepicker td, +.datepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover, +.datepicker table tr td.day.focused { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(top, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #000; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active { + background-color: #fbf069 \9; +} +.datepicker table tr td.today:hover:hover { + color: #000; +} +.datepicker table tr td.today.active:hover { + color: #fff; +} +.datepicker table tr td.range, +.datepicker table tr td.range:hover, +.datepicker table tr td.range.disabled, +.datepicker table tr td.range.disabled:hover { + background: #eeeeee; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today, +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today.disabled:hover { + background-color: #f3d17a; + background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); + background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); + background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); + background-image: linear-gradient(top, #f3c17a, #f3e97a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); + border-color: #f3e97a #f3e97a #edde34; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today:hover:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today:hover.disabled, +.datepicker table tr td.range.today.disabled.disabled, +.datepicker table tr td.range.today.disabled:hover.disabled, +.datepicker table tr td.range.today[disabled], +.datepicker table tr td.range.today:hover[disabled], +.datepicker table tr td.range.today.disabled[disabled], +.datepicker table tr td.range.today.disabled:hover[disabled] { + background-color: #f3e97a; +} +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active { + background-color: #efe24b \9; +} +.datepicker table tr td.selected, +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected.disabled:hover { + background-color: #9e9e9e; + background-image: -moz-linear-gradient(top, #b3b3b3, #808080); + background-image: -ms-linear-gradient(top, #b3b3b3, #808080); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); + background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); + background-image: -o-linear-gradient(top, #b3b3b3, #808080); + background-image: linear-gradient(top, #b3b3b3, #808080); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); + border-color: #808080 #808080 #595959; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected:hover:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected:hover.disabled, +.datepicker table tr td.selected.disabled.disabled, +.datepicker table tr td.selected.disabled:hover.disabled, +.datepicker table tr td.selected[disabled], +.datepicker table tr td.selected:hover[disabled], +.datepicker table tr td.selected.disabled[disabled], +.datepicker table tr td.selected.disabled:hover[disabled] { + background-color: #808080; +} +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active { + background-color: #666666 \9; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span.old, +.datepicker table tr td span.new { + color: #999999; +} +.datepicker th.datepicker-switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr th:hover { + background: #eeeeee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + cursor: pointer; + width: 16px; + height: 16px; +} +.input-daterange input { + text-align: center; +} +.input-daterange input:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-daterange input:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-daterange .add-on { + display: inline-block; + width: auto; + min-width: 16px; + height: 20px; + padding: 4px 5px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; + margin-left: -5px; + margin-right: -5px; +} +.datepicker.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -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); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; + color: #333333; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 20px; +} +.datepicker.dropdown-menu th, +.datepicker.datepicker-inline th, +.datepicker.dropdown-menu td, +.datepicker.datepicker-inline td { + padding: 4px 5px; +} diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/css/datepicker3.css b/scratch-parent/framework/includes/option-types/date-picker/static/css/datepicker3.css new file mode 100644 index 00000000..7c3e40bc --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/css/datepicker3.css @@ -0,0 +1,792 @@ +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-top: 0; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-top: 0; + position: absolute; +} +.datepicker-dropdown.datepicker-orient-left:before { + left: 6px; +} +.datepicker-dropdown.datepicker-orient-left:after { + left: 7px; +} +.datepicker-dropdown.datepicker-orient-right:before { + right: 6px; +} +.datepicker-dropdown.datepicker-orient-right:after { + right: 7px; +} +.datepicker-dropdown.datepicker-orient-top:before { + top: -7px; +} +.datepicker-dropdown.datepicker-orient-top:after { + top: -6px; +} +.datepicker-dropdown.datepicker-orient-bottom:before { + bottom: -7px; + border-bottom: 0; + border-top: 7px solid #999; +} +.datepicker-dropdown.datepicker-orient-bottom:after { + bottom: -6px; + border-bottom: 0; + border-top: 6px solid #fff; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.datepicker table tr td, +.datepicker table tr th { + text-align: center; + width: 30px; + height: 30px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover, +.datepicker table tr td.day.focused { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + color: #000000; + background-color: #ffdb99; + border-color: #ffb733; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:focus, +.datepicker table tr td.today:hover:focus, +.datepicker table tr td.today.disabled:focus, +.datepicker table tr td.today.disabled:hover:focus, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.today, +.open .dropdown-toggle.datepicker table tr td.today:hover, +.open .dropdown-toggle.datepicker table tr td.today.disabled, +.open .dropdown-toggle.datepicker table tr td.today.disabled:hover { + color: #000000; + background-color: #ffcd70; + border-color: #f59e00; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.today, +.open .dropdown-toggle.datepicker table tr td.today:hover, +.open .dropdown-toggle.datepicker table tr td.today.disabled, +.open .dropdown-toggle.datepicker table tr td.today.disabled:hover { + background-image: none; +} +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.today, +fieldset[disabled] .datepicker table tr td.today:hover, +fieldset[disabled] .datepicker table tr td.today.disabled, +fieldset[disabled] .datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today:hover.disabled:hover, +.datepicker table tr td.today.disabled.disabled:hover, +.datepicker table tr td.today.disabled:hover.disabled:hover, +.datepicker table tr td.today[disabled]:hover, +.datepicker table tr td.today:hover[disabled]:hover, +.datepicker table tr td.today.disabled[disabled]:hover, +.datepicker table tr td.today.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.today:hover, +fieldset[disabled] .datepicker table tr td.today:hover:hover, +fieldset[disabled] .datepicker table tr td.today.disabled:hover, +fieldset[disabled] .datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today.disabled:focus, +.datepicker table tr td.today:hover.disabled:focus, +.datepicker table tr td.today.disabled.disabled:focus, +.datepicker table tr td.today.disabled:hover.disabled:focus, +.datepicker table tr td.today[disabled]:focus, +.datepicker table tr td.today:hover[disabled]:focus, +.datepicker table tr td.today.disabled[disabled]:focus, +.datepicker table tr td.today.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.today:focus, +fieldset[disabled] .datepicker table tr td.today:hover:focus, +fieldset[disabled] .datepicker table tr td.today.disabled:focus, +fieldset[disabled] .datepicker table tr td.today.disabled:hover:focus, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today:hover.disabled:active, +.datepicker table tr td.today.disabled.disabled:active, +.datepicker table tr td.today.disabled:hover.disabled:active, +.datepicker table tr td.today[disabled]:active, +.datepicker table tr td.today:hover[disabled]:active, +.datepicker table tr td.today.disabled[disabled]:active, +.datepicker table tr td.today.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.today:active, +fieldset[disabled] .datepicker table tr td.today:hover:active, +fieldset[disabled] .datepicker table tr td.today.disabled:active, +fieldset[disabled] .datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today:hover.disabled.active, +.datepicker table tr td.today.disabled.disabled.active, +.datepicker table tr td.today.disabled:hover.disabled.active, +.datepicker table tr td.today[disabled].active, +.datepicker table tr td.today:hover[disabled].active, +.datepicker table tr td.today.disabled[disabled].active, +.datepicker table tr td.today.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.today.active, +fieldset[disabled] .datepicker table tr td.today:hover.active, +fieldset[disabled] .datepicker table tr td.today.disabled.active, +fieldset[disabled] .datepicker table tr td.today.disabled:hover.active { + background-color: #ffdb99; + border-color: #ffb733; +} +.datepicker table tr td.today:hover:hover { + color: #000; +} +.datepicker table tr td.today.active:hover { + color: #fff; +} +.datepicker table tr td.range, +.datepicker table tr td.range:hover, +.datepicker table tr td.range.disabled, +.datepicker table tr td.range.disabled:hover { + background: #eeeeee; + border-radius: 0; +} +.datepicker table tr td.range.today, +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today.disabled:hover { + color: #000000; + background-color: #f7ca77; + border-color: #f1a417; + border-radius: 0; +} +.datepicker table tr td.range.today:hover, +.datepicker table tr td.range.today:hover:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today:focus, +.datepicker table tr td.range.today:hover:focus, +.datepicker table tr td.range.today.disabled:focus, +.datepicker table tr td.range.today.disabled:hover:focus, +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.range.today, +.open .dropdown-toggle.datepicker table tr td.range.today:hover, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover { + color: #000000; + background-color: #f4bb51; + border-color: #bf800c; +} +.datepicker table tr td.range.today:active, +.datepicker table tr td.range.today:hover:active, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.active, +.datepicker table tr td.range.today:hover.active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.range.today, +.open .dropdown-toggle.datepicker table tr td.range.today:hover, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled, +.open .dropdown-toggle.datepicker table tr td.range.today.disabled:hover { + background-image: none; +} +.datepicker table tr td.range.today.disabled, +.datepicker table tr td.range.today:hover.disabled, +.datepicker table tr td.range.today.disabled.disabled, +.datepicker table tr td.range.today.disabled:hover.disabled, +.datepicker table tr td.range.today[disabled], +.datepicker table tr td.range.today:hover[disabled], +.datepicker table tr td.range.today.disabled[disabled], +.datepicker table tr td.range.today.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.range.today, +fieldset[disabled] .datepicker table tr td.range.today:hover, +fieldset[disabled] .datepicker table tr td.range.today.disabled, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today.disabled:hover, +.datepicker table tr td.range.today:hover.disabled:hover, +.datepicker table tr td.range.today.disabled.disabled:hover, +.datepicker table tr td.range.today.disabled:hover.disabled:hover, +.datepicker table tr td.range.today[disabled]:hover, +.datepicker table tr td.range.today:hover[disabled]:hover, +.datepicker table tr td.range.today.disabled[disabled]:hover, +.datepicker table tr td.range.today.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.range.today:hover, +fieldset[disabled] .datepicker table tr td.range.today:hover:hover, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:hover, +.datepicker table tr td.range.today.disabled:focus, +.datepicker table tr td.range.today:hover.disabled:focus, +.datepicker table tr td.range.today.disabled.disabled:focus, +.datepicker table tr td.range.today.disabled:hover.disabled:focus, +.datepicker table tr td.range.today[disabled]:focus, +.datepicker table tr td.range.today:hover[disabled]:focus, +.datepicker table tr td.range.today.disabled[disabled]:focus, +.datepicker table tr td.range.today.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.range.today:focus, +fieldset[disabled] .datepicker table tr td.range.today:hover:focus, +fieldset[disabled] .datepicker table tr td.range.today.disabled:focus, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:focus, +.datepicker table tr td.range.today.disabled:active, +.datepicker table tr td.range.today:hover.disabled:active, +.datepicker table tr td.range.today.disabled.disabled:active, +.datepicker table tr td.range.today.disabled:hover.disabled:active, +.datepicker table tr td.range.today[disabled]:active, +.datepicker table tr td.range.today:hover[disabled]:active, +.datepicker table tr td.range.today.disabled[disabled]:active, +.datepicker table tr td.range.today.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.range.today:active, +fieldset[disabled] .datepicker table tr td.range.today:hover:active, +fieldset[disabled] .datepicker table tr td.range.today.disabled:active, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover:active, +.datepicker table tr td.range.today.disabled.active, +.datepicker table tr td.range.today:hover.disabled.active, +.datepicker table tr td.range.today.disabled.disabled.active, +.datepicker table tr td.range.today.disabled:hover.disabled.active, +.datepicker table tr td.range.today[disabled].active, +.datepicker table tr td.range.today:hover[disabled].active, +.datepicker table tr td.range.today.disabled[disabled].active, +.datepicker table tr td.range.today.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.range.today.active, +fieldset[disabled] .datepicker table tr td.range.today:hover.active, +fieldset[disabled] .datepicker table tr td.range.today.disabled.active, +fieldset[disabled] .datepicker table tr td.range.today.disabled:hover.active { + background-color: #f7ca77; + border-color: #f1a417; +} +.datepicker table tr td.selected, +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected.disabled:hover { + color: #ffffff; + background-color: #999999; + border-color: #555555; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.selected:hover, +.datepicker table tr td.selected:hover:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected:focus, +.datepicker table tr td.selected:hover:focus, +.datepicker table tr td.selected.disabled:focus, +.datepicker table tr td.selected.disabled:hover:focus, +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.selected, +.open .dropdown-toggle.datepicker table tr td.selected:hover, +.open .dropdown-toggle.datepicker table tr td.selected.disabled, +.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover { + color: #ffffff; + background-color: #858585; + border-color: #373737; +} +.datepicker table tr td.selected:active, +.datepicker table tr td.selected:hover:active, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.active, +.datepicker table tr td.selected:hover.active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.selected, +.open .dropdown-toggle.datepicker table tr td.selected:hover, +.open .dropdown-toggle.datepicker table tr td.selected.disabled, +.open .dropdown-toggle.datepicker table tr td.selected.disabled:hover { + background-image: none; +} +.datepicker table tr td.selected.disabled, +.datepicker table tr td.selected:hover.disabled, +.datepicker table tr td.selected.disabled.disabled, +.datepicker table tr td.selected.disabled:hover.disabled, +.datepicker table tr td.selected[disabled], +.datepicker table tr td.selected:hover[disabled], +.datepicker table tr td.selected.disabled[disabled], +.datepicker table tr td.selected.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.selected, +fieldset[disabled] .datepicker table tr td.selected:hover, +fieldset[disabled] .datepicker table tr td.selected.disabled, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected.disabled:hover, +.datepicker table tr td.selected:hover.disabled:hover, +.datepicker table tr td.selected.disabled.disabled:hover, +.datepicker table tr td.selected.disabled:hover.disabled:hover, +.datepicker table tr td.selected[disabled]:hover, +.datepicker table tr td.selected:hover[disabled]:hover, +.datepicker table tr td.selected.disabled[disabled]:hover, +.datepicker table tr td.selected.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.selected:hover, +fieldset[disabled] .datepicker table tr td.selected:hover:hover, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover:hover, +.datepicker table tr td.selected.disabled:focus, +.datepicker table tr td.selected:hover.disabled:focus, +.datepicker table tr td.selected.disabled.disabled:focus, +.datepicker table tr td.selected.disabled:hover.disabled:focus, +.datepicker table tr td.selected[disabled]:focus, +.datepicker table tr td.selected:hover[disabled]:focus, +.datepicker table tr td.selected.disabled[disabled]:focus, +.datepicker table tr td.selected.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.selected:focus, +fieldset[disabled] .datepicker table tr td.selected:hover:focus, +fieldset[disabled] .datepicker table tr td.selected.disabled:focus, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover:focus, +.datepicker table tr td.selected.disabled:active, +.datepicker table tr td.selected:hover.disabled:active, +.datepicker table tr td.selected.disabled.disabled:active, +.datepicker table tr td.selected.disabled:hover.disabled:active, +.datepicker table tr td.selected[disabled]:active, +.datepicker table tr td.selected:hover[disabled]:active, +.datepicker table tr td.selected.disabled[disabled]:active, +.datepicker table tr td.selected.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.selected:active, +fieldset[disabled] .datepicker table tr td.selected:hover:active, +fieldset[disabled] .datepicker table tr td.selected.disabled:active, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover:active, +.datepicker table tr td.selected.disabled.active, +.datepicker table tr td.selected:hover.disabled.active, +.datepicker table tr td.selected.disabled.disabled.active, +.datepicker table tr td.selected.disabled:hover.disabled.active, +.datepicker table tr td.selected[disabled].active, +.datepicker table tr td.selected:hover[disabled].active, +.datepicker table tr td.selected.disabled[disabled].active, +.datepicker table tr td.selected.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.selected.active, +fieldset[disabled] .datepicker table tr td.selected:hover.active, +fieldset[disabled] .datepicker table tr td.selected.disabled.active, +fieldset[disabled] .datepicker table tr td.selected.disabled:hover.active { + background-color: #999999; + border-color: #555555; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:focus, +.datepicker table tr td.active:hover:focus, +.datepicker table tr td.active.disabled:focus, +.datepicker table tr td.active.disabled:hover:focus, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.active, +.open .dropdown-toggle.datepicker table tr td.active:hover, +.open .dropdown-toggle.datepicker table tr td.active.disabled, +.open .dropdown-toggle.datepicker table tr td.active.disabled:hover { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td.active, +.open .dropdown-toggle.datepicker table tr td.active:hover, +.open .dropdown-toggle.datepicker table tr td.active.disabled, +.open .dropdown-toggle.datepicker table tr td.active.disabled:hover { + background-image: none; +} +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td.active, +fieldset[disabled] .datepicker table tr td.active:hover, +fieldset[disabled] .datepicker table tr td.active.disabled, +fieldset[disabled] .datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active:hover.disabled:hover, +.datepicker table tr td.active.disabled.disabled:hover, +.datepicker table tr td.active.disabled:hover.disabled:hover, +.datepicker table tr td.active[disabled]:hover, +.datepicker table tr td.active:hover[disabled]:hover, +.datepicker table tr td.active.disabled[disabled]:hover, +.datepicker table tr td.active.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td.active:hover, +fieldset[disabled] .datepicker table tr td.active:hover:hover, +fieldset[disabled] .datepicker table tr td.active.disabled:hover, +fieldset[disabled] .datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active.disabled:focus, +.datepicker table tr td.active:hover.disabled:focus, +.datepicker table tr td.active.disabled.disabled:focus, +.datepicker table tr td.active.disabled:hover.disabled:focus, +.datepicker table tr td.active[disabled]:focus, +.datepicker table tr td.active:hover[disabled]:focus, +.datepicker table tr td.active.disabled[disabled]:focus, +.datepicker table tr td.active.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td.active:focus, +fieldset[disabled] .datepicker table tr td.active:hover:focus, +fieldset[disabled] .datepicker table tr td.active.disabled:focus, +fieldset[disabled] .datepicker table tr td.active.disabled:hover:focus, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active:hover.disabled:active, +.datepicker table tr td.active.disabled.disabled:active, +.datepicker table tr td.active.disabled:hover.disabled:active, +.datepicker table tr td.active[disabled]:active, +.datepicker table tr td.active:hover[disabled]:active, +.datepicker table tr td.active.disabled[disabled]:active, +.datepicker table tr td.active.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td.active:active, +fieldset[disabled] .datepicker table tr td.active:hover:active, +fieldset[disabled] .datepicker table tr td.active.disabled:active, +fieldset[disabled] .datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active:hover.disabled.active, +.datepicker table tr td.active.disabled.disabled.active, +.datepicker table tr td.active.disabled:hover.disabled.active, +.datepicker table tr td.active[disabled].active, +.datepicker table tr td.active:hover[disabled].active, +.datepicker table tr td.active.disabled[disabled].active, +.datepicker table tr td.active.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td.active.active, +fieldset[disabled] .datepicker table tr td.active:hover.active, +fieldset[disabled] .datepicker table tr td.active.disabled.active, +fieldset[disabled] .datepicker table tr td.active.disabled:hover.active { + background-color: #428bca; + border-color: #357ebd; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:focus, +.datepicker table tr td span.active:hover:focus, +.datepicker table tr td span.active.disabled:focus, +.datepicker table tr td span.active.disabled:hover:focus, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td span.active, +.open .dropdown-toggle.datepicker table tr td span.active:hover, +.open .dropdown-toggle.datepicker table tr td span.active.disabled, +.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.open .dropdown-toggle.datepicker table tr td span.active, +.open .dropdown-toggle.datepicker table tr td span.active:hover, +.open .dropdown-toggle.datepicker table tr td span.active.disabled, +.open .dropdown-toggle.datepicker table tr td span.active.disabled:hover { + background-image: none; +} +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled], +fieldset[disabled] .datepicker table tr td span.active, +fieldset[disabled] .datepicker table tr td span.active:hover, +fieldset[disabled] .datepicker table tr td span.active.disabled, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active:hover.disabled:hover, +.datepicker table tr td span.active.disabled.disabled:hover, +.datepicker table tr td span.active.disabled:hover.disabled:hover, +.datepicker table tr td span.active[disabled]:hover, +.datepicker table tr td span.active:hover[disabled]:hover, +.datepicker table tr td span.active.disabled[disabled]:hover, +.datepicker table tr td span.active.disabled:hover[disabled]:hover, +fieldset[disabled] .datepicker table tr td span.active:hover, +fieldset[disabled] .datepicker table tr td span.active:hover:hover, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active.disabled:focus, +.datepicker table tr td span.active:hover.disabled:focus, +.datepicker table tr td span.active.disabled.disabled:focus, +.datepicker table tr td span.active.disabled:hover.disabled:focus, +.datepicker table tr td span.active[disabled]:focus, +.datepicker table tr td span.active:hover[disabled]:focus, +.datepicker table tr td span.active.disabled[disabled]:focus, +.datepicker table tr td span.active.disabled:hover[disabled]:focus, +fieldset[disabled] .datepicker table tr td span.active:focus, +fieldset[disabled] .datepicker table tr td span.active:hover:focus, +fieldset[disabled] .datepicker table tr td span.active.disabled:focus, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover:focus, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active:hover.disabled:active, +.datepicker table tr td span.active.disabled.disabled:active, +.datepicker table tr td span.active.disabled:hover.disabled:active, +.datepicker table tr td span.active[disabled]:active, +.datepicker table tr td span.active:hover[disabled]:active, +.datepicker table tr td span.active.disabled[disabled]:active, +.datepicker table tr td span.active.disabled:hover[disabled]:active, +fieldset[disabled] .datepicker table tr td span.active:active, +fieldset[disabled] .datepicker table tr td span.active:hover:active, +fieldset[disabled] .datepicker table tr td span.active.disabled:active, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active:hover.disabled.active, +.datepicker table tr td span.active.disabled.disabled.active, +.datepicker table tr td span.active.disabled:hover.disabled.active, +.datepicker table tr td span.active[disabled].active, +.datepicker table tr td span.active:hover[disabled].active, +.datepicker table tr td span.active.disabled[disabled].active, +.datepicker table tr td span.active.disabled:hover[disabled].active, +fieldset[disabled] .datepicker table tr td span.active.active, +fieldset[disabled] .datepicker table tr td span.active:hover.active, +fieldset[disabled] .datepicker table tr td span.active.disabled.active, +fieldset[disabled] .datepicker table tr td span.active.disabled:hover.active { + background-color: #428bca; + border-color: #357ebd; +} +.datepicker table tr td span.old, +.datepicker table tr td span.new { + color: #999999; +} +.datepicker th.datepicker-switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr th:hover { + background: #eeeeee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-group.date .input-group-addon i { + cursor: pointer; + width: 16px; + height: 16px; +} +.input-daterange input { + text-align: center; +} +.input-daterange input:first-child { + border-radius: 3px 0 0 3px; +} +.input-daterange input:last-child { + border-radius: 0 3px 3px 0; +} +.input-daterange .input-group-addon { + width: auto; + min-width: 16px; + padding: 4px 5px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + text-shadow: 0 1px 0 #fff; + vertical-align: middle; + background-color: #eeeeee; + border: solid #cccccc; + border-width: 1px 0; + margin-left: -5px; + margin-right: -5px; +} +.datepicker.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 5px; + -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); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; + color: #333333; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 1.428571429; +} +.datepicker.dropdown-menu th, +.datepicker.datepicker-inline th, +.datepicker.dropdown-menu td, +.datepicker.datepicker-inline td { + padding: 0px 5px; +} diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/bootstrap-datepicker.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/bootstrap-datepicker.js new file mode 100644 index 00000000..6fbbeb3d --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/bootstrap-datepicker.js @@ -0,0 +1,1671 @@ +/* ========================================================= + * bootstrap-datepicker.js + * Repo: https://github.com/eternicode/bootstrap-datepicker/ + * Demo: http://eternicode.github.io/bootstrap-datepicker/ + * Docs: http://bootstrap-datepicker.readthedocs.org/ + * Forked from http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Started by Stefan Petre; improvements by Andrew Rowls + contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +(function($, undefined){ + + var $window = $(window); + + function UTCDate(){ + return new Date(Date.UTC.apply(Date, arguments)); + } + function UTCToday(){ + var today = new Date(); + return UTCDate(today.getFullYear(), today.getMonth(), today.getDate()); + } + function alias(method){ + return function(){ + return this[method].apply(this, arguments); + }; + } + + var DateArray = (function(){ + var extras = { + get: function(i){ + return this.slice(i)[0]; + }, + contains: function(d){ + // Array.indexOf is not cross-browser; + // $.inArray doesn't work with Dates + var val = d && d.valueOf(); + for (var i=0, l=this.length; i < l; i++) + if (this[i].valueOf() === val) + return i; + return -1; + }, + remove: function(i){ + this.splice(i,1); + }, + replace: function(new_array){ + if (!new_array) + return; + if (!$.isArray(new_array)) + new_array = [new_array]; + this.clear(); + this.push.apply(this, new_array); + }, + clear: function(){ + this.length = 0; + }, + copy: function(){ + var a = new DateArray(); + a.replace(this); + return a; + } + }; + + return function(){ + var a = []; + a.push.apply(a, arguments); + $.extend(a, extras); + return a; + }; + })(); + + + // Picker object + + var Datepicker = function(element, options){ + this.dates = new DateArray(); + this.viewDate = UTCToday(); + this.focusDate = null; + + this._process_options(options); + + this.element = $(element); + this.isInline = false; + this.isInput = this.element.is('input'); + this.component = this.element.is('.date') ? this.element.find('.add-on, .input-group-addon, .btn') : false; + this.hasInput = this.component && this.element.find('input').length; + if (this.component && this.component.length === 0) + this.component = false; + + this.picker = $(DPGlobal.template); + this._buildEvents(); + this._attachEvents(); + + if (this.isInline){ + this.picker.addClass('datepicker-inline').appendTo(this.element); + } + else { + this.picker.addClass('datepicker-dropdown dropdown-menu'); + } + + if (this.o.rtl){ + this.picker.addClass('datepicker-rtl'); + } + + this.viewMode = this.o.startView; + + if (this.o.calendarWeeks) + this.picker.find('tfoot th.today') + .attr('colspan', function(i, val){ + return parseInt(val) + 1; + }); + + this._allow_update = false; + + this.setStartDate(this._o.startDate); + this.setEndDate(this._o.endDate); + this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled); + + this.fillDow(); + this.fillMonths(); + + this._allow_update = true; + + this.update(); + this.showMode(); + + if (this.isInline){ + this.show(); + } + }; + + Datepicker.prototype = { + constructor: Datepicker, + + _process_options: function(opts){ + // Store raw options for reference + this._o = $.extend({}, this._o, opts); + // Processed options + var o = this.o = $.extend({}, this._o); + + // Check if "de-DE" style date is available, if not language should + // fallback to 2 letter code eg "de" + var lang = o.language; + if (!dates[lang]){ + lang = lang.split('-')[0]; + if (!dates[lang]) + lang = defaults.language; + } + o.language = lang; + + switch (o.startView){ + case 2: + case 'decade': + o.startView = 2; + break; + case 1: + case 'year': + o.startView = 1; + break; + default: + o.startView = 0; + } + + switch (o.minViewMode){ + case 1: + case 'months': + o.minViewMode = 1; + break; + case 2: + case 'years': + o.minViewMode = 2; + break; + default: + o.minViewMode = 0; + } + + o.startView = Math.max(o.startView, o.minViewMode); + + // true, false, or Number > 0 + if (o.multidate !== true){ + o.multidate = Number(o.multidate) || false; + if (o.multidate !== false) + o.multidate = Math.max(0, o.multidate); + else + o.multidate = 1; + } + o.multidateSeparator = String(o.multidateSeparator); + + o.weekStart %= 7; + o.weekEnd = ((o.weekStart + 6) % 7); + + var format = DPGlobal.parseFormat(o.format); + if (o.startDate !== -Infinity){ + if (!!o.startDate){ + if (o.startDate instanceof Date) + o.startDate = this._local_to_utc(this._zero_time(o.startDate)); + else + o.startDate = DPGlobal.parseDate(o.startDate, format, o.language); + } + else { + o.startDate = -Infinity; + } + } + if (o.endDate !== Infinity){ + if (!!o.endDate){ + if (o.endDate instanceof Date) + o.endDate = this._local_to_utc(this._zero_time(o.endDate)); + else + o.endDate = DPGlobal.parseDate(o.endDate, format, o.language); + } + else { + o.endDate = Infinity; + } + } + + o.daysOfWeekDisabled = o.daysOfWeekDisabled||[]; + if (!$.isArray(o.daysOfWeekDisabled)) + o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/); + o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){ + return parseInt(d, 10); + }); + + var plc = String(o.orientation).toLowerCase().split(/\s+/g), + _plc = o.orientation.toLowerCase(); + plc = $.grep(plc, function(word){ + return (/^auto|left|right|top|bottom$/).test(word); + }); + o.orientation = {x: 'auto', y: 'auto'}; + if (!_plc || _plc === 'auto') + ; // no action + else if (plc.length === 1){ + switch (plc[0]){ + case 'top': + case 'bottom': + o.orientation.y = plc[0]; + break; + case 'left': + case 'right': + o.orientation.x = plc[0]; + break; + } + } + else { + _plc = $.grep(plc, function(word){ + return (/^left|right$/).test(word); + }); + o.orientation.x = _plc[0] || 'auto'; + + _plc = $.grep(plc, function(word){ + return (/^top|bottom$/).test(word); + }); + o.orientation.y = _plc[0] || 'auto'; + } + }, + _events: [], + _secondaryEvents: [], + _applyEvents: function(evs){ + for (var i=0, el, ch, ev; i < evs.length; i++){ + el = evs[i][0]; + if (evs[i].length === 2){ + ch = undefined; + ev = evs[i][1]; + } + else if (evs[i].length === 3){ + ch = evs[i][1]; + ev = evs[i][2]; + } + el.on(ev, ch); + } + }, + _unapplyEvents: function(evs){ + for (var i=0, el, ev, ch; i < evs.length; i++){ + el = evs[i][0]; + if (evs[i].length === 2){ + ch = undefined; + ev = evs[i][1]; + } + else if (evs[i].length === 3){ + ch = evs[i][1]; + ev = evs[i][2]; + } + el.off(ev, ch); + } + }, + _buildEvents: function(){ + if (this.isInput){ // single input + this._events = [ + [this.element, { + focus: $.proxy(this.show, this), + keyup: $.proxy(function(e){ + if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1) + this.update(); + }, this), + keydown: $.proxy(this.keydown, this) + }] + ]; + } + else if (this.component && this.hasInput){ // component: input + button + this._events = [ + // For components that are not readonly, allow keyboard nav + [this.element.find('input'), { + focus: $.proxy(this.show, this), + keyup: $.proxy(function(e){ + if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1) + this.update(); + }, this), + keydown: $.proxy(this.keydown, this) + }], + [this.component, { + click: $.proxy(this.show, this) + }] + ]; + } + else if (this.element.is('div')){ // inline datepicker + this.isInline = true; + } + else { + this._events = [ + [this.element, { + click: $.proxy(this.show, this) + }] + ]; + } + this._events.push( + // Component: listen for blur on element descendants + [this.element, '*', { + blur: $.proxy(function(e){ + this._focused_from = e.target; + }, this) + }], + // Input: listen for blur on element + [this.element, { + blur: $.proxy(function(e){ + this._focused_from = e.target; + }, this) + }] + ); + + this._secondaryEvents = [ + [this.picker, { + click: $.proxy(this.click, this) + }], + [$(window), { + resize: $.proxy(this.place, this) + }], + [$(document), { + 'mousedown touchstart': $.proxy(function(e){ + // Clicked outside the datepicker, hide it + if (!( + this.element.is(e.target) || + this.element.find(e.target).length || + this.picker.is(e.target) || + this.picker.find(e.target).length + )){ + this.hide(); + } + }, this) + }] + ]; + }, + _attachEvents: function(){ + this._detachEvents(); + this._applyEvents(this._events); + }, + _detachEvents: function(){ + this._unapplyEvents(this._events); + }, + _attachSecondaryEvents: function(){ + this._detachSecondaryEvents(); + this._applyEvents(this._secondaryEvents); + }, + _detachSecondaryEvents: function(){ + this._unapplyEvents(this._secondaryEvents); + }, + _trigger: function(event, altdate){ + var date = altdate || this.dates.get(-1), + local_date = this._utc_to_local(date); + + this.element.trigger({ + type: event, + date: local_date, + dates: $.map(this.dates, this._utc_to_local), + format: $.proxy(function(ix, format){ + if (arguments.length === 0){ + ix = this.dates.length - 1; + format = this.o.format; + } + else if (typeof ix === 'string'){ + format = ix; + ix = this.dates.length - 1; + } + format = format || this.o.format; + var date = this.dates.get(ix); + return DPGlobal.formatDate(date, format, this.o.language); + }, this) + }); + }, + + show: function(){ + if (!this.isInline) + this.picker.appendTo('body'); + this.picker.show(); + this.place(); + this._attachSecondaryEvents(); + this._trigger('show'); + }, + + hide: function(){ + if (this.isInline) + return; + if (!this.picker.is(':visible')) + return; + this.focusDate = null; + this.picker.hide().detach(); + this._detachSecondaryEvents(); + this.viewMode = this.o.startView; + this.showMode(); + + if ( + this.o.forceParse && + ( + this.isInput && this.element.val() || + this.hasInput && this.element.find('input').val() + ) + ) + this.setValue(); + this._trigger('hide'); + }, + + remove: function(){ + this.hide(); + this._detachEvents(); + this._detachSecondaryEvents(); + this.picker.remove(); + delete this.element.data().datepicker; + if (!this.isInput){ + delete this.element.data().date; + } + }, + + _utc_to_local: function(utc){ + return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000)); + }, + _local_to_utc: function(local){ + return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000)); + }, + _zero_time: function(local){ + return local && new Date(local.getFullYear(), local.getMonth(), local.getDate()); + }, + _zero_utc_time: function(utc){ + return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate())); + }, + + getDates: function(){ + return $.map(this.dates, this._utc_to_local); + }, + + getUTCDates: function(){ + return $.map(this.dates, function(d){ + return new Date(d); + }); + }, + + getDate: function(){ + return this._utc_to_local(this.getUTCDate()); + }, + + getUTCDate: function(){ + return new Date(this.dates.get(-1)); + }, + + setDates: function(){ + var args = $.isArray(arguments[0]) ? arguments[0] : arguments; + this.update.apply(this, args); + this._trigger('changeDate'); + this.setValue(); + }, + + setUTCDates: function(){ + var args = $.isArray(arguments[0]) ? arguments[0] : arguments; + this.update.apply(this, $.map(args, this._utc_to_local)); + this._trigger('changeDate'); + this.setValue(); + }, + + setDate: alias('setDates'), + setUTCDate: alias('setUTCDates'), + + setValue: function(){ + var formatted = this.getFormattedDate(); + if (!this.isInput){ + if (this.component){ + this.element.find('input').val(formatted).change(); + } + } + else { + this.element.val(formatted).change(); + } + }, + + getFormattedDate: function(format){ + if (format === undefined) + format = this.o.format; + + var lang = this.o.language; + return $.map(this.dates, function(d){ + return DPGlobal.formatDate(d, format, lang); + }).join(this.o.multidateSeparator); + }, + + setStartDate: function(startDate){ + this._process_options({startDate: startDate}); + this.update(); + this.updateNavArrows(); + }, + + setEndDate: function(endDate){ + this._process_options({endDate: endDate}); + this.update(); + this.updateNavArrows(); + }, + + setDaysOfWeekDisabled: function(daysOfWeekDisabled){ + this._process_options({daysOfWeekDisabled: daysOfWeekDisabled}); + this.update(); + this.updateNavArrows(); + }, + + place: function(){ + if (this.isInline) + return; + var calendarWidth = this.picker.outerWidth(), + calendarHeight = this.picker.outerHeight(), + visualPadding = 10, + windowWidth = $window.width(), + windowHeight = $window.height(), + scrollTop = $window.scrollTop(); + + var zIndex = parseInt(this.element.parents().filter(function(){ + return $(this).css('z-index') !== 'auto'; + }).first().css('z-index'))+10; + var offset = this.component ? this.component.parent().offset() : this.element.offset(); + var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false); + var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false); + var left = offset.left, + top = offset.top; + + this.picker.removeClass( + 'datepicker-orient-top datepicker-orient-bottom '+ + 'datepicker-orient-right datepicker-orient-left' + ); + + if (this.o.orientation.x !== 'auto'){ + this.picker.addClass('datepicker-orient-' + this.o.orientation.x); + if (this.o.orientation.x === 'right') + left -= calendarWidth - width; + } + // auto x orientation is best-placement: if it crosses a window + // edge, fudge it sideways + else { + // Default to left + this.picker.addClass('datepicker-orient-left'); + if (offset.left < 0) + left -= offset.left - visualPadding; + else if (offset.left + calendarWidth > windowWidth) + left = windowWidth - calendarWidth - visualPadding; + } + + // auto y orientation is best-situation: top or bottom, no fudging, + // decision based on which shows more of the calendar + var yorient = this.o.orientation.y, + top_overflow, bottom_overflow; + if (yorient === 'auto'){ + top_overflow = -scrollTop + offset.top - calendarHeight; + bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight); + if (Math.max(top_overflow, bottom_overflow) === bottom_overflow) + yorient = 'top'; + else + yorient = 'bottom'; + } + this.picker.addClass('datepicker-orient-' + yorient); + if (yorient === 'top') + top += height; + else + top -= calendarHeight + parseInt(this.picker.css('padding-top')); + + this.picker.css({ + top: top, + left: left, + zIndex: zIndex + }); + }, + + _allow_update: true, + update: function(){ + if (!this._allow_update) + return; + + var oldDates = this.dates.copy(), + dates = [], + fromArgs = false; + if (arguments.length){ + $.each(arguments, $.proxy(function(i, date){ + if (date instanceof Date) + date = this._local_to_utc(date); + dates.push(date); + }, this)); + fromArgs = true; + } + else { + dates = this.isInput + ? this.element.val() + : this.element.data('date') || this.element.find('input').val(); + if (dates && this.o.multidate) + dates = dates.split(this.o.multidateSeparator); + else + dates = [dates]; + delete this.element.data().date; + } + + dates = $.map(dates, $.proxy(function(date){ + return DPGlobal.parseDate(date, this.o.format, this.o.language); + }, this)); + dates = $.grep(dates, $.proxy(function(date){ + return ( + date < this.o.startDate || + date > this.o.endDate || + !date + ); + }, this), true); + this.dates.replace(dates); + + if (this.dates.length) + this.viewDate = new Date(this.dates.get(-1)); + else if (this.viewDate < this.o.startDate) + this.viewDate = new Date(this.o.startDate); + else if (this.viewDate > this.o.endDate) + this.viewDate = new Date(this.o.endDate); + + if (fromArgs){ + // setting date by clicking + this.setValue(); + } + else if (dates.length){ + // setting date by typing + if (String(oldDates) !== String(this.dates)) + this._trigger('changeDate'); + } + if (!this.dates.length && oldDates.length) + this._trigger('clearDate'); + + this.fill(); + }, + + fillDow: function(){ + var dowCnt = this.o.weekStart, + html = ''; + if (this.o.calendarWeeks){ + var cell = ' '; + html += cell; + this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); + } + while (dowCnt < this.o.weekStart + 7){ + html += ''+dates[this.o.language].daysMin[(dowCnt++)%7]+''; + } + html += ''; + this.picker.find('.datepicker-days thead').append(html); + }, + + fillMonths: function(){ + var html = '', + i = 0; + while (i < 12){ + html += ''+dates[this.o.language].monthsShort[i++]+''; + } + this.picker.find('.datepicker-months td').html(html); + }, + + setRange: function(range){ + if (!range || !range.length) + delete this.range; + else + this.range = $.map(range, function(d){ + return d.valueOf(); + }); + this.fill(); + }, + + getClassNames: function(date){ + var cls = [], + year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(), + today = new Date(); + if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){ + cls.push('old'); + } + else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){ + cls.push('new'); + } + if (this.focusDate && date.valueOf() === this.focusDate.valueOf()) + cls.push('focused'); + // Compare internal UTC date with local today, not UTC today + if (this.o.todayHighlight && + date.getUTCFullYear() === today.getFullYear() && + date.getUTCMonth() === today.getMonth() && + date.getUTCDate() === today.getDate()){ + cls.push('today'); + } + if (this.dates.contains(date) !== -1) + cls.push('active'); + if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate || + $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1){ + cls.push('disabled'); + } + if (this.range){ + if (date > this.range[0] && date < this.range[this.range.length-1]){ + cls.push('range'); + } + if ($.inArray(date.valueOf(), this.range) !== -1){ + cls.push('selected'); + } + } + return cls; + }, + + fill: function(){ + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(), + startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, + startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, + endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, + endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, + todaytxt = dates[this.o.language].today || dates['en'].today || '', + cleartxt = dates[this.o.language].clear || dates['en'].clear || '', + tooltip; + this.picker.find('.datepicker-days thead th.datepicker-switch') + .text(dates[this.o.language].months[month]+' '+year); + this.picker.find('tfoot th.today') + .text(todaytxt) + .toggle(this.o.todayBtn !== false); + this.picker.find('tfoot th.clear') + .text(cleartxt) + .toggle(this.o.clearBtn !== false); + this.updateNavArrows(); + this.fillMonths(); + var prevMonth = UTCDate(year, month-1, 28), + day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); + prevMonth.setUTCDate(day); + prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7); + var nextMonth = new Date(prevMonth); + nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var clsName; + while (prevMonth.valueOf() < nextMonth){ + if (prevMonth.getUTCDay() === this.o.weekStart){ + html.push(''); + if (this.o.calendarWeeks){ + // ISO 8601: First week contains first thursday. + // ISO also states week starts on Monday, but we can be more abstract here. + var + // Start of current week: based on weekstart/current date + ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), + // Thursday of this week + th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), + // First Thursday of year, year from thursday + yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), + // Calendar week: ms between thursdays, div ms per day, div 7 days + calWeek = (th - yth) / 864e5 / 7 + 1; + html.push(''+ calWeek +''); + + } + } + clsName = this.getClassNames(prevMonth); + clsName.push('day'); + + if (this.o.beforeShowDay !== $.noop){ + var before = this.o.beforeShowDay(this._utc_to_local(prevMonth)); + if (before === undefined) + before = {}; + else if (typeof(before) === 'boolean') + before = {enabled: before}; + else if (typeof(before) === 'string') + before = {classes: before}; + if (before.enabled === false) + clsName.push('disabled'); + if (before.classes) + clsName = clsName.concat(before.classes.split(/\s+/)); + if (before.tooltip) + tooltip = before.tooltip; + } + + clsName = $.unique(clsName); + html.push(''+prevMonth.getUTCDate() + ''); + if (prevMonth.getUTCDay() === this.o.weekEnd){ + html.push(''); + } + prevMonth.setUTCDate(prevMonth.getUTCDate()+1); + } + this.picker.find('.datepicker-days tbody').empty().append(html.join('')); + + var months = this.picker.find('.datepicker-months') + .find('th:eq(1)') + .text(year) + .end() + .find('span').removeClass('active'); + + $.each(this.dates, function(i, d){ + if (d.getUTCFullYear() === year) + months.eq(d.getUTCMonth()).addClass('active'); + }); + + if (year < startYear || year > endYear){ + months.addClass('disabled'); + } + if (year === startYear){ + months.slice(0, startMonth).addClass('disabled'); + } + if (year === endYear){ + months.slice(endMonth+1).addClass('disabled'); + } + + html = ''; + year = parseInt(year/10, 10) * 10; + var yearCont = this.picker.find('.datepicker-years') + .find('th:eq(1)') + .text(year + '-' + (year + 9)) + .end() + .find('td'); + year -= 1; + var years = $.map(this.dates, function(d){ + return d.getUTCFullYear(); + }), + classes; + for (var i = -1; i < 11; i++){ + classes = ['year']; + if (i === -1) + classes.push('old'); + else if (i === 10) + classes.push('new'); + if ($.inArray(year, years) !== -1) + classes.push('active'); + if (year < startYear || year > endYear) + classes.push('disabled'); + html += ''+year+''; + year += 1; + } + yearCont.html(html); + }, + + updateNavArrows: function(){ + if (!this._allow_update) + return; + + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(); + switch (this.viewMode){ + case 0: + if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){ + this.picker.find('.prev').css({visibility: 'hidden'}); + } + else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){ + this.picker.find('.next').css({visibility: 'hidden'}); + } + else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 1: + case 2: + if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()){ + this.picker.find('.prev').css({visibility: 'hidden'}); + } + else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()){ + this.picker.find('.next').css({visibility: 'hidden'}); + } + else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + } + }, + + click: function(e){ + e.preventDefault(); + var target = $(e.target).closest('span, td, th'), + year, month, day; + if (target.length === 1){ + switch (target[0].nodeName.toLowerCase()){ + case 'th': + switch (target[0].className){ + case 'datepicker-switch': + this.showMode(1); + break; + case 'prev': + case 'next': + var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1); + switch (this.viewMode){ + case 0: + this.viewDate = this.moveMonth(this.viewDate, dir); + this._trigger('changeMonth', this.viewDate); + break; + case 1: + case 2: + this.viewDate = this.moveYear(this.viewDate, dir); + if (this.viewMode === 1) + this._trigger('changeYear', this.viewDate); + break; + } + this.fill(); + break; + case 'today': + var date = new Date(); + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); + + this.showMode(-2); + var which = this.o.todayBtn === 'linked' ? null : 'view'; + this._setDate(date, which); + break; + case 'clear': + var element; + if (this.isInput) + element = this.element; + else if (this.component) + element = this.element.find('input'); + if (element) + element.val("").change(); + this.update(); + this._trigger('changeDate'); + if (this.o.autoclose) + this.hide(); + break; + } + break; + case 'span': + if (!target.is('.disabled')){ + this.viewDate.setUTCDate(1); + if (target.is('.month')){ + day = 1; + month = target.parent().find('span').index(target); + year = this.viewDate.getUTCFullYear(); + this.viewDate.setUTCMonth(month); + this._trigger('changeMonth', this.viewDate); + if (this.o.minViewMode === 1){ + this._setDate(UTCDate(year, month, day)); + } + } + else { + day = 1; + month = 0; + year = parseInt(target.text(), 10)||0; + this.viewDate.setUTCFullYear(year); + this._trigger('changeYear', this.viewDate); + if (this.o.minViewMode === 2){ + this._setDate(UTCDate(year, month, day)); + } + } + this.showMode(-1); + this.fill(); + } + break; + case 'td': + if (target.is('.day') && !target.is('.disabled')){ + day = parseInt(target.text(), 10)||1; + year = this.viewDate.getUTCFullYear(); + month = this.viewDate.getUTCMonth(); + if (target.is('.old')){ + if (month === 0){ + month = 11; + year -= 1; + } + else { + month -= 1; + } + } + else if (target.is('.new')){ + if (month === 11){ + month = 0; + year += 1; + } + else { + month += 1; + } + } + this._setDate(UTCDate(year, month, day)); + } + break; + } + } + if (this.picker.is(':visible') && this._focused_from){ + $(this._focused_from).focus(); + } + delete this._focused_from; + }, + + _toggle_multidate: function(date){ + var ix = this.dates.contains(date); + if (!date){ + this.dates.clear(); + } + else if (ix !== -1){ + this.dates.remove(ix); + } + else { + this.dates.push(date); + } + if (typeof this.o.multidate === 'number') + while (this.dates.length > this.o.multidate) + this.dates.remove(0); + }, + + _setDate: function(date, which){ + if (!which || which === 'date') + this._toggle_multidate(date && new Date(date)); + if (!which || which === 'view') + this.viewDate = date && new Date(date); + + this.fill(); + this.setValue(); + this._trigger('changeDate'); + var element; + if (this.isInput){ + element = this.element; + } + else if (this.component){ + element = this.element.find('input'); + } + if (element){ + element.change(); + } + if (this.o.autoclose && (!which || which === 'date')){ + this.hide(); + } + }, + + moveMonth: function(date, dir){ + if (!date) + return undefined; + if (!dir) + return date; + var new_date = new Date(date.valueOf()), + day = new_date.getUTCDate(), + month = new_date.getUTCMonth(), + mag = Math.abs(dir), + new_month, test; + dir = dir > 0 ? 1 : -1; + if (mag === 1){ + test = dir === -1 + // If going back one month, make sure month is not current month + // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) + ? function(){ + return new_date.getUTCMonth() === month; + } + // If going forward one month, make sure month is as expected + // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) + : function(){ + return new_date.getUTCMonth() !== new_month; + }; + new_month = month + dir; + new_date.setUTCMonth(new_month); + // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 + if (new_month < 0 || new_month > 11) + new_month = (new_month + 12) % 12; + } + else { + // For magnitudes >1, move one month at a time... + for (var i=0; i < mag; i++) + // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)... + new_date = this.moveMonth(new_date, dir); + // ...then reset the day, keeping it in the new month + new_month = new_date.getUTCMonth(); + new_date.setUTCDate(day); + test = function(){ + return new_month !== new_date.getUTCMonth(); + }; + } + // Common date-resetting loop -- if date is beyond end of month, make it + // end of month + while (test()){ + new_date.setUTCDate(--day); + new_date.setUTCMonth(new_month); + } + return new_date; + }, + + moveYear: function(date, dir){ + return this.moveMonth(date, dir*12); + }, + + dateWithinRange: function(date){ + return date >= this.o.startDate && date <= this.o.endDate; + }, + + keydown: function(e){ + if (this.picker.is(':not(:visible)')){ + if (e.keyCode === 27) // allow escape to hide and re-show picker + this.show(); + return; + } + var dateChanged = false, + dir, newDate, newViewDate, + focusDate = this.focusDate || this.viewDate; + switch (e.keyCode){ + case 27: // escape + if (this.focusDate){ + this.focusDate = null; + this.viewDate = this.dates.get(-1) || this.viewDate; + this.fill(); + } + else + this.hide(); + e.preventDefault(); + break; + case 37: // left + case 39: // right + if (!this.o.keyboardNavigation) + break; + dir = e.keyCode === 37 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir); + newViewDate = this.moveYear(focusDate, dir); + this._trigger('changeYear', this.viewDate); + } + else if (e.shiftKey){ + newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir); + newViewDate = this.moveMonth(focusDate, dir); + this._trigger('changeMonth', this.viewDate); + } + else { + newDate = new Date(this.dates.get(-1) || UTCToday()); + newDate.setUTCDate(newDate.getUTCDate() + dir); + newViewDate = new Date(focusDate); + newViewDate.setUTCDate(focusDate.getUTCDate() + dir); + } + if (this.dateWithinRange(newDate)){ + this.focusDate = this.viewDate = newViewDate; + this.setValue(); + this.fill(); + e.preventDefault(); + } + break; + case 38: // up + case 40: // down + if (!this.o.keyboardNavigation) + break; + dir = e.keyCode === 38 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir); + newViewDate = this.moveYear(focusDate, dir); + this._trigger('changeYear', this.viewDate); + } + else if (e.shiftKey){ + newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir); + newViewDate = this.moveMonth(focusDate, dir); + this._trigger('changeMonth', this.viewDate); + } + else { + newDate = new Date(this.dates.get(-1) || UTCToday()); + newDate.setUTCDate(newDate.getUTCDate() + dir * 7); + newViewDate = new Date(focusDate); + newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7); + } + if (this.dateWithinRange(newDate)){ + this.focusDate = this.viewDate = newViewDate; + this.setValue(); + this.fill(); + e.preventDefault(); + } + break; + case 32: // spacebar + // Spacebar is used in manually typing dates in some formats. + // As such, its behavior should not be hijacked. + break; + case 13: // enter + focusDate = this.focusDate || this.dates.get(-1) || this.viewDate; + this._toggle_multidate(focusDate); + dateChanged = true; + this.focusDate = null; + this.viewDate = this.dates.get(-1) || this.viewDate; + this.setValue(); + this.fill(); + if (this.picker.is(':visible')){ + e.preventDefault(); + if (this.o.autoclose) + this.hide(); + } + break; + case 9: // tab + this.focusDate = null; + this.viewDate = this.dates.get(-1) || this.viewDate; + this.fill(); + this.hide(); + break; + } + if (dateChanged){ + if (this.dates.length) + this._trigger('changeDate'); + else + this._trigger('clearDate'); + var element; + if (this.isInput){ + element = this.element; + } + else if (this.component){ + element = this.element.find('input'); + } + if (element){ + element.change(); + } + } + }, + + showMode: function(dir){ + if (dir){ + this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir)); + } + this.picker + .find('>div') + .hide() + .filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName) + .css('display', 'block'); + this.updateNavArrows(); + } + }; + + var DateRangePicker = function(element, options){ + this.element = $(element); + this.inputs = $.map(options.inputs, function(i){ + return i.jquery ? i[0] : i; + }); + delete options.inputs; + + $(this.inputs) + .datepicker(options) + .bind('changeDate', $.proxy(this.dateUpdated, this)); + + this.pickers = $.map(this.inputs, function(i){ + return $(i).data('datepicker'); + }); + this.updateDates(); + }; + DateRangePicker.prototype = { + updateDates: function(){ + this.dates = $.map(this.pickers, function(i){ + return i.getUTCDate(); + }); + this.updateRanges(); + }, + updateRanges: function(){ + var range = $.map(this.dates, function(d){ + return d.valueOf(); + }); + $.each(this.pickers, function(i, p){ + p.setRange(range); + }); + }, + dateUpdated: function(e){ + // `this.updating` is a workaround for preventing infinite recursion + // between `changeDate` triggering and `setUTCDate` calling. Until + // there is a better mechanism. + if (this.updating) + return; + this.updating = true; + + var dp = $(e.target).data('datepicker'), + new_date = dp.getUTCDate(), + i = $.inArray(e.target, this.inputs), + l = this.inputs.length; + if (i === -1) + return; + + $.each(this.pickers, function(i, p){ + if (!p.getUTCDate()) + p.setUTCDate(new_date); + }); + + if (new_date < this.dates[i]){ + // Date being moved earlier/left + while (i >= 0 && new_date < this.dates[i]){ + this.pickers[i--].setUTCDate(new_date); + } + } + else if (new_date > this.dates[i]){ + // Date being moved later/right + while (i < l && new_date > this.dates[i]){ + this.pickers[i++].setUTCDate(new_date); + } + } + this.updateDates(); + + delete this.updating; + }, + remove: function(){ + $.map(this.pickers, function(p){ p.remove(); }); + delete this.element.data().datepicker; + } + }; + + function opts_from_el(el, prefix){ + // Derive options from element data-attrs + var data = $(el).data(), + out = {}, inkey, + replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'); + prefix = new RegExp('^' + prefix.toLowerCase()); + function re_lower(_,a){ + return a.toLowerCase(); + } + for (var key in data) + if (prefix.test(key)){ + inkey = key.replace(replace, re_lower); + out[inkey] = data[key]; + } + return out; + } + + function opts_from_locale(lang){ + // Derive options from locale plugins + var out = {}; + // Check if "de-DE" style date is available, if not language should + // fallback to 2 letter code eg "de" + if (!dates[lang]){ + lang = lang.split('-')[0]; + if (!dates[lang]) + return; + } + var d = dates[lang]; + $.each(locale_opts, function(i,k){ + if (k in d) + out[k] = d[k]; + }); + return out; + } + + var old = $.fn.datepicker; + $.fn.datepicker = function(option){ + var args = Array.apply(null, arguments); + args.shift(); + var internal_return; + this.each(function(){ + var $this = $(this), + data = $this.data('datepicker'), + options = typeof option === 'object' && option; + if (!data){ + var elopts = opts_from_el(this, 'date'), + // Preliminary otions + xopts = $.extend({}, defaults, elopts, options), + locopts = opts_from_locale(xopts.language), + // Options priority: js args, data-attrs, locales, defaults + opts = $.extend({}, defaults, locopts, elopts, options); + if ($this.is('.input-daterange') || opts.inputs){ + var ropts = { + inputs: opts.inputs || $this.find('input').toArray() + }; + $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts)))); + } + else { + $this.data('datepicker', (data = new Datepicker(this, opts))); + } + } + if (typeof option === 'string' && typeof data[option] === 'function'){ + internal_return = data[option].apply(data, args); + if (internal_return !== undefined) + return false; + } + }); + if (internal_return !== undefined) + return internal_return; + else + return this; + }; + + var defaults = $.fn.datepicker.defaults = { + autoclose: false, + beforeShowDay: $.noop, + calendarWeeks: false, + clearBtn: false, + daysOfWeekDisabled: [], + endDate: Infinity, + forceParse: true, + format: 'mm/dd/yyyy', + keyboardNavigation: true, + language: 'en', + minViewMode: 0, + multidate: false, + multidateSeparator: ',', + orientation: "auto", + rtl: false, + startDate: -Infinity, + startView: 0, + todayBtn: false, + todayHighlight: false, + weekStart: 0 + }; + var locale_opts = $.fn.datepicker.locale_opts = [ + 'format', + 'rtl', + 'weekStart' + ]; + $.fn.datepicker.Constructor = Datepicker; + var dates = $.fn.datepicker.dates = { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + clear: "Clear" + } + }; + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + }], + isLeapYear: function(year){ + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); + }, + getDaysInMonth: function(year, month){ + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }, + validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, + nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, + parseFormat: function(format){ + // IE treats \0 as a string end in inputs (truncating the value), + // so it's a bad format delimiter, anyway + var separators = format.replace(this.validParts, '\0').split('\0'), + parts = format.match(this.validParts); + if (!separators || !separators.length || !parts || parts.length === 0){ + throw new Error("Invalid date format."); + } + return {separators: separators, parts: parts}; + }, + parseDate: function(date, format, language){ + if (!date) + return undefined; + if (date instanceof Date) + return date; + if (typeof format === 'string') + format = DPGlobal.parseFormat(format); + var part_re = /([\-+]\d+)([dmwy])/, + parts = date.match(/([\-+]\d+)([dmwy])/g), + part, dir, i; + if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){ + date = new Date(); + for (i=0; i < parts.length; i++){ + part = part_re.exec(parts[i]); + dir = parseInt(part[1]); + switch (part[2]){ + case 'd': + date.setUTCDate(date.getUTCDate() + dir); + break; + case 'm': + date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir); + break; + case 'w': + date.setUTCDate(date.getUTCDate() + dir * 7); + break; + case 'y': + date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir); + break; + } + } + return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0); + } + parts = date && date.match(this.nonpunctuation) || []; + date = new Date(); + var parsed = {}, + setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'], + setters_map = { + yyyy: function(d,v){ + return d.setUTCFullYear(v); + }, + yy: function(d,v){ + return d.setUTCFullYear(2000+v); + }, + m: function(d,v){ + if (isNaN(d)) + return d; + v -= 1; + while (v < 0) v += 12; + v %= 12; + d.setUTCMonth(v); + while (d.getUTCMonth() !== v) + d.setUTCDate(d.getUTCDate()-1); + return d; + }, + d: function(d,v){ + return d.setUTCDate(v); + } + }, + val, filtered; + setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m']; + setters_map['dd'] = setters_map['d']; + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); + var fparts = format.parts.slice(); + // Remove noop parts + if (parts.length !== fparts.length){ + fparts = $(fparts).filter(function(i,p){ + return $.inArray(p, setters_order) !== -1; + }).toArray(); + } + // Process remainder + function match_part(){ + var m = this.slice(0, parts[i].length), + p = parts[i].slice(0, m.length); + return m === p; + } + if (parts.length === fparts.length){ + var cnt; + for (i=0, cnt = fparts.length; i < cnt; i++){ + val = parseInt(parts[i], 10); + part = fparts[i]; + if (isNaN(val)){ + switch (part){ + case 'MM': + filtered = $(dates[language].months).filter(match_part); + val = $.inArray(filtered[0], dates[language].months) + 1; + break; + case 'M': + filtered = $(dates[language].monthsShort).filter(match_part); + val = $.inArray(filtered[0], dates[language].monthsShort) + 1; + break; + } + } + parsed[part] = val; + } + var _date, s; + for (i=0; i < setters_order.length; i++){ + s = setters_order[i]; + if (s in parsed && !isNaN(parsed[s])){ + _date = new Date(date); + setters_map[s](_date, parsed[s]); + if (!isNaN(_date)) + date = _date; + } + } + } + return date; + }, + formatDate: function(date, format, language){ + if (!date) + return ''; + if (typeof format === 'string') + format = DPGlobal.parseFormat(format); + var val = { + d: date.getUTCDate(), + D: dates[language].daysShort[date.getUTCDay()], + DD: dates[language].days[date.getUTCDay()], + m: date.getUTCMonth() + 1, + M: dates[language].monthsShort[date.getUTCMonth()], + MM: dates[language].months[date.getUTCMonth()], + yy: date.getUTCFullYear().toString().substring(2), + yyyy: date.getUTCFullYear() + }; + val.dd = (val.d < 10 ? '0' : '') + val.d; + val.mm = (val.m < 10 ? '0' : '') + val.m; + date = []; + var seps = $.extend([], format.separators); + for (var i=0, cnt = format.parts.length; i <= cnt; i++){ + if (seps.length) + date.push(seps.shift()); + date.push(val[format.parts[i]]); + } + return date.join(''); + }, + headTemplate: ''+ + ''+ + '«'+ + ''+ + '»'+ + ''+ + '', + contTemplate: '', + footTemplate: ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '' + }; + DPGlobal.template = '
    '+ + '
    '+ + ''+ + DPGlobal.headTemplate+ + ''+ + DPGlobal.footTemplate+ + '
    '+ + '
    '+ + '
    '+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
    '+ + '
    '+ + '
    '+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
    '+ + '
    '+ + '
    '; + + $.fn.datepicker.DPGlobal = DPGlobal; + + + /* DATEPICKER NO CONFLICT + * =================== */ + + $.fn.datepicker.noConflict = function(){ + $.fn.datepicker = old; + return this; + }; + + + /* DATEPICKER DATA-API + * ================== */ + + $(document).on( + 'focus.datepicker.data-api click.datepicker.data-api', + '[data-provide="datepicker"]', + function(e){ + var $this = $(this); + if ($this.data('datepicker')) + return; + e.preventDefault(); + // component click requires us to explicitly show it + $this.datepicker('show'); + } + ); + $(function(){ + $('[data-provide="datepicker-inline"]').datepicker(); + }); + +}(window.jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ar.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ar.js new file mode 100644 index 00000000..12ae1821 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ar.js @@ -0,0 +1,15 @@ +/** + * Arabic translation for bootstrap-datepicker + * Mohammed Alshehri + */ +;(function($){ + $.fn.datepicker.dates['ar'] = { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + monthsShort: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + today: "هذا اليوم", + rtl: true + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.az.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.az.js new file mode 100644 index 00000000..0285341c --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.az.js @@ -0,0 +1,12 @@ +// Azerbaijani +;(function($){ + $.fn.datepicker.dates['az'] = { + days: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə", "Bazar"], + daysShort: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş.", "B."], + daysMin: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş.", "B."], + months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"], + monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "İyun", "İyul", "Avq", "Sen", "Okt", "Noy", "Dek"], + today: "Bu gün", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.bg.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.bg.js new file mode 100644 index 00000000..6837afd9 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.bg.js @@ -0,0 +1,14 @@ +/** + * Bulgarian translation for bootstrap-datepicker + * Apostol Apostolov + */ +;(function($){ + $.fn.datepicker.dates['bg'] = { + days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"], + daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"], + daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"], + months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "днес" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ca.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ca.js new file mode 100644 index 00000000..3fc4d844 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ca.js @@ -0,0 +1,14 @@ +/** + * Catalan translation for bootstrap-datepicker + * J. Garcia + */ +;(function($){ + $.fn.datepicker.dates['ca'] = { + days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"], + daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"], + daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"], + months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"], + monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"], + today: "Avui" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.cs.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.cs.js new file mode 100644 index 00000000..f76a2c08 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.cs.js @@ -0,0 +1,15 @@ +/** + * Czech translation for bootstrap-datepicker + * Matěj Koubík + * Fixes by Michal Remiš + */ +;(function($){ + $.fn.datepicker.dates['cs'] = { + days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"], + daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"], + daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"], + months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], + monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], + today: "Dnes" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.cy.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.cy.js new file mode 100644 index 00000000..7e1136ab --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.cy.js @@ -0,0 +1,14 @@ +/** + * Welsh translation for bootstrap-datepicker + * S. Morris + */ +;(function($){ + $.fn.datepicker.dates['cy'] = { + days: ["Sul", "Llun", "Mawrth", "Mercher", "Iau", "Gwener", "Sadwrn", "Sul"], + daysShort: ["Sul", "Llu", "Maw", "Mer", "Iau", "Gwe", "Sad", "Sul"], + daysMin: ["Su", "Ll", "Ma", "Me", "Ia", "Gwe", "Sa", "Su"], + months: ["Ionawr", "Chewfror", "Mawrth", "Ebrill", "Mai", "Mehefin", "Gorfennaf", "Awst", "Medi", "Hydref", "Tachwedd", "Rhagfyr"], + monthsShort: ["Ion", "Chw", "Maw", "Ebr", "Mai", "Meh", "Gor", "Aws", "Med", "Hyd", "Tach", "Rha"], + today: "Heddiw" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.da.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.da.js new file mode 100644 index 00000000..c3d702d4 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.da.js @@ -0,0 +1,15 @@ +/** + * Danish translation for bootstrap-datepicker + * Christian Pedersen + */ +;(function($){ + $.fn.datepicker.dates['da'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag", + clear: "Nulstil" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.de.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.de.js new file mode 100644 index 00000000..a27ba578 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.de.js @@ -0,0 +1,17 @@ +/** + * German translation for bootstrap-datepicker + * Sam Zurcher + */ +;(function($){ + $.fn.datepicker.dates['de'] = { + days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], + daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], + daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], + months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], + monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], + today: "Heute", + clear: "Löschen", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.el.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.el.js new file mode 100644 index 00000000..3b630f38 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.el.js @@ -0,0 +1,13 @@ +/** + * Greek translation for bootstrap-datepicker + */ +;(function($){ + $.fn.datepicker.dates['el'] = { + days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"], + daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"], + daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"], + months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], + monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], + today: "Σήμερα" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.es.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.es.js new file mode 100644 index 00000000..72176902 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.es.js @@ -0,0 +1,14 @@ +/** + * Spanish translation for bootstrap-datepicker + * Bruno Bonamin + */ +;(function($){ + $.fn.datepicker.dates['es'] = { + days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], + daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"], + months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], + monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], + today: "Hoy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.et.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.et.js new file mode 100644 index 00000000..87c812ed --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.et.js @@ -0,0 +1,18 @@ +/** + * Estonian translation for bootstrap-datepicker + * Ando Roots + * Fixes by Illimar Tambek < + */ +;(function($){ + $.fn.datepicker.dates['et'] = { + days: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev", "Pühapäev"], + daysShort: ["Pühap", "Esmasp", "Teisip", "Kolmap", "Neljap", "Reede", "Laup", "Pühap"], + daysMin: ["P", "E", "T", "K", "N", "R", "L", "P"], + months: ["Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember"], + monthsShort: ["Jaan", "Veebr", "Märts", "Apr", "Mai", "Juuni", "Juuli", "Aug", "Sept", "Okt", "Nov", "Dets"], + today: "Täna", + clear: "Tühjenda", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fa.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fa.js new file mode 100644 index 00000000..6503c85d --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fa.js @@ -0,0 +1,17 @@ +/** + * Persian translation for bootstrap-datepicker + * Mostafa Rokooie + */ +;(function($){ + $.fn.datepicker.dates['fa'] = { + days: ["یک‌شنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنج‌شنبه", "جمعه", "شنبه", "یک‌شنبه"], + daysShort: ["یک", "دو", "سه", "چهار", "پنج", "جمعه", "شنبه", "یک"], + daysMin: ["ی", "د", "س", "چ", "پ", "ج", "ش", "ی"], + months: ["ژانویه", "فوریه", "مارس", "آوریل", "مه", "ژوئن", "ژوئیه", "اوت", "سپتامبر", "اکتبر", "نوامبر", "دسامبر"], + monthsShort: ["ژان", "فور", "مار", "آور", "مه", "ژون", "ژوی", "اوت", "سپت", "اکت", "نوا", "دسا"], + today: "امروز", + clear: "پاک کن", + weekStart: 1, + format: "yyyy/mm/dd" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fi.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fi.js new file mode 100644 index 00000000..01f40dc2 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fi.js @@ -0,0 +1,16 @@ +/** + * Finnish translation for bootstrap-datepicker + * Jaakko Salonen + */ +;(function($){ + $.fn.datepicker.dates['fi'] = { + days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"], + daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"], + daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"], + months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], + monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"], + today: "tänään", + weekStart: 1, + format: "d.m.yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fr.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fr.js new file mode 100644 index 00000000..eff07aa6 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.fr.js @@ -0,0 +1,17 @@ +/** + * French translation for bootstrap-datepicker + * Nico Mollet + */ +;(function($){ + $.fn.datepicker.dates['fr'] = { + days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], + daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], + daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"], + months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + monthsShort: ["Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc"], + today: "Aujourd'hui", + clear: "Effacer", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.gl.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.gl.js new file mode 100644 index 00000000..538fd5e3 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.gl.js @@ -0,0 +1,11 @@ +;(function($){ + $.fn.datepicker.dates['gl'] = { + days: ["Domingo", "Luns", "Martes", "Mércores", "Xoves", "Venres", "Sábado", "Domingo"], + daysShort: ["Dom", "Lun", "Mar", "Mér", "Xov", "Ven", "Sáb", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Me", "Xo", "Ve", "Sa", "Do"], + months: ["Xaneiro", "Febreiro", "Marzo", "Abril", "Maio", "Xuño", "Xullo", "Agosto", "Setembro", "Outubro", "Novembro", "Decembro"], + monthsShort: ["Xan", "Feb", "Mar", "Abr", "Mai", "Xun", "Xul", "Ago", "Sep", "Out", "Nov", "Dec"], + today: "Hoxe", + clear: "Limpar" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.he.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.he.js new file mode 100644 index 00000000..2e17393b --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.he.js @@ -0,0 +1,15 @@ +/** + * Hebrew translation for bootstrap-datepicker + * Sagie Maoz + */ +;(function($){ + $.fn.datepicker.dates['he'] = { + days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], + daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], + monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], + today: "היום", + rtl: true + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.hr.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.hr.js new file mode 100644 index 00000000..655ea54b --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.hr.js @@ -0,0 +1,13 @@ +/** + * Croatian localisation + */ +;(function($){ + $.fn.datepicker.dates['hr'] = { + days: ["Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota", "Nedjelja"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub", "Ned"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su", "Ne"], + months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], + monthsShort: ["Sij", "Velj", "Ožu", "Tra", "Svi", "Lip", "Srp", "Kol", "Ruj", "Lis", "Stu", "Pro"], + today: "Danas" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.hu.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.hu.js new file mode 100644 index 00000000..bf5308a1 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.hu.js @@ -0,0 +1,16 @@ +/** + * Hungarian translation for bootstrap-datepicker + * Sotus László + */ +;(function($){ + $.fn.datepicker.dates['hu'] = { + days: ["Vasárnap", "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat", "Vasárnap"], + daysShort: ["Vas", "Hét", "Ked", "Sze", "Csü", "Pén", "Szo", "Vas"], + daysMin: ["Va", "Hé", "Ke", "Sz", "Cs", "Pé", "Sz", "Va"], + months: ["Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Már", "Ápr", "Máj", "Jún", "Júl", "Aug", "Sze", "Okt", "Nov", "Dec"], + today: "Ma", + weekStart: 1, + format: "yyyy.mm.dd" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.id.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.id.js new file mode 100644 index 00000000..aae6e896 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.id.js @@ -0,0 +1,15 @@ +/** + * Bahasa translation for bootstrap-datepicker + * Azwar Akbar + */ +;(function($){ + $.fn.datepicker.dates['id'] = { + days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], + daysShort: ["Mgu", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mgu"], + daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"], + months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"], + today: "Hari Ini", + clear: "Kosongkan" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.is.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.is.js new file mode 100644 index 00000000..0e57a916 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.is.js @@ -0,0 +1,14 @@ +/** + * Icelandic translation for bootstrap-datepicker + * Hinrik Örn Sigurðsson + */ +;(function($){ + $.fn.datepicker.dates['is'] = { + days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur", "Sunnudagur"], + daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau", "Sun"], + daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La", "Su"], + months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], + today: "Í Dag" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.it.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.it.js new file mode 100644 index 00000000..9f476fa2 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.it.js @@ -0,0 +1,17 @@ +/** + * Italian translation for bootstrap-datepicker + * Enrico Rubboli + */ +;(function($){ + $.fn.datepicker.dates['it'] = { + days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato", "Domenica"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + clear: "Cancella", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ja.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ja.js new file mode 100644 index 00000000..ed0bc0f9 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ja.js @@ -0,0 +1,15 @@ +/** + * Japanese translation for bootstrap-datepicker + * Norio Suzuki + */ +;(function($){ + $.fn.datepicker.dates['ja'] = { + days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜", "日曜"], + daysShort: ["日", "月", "火", "水", "木", "金", "土", "日"], + daysMin: ["日", "月", "火", "水", "木", "金", "土", "日"], + months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今日", + format: "yyyy/mm/dd" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ka.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ka.js new file mode 100644 index 00000000..54344549 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ka.js @@ -0,0 +1,17 @@ +/** + * Georgian translation for bootstrap-datepicker + * Levan Melikishvili + */ +;(function($){ + $.fn.datepicker.dates['ka'] = { + days: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი", "კვირა"], + daysShort: ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ", "კვი"], + daysMin: ["კვ", "ორ", "სა", "ოთ", "ხუ", "პა", "შა", "კვ"], + months: ["იანვარი", "თებერვალი", "მარტი", "აპრილი", "მაისი", "ივნისი", "ივლისი", "აგვისტო", "სექტემბერი", "ოქტომები", "ნოემბერი", "დეკემბერი"], + monthsShort: ["იან", "თებ", "მარ", "აპრ", "მაი", "ივნ", "ივლ", "აგვ", "სექ", "ოქტ", "ნოე", "დეკ"], + today: "დღეს", + clear: "გასუფთავება", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.kk.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.kk.js new file mode 100644 index 00000000..94dd6b8f --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.kk.js @@ -0,0 +1,15 @@ +/** + * Kazakh translation for bootstrap-datepicker + * Yerzhan Tolekov + */ +;(function($){ + $.fn.datepicker.dates['kk'] = { + days: ["Жексенбі", "Дүйсенбі", "Сейсенбі", "Сәрсенбі", "Бейсенбі", "Жұма", "Сенбі", "Жексенбі"], + daysShort: ["Жек", "Дүй", "Сей", "Сәр", "Бей", "Жұм", "Сен", "Жек"], + daysMin: ["Жк", "Дс", "Сс", "Ср", "Бс", "Жм", "Сн", "Жк"], + months: ["Қаңтар", "Ақпан", "Наурыз", "Сәуір", "Мамыр", "Маусым", "Шілде", "Тамыз", "Қыркүйек", "Қазан", "Қараша", "Желтоқсан"], + monthsShort: ["Қаң", "Ақп", "Нау", "Сәу", "Мамыр", "Мау", "Шлд", "Тмз", "Қыр", "Қзн", "Қар", "Жел"], + today: "Бүгін", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.kr.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.kr.js new file mode 100644 index 00000000..183a88d1 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.kr.js @@ -0,0 +1,13 @@ +/** + * Korean translation for bootstrap-datepicker + * Gu Youn + */ +;(function($){ + $.fn.datepicker.dates['kr'] = { + days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"], + daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"], + daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"], + months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"] + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.lt.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.lt.js new file mode 100644 index 00000000..11c1b3ad --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.lt.js @@ -0,0 +1,16 @@ +/** + * Lithuanian translation for bootstrap-datepicker + * Šarūnas Gliebus + */ + +;(function($){ + $.fn.datepicker.dates['lt'] = { + days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis", "Sekmadienis"], + daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š", "S"], + daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št", "Sk"], + months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], + monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], + today: "Šiandien", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.lv.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.lv.js new file mode 100644 index 00000000..76d0f3a6 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.lv.js @@ -0,0 +1,16 @@ +/** + * Latvian translation for bootstrap-datepicker + * Artis Avotins + */ + +;(function($){ + $.fn.datepicker.dates['lv'] = { + days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena", "Svētdiena"], + daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S", "Sv"], + daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se", "Sv"], + months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Šodien", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.mk.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.mk.js new file mode 100644 index 00000000..0ab8cf68 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.mk.js @@ -0,0 +1,15 @@ +/** + * Macedonian translation for bootstrap-datepicker + * Marko Aleksic + */ +;(function($){ + $.fn.datepicker.dates['mk'] = { + days: ["Недела", "Понеделник", "Вторник", "Среда", "Четврток", "Петок", "Сабота", "Недела"], + daysShort: ["Нед", "Пон", "Вто", "Сре", "Чет", "Пет", "Саб", "Нед"], + daysMin: ["Не", "По", "Вт", "Ср", "Че", "Пе", "Са", "Не"], + months: ["Јануари", "Февруари", "Март", "Април", "Мај", "Јуни", "Јули", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Јан", "Фев", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "Денес", + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ms.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ms.js new file mode 100644 index 00000000..fa3a21a5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ms.js @@ -0,0 +1,14 @@ +/** + * Malay translation for bootstrap-datepicker + * Ateman Faiz + */ +;(function($){ + $.fn.datepicker.dates['ms'] = { + days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu", "Ahad"], + daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"], + daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"], + months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], + today: "Hari Ini" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nb.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nb.js new file mode 100644 index 00000000..7b28e84f --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nb.js @@ -0,0 +1,14 @@ +/** + * Norwegian (bokmål) translation for bootstrap-datepicker + * Fredrik Sundmyhr + */ +;(function($){ + $.fn.datepicker.dates['nb'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], + today: "I Dag" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nl-BE.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nl-BE.js new file mode 100644 index 00000000..ee4201a6 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nl-BE.js @@ -0,0 +1,17 @@ +/** + * Belgium-Dutch translation for bootstrap-datepicker + * Julien Poulin + */ +;(function($){ + $.fn.datepicker.dates['nl-BE'] = { + days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], + daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Vandaag", + clear: "Leegmaken", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nl.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nl.js new file mode 100644 index 00000000..13a2f1a3 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.nl.js @@ -0,0 +1,14 @@ +/** + * Dutch translation for bootstrap-datepicker + * Reinier Goltstein + */ +;(function($){ + $.fn.datepicker.dates['nl'] = { + days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], + daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Vandaag" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.no.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.no.js new file mode 100644 index 00000000..c29ec83b --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.no.js @@ -0,0 +1,16 @@ +/** + * Norwegian translation for bootstrap-datepicker + **/ +;(function($){ + $.fn.datepicker.dates['no'] = { + days: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], + daysShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], + daysMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], + months: ['Januar','Februar','Mars','April','Mai','Juni','Juli','August','September','Oktober','November','Desember'], + monthsShort: ['Jan','Feb','Mar','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Des'], + today: 'I dag', + clear: 'Nullstill', + weekStart: 1, + format: 'dd.mm.yyyy' + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pl.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pl.js new file mode 100644 index 00000000..f3fff8c8 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pl.js @@ -0,0 +1,15 @@ +/** + * Polish translation for bootstrap-datepicker + * Robert + */ +;(function($){ + $.fn.datepicker.dates['pl'] = { + days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"], + daysShort: ["Nie", "Pn", "Wt", "Śr", "Czw", "Pt", "So", "Nie"], + daysMin: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"], + months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], + monthsShort: ["Sty", "Lu", "Mar", "Kw", "Maj", "Cze", "Lip", "Sie", "Wrz", "Pa", "Lis", "Gru"], + today: "Dzisiaj", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pt-BR.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pt-BR.js new file mode 100644 index 00000000..eb642b7c --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pt-BR.js @@ -0,0 +1,15 @@ +/** + * Brazilian translation for bootstrap-datepicker + * Cauan Cabral + */ +;(function($){ + $.fn.datepicker.dates['pt-BR'] = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + clear: "Limpar" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pt.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pt.js new file mode 100644 index 00000000..e54981d3 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.pt.js @@ -0,0 +1,16 @@ +/** + * Portuguese translation for bootstrap-datepicker + * Original code: Cauan Cabral + * Tiago Melo + */ +;(function($){ + $.fn.datepicker.dates['pt'] = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + clear: "Limpar" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ro.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ro.js new file mode 100644 index 00000000..e1e65df2 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ro.js @@ -0,0 +1,16 @@ +/** + * Romanian translation for bootstrap-datepicker + * Cristian Vasile + */ +;(function($){ + $.fn.datepicker.dates['ro'] = { + days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"], + daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"], + daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"], + months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], + monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Astăzi", + clear: "Șterge", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.rs-latin.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.rs-latin.js new file mode 100644 index 00000000..d9424852 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.rs-latin.js @@ -0,0 +1,14 @@ +/** + * Serbian latin translation for bootstrap-datepicker + * Bojan Milosavlević + */ +;(function($){ + $.fn.datepicker.dates['rs-latin'] = { + days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota", "Nedelja"], + daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub", "Ned"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su", "N"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.rs.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.rs.js new file mode 100644 index 00000000..6b657473 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.rs.js @@ -0,0 +1,14 @@ +/** + * Serbian cyrillic translation for bootstrap-datepicker + * Bojan Milosavlević + */ +;(function($){ + $.fn.datepicker.dates['rs'] = { + days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота", "Недеља"], + daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб", "Нед"], + daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су", "Н"], + months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], + monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], + today: "Данас" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ru.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ru.js new file mode 100644 index 00000000..e230aa92 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ru.js @@ -0,0 +1,15 @@ +/** + * Russian translation for bootstrap-datepicker + * Victor Taranenko + */ +;(function($){ + $.fn.datepicker.dates['ru'] = { + days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], + daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"], + daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"], + months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Сегодня", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sk.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sk.js new file mode 100644 index 00000000..c48032a5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sk.js @@ -0,0 +1,15 @@ +/** + * Slovak translation for bootstrap-datepicker + * Marek Lichtner + * Fixes by Michal Remiš + */ +;(function($){ + $.fn.datepicker.dates["sk"] = { + days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"], + daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob", "Ned"], + daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So", "Ne"], + months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Dnes" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sl.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sl.js new file mode 100644 index 00000000..41b0e060 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sl.js @@ -0,0 +1,14 @@ +/** + * Slovene translation for bootstrap-datepicker + * Gregor Rudolf + */ +;(function($){ + $.fn.datepicker.dates['sl'] = { + days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"], + daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"], + daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"], + months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danes" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sq.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sq.js new file mode 100644 index 00000000..a045a9d9 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sq.js @@ -0,0 +1,15 @@ +/** + * Albanian translation for bootstrap-datepicker + * Tomor Pupovci + */ +;(function($){ + $.fn.datepicker.dates['sq'] = { + days: ["E Diel", "E Hënë", "E martē", "E mërkurë", "E Enjte", "E Premte", "E Shtunë", "E Diel"], + daysShort: ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Shtu", "Die"], + daysMin: ["Di", "Hë", "Ma", "Më", "En", "Pr", "Sht", "Di"], + months: ["Janar", "Shkurt", "Mars", "Prill", "Maj", "Qershor", "Korrik", "Gusht", "Shtator", "Tetor", "Nëntor", "Dhjetor"], + monthsShort: ["Jan", "Shk", "Mar", "Pri", "Maj", "Qer", "Korr", "Gu", "Sht", "Tet", "Nën", "Dhjet"], + today: "Sot" + }; +}(jQuery)); + diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sv.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sv.js new file mode 100644 index 00000000..029cea00 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sv.js @@ -0,0 +1,16 @@ +/** + * Swedish translation for bootstrap-datepicker + * Patrik Ragnarsson + */ +;(function($){ + $.fn.datepicker.dates['sv'] = { + days: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"], + daysShort: ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"], + daysMin: ["Sö", "Må", "Ti", "On", "To", "Fr", "Lö", "Sö"], + months: ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Idag", + format: "yyyy-mm-dd", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sw.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sw.js new file mode 100644 index 00000000..622e0ef0 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.sw.js @@ -0,0 +1,15 @@ +/** + * Swahili translation for bootstrap-datepicker + * Edwin Mugendi + * Source: http://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku + */ +;(function($){ + $.fn.datepicker.dates['sw'] = { + days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili"], + daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1", "J2"], + daysMin: ["2", "3", "4", "5", "A", "I", "1", "2"], + months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], + monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], + today: "Leo" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.th.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.th.js new file mode 100644 index 00000000..562b063c --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.th.js @@ -0,0 +1,14 @@ +/** + * Thai translation for bootstrap-datepicker + * Suchau Jiraprapot + */ +;(function($){ + $.fn.datepicker.dates['th'] = { + days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], + daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], + monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], + today: "วันนี้" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.tr.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.tr.js new file mode 100644 index 00000000..2be8b6d8 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.tr.js @@ -0,0 +1,16 @@ +/** + * Turkish translation for bootstrap-datepicker + * Serkan Algur + */ +;(function($){ + $.fn.datepicker.dates['tr'] = { + days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar"], + daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts", "Pz"], + daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct", "Pz"], + months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], + monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], + today: "Bugün", + format: "dd.mm.yyyy" + }; +}(jQuery)); + diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ua.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ua.js new file mode 100644 index 00000000..d4bb0f02 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.ua.js @@ -0,0 +1,15 @@ +/** + * Ukrainian translation for bootstrap-datepicker + * Igor Polynets + */ +;(function($){ + $.fn.datepicker.dates['ua'] = { + days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятница", "Субота", "Неділя"], + daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], + daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], + months: ["Cічень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], + monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], + today: "Сьогодні", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.vi.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.vi.js new file mode 100644 index 00000000..a8cc52ee --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.vi.js @@ -0,0 +1,16 @@ +/** + * Vietnamese translation for bootstrap-datepicker + * An Vo + */ +;(function($){ + $.fn.datepicker.dates['vi'] = { + days: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy", "Chủ nhật"], + daysShort: ["CN", "Thứ 2", "Thứ 3", "Thứ 4", "Thứ 5", "Thứ 6", "Thứ 7", "CN"], + daysMin: ["CN", "T2", "T3", "T4", "T5", "T6", "T7", "CN"], + months: ["Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"], + monthsShort: ["Th1", "Th2", "Th3", "Th4", "Th5", "Th6", "Th7", "Th8", "Th9", "Th10", "Th11", "Th12"], + today: "Hôm nay", + clear: "Xóa", + format: "dd/mm/yyyy" + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.zh-TW.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.zh-TW.js new file mode 100644 index 00000000..53337ae0 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.zh-TW.js @@ -0,0 +1,17 @@ +/** + * Traditional Chinese translation for bootstrap-datepicker + * Rung-Sheng Jang + * FrankWu Fix more appropriate use of Traditional Chinese habit + */ +;(function($){ + $.fn.datepicker.dates['zh-TW'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], + daysShort: ["週日", "週一", "週二", "週三", "週四", "週五", "週六", "週日"], + daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + today: "今天", + format: "yyyy年mm月dd日", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.zh.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.zh.js new file mode 100644 index 00000000..d6625ec6 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/locales/bootstrap-datepicker.zh.js @@ -0,0 +1,16 @@ +/** + * Simplified Chinese translation for bootstrap-datepicker + * Yuan Cheung + */ +;(function($){ + $.fn.datepicker.dates['zh-CN'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], + daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + today: "今日", + format: "yyyy年mm月dd日", + weekStart: 1 + }; +}(jQuery)); diff --git a/scratch-parent/framework/includes/option-types/date-picker/static/js/scripts.js b/scratch-parent/framework/includes/option-types/date-picker/static/js/scripts.js new file mode 100644 index 00000000..8b5fbba4 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/date-picker/static/js/scripts.js @@ -0,0 +1,45 @@ +/** + * Script file that will manage the "map" option + */ + +"use strict"; + +function fw_option_type_date_picker_initialize( object ) { + var defaults = { + autoclose : true, + format : "dd-mm-yyyy", + weekStart : 1, + startDate : new Date(), + endDate : null + }; + var options = JSON.parse(object.attr('data-fw-option-date-picker-opts')); + + if( options.startDate != null || options.startDate != undefined ) { + var date = options.startDate.split('-'); + defaults.startDate = new Date( date[1]-1, date[2], date[0] ); + } + + if( options.endDate != null || options.endDate != undefined ) { + var date = options.endDate.split('-'); + defaults.endDate = new Date(date[1] - 1, date[2], date[0]); + } + + if( options.weekStart != null || options.weekStart != undefined ) { + defaults.weekStart = options.weekStart; + } + + object.datepicker(defaults); +} + +jQuery( document).ready( function( $ ) { + fwEvents.on('fw:options:init', function (data) { + var obj = data.$elements.find('.fw-option-type-date-picker'); + + if (!obj.length) + return; + + for (var i = 0; i < obj.length; i++) { + fw_option_type_date_picker_initialize( jQuery(obj[i]) ); + } + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/gradient/class-fw-option-type-gradient.php b/scratch-parent/framework/includes/option-types/gradient/class-fw-option-type-gradient.php new file mode 100644 index 00000000..c417223f --- /dev/null +++ b/scratch-parent/framework/includes/option-types/gradient/class-fw-option-type-gradient.php @@ -0,0 +1,87 @@ +get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/styles.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js', + array('jquery'), + fw()->manifest->get_version() + ); + } + + $output = fw_render_view(FW_DIR . '/includes/option-types/' . $this->get_type() . '/view.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data + )); + + return $output; + } + + public function get_type() + { + return 'gradient'; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (is_array($input_value)) { + if (!isset($input_value['primary']) || !preg_match('/^#[a-f0-9]{6}$/i', $input_value['primary'])) { + $input_value['primary'] = $option['value']['primary']; + } + + if (!isset($input_value['secondary']) || !preg_match('/^#[a-f0-9]{6}$/i', $input_value['secondary'])) { + $input_value['secondary'] = (isset($option['value']['secondary'])) ? $option['value']['secondary'] : false; + } + } else { + $input_value = $option['value']; + } + + return $input_value; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array( + 'primary' => '#FF0000', + 'secondary' => '#0000FF', + ) + ); + } +} + +FW_Option_Type::register('FW_Option_Type_Gradient'); diff --git a/scratch-parent/framework/includes/option-types/gradient/static/css/styles.css b/scratch-parent/framework/includes/option-types/gradient/static/css/styles.css new file mode 100644 index 00000000..92657d38 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/gradient/static/css/styles.css @@ -0,0 +1,21 @@ +.fw-backend-option-input-type-gradient .fw-option-help-in-input { + top: 4px !important; +} + +.fw-option-type-gradient .primary-color { + display: inline-block; +} + +.fw-option-type-gradient .secondary-color { + display: inline-block; +} + +.fw-option-type-gradient .delimiter { + display: inline-block; + padding: 0 4px; +} + +#side-sortables .fw-option-type-gradient .secondary-color, +#side-sortables .fw-option-type-gradient .primary-color { + width: inherit !important; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/gradient/static/js/scripts.js b/scratch-parent/framework/includes/option-types/gradient/static/js/scripts.js new file mode 100644 index 00000000..b0e17412 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/gradient/static/js/scripts.js @@ -0,0 +1,14 @@ +(function ($) { + fwEvents.on('fw:options:init', function (data) { + data.$elements.find('.fw-option.fw-option-type-gradient:not(.initialized)').each(function(){ + //onChange primary, set secondary with primary color + $(this).on('fw:color:picker:changed', function (event, data) { + if (data.$element.closest('.primary-color').length === 1) { + data.$element.closest('.fw-option-type-gradient').find('.secondary-color input.fw-option-type-color-picker.secondary.initialized').iris('color', data.ui.color.toString()); + } + }); + + $(this).addClass('initialized'); + }); + }); +})(jQuery); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/gradient/view.php b/scratch-parent/framework/includes/option-types/gradient/view.php new file mode 100644 index 00000000..7bdc7253 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/gradient/view.php @@ -0,0 +1,71 @@ + +
    > +
    + backend->option_type( 'color-picker' )->render( + 'primary', + array( + 'type' => 'color-picker', + 'value' => ( isset( $option['value']['primary'] ) && preg_match( $color_regex, $option['value']['primary'] ) ) + ? $option['value']['primary'] + : '#ffffff', + 'attr' => array( + 'class' => 'primary' + ) + ), + array( + 'value' => ( isset( $data['value']['primary'] ) && preg_match( $color_regex, $data['value']['primary'] ) ) + ? $data['value']['primary'] + : $option['value']['primary'], + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ); + ?> +
    + +
    +
    + backend->option_type( 'color-picker' )->render( + 'secondary', + array( + 'type' => 'color-picker', + 'value' => ( isset( $option['value']['secondary'] ) && preg_match( $color_regex, $option['value']['secondary'] ) ) + ? $option['value']['secondary'] + : '#ffffff', + 'attr' => array( + 'class' => 'secondary' + ) + ), + array( + 'value' => ( isset( $data['value']['secondary'] ) && preg_match( $color_regex, $data['value']['secondary'] ) ) + ? $data['value']['secondary'] + : $option['value']['secondary'], + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ); + ?> +
    + +
    diff --git a/scratch-parent/framework/includes/option-types/icon/class-fw-option-type-icon.php b/scratch-parent/framework/includes/option-types/icon/class-fw-option-type-icon.php new file mode 100644 index 00000000..bdb71f03 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/icon/class-fw-option-type-icon.php @@ -0,0 +1,67 @@ +get_type() .'-if', + FW_URI . '/includes/option-types/'. $this->get_type() .'/static/css/styles.css', + array('fw-font-awesome'), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-type-'. $this->get_type() .'-dialog', + FW_URI . '/includes/option-types/'. $this->get_type() .'/static/js/scripts.js', + array('jquery', 'fw-events'), + fw()->manifest->get_version() + ); + } + + $option['value'] = (string)$data['value']; + unset($option['attr']['value']); // be sure to remove value from attributes + + return fw_render_view(dirname(__FILE__) . '/view.php', compact('id', 'option', 'data')); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (is_null($input_value)) { + $input_value = $option['value']; + } + + return (string)$input_value; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => '' + ); + } +} +FW_Option_Type::register('FW_Option_Type_Icon'); diff --git a/scratch-parent/framework/includes/option-types/icon/static/css/styles.css b/scratch-parent/framework/includes/option-types/icon/static/css/styles.css new file mode 100644 index 00000000..8a4bfdf4 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/icon/static/css/styles.css @@ -0,0 +1,109 @@ +.fw-option-type-icon .show-if-dialog-icon-category-all, +.fw-option-type-icon .show-if-dialog-icon-category-web-app, +.fw-option-type-icon .show-if-dialog-icon-category-form, +.fw-option-type-icon .show-if-dialog-icon-category-currency, +.fw-option-type-icon .show-if-dialog-icon-category-editor, +.fw-option-type-icon .show-if-dialog-icon-category-direction, +.fw-option-type-icon .show-if-dialog-icon-category-video-player, +.fw-option-type-icon .show-if-dialog-icon-category-brand, +.fw-option-type-icon .show-if-dialog-icon-category-medical, +.fw-option-type-icon .ib-if-dialog-icon-category-all, +.fw-option-type-icon .ib-if-dialog-icon-category-web-app, +.fw-option-type-icon .ib-if-dialog-icon-category-form, +.fw-option-type-icon .ib-if-dialog-icon-category-currency, +.fw-option-type-icon .ib-if-dialog-icon-category-editor, +.fw-option-type-icon .ib-if-dialog-icon-category-direction, +.fw-option-type-icon .ib-if-dialog-icon-category-video-player, +.fw-option-type-icon .ib-if-dialog-icon-category-brand, +.fw-option-type-icon .ib-if-dialog-icon-category-medical { + display: none; +} + +.fw-option-type-icon .dialog-icon-category-all .show-if-dialog-icon-category-all, +.fw-option-type-icon .dialog-icon-category-web-app .show-if-dialog-icon-category-web-app, +.fw-option-type-icon .dialog-icon-category-form .show-if-dialog-icon-category-form, +.fw-option-type-icon .dialog-icon-category-currency .show-if-dialog-icon-category-currency, +.fw-option-type-icon .dialog-icon-category-editor .show-if-dialog-icon-category-editor, +.fw-option-type-icon .dialog-icon-category-direction .show-if-dialog-icon-category-direction, +.fw-option-type-icon .dialog-icon-category-video-player .show-if-dialog-icon-category-video-player, +.fw-option-type-icon .dialog-icon-category-brand .show-if-dialog-icon-category-brand, +.fw-option-type-icon .dialog-icon-category-medical .show-if-dialog-icon-category-medical { + display: block; +} + +.fw-option-type-icon .dialog-icon-category-all .ib-if-dialog-icon-category-all, +.fw-option-type-icon .dialog-icon-category-web-app .ib-if-dialog-icon-category-web-app, +.fw-option-type-icon .dialog-icon-category-form .ib-if-dialog-icon-category-form, +.fw-option-type-icon .dialog-icon-category-currency .ib-if-dialog-icon-category-currency, +.fw-option-type-icon .dialog-icon-category-editor .ib-if-dialog-icon-category-editor, +.fw-option-type-icon .dialog-icon-category-direction .ib-if-dialog-icon-category-direction, +.fw-option-type-icon .dialog-icon-category-video-player .ib-if-dialog-icon-category-video-player, +.fw-option-type-icon .dialog-icon-category-brand .ib-if-dialog-icon-category-brand, +.fw-option-type-icon .dialog-icon-category-medical .ib-if-dialog-icon-category-medical { + display: inline-block; +} + +.fw-option-type-icon .fontawesome-icon-list { + margin-top: 1em; + padding-left: 1px; + padding-bottom: 1px; + overflow: auto; + max-height: 10.1em; +} + +.fw-option-type-icon .fontawesome-icon-list:after { + content: ''; + display: block; + clear: both; +} + +.fw-option-type-icon .fontawesome-icon-list i { + float: left; + width: 1em; + border: 1px solid #e1e1e1; + margin: 0 0 -1px -1px; + padding: 0.5em; +} + +.fw-option-type-icon .fontawesome-icon-list i:before { + display: inline-block; + width: 1em; + text-align: center; +} + +.fw-option-type-icon .fontawesome-icon-list i.active, +.fw-option-type-icon .fontawesome-icon-list i:hover { + background: #2ea2cc; + color: #fff; + cursor: pointer; +} + +.fw-option-type-icon .fw-backend-option { + border-bottom: none; + padding-bottom: 0; +} + +.fw-option-type-icon .fw-options-tabs-wrapper .fw-options-tabs-contents { + margin-top: 0 !important; +} + + +/* Let's get this party started */ + +.fw-option-type-icon .fontawesome-icon-list::-webkit-scrollbar { + width: 5px; +} + + +/* Handle */ + +.fw-option-type-icon .fontawesome-icon-list::-webkit-scrollbar-thumb { + -webkit-border-radius: 2px; + border-radius: 2px; + background: rgba(92,92,92,0.8); + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); +} + +.fw-option-type-icon .fontawesome-icon-list::-webkit-scrollbar-thumb:window-inactive { + background: rgba(92,92,92,0.4); +} diff --git a/scratch-parent/framework/includes/option-types/icon/static/js/scripts.js b/scratch-parent/framework/includes/option-types/icon/static/js/scripts.js new file mode 100644 index 00000000..a307b67e --- /dev/null +++ b/scratch-parent/framework/includes/option-types/icon/static/js/scripts.js @@ -0,0 +1,35 @@ +jQuery(function ($) { + var categoryPrefix = 'dialog-icon-category-'; + var beginsWithPrefix = new RegExp('^' + categoryPrefix); + + fwEvents.on('fw:options:init', function (data) { + var optionSelector = '.fw-option-type-icon'; + var $options = data.$elements.find(optionSelector +':not(.initialized)'); + + // click on an icon + $options.on('click', '.fa', function () { + $(this).addClass('active').siblings().removeClass('active'); + $(this).closest(optionSelector).find('input').val( $(this).data('value') ); + }); + + // category select, show/hide categories + { + $options.find('[data-type=dialog-icon-category]') + .on('change', function () { + var $this = $(this); + var $container = $this.closest(optionSelector).find('.fontawesome-icon-list'); + + $.each(($container.attr('class') || '').split(/\s+/), function (index, cssClass) { + if (cssClass.match(beginsWithPrefix)) { + $container.removeClass(cssClass); + } + }); + + $container.addClass(categoryPrefix + $this.val()); + }) + .trigger('change'); + } + + $options.addClass('initialized'); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/icon/view.php b/scratch-parent/framework/includes/option-types/icon/view.php new file mode 100644 index 00000000..32baa686 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/icon/view.php @@ -0,0 +1,50 @@ + $option['attr']['class'], + 'id' => $option['attr']['id'], +); +unset($option['attr']['class'], $option['attr']['id']); + +$attr = $option['attr']; +$attr['value'] = $data['value']; + +?> +
    > + type="hidden" /> + +
    + +
    + +
    + + + + + +
    +
    diff --git a/scratch-parent/framework/includes/option-types/image-picker/class-fw-option-type-image-picker.php b/scratch-parent/framework/includes/option-types/image-picker/class-fw-option-type-image-picker.php new file mode 100644 index 00000000..164fa6a3 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/image-picker/class-fw-option-type-image-picker.php @@ -0,0 +1,195 @@ + '', + 'blank' => false, // if true, images can be deselected + 'choices' => array( + /* + 'value' => '.../small.png' + // or + 'value' => array( + 'small' => '.../small.png' + 'large' => '.../large.png' // optional + 'data' => array(...) // (optional) choice extra data for js, available in custom events + ) + // or + 'value' => array( + 'small' => array( + 'src' => '.../small.png', + 'alt' => '...' + ) + 'large' => array( // optional + 'src' => '.../large.png', + 'alt' => '...' + ) + 'data' => array(...) // (optional) choice extra data for js, available in custom events + ) + */ + ), + ); + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + // static + { + // this js contains custom changes + wp_enqueue_script( + 'fw-option-' . $this->get_type() . '-image-picker', + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/image-picker/image-picker.js', + array(), + fw()->manifest->get_version(), + true + ); + + wp_enqueue_style( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/styles.css', + array('qtip'), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js', + array('fw-events', 'qtip'), + fw()->manifest->get_version(), + true + ); + } + + { + $wrapper_attr = array( + 'id' => $option['attr']['id'], + 'class' => $option['attr']['class'], + ); + + foreach ($wrapper_attr as $attr_name => $attr_val) { + unset($option['attr'][$attr_name]); + } + } + + $option['value'] = (string)$data['value']; + unset($option['attr']['multiple']); + + /** + * pre loads images on page load + * + * fixes glitch with preview: + * * hover first time - show wrong because image not loaded and has no height/width and cannot detect correctly popup position + * * hover second time - show correctly + */ + $pre_load_images_html = ''; + + $html = ''; + + { + $html .= ''; + } + + return fw_html_tag('div', $wrapper_attr, + $html . '


    '. $pre_load_images_html .'
    ' + ); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!isset($option['choices'][$input_value])) { + if ( + empty($option['choices']) || + isset($option['choices'][ $option['value'] ]) + ) { + $input_value = $option['value']; + } else { + reset($option['choices']); + $input_value = key($option['choices']); + } + } + + return (string)$input_value; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } +} + +FW_Option_Type::register('FW_Option_Type_Image_Picker'); diff --git a/scratch-parent/framework/includes/option-types/image-picker/static/css/styles.css b/scratch-parent/framework/includes/option-types/image-picker/static/css/styles.css new file mode 100644 index 00000000..8b709ffa --- /dev/null +++ b/scratch-parent/framework/includes/option-types/image-picker/static/css/styles.css @@ -0,0 +1,92 @@ +.fw-option-type-image-picker .ui-tooltip { + width: 100px; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector { + overflow: auto; + list-style-image: none; + list-style-position: outside; + list-style-type: none; + padding: 0; + margin: 0 0 -5px 0; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li.group_title { + float: none; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li { + margin: 0 5px 5px 0; + float: left; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li:last-child { + margin-right: 0; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li:hover { + cursor: pointer; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail { + overflow: hidden; + -webkit-user-select: none; + border-radius: 2px; + -moz-user-select: none; + -ms-user-select: none; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail img { + -webkit-user-drag: none; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail.selected { + border: 3px solid #64bd1f; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail { + line-height: 0; + border: 3px solid transparent; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail.selected:hover { + border: 3px solid #64bd1f; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail:hover { + border: 3px solid #dddddd; +} + +.fw-option-type-image-picker li .thumbnail { + position: relative; + padding: 2px; +} + +.fw-option-type-image-picker ul.thumbnails.image_picker_selector li .thumbnail.selected:after { + content: "\f147"; + font-family: dashicons; + background-color: #64bd1f; + position: absolute; + right: 0px; + bottom: 0px; + border-top-left-radius: 2px; + color: #fff; + line-height: normal; + font-size: 20px; + padding: 1px 0 0 1px; +} + +.fw-option-type-image-picker .pre-loaded-images { + height: 1px; + width: 1px; + overflow: hidden; + position: absolute; +} + +.fw-option-type-image-picker select{ + display: none; +} + +.qtip .qtip-content img.fw-option-type-image-picker-large-image { + display: block; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/image-picker.js b/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/image-picker.js new file mode 100644 index 00000000..a9179ab8 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/image-picker.js @@ -0,0 +1,316 @@ +// Image Picker +// by Rodrigo Vera +// +// Version 0.2.4 +// Full source at https://github.com/rvera/image-picker +// MIT License, https://github.com/rvera/image-picker/blob/master/LICENSE +// Generated by CoffeeScript 1.4.0 +(function() { + var ImagePicker, ImagePickerOption, both_array_are_equal, sanitized_options, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + jQuery.fn.extend({ + imagepicker: function(opts) { + if (opts == null) { + opts = {}; + } + return this.each(function() { + var select; + select = jQuery(this); + if (select.data("picker")) { + select.data("picker").destroy(); + } + select.data("picker", new ImagePicker(this, sanitized_options(opts))); + if (opts.initialized != null) { + return opts.initialized.call(select.data("picker")); + } + }); + } + }); + + sanitized_options = function(opts) { + var default_options; + default_options = { + hide_select: true, + show_label: false, + initialized: void 0, + changed: void 0, + clicked: void 0, + selected: void 0, + limit: void 0, + limit_reached: void 0 + }; + return jQuery.extend(default_options, opts); + }; + + both_array_are_equal = function(a, b) { + return jQuery(a).not(b).length === 0 && jQuery(b).not(a).length === 0; + }; + + ImagePicker = (function() { + + function ImagePicker(select_element, opts) { + this.opts = opts != null ? opts : {}; + this.sync_picker_with_select = __bind(this.sync_picker_with_select, this); + + this.select = jQuery(select_element); + this.multiple = this.select.attr("multiple") === "multiple"; + if (this.select.data("limit") != null) { + this.opts.limit = parseInt(this.select.data("limit")); + } + this.build_and_append_picker(); + } + + ImagePicker.prototype.destroy = function() { + var option, _i, _len, _ref; + _ref = this.picker_options; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option = _ref[_i]; + option.destroy(); + } + this.picker.remove(); + this.select.unbind("change"); + this.select.removeData("picker"); + return this.select.show(); + }; + + ImagePicker.prototype.build_and_append_picker = function() { + var _this = this; + if (this.opts.hide_select) { + this.select.hide(); + } + this.select.change(function() { + return _this.sync_picker_with_select(); + }); + if (this.picker != null) { + this.picker.remove(); + } + this.create_picker(); + this.select.after(this.picker); + return this.sync_picker_with_select(); + }; + + ImagePicker.prototype.sync_picker_with_select = function() { + var option, _i, _len, _ref, _results; + _ref = this.picker_options; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option = _ref[_i]; + if (option.is_selected()) { + _results.push(option.mark_as_selected()); + } else { + _results.push(option.unmark_as_selected()); + } + } + return _results; + }; + + ImagePicker.prototype.create_picker = function() { + this.picker = jQuery("
      "); + this.picker_options = []; + this.recursively_parse_option_groups(this.select, this.picker); + return this.picker; + }; + + ImagePicker.prototype.recursively_parse_option_groups = function(scoped_dom, target_container) { + var container, option, option_group, _i, _j, _len, _len1, _ref, _ref1, _results; + _ref = scoped_dom.children("optgroup"); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option_group = _ref[_i]; + option_group = jQuery(option_group); + container = jQuery("
        "); + container.append(jQuery("
      • " + (option_group.attr("label")) + "
      • ")); + target_container.append(jQuery("
      • ").append(container)); + this.recursively_parse_option_groups(option_group, container); + } + _ref1 = (function() { + var _k, _len1, _ref1, _results1; + _ref1 = scoped_dom.children("option"); + _results1 = []; + for (_k = 0, _len1 = _ref1.length; _k < _len1; _k++) { + option = _ref1[_k]; + _results1.push(new ImagePickerOption(option, this, this.opts)); + } + return _results1; + }).call(this); + _results = []; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + option = _ref1[_j]; + this.picker_options.push(option); + if (!option.has_image()) { + continue; + } + _results.push(target_container.append(option.node)); + } + return _results; + }; + + ImagePicker.prototype.has_implicit_blanks = function() { + var option; + return ((function() { + var _i, _len, _ref, _results; + _ref = this.picker_options; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + option = _ref[_i]; + if (option.is_blank() && !option.has_image()) { + _results.push(option); + } + } + return _results; + }).call(this)).length > 0; + }; + + ImagePicker.prototype.selected_values = function() { + if (this.multiple) { + return this.select.val() || []; + } else { + return [this.select.val()]; + } + }; + + ImagePicker.prototype.toggle = function(imagepicker_option) { + var new_values, old_values, selected_value; + old_values = this.selected_values(); + selected_value = imagepicker_option.value().toString(); + if (this.multiple) { + if (__indexOf.call(this.selected_values(), selected_value) >= 0) { + new_values = this.selected_values(); + new_values.splice(jQuery.inArray(selected_value, old_values), 1); + this.select.val([]); + this.select.val(new_values); + } else { + if ((this.opts.limit != null) && this.selected_values().length >= this.opts.limit) { + if (this.opts.limit_reached != null) { + this.opts.limit_reached.call(this.select); + } + } else { + this.select.val(this.selected_values().concat(selected_value)); + } + } + } else { + if (this.has_implicit_blanks() && imagepicker_option.is_selected()) { + this.select.val(""); + } else { + this.select.val(selected_value); + } + } + if (!both_array_are_equal(old_values, this.selected_values())) { + this.select.change(); + if (this.opts.changed != null) { + return this.opts.changed.call(this.select, old_values, this.selected_values()); + } + } + }; + + return ImagePicker; + + })(); + + ImagePickerOption = (function() { + + function ImagePickerOption(option_element, picker, opts) { + this.picker = picker; + this.opts = opts != null ? opts : {}; + this.clicked = __bind(this.clicked, this); + + this.option = jQuery(option_element); + this.create_node(); + } + + ImagePickerOption.prototype.destroy = function() { + return this.node.find(".thumbnail").unbind(); + }; + + ImagePickerOption.prototype.has_image = function() { + return this.option.data("img-src") != null; + }; + + ImagePickerOption.prototype.is_blank = function() { + return !((this.value() != null) && this.value() !== ""); + }; + + ImagePickerOption.prototype.is_selected = function() { + var select_value; + select_value = this.picker.select.val(); + if (this.picker.multiple) { + return jQuery.inArray(this.value(), select_value) >= 0; + } else { + return this.value() === select_value; + } + }; + + ImagePickerOption.prototype.mark_as_selected = function() { + return this.node.find(".thumbnail").addClass("selected"); + }; + + ImagePickerOption.prototype.unmark_as_selected = function() { + return this.node.find(".thumbnail").removeClass("selected"); + }; + + ImagePickerOption.prototype.value = function() { + return this.option.val(); + }; + + ImagePickerOption.prototype.label = function() { + if (this.option.data("img-label")) { + return this.option.data("img-label"); + } else { + return this.option.text(); + } + }; + + ImagePickerOption.prototype.clicked = function() { + this.picker.toggle(this); + if (this.opts.clicked != null) { + this.opts.clicked.call(this.picker.select, this); + } + if ((this.opts.selected != null) && this.is_selected()) { + return this.opts.selected.call(this.picker.select, this); + } + }; + + ImagePickerOption.prototype.create_node = function() { + this.node = jQuery('
      • '); + + var $image = jQuery(''); + + if (this.option.data('small-img-attr')) { + $image.attr(this.option.data('small-img-attr')); + } else { + // this is the blank option + } + + $image.addClass('image_picker_image'); + + if (this.option.attr('data-large-img-attr')) { + $image.attr('data-large-img-attr', this.option.attr('data-large-img-attr')); + } + + var $thumbnail = jQuery('
        '); + + $thumbnail.click({ + option: this + }, function(event) { + return event.data.option.clicked(); + }); + + $thumbnail.append($image); + + if (this.opts.show_label) { + $thumbnail.append( + jQuery('

        ').html(this.label()) + ); + } + + this.node.append($thumbnail); + + return this.node; + }; + + return ImagePickerOption; + + })(); + +}).call(this); diff --git a/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/image-picker.min.js b/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/image-picker.min.js new file mode 100644 index 00000000..c0c731d6 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/image-picker.min.js @@ -0,0 +1,7 @@ +// Image Picker +// by Rodrigo Vera +// +// Version 0.2.4 +// Full source at https://github.com/rvera/image-picker +// MIT License, https://github.com/rvera/image-picker/blob/master/LICENSE +(function(){var t,e,i,s,l=function(t,e){return function(){return t.apply(e,arguments)}},n=[].indexOf||function(t){for(var e=0,i=this.length;i>e;e++)if(e in this&&this[e]===t)return e;return-1};jQuery.fn.extend({imagepicker:function(e){return null==e&&(e={}),this.each(function(){var i;return i=jQuery(this),i.data("picker")&&i.data("picker").destroy(),i.data("picker",new t(this,s(e))),null!=e.initialized?e.initialized.call(i.data("picker")):void 0})}}),s=function(t){var e;return e={hide_select:!0,show_label:!1,initialized:void 0,changed:void 0,clicked:void 0,selected:void 0,limit:void 0,limit_reached:void 0},jQuery.extend(e,t)},i=function(t,e){return 0===jQuery(t).not(e).length&&0===jQuery(e).not(t).length},t=function(){function t(t,e){this.opts=null!=e?e:{},this.sync_picker_with_select=l(this.sync_picker_with_select,this),this.select=jQuery(t),this.multiple="multiple"===this.select.attr("multiple"),null!=this.select.data("limit")&&(this.opts.limit=parseInt(this.select.data("limit"))),this.build_and_append_picker()}return t.prototype.destroy=function(){var t,e,i,s;for(s=this.picker_options,e=0,i=s.length;i>e;e++)t=s[e],t.destroy();return this.picker.remove(),this.select.unbind("change"),this.select.removeData("picker"),this.select.show()},t.prototype.build_and_append_picker=function(){var t=this;return this.opts.hide_select&&this.select.hide(),this.select.change(function(){return t.sync_picker_with_select()}),null!=this.picker&&this.picker.remove(),this.create_picker(),this.select.after(this.picker),this.sync_picker_with_select()},t.prototype.sync_picker_with_select=function(){var t,e,i,s,l;for(s=this.picker_options,l=[],e=0,i=s.length;i>e;e++)t=s[e],t.is_selected()?l.push(t.mark_as_selected()):l.push(t.unmark_as_selected());return l},t.prototype.create_picker=function(){return this.picker=jQuery("

          "),this.picker_options=[],this.recursively_parse_option_groups(this.select,this.picker),this.picker},t.prototype.recursively_parse_option_groups=function(t,i){var s,l,n,r,c,o,h,a,p,u;for(a=t.children("optgroup"),r=0,o=a.length;o>r;r++)n=a[r],n=jQuery(n),s=jQuery("
            "),s.append(jQuery("
          • "+n.attr("label")+"
          • ")),i.append(jQuery("
          • ").append(s)),this.recursively_parse_option_groups(n,s);for(p=function(){var i,s,n,r;for(n=t.children("option"),r=[],i=0,s=n.length;s>i;i++)l=n[i],r.push(new e(l,this,this.opts));return r}.call(this),u=[],c=0,h=p.length;h>c;c++)l=p[c],this.picker_options.push(l),l.has_image()&&u.push(i.append(l.node));return u},t.prototype.has_implicit_blanks=function(){var t;return function(){var e,i,s,l;for(s=this.picker_options,l=[],e=0,i=s.length;i>e;e++)t=s[e],t.is_blank()&&!t.has_image()&&l.push(t);return l}.call(this).length>0},t.prototype.selected_values=function(){return this.multiple?this.select.val()||[]:[this.select.val()]},t.prototype.toggle=function(t){var e,s,l;return s=this.selected_values(),l=""+t.value(),this.multiple?n.call(this.selected_values(),l)>=0?(e=this.selected_values(),e.splice(jQuery.inArray(l,s),1),this.select.val([]),this.select.val(e)):null!=this.opts.limit&&this.selected_values().length>=this.opts.limit?null!=this.opts.limit_reached&&this.opts.limit_reached.call(this.select):this.select.val(this.selected_values().concat(l)):this.has_implicit_blanks()&&t.is_selected()?this.select.val(""):this.select.val(l),i(s,this.selected_values())||(this.select.change(),null==this.opts.changed)?void 0:this.opts.changed.call(this.select,s,this.selected_values())},t}(),e=function(){function t(t,e,i){this.picker=e,this.opts=null!=i?i:{},this.clicked=l(this.clicked,this),this.option=jQuery(t),this.create_node()}return t.prototype.destroy=function(){return this.node.find(".thumbnail").unbind()},t.prototype.has_image=function(){return null!=this.option.data("img-src")},t.prototype.is_blank=function(){return!(null!=this.value()&&""!==this.value())},t.prototype.is_selected=function(){var t;return t=this.picker.select.val(),this.picker.multiple?jQuery.inArray(this.value(),t)>=0:this.value()===t},t.prototype.mark_as_selected=function(){return this.node.find(".thumbnail").addClass("selected")},t.prototype.unmark_as_selected=function(){return this.node.find(".thumbnail").removeClass("selected")},t.prototype.value=function(){return this.option.val()},t.prototype.label=function(){return this.option.data("img-label")?this.option.data("img-label"):this.option.text()},t.prototype.clicked=function(){return this.picker.toggle(this),null!=this.opts.clicked&&this.opts.clicked.call(this.picker.select,this),null!=this.opts.selected&&this.is_selected()?this.opts.selected.call(this.picker.select,this):void 0},t.prototype.create_node=function(){var t,e;return this.node=jQuery("
          • "),t=jQuery(""),t.attr("src",this.option.data("img-src")),e=jQuery("
            "),e.click({option:this},function(t){return t.data.option.clicked()}),e.append(t),this.opts.show_label&&e.append(jQuery("

            ").html(this.label())),this.node.append(e),this.node},t}()}).call(this); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/imagesloaded.pkg.min.js b/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/imagesloaded.pkg.min.js new file mode 100644 index 00000000..f4b2f5f7 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/image-picker/static/js/image-picker/imagesloaded.pkg.min.js @@ -0,0 +1,19 @@ +/* qTip2 v2.2.0 tips viewport | qtip2.com | Licensed MIT, GPL | Mon Dec 16 2013 07:15:00 */ +/*! + * EventEmitter v4.2.6 - git.io/ee + * Oliver Caldwell + * MIT license + * @preserve + */ +(function(){"use strict";function a(){}function b(a,b){for(var c=a.length;c--;)if(a[c].listener===b)return c;return-1}function c(a){return function(){return this[a].apply(this,arguments)}}var d=a.prototype,e=this,f=e.EventEmitter;d.getListeners=function(a){var b,c,d=this._getEvents();if("object"==typeof a){b={};for(c in d)d.hasOwnProperty(c)&&a.test(c)&&(b[c]=d[c])}else b=d[a]||(d[a]=[]);return b},d.flattenListeners=function(a){var b,c=[];for(b=0;bd;d++)b.push(a[d]);else b.push(a);return b}function e(a,c){function e(a,c,g){if(!(this instanceof e))return new e(a,c);"string"==typeof a&&(a=document.querySelectorAll(a)),this.elements=d(a),this.options=b({},this.options),"function"==typeof c?g=c:b(this.options,c),g&&this.on("always",g),this.getImages(),f&&(this.jqDeferred=new f.Deferred);var h=this;setTimeout(function(){h.check()})}function i(a){this.img=a}e.prototype=new a,e.prototype.options={},e.prototype.getImages=function(){this.images=[];for(var a=0,b=this.elements.length;b>a;a++){var c=this.elements[a];"IMG"===c.nodeName&&this.addImage(c);for(var d=c.querySelectorAll("img"),e=0,f=d.length;f>e;e++){var g=d[e];this.addImage(g)}}},e.prototype.addImage=function(a){var b=new i(a);this.images.push(b)},e.prototype.check=function(){function a(a,e){return b.options.debug&&h&&g.log("confirm",a,e),b.progress(a),c++,c===d&&b.complete(),!0}var b=this,c=0,d=this.images.length;if(this.hasAnyBroken=!1,!d)return this.complete(),void 0;for(var e=0;d>e;e++){var f=this.images[e];f.on("confirm",a),f.check()}},e.prototype.progress=function(a){this.hasAnyBroken=this.hasAnyBroken||!a.isLoaded,this.emit("progress",this,a),this.jqDeferred&&this.jqDeferred.notify(this,a)},e.prototype.complete=function(){var a=this.hasAnyBroken?"fail":"done";if(this.isComplete=!0,this.emit(a,this),this.emit("always",this),this.jqDeferred){var b=this.hasAnyBroken?"reject":"resolve";this.jqDeferred[b](this)}},f&&(f.fn.imagesLoaded=function(a,b){var c=new e(this,a,b);return c.jqDeferred.promise(f(this))});var j={};return i.prototype=new a,i.prototype.check=function(){var a=j[this.img.src];if(a)return this.useCached(a),void 0;if(j[this.img.src]=this,this.img.complete&&void 0!==this.img.naturalWidth)return this.confirm(0!==this.img.naturalWidth,"naturalWidth"),void 0;var b=this.proxyImage=new Image;c.bind(b,"load",this),c.bind(b,"error",this),b.src=this.img.src},i.prototype.useCached=function(a){if(a.isConfirmed)this.confirm(a.isLoaded,"cached was confirmed");else{var b=this;a.on("confirm",function(a){return b.confirm(a.isLoaded,"cache emitted confirmed"),!0})}},i.prototype.confirm=function(a,b){this.isConfirmed=!0,this.isLoaded=a,this.emit("confirm",this,b)},i.prototype.handleEvent=function(a){var b="on"+a.type;this[b]&&this[b](a)},i.prototype.onload=function(){this.confirm(!0,"onload"),this.unbindProxyEvents()},i.prototype.onerror=function(){this.confirm(!1,"onerror"),this.unbindProxyEvents()},i.prototype.unbindProxyEvents=function(){c.unbind(this.proxyImage,"load",this),c.unbind(this.proxyImage,"error",this)},e}var f=a.jQuery,g=a.console,h="undefined"!=typeof g,i=Object.prototype.toString;"function"==typeof define&&define.amd?define(["eventEmitter","eventie"],e):a.imagesLoaded=e(a.EventEmitter,a.eventie)}(window); +//# sourceMappingURL=http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0//var/www/qtip2/build/tmp/tmp-9404c7a9f5c/imagesloaded.pkg.min.map \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/image-picker/static/js/scripts.js b/scratch-parent/framework/includes/option-types/image-picker/static/js/scripts.js new file mode 100644 index 00000000..1cd58728 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/image-picker/static/js/scripts.js @@ -0,0 +1,84 @@ +(function(){ + var optionTypeClass = 'fw-option-type-image-picker'; + var eventNamePrefix = 'fw:option-type:image-picker:'; + + jQuery(document).ready(function ($) { + /** Init image_picker options */ + fwEvents.on('fw:options:init', function (data) { + var $elements = data.$elements.find('.'+ optionTypeClass +':not(.fw-option-initialized)'); + + if (!$elements.length) { + return; + } + + $elements.find('select') + .imagepicker({ + clicked: function(options) { + var $this = $(this); + var value = $this.val(); + var data = $this.find('option[value="'+ value +'"]').data('extra-data'); + + $this.closest('.'+ optionTypeClass).trigger(eventNamePrefix +'clicked', { + options : options, + value : value, + data : (typeof data !== 'undefined') ? data : false + }); + }, + changed: function (oldValues, newValues) { + var $this = $(this); + + $this.closest('.'+ optionTypeClass).trigger(eventNamePrefix +'changed', { + oldValues : oldValues, + newValues : newValues + }); + } + }) + .closest('.'+ optionTypeClass).find('.image_picker_selector .image_picker_image').each(function(){ + var $this = $(this); + var largeImageAttr = $this.data('large-img-attr'); + + if (largeImageAttr) { + $this.qtip({ + content: $('

            ').append( + $('').attr(largeImageAttr).addClass(optionTypeClass +'-large-image') + ).html(), + position: { + at: 'top center', + my: 'bottom center', + viewport: $('body'), + adjust: { + y: -5 + } + }, + style: { + classes: 'qtip-fw', + tip: { + width: 12, + height: 5 + } + }, + show: { + effect: function(offset) { + $(this).fadeIn(300); + + // fix tip position + setTimeout(function(){ + offset.elements.tooltip.css('top', + (parseInt(offset.elements.tooltip.css('top')) + 5) + 'px' + ); + }, 12); + } + }, + hide: { + effect: function() { + $(this).fadeOut(300); + } + } + }); + } + }); + + $elements.addClass('fw-option-initialized'); + }); + }); +})(); diff --git a/scratch-parent/framework/includes/option-types/multi-picker/class-fw-option-type-multi-picker.php b/scratch-parent/framework/includes/option-types/multi-picker/class-fw-option-type-multi-picker.php new file mode 100644 index 00000000..2f267fe5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-picker/class-fw-option-type-multi-picker.php @@ -0,0 +1,198 @@ + array(), + 'choices' => array(), + 'value' => array() + ); + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + $css_path = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/'; + $js_path = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/'; + wp_enqueue_style( + 'fw-option-type' . $this->get_type(), + $css_path . 'multi-picker.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-type' . $this->get_type(), + $js_path . 'multi-picker.js', + array('jquery', 'fw-events'), + fw()->manifest->get_version(), + true + ); + + $options_array = $this->prepare_option($id, $option); + unset($option['attr']['name'], $option['attr']['value']); + + return '
            ' . + fw()->backend->render_options($options_array, $data['value'], array( + 'id_prefix' => $data['id_prefix'] . $id . '-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + )) . + '
            '; + } + + public function get_type() + { + return 'multi-picker'; + } + + private function prepare_option($id, $option) + { + if (empty($option['picker'])) { + // TODO: think of text for error when no picker is set + trigger_error( + sprintf(__('No \'picker\' key set for multi-picker option: %s', 'fw'), $id), + E_USER_ERROR + ); + } + + reset($option['picker']); + $picker_key = key($option['picker']); + $picker = $option['picker'][$picker_key]; + $picker_type = $picker['type']; + $supported_picker_types = array('select', 'radio', 'image-picker', 'switch'); + if (!in_array($picker_type, $supported_picker_types)) { + // TODO: think of text for error when incorrect picker type is used + trigger_error( + sprintf( + __('Invalid picker type for multi-picker option %s, only pickers of types %s are supported', 'fw'), + $id, + implode(', ', $supported_picker_types) + ), + E_USER_ERROR + ); + } + + switch($picker_type) { + case 'switch': + $picker_choices = array_intersect_key($option['choices'], array( + $picker['left-choice']['value'] => array(), + $picker['right-choice']['value'] => array() + )); + break; + default: + $picker_choices = array_intersect_key($option['choices'], $picker['choices']); + } + + $hide_picker = ''; + $show_borders = ''; + + //set default value if nothing isset +// if (empty($option['controls']['value'])) { +// reset($groups); +// $option['controls']['value'] = key($groups); +// } + + if ( + 1 === count($picker_choices) && + isset($option['hide_picker']) && + true === $option['hide_picker'] + ) { + $hide_picker = 'fw-hidden '; + } + + if ( + isset($option['show_borders']) && + true === $option['show_borders'] + ) { + $show_borders = 'fw-show-borders'; + } + + $choices_groups = array(); + foreach ($picker_choices as $key => $set) { + if (!empty($set)) { + $choices_groups[$id . '-' . $key] = array( + 'type' => 'group', + 'attr' => array('class' => 'choice-group choice-' . $key), + 'options' => array( + $key => array( + 'type' => 'multi', + 'attr' => array('class' => $show_borders), + 'label' => false, + 'desc' => false, + 'inner-options' => $set + ) + ) + ); + } + } + + $picker_group = array( + $id . '-picker' => array( + 'type' => 'group', + 'desc' => false, + 'label' => false, + 'attr' => array('class' => $show_borders.' '.$hide_picker . ' picker-group picker-type-' . $picker_type), + 'options' => array($picker_key => $picker) + ) + ); + + return array_merge($picker_group, $choices_groups); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + $value = array(); + + // picker + reset($option['picker']); + $picker_key = key($option['picker']); + $picker_type = $option['picker'][$picker_key]['type']; + $picker = $option['picker'][$picker_key]; + $value[$picker_key] = fw()->backend->option_type($picker_type)->get_value_from_input( + $picker, + isset($input_value[$picker_key]) ? $input_value[$picker_key] : null + ); + + // choices + switch($picker_type) { + case 'switch': + $choices = array_intersect_key($option['choices'], array( + $picker['left-choice']['value'] => array(), + $picker['right-choice']['value'] => array() + )); + break; + default: + $choices = array_intersect_key($option['choices'], $picker['choices']); + } + foreach ($choices as $choice_id => $options) { + + foreach ($options as $option_id => $option) { + $value[$choice_id][$option_id] = fw()->backend->option_type($option['type'])->get_value_from_input( + $option, + isset($input_value[$choice_id][$option_id]) ? $input_value[$choice_id][$option_id] : null + ); + } + + } + + return $value; + } +} +FW_Option_Type::register('FW_Option_Type_Multi_Picker'); diff --git a/scratch-parent/framework/includes/option-types/multi-picker/static/css/multi-picker.css b/scratch-parent/framework/includes/option-types/multi-picker/static/css/multi-picker.css new file mode 100644 index 00000000..a3c472a8 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-picker/static/css/multi-picker.css @@ -0,0 +1,29 @@ +.fw-backend-option-type-multi-picker { + padding: 0 !important; +} + +.fw-option-type-multi-picker > .choice-group { + display: none; + padding-bottom: 0; + border-bottom: 0; +} + +.fw-option-type-multi-picker > .choice-group.chosen { + display: block; +} + +.fw-option-type-multi-picker > .choice-group .fw-show-borders .fw-backend-option{ + border-bottom-width: 1px; +} + +.fw-option-type-multi-picker > .choice-group .fw-show-borders .fw-backend-option:last-child{ + border-bottom-width: 0px !important; +} + +.fw-option-type-multi-picker > .picker-group { + border-bottom-width: 0px; +} + +.fw-option-type-multi-picker > .picker-group.fw-show-borders { + border-bottom-width: 1px; +} diff --git a/scratch-parent/framework/includes/option-types/multi-picker/static/js/multi-picker.js b/scratch-parent/framework/includes/option-types/multi-picker/static/js/multi-picker.js new file mode 100644 index 00000000..c5b67a8d --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-picker/static/js/multi-picker.js @@ -0,0 +1,56 @@ +(function($, fwe) { + var init = function() { + var $this = $(this), + elements = { + $pickerGroup: $this.find('.picker-group'), + $choicesGroups: $this.find('.choice-group') + }, + chooseGroup = function(groupId) { + elements.$choicesGroups + .removeClass('chosen') + .filter('.choice-' + groupId) + .addClass('chosen'); + }, + pickerType = elements.$pickerGroup.attr('class').match(/picker-type-(\S+)/)[1], + flows = { + 'switch': function() { + elements.$pickerGroup.find(':checkbox').on('change', function() { + var $this = $(this), + checked = $(this).is(':checked'), + value = checked + ? $this.attr('data-switch-right-value') + : $this.attr('data-switch-left-value'); + + chooseGroup(value); + }).trigger('change'); + }, + 'select': function() { + elements.$pickerGroup.find('select').on('change', function() { + chooseGroup(this.value); + }).trigger('change'); + }, + 'radio': function() { + elements.$pickerGroup.find(':radio').on('change', function() { + chooseGroup(this.value); + }).filter(':checked').trigger('change'); + }, + 'image-picker': function() { + elements.$pickerGroup.find('select').on('change', function() { + chooseGroup(this.value); + }).trigger('change'); + } + }; + + if (!pickerType || !flows[pickerType]) { + console.error('unknown multi-picker type:', pickerType); + } else { + flows[pickerType](); + } + }; + + fwe.on('fw:options:init', function(data) { + data.$elements + .find('.fw-option-type-multi-picker:not(.fw-option-initialized)').each(init) + .addClass('fw-option-initialized'); + }); +})(jQuery, fwEvents); diff --git a/scratch-parent/framework/includes/option-types/multi-select/class-fw-option-type-multi-select.php b/scratch-parent/framework/includes/option-types/multi-select/class-fw-option-type-multi-select.php new file mode 100644 index 00000000..e771af9c --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-select/class-fw-option-type-multi-select.php @@ -0,0 +1,309 @@ +internal_options = array( + 'label' => false, + 'type' => 'text', + 'value' => '', + ); + } + + /** + * @internal + */ + public static function _admin_action_get_ajax_response() { + global $wpdb; + + $type = $_POST['data']['type']; + $names = stripslashes( $_POST['data']['names'] ); + $title = $_POST['data']['string']; + + $items = array(); + + if ( $type == 'posts' ) { + $items = $wpdb->get_results( + "SELECT ID val, post_title title " . + "FROM $wpdb->posts " . + "WHERE post_title LIKE '%$title%' " . + "AND post_status = 'publish' " . + "AND NULLIF(post_password, '') IS NULL " . + "AND post_type IN ( '$names' ) LIMIT 100" + ); + } + + if ( $type == 'taxonomy' ) { + $items = $wpdb->get_results( + "SELECT terms.term_id val, terms.name title " . + "FROM $wpdb->terms as terms, $wpdb->term_taxonomy as taxonomies " . + "WHERE terms.name LIKE '%$title%' AND taxonomies.taxonomy IN ( '$names' )' " . + "AND terms.term_id = taxonomies.term_id " . + "AND taxonomies.term_id = taxonomies.term_taxonomy_id LIMIT 100" + ); + } + if ( $type == 'users' ) { + if ( empty( $names ) ) { + $items = $wpdb->get_results( + "SELECT users.id val, users.display_name title " . + "FROM $wpdb->users as users " . + "WHERE users.display_name LIKE '%$title%' " . + "LIMIT 100" + ); + } else { + $names = explode( ",", $names ); + $names = implode( "%' OR usermeta.meta_value LIKE '%", $names ); + $items = $wpdb->get_results( + "SELECT users.id val, users.display_name title " . + "FROM $wpdb->users as users, $wpdb->usermeta usermeta " . + "WHERE users.display_name LIKE '%$title%' AND ( usermeta.meta_key = 'wp_capabilities' AND usermeta.meta_value LIKE '%$names%' ) " . + "AND usermeta.user_id = users.ID" + ); + } + } + + wp_send_json_success( $items ); + } + + /** + * @internal + */ + public function _get_backend_width_type() { + return 'fixed'; + } + + /** + * @internal + */ + protected function _get_defaults() { + return array( + 'value' => array(), + 'population' => 'array', + 'source' => '', + 'limit' => 100 + ); + } + + /** + * @internal + */ + protected function _render( $id, $option, $data ) { + $this->add_css(); + $this->add_js(); + + $items = ''; + $population = 'array'; + $source = ''; + + if ( isset( $option['population'] ) ) { + switch ( $option['population'] ) { + case 'array' : + if ( isset( $option['choices'] ) && is_array( $option['choices'] ) ) { + $items = $option['choices']; + } + break; + case 'posts' : + if ( isset( $option['source'] ) ) { + global $wpdb; + $source = ( is_array( $option['source'] ) ) ? implode( "', '", $option['source'] ) : $option['source']; + $population = 'posts'; + + if ( empty( $data['value'] ) ) { + break; + } + + $ids = $data['value']; + + foreach ( $ids as $key => $post_id ) { + $ids[ $key ] = intval( $post_id ); + } + + $ids = implode( ', ', $ids ); + + //$query = new WP_Query( array( 'post__in' => $ids ) ); + + $query = $wpdb->get_results( + "SELECT posts.ID, posts.post_title " . + "FROM $wpdb->posts as posts " . + "WHERE posts.ID IN ( $ids )" + ); + + if ( is_wp_error( $query ) ) { + break; + } + + $items = array(); + + foreach ( $query as $post ) { + $items[ $post->ID ] = $post->post_title; + } + } + break; + case 'taxonomy' : + if ( isset( $option['source'] ) ) { + $population = 'taxonomy'; + $source = ( is_array( $option['source'] ) ) ? implode( "', '", $option['source'] ) : $option['source']; + + if ( empty( $data['value'] ) ) { + break; + } + + global $wpdb; + + $ids = implode( ',', $data['value'] ); + + $query = $wpdb->get_results( + "SELECT terms.term_id id, terms.name title " . + "FROM $wpdb->terms as terms, $wpdb->term_taxonomy as taxonomies " . + "WHERE terms.term_id IN ($ids) AND taxonomies.taxonomy IN ( $source ) " . + "AND terms.term_id = taxonomies.term_id " . + "AND taxonomies.term_id = taxonomies.term_taxonomy_id" + ); + + if ( is_wp_error( $query ) || empty( $query ) ) { + break; + } + + $items = array(); + + foreach ( $query as $term ) { + $items[ $term->id ] = $term->title; + } + } + break; + case 'users' : + global $wpdb; + $population = 'users'; + + if ( isset( $option['source'] ) && ! empty( $option['source'] ) ) { + ; + $source = ( is_array( $option['source'] ) ) ? implode( ",", $option['source'] ) : $option['source']; + $current_source = ( is_array( $option['source'] ) ) ? implode( "%' OR usermeta.meta_value LIKE '%", $option['source'] ) : $option['source']; + + if ( empty( $data['value'] ) ) { + break; + } + + $ids = implode( ',', $data['value'] ); + + $query = $wpdb->get_results( + "SELECT users.id, users.display_name title " . + "FROM $wpdb->users as users, $wpdb->usermeta usermeta " . + "WHERE users.ID IN ($ids) AND usermeta.meta_key = 'wp_capabilities' AND ( usermeta.meta_value LIKE '%$current_source%' ) " . + "AND usermeta.user_id = users.ID" + ); + + } else { + $source = ''; + + if ( empty( $data['value'] ) ) { + break; + } + + $ids = implode( ',', $data['value'] ); + + $query = $wpdb->get_results( + "SELECT users.id, users.display_name title " . + "FROM $wpdb->users as users " . + "WHERE users.ID IN ($ids)" + ); + } + + if ( is_wp_error( $query ) || empty( $query ) ) { + break; + } + + $items = array(); + + foreach ( $query as $term ) { + $items[ $term->id ] = $term->title; + } + + break; + default : + $items = ''; + } + + $option['attr']['data-options'] = json_encode( $this->convert_array( $items ) ); + $option['attr']['data-population'] = $population; + $option['attr']['data-source'] = $source; + $option['attr']['data-limit'] = ( intval( $option['limit'] ) > 0 ) ? $option['limit'] : 0; + } else { + return ''; + } + if ( ! empty( $data['value'] ) ) { + $data['value'] = implode( '/*/', $data['value'] ); + } else { + $data['value'] = ''; + } + + return fw()->backend->option_type( 'text' )->render( $id, $option, $data ); + } + + /** + * @internal + */ + private function add_css() { + wp_enqueue_style( + $this->get_type() . '-styles', + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/style.css', + array('fw-selectize'), + fw()->manifest->get_version() + ); + } + + /** + * @internal + */ + private function add_js() { + wp_enqueue_script( + $this->get_type() . '-styles', + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js', + array( 'jquery', 'fw-events', 'fw-selectize' ), + fw()->manifest->get_version(), + true + ); + } + + /** + * @internal + */ + private function convert_array( $array = array() ) { + if ( ! is_array( $array ) || empty( $array ) ) { + return array(); + } + + $return = array(); + foreach ( $array as $key => $item ) { + $return[] = array( + 'val' => $key, + 'title' => $item, + ); + } + + return $return; + } + + /** + * @internal + */ + protected function _get_value_from_input( $option, $input_value ) { + $value = explode( '/*/', $input_value ); + + return empty( $input_value ) ? array() : $value; + } +} + +FW_Option_Type::register( 'FW_Option_Type_Multi_Select' ); + +add_action( 'wp_ajax_admin_action_get_ajax_response', array( "FW_Option_Type_Multi_Select", '_admin_action_get_ajax_response' ) ); diff --git a/scratch-parent/framework/includes/option-types/multi-select/static/css/style.css b/scratch-parent/framework/includes/option-types/multi-select/static/css/style.css new file mode 100644 index 00000000..7ff9ea71 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-select/static/css/style.css @@ -0,0 +1,24 @@ +.fw-option-type-multi-select.selectize-control.multi .selectize-input.has-items, +.fw-option-type-multi-select .selectize-input { + padding: 0 0 3px 3px; + border-radius: 0; + border: 1px solid #ddd; +} + +.fw-option-type-multi-select .selectize-input { + padding: 4px 6px; +} + +.fw-option-type-multi-select.selectize-control.multi .selectize-input > div { + margin: 3px 3px 0 0; +} + +.fw-option-type-multi-select .selectize-input.focus.input-active.dropdown-active:before, +.fw-option-type-multi-select .selectize-input.focus.input-active.dropdown-active:before { + display: none; +} + +.fw-option-type-multi-select .selectize-input.focus.input-active.dropdown-active:after { + margin-top: -3px; + border-width: 5px 5px 0 5px; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi-select/static/js/scripts.js b/scratch-parent/framework/includes/option-types/multi-select/static/js/scripts.js new file mode 100644 index 00000000..0979bcf5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-select/static/js/scripts.js @@ -0,0 +1,60 @@ +function fw_option_multi_select_initialize(item) { + var population = item.attr('data-population'); + var source = item.attr('data-source'); + var limit = parseInt(item.attr('data-limit')); + var xhr; + + item.selectize({ + maxItems: ( limit > 0 ) ? limit : null, + delimiter: '/*/', + valueField: 'val', + labelField: 'title', + searchField: 'title', + options: JSON.parse(item.attr('data-options')), + create: false, + onType: function (value) { + if (population == 'array') { + return; + } + + if (value.length < 2) { + return; + } + + this.load(function (callback) { + xhr && xhr.abort(); + + var data = { + action: 'admin_action_get_ajax_response', + data: { + string: value, + type: population, + names: source + } + }; + + xhr = jQuery.post( + ajaxurl, + data, + function (response) { + callback(response.data) + } + ) + }); + + } + }); +} + +jQuery(document).ready(function () { + fwEvents.on('fw:options:init', function (data) { + + var obj = data.$elements.find('.fw-option-type-multi-select:not(.initialized)'); + + obj.each(function () { + fw_option_multi_select_initialize(jQuery(this)); + }); + + obj.addClass('initialized'); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi-upload/class-fw-option-type-multi-upload.php b/scratch-parent/framework/includes/option-types/multi-upload/class-fw-option-type-multi-upload.php new file mode 100644 index 00000000..bdecc66f --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/class-fw-option-type-multi-upload.php @@ -0,0 +1,220 @@ + true, + 'texts' => array(), + 'value' => array(), + ); + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _init() + { + $this->views_path = dirname(__FILE__) . '/views/'; + $static_uri = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/'; + $this->js_uri = $static_uri . 'js/'; + $this->css_uri = $static_uri . 'css/'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + // attributes for the hidden input + $input_attr = array(); + $input_attr['name'] = $option['attr']['name']; + $input_attr['value'] = $this->get_processed_value($data['value']); + unset($option['attr']['name'], $option['attr']['value']); + + // attributes for the option wrapper + $wrapper_attr = $option['attr']; + + $l10n = $option['texts']; + + if ($option['images_only']) { + return $this->render_images_only($input_attr, $wrapper_attr, $l10n); + } else { + return $this->render_any_files($input_attr, $wrapper_attr, $l10n); + } + } + + private function get_processed_value($value) + { + if ( + !is_array($value) || + empty($value) + ) { + $defaults = $this->get_defaults(); + return json_encode($defaults['value']); + } + + $ids = array(); + foreach ($value as $attachment) { + $ids[] = $attachment['attachment_id']; + } + return json_encode($ids); + } + + private function render_images_only($input_attr, $wrapper_attr, $l10n) + { + $l10n = array_merge( + array( + 'button_add' => __('Add Images', 'fw'), // TODO: add context ? + 'button_edit' => __('Edit', 'fw') // TODO: add context ? + ), + $l10n + ); + $wrapper_attr = array_merge($wrapper_attr, array( + 'data-l10n-button-add' => $l10n['button_add'], + 'data-l10n-button-edit' => $l10n['button_edit'], + )); + + wp_enqueue_media(); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-modal', + $this->css_uri . 'modal.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-images-only', + $this->css_uri . 'images-only.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-type-'. $this->get_type() . '-images-only', + $this->js_uri . 'images-only.js', + array('jquery', 'fw-events', 'underscore', 'jquery-ui-sortable'), + fw()->manifest->get_version(), + true + ); + + $wrapper_attr['class'] .= ' images-only'; + $is_empty = $input_attr['value'] === '[]'; // check for empty json array + $wrapper_attr['class'] .= $is_empty ? ' empty' : ''; + + return fw_render_view($this->views_path . 'images-only.php', array( + 'wrapper_attr' => $wrapper_attr, + 'input_attr' => $input_attr, + 'is_empty' => $is_empty, + 'l10n' => $l10n + )); + } + + private function render_any_files($input_attr, $wrapper_attr, $l10n) + { + $l10n = array_merge( + array( + 'button_add' => __('Upload', 'fw'), // TODO: add context ? + 'button_edit' => __('Edit', 'fw'), // TODO: add context ? + 'files_one' => __('1 File', 'fw'), // TODO: maybe add context ? + 'files_more' => __('%u Files', 'fw'), // TODO: maybe add context ? + ), + $l10n + ); + $wrapper_attr = array_merge($wrapper_attr, array( + 'data-l10n-button-add' => $l10n['button_add'], + 'data-l10n-button-edit' => $l10n['button_edit'], + 'data-l10n-files-one' => $l10n['files_one'], + 'data-l10n-files-more' => $l10n['files_more'], + )); + + wp_enqueue_media(); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-modal', + $this->css_uri . 'modal.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-any-files', + $this->css_uri . 'any-files.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-type-'. $this->get_type() . '-any-files', + $this->js_uri . 'any-files.js', + array('jquery', 'fw-events'), + fw()->manifest->get_version(), + true + ); + + $wrapper_attr['class'] .= ' any-files'; + $is_empty = $input_attr['value'] === '[]'; // check for empty json array + $wrapper_attr['class'] .= $is_empty ? ' empty' : ''; + + return fw_render_view($this->views_path . 'any-files.php', array( + 'wrapper_attr' => $wrapper_attr, + 'input_attr' => $input_attr, + 'is_empty' => $is_empty, + 'l10n' => $l10n + )); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (empty($input_value)) { + return $option['value']; + } else { + return $this->get_attachments_info($input_value); + } + } + + private function get_attachments_info($attachment_ids) + { + $decoded_ids = json_decode($attachment_ids, true); + if ( + !is_array($decoded_ids) || + empty($decoded_ids) + ) { + $defaults = $this->get_defaults(); + return $defaults['value']; + } + + $return_arr = array(); + foreach ($decoded_ids as $id) { + $url = wp_get_attachment_url($id); + if ($url) { + $return_arr[] = array( + 'attachment_id' => $id, + 'url' => preg_replace('/^https?:\/\//', '//', $url) + ); + } + } + return $return_arr; + } +} +FW_Option_Type::register('FW_Option_Type_Multi_Upload'); diff --git a/scratch-parent/framework/includes/option-types/multi-upload/static/css/any-files.css b/scratch-parent/framework/includes/option-types/multi-upload/static/css/any-files.css new file mode 100644 index 00000000..0167bf98 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/static/css/any-files.css @@ -0,0 +1,17 @@ +.fw-option-type-multi-upload.any-files.empty span { + display: none; +} +.fw-option-type-multi-upload.any-files span { + display: inline-block; + vertical-align: middle; + margin-right: 5px; +} +.fw-option-type-multi-upload.any-files em { + font-style: normal; +} +.fw-option-type-multi-upload.any-files a { + outline: none; +} +.fw-option-type-multi-upload.any-files button { + vertical-align: middle; +} diff --git a/scratch-parent/framework/includes/option-types/multi-upload/static/css/images-only.css b/scratch-parent/framework/includes/option-types/multi-upload/static/css/images-only.css new file mode 100644 index 00000000..b8ea2f60 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/static/css/images-only.css @@ -0,0 +1,60 @@ +/* thumb */ +.fw-option-type-multi-upload.images-only .thumbs-container { + font-size: 0; + line-height: 0; +} +.fw-option-type-multi-upload.images-only .thumb { + position: relative; + display: inline-block; + width: 50px; + height: 50px; + margin-right: 5px; + margin-bottom: 5px; + text-align: center; + cursor: move; +} +.fw-option-type-multi-upload.images-only .thumb:last-of-type { + margin-right: 0; +} +.fw-option-type-multi-upload.images-only .thumb.no-image { + cursor: default; +} + +/* Non empty thumb */ +.fw-option-type-multi-upload.images-only .thumb img { + display: block; + width: 100%; + height: 100%; +} +.fw-option-type-multi-upload.images-only .thumb a { + position: absolute; + display: none; + width: 12px; + height: 12px; + top: -6px; + right: -6px; + font-size: 14px; + outline: none; +} +.fw-option-type-multi-upload.images-only .thumb:hover a { + display: block; + background-color: #fff; + border-radius: 50%; + z-index: 10; +} +.fw-option-type-multi-upload.images-only .thumb.ui-sortable-helper a { + display: none; +} +.fw-option-type-multi-upload.images-only .thumb a:before { + margin-left: -1px; +} + +/* Upload link */ +.fw-option-type-multi-upload.images-only p { + margin-bottom: 0; +} + +/* Option is set in right sidebar */ +.fw-force-xs .fw-option-type-multi-upload.images-only .thumb.no-image { + display: none; +} diff --git a/scratch-parent/framework/includes/option-types/multi-upload/static/css/modal.css b/scratch-parent/framework/includes/option-types/multi-upload/static/css/modal.css new file mode 100644 index 00000000..d6522058 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/static/css/modal.css @@ -0,0 +1,9 @@ +.fw-option-type-multi-upload .media-modal { + z-index: 170001; +} +.fw-option-type-multi-upload .media-modal-backdrop { + z-index: 170000; +} +.fw-option-type-multi-upload .delete-attachment { + display: none; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi-upload/static/js/any-files.js b/scratch-parent/framework/includes/option-types/multi-upload/static/js/any-files.js new file mode 100644 index 00000000..e0dca556 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/static/js/any-files.js @@ -0,0 +1,101 @@ +(function($, fwe) { + + var init = function() { + var $this = $(this), + elements = { + $container: $this, + $input: $this.find('input[type="hidden"]'), + $uploadButton: $this.find('button'), + $deleteButton: $this.find('a'), // it 'clears' the input + $textField: $this.find('em') // for the name of the attachment + }, + l10n = { + buttonAdd: elements.$container.attr('data-l10n-button-add'), + buttonEdit: elements.$container.attr('data-l10n-button-edit'), + filesOne: elements.$container.attr('data-l10n-files-one'), + filesMore: elements.$container.attr('data-l10n-files-more') + }, + frame, + createFrame = function() { + frame = wp.media({ + multiple: true + }); + + frame.on('ready', function() { + frame.modal.$el.addClass('fw-option-type-multi-upload'); + }); + + // opens the modal with the correct attachments already selected + frame.on('open', function() { + var selection = frame.state().get('selection'), + ids = elements.$input.val(), + parsedIds, + attachment; + + frame.reset(); + try { + parsedIds = JSON.parse(ids); + $.each(parsedIds, function(index, id) { + attachment = wp.media.attachment(id); + if (attachment.id) { + selection.add(attachment); + } + }); + } catch(e) { + + } + }); + + frame.on('select', function() { + var attachments = frame.state().get('selection'), + ids = attachments.map(function(attachment) { + return attachment.id; + }), + selectedText = ids.length === 1 + ? l10n.filesOne + : l10n.filesMore.replace('%u', ids.length); + + elements.$input.val(JSON.stringify(ids)); + elements.$textField.text(selectedText); + elements.$uploadButton.text(l10n.buttonEdit); + elements.$container.removeClass('empty'); + + fwe.trigger('fw:option-type:multi-upload:change', { + $element: elements.$container, + attachments: attachments + }); + elements.$container.trigger('fw:option-type:multi-upload:change', { + attachments: attachments + }); + }); + }; + + elements.$uploadButton.on('click', function(e) { + e.preventDefault(); + + if (!frame) { + createFrame(); + } + frame.open(); + }); + + elements.$deleteButton.on('click', function(e) { + elements.$input.val('[]'); + elements.$textField.text(''); + elements.$uploadButton.text(l10n.buttonAdd); + elements.$container.addClass('empty'); + + fwe.trigger('fw:option-type:multi-upload:clear', {$element: elements.$container}); + elements.$container.trigger('fw:option-type:multi-upload:clear'); + + e.preventDefault(); + }); + }; + + fwe.on('fw:options:init', function(data) { + data.$elements + .find('.fw-option-type-multi-upload.any-files:not(.fw-option-initialized)').each(init) + .addClass('fw-option-initialized'); + }); + +})(jQuery, fwEvents); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi-upload/static/js/images-only.js b/scratch-parent/framework/includes/option-types/multi-upload/static/js/images-only.js new file mode 100644 index 00000000..77d31470 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/static/js/images-only.js @@ -0,0 +1,142 @@ +(function($, _, fwe) { + + var init = function() { + var $this = $(this), + elements = { + $container: $this, + $input: $this.find('input[type="hidden"]'), + $uploadButton: $this.find('p a'), + $thumbsContainer: $this.find('.thumbs-container') + }, + templates = { + thumb: { + empty: $this.find('.thumb-template-empty').attr('data-template'), + notEmpty: $this.find('.thumb-template-not-empty').attr('data-template') + } + }, + collectThumbsIds = function() { + var ids = []; + elements.$thumbsContainer.find('.thumb').each(function() { + ids.push($(this).data('attid')); + }); + return ids; + }, + l10n = { + buttonAdd: elements.$container.attr('data-l10n-button-add'), + buttonEdit: elements.$container.attr('data-l10n-button-edit') + }, + frame, + createFrame = function() { + frame = wp.media({ + library: { + type: 'image' + }, + multiple: true + }); + + frame.on('ready', function() { + frame.modal.$el.addClass('fw-option-type-multi-upload'); + }); + + // opens the modal with the correct attachments already selected + frame.on('open', function() { + var selection = frame.state().get('selection'), + ids = elements.$input.val(), + parsedIds, + attachment; + + frame.reset(); + try { + parsedIds = JSON.parse(ids); + $.each(parsedIds, function(index, id) { + attachment = wp.media.attachment(id); + if (attachment.id) { + selection.add(attachment); + } + }); + } catch(e) { + + } + }); + + frame.on('select', function() { + var attachments = frame.state().get('selection'), + ids = [], + compiledTemplates = []; + + attachments.each(function(attachment) { + ids.push(attachment.id); + compiledTemplates.push(_.template( + templates.thumb.notEmpty, + { + src: attachment.get('sizes').thumbnail.url, + alt: attachment.get('filename'), + id: attachment.id, + originalSrc: attachment.get('url') + }, + {variable: 'data'} + )); + }); + + elements.$input.val(JSON.stringify(ids)); + elements.$uploadButton.text(l10n.buttonEdit); + elements.$thumbsContainer.html(compiledTemplates.join('')); + elements.$container.removeClass('empty'); + + fwe.trigger('fw:option-type:multi-upload:change', { + $element: elements.$container, + attachments: attachments + }); + elements.$container.trigger('fw:option-type:multi-upload:change', { + attachments: attachments + }); + }); + }; + + elements.$uploadButton.on('click', function(e) { + e.preventDefault(); + + if (!frame) { + createFrame(); + } + frame.open(); + }); + + elements.$thumbsContainer.on('click', '.clear-uploads-thumb', function(e) { + var ids; + + $(this).closest('.thumb').remove(); + ids = collectThumbsIds(); + + if (ids.length) { + elements.$input.val(JSON.stringify(ids)); + fwe.trigger('fw:option-type:multi-upload:remove', {$element: elements.$container}); // TODO: think what other data would be usefull + elements.$container.trigger('fw:option-type:multi-upload:remove'); // TODO: think what other data would be usefull + } else { + elements.$input.val('[]'); + elements.$uploadButton.text(l10n.buttonAdd); + elements.$thumbsContainer.html(templates.thumb.empty); + elements.$container.addClass('empty'); + fwe.trigger('fw:option-type:multi-upload:clear', {$element: elements.$container}); + elements.$container.trigger('fw:option-type:multi-upload:clear'); + } + + e.preventDefault(); + }); + + elements.$thumbsContainer.sortable({ + cancel: '.no-image', + update: function() { + var ids = collectThumbsIds(); + elements.$input.val(JSON.stringify(ids)); + } + }); + }; + + fwe.on('fw:options:init', function(data) { + data.$elements + .find('.fw-option-type-multi-upload.images-only:not(.fw-option-initialized)').each(init) + .addClass('fw-option-initialized'); + }); + +})(jQuery, _, fwEvents); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi-upload/views/any-files.php b/scratch-parent/framework/includes/option-types/multi-upload/views/any-files.php new file mode 100644 index 00000000..a6fd0a23 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/views/any-files.php @@ -0,0 +1,25 @@ + + + +
            > + /> + + + + + +
            \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi-upload/views/images-only.php b/scratch-parent/framework/includes/option-types/multi-upload/views/images-only.php new file mode 100644 index 00000000..4157464f --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi-upload/views/images-only.php @@ -0,0 +1,44 @@ + +
            > + /> +
            + +
            + no-image.png +
            + + + + + +
            + <?php echo $attachment_filename; ?> + +
            + + +
            +

            +
            + no-image.png +
            + "> +
            + <%= data.alt %> + +
            + "> +
          • \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/multi/class-fw-option-type-multi.php b/scratch-parent/framework/includes/option-types/multi/class-fw-option-type-multi.php new file mode 100644 index 00000000..0ff918dc --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi/class-fw-option-type-multi.php @@ -0,0 +1,85 @@ +get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/css/styles.css', + array(), + fw()->manifest->get_version() + ); + } + + if (empty($data['value'])) + $data['value'] = array(); + + $div_attr = $option['attr']; + unset($div_attr['name'], $div_attr['value']); + + return '
            '. + fw()->backend->render_options($option['inner-options'], $data['value'], array( + 'id_prefix' => $data['id_prefix'] . $id .'-', + 'name_prefix' => $data['name_prefix'] .'['. $id .']', + )). + '
            '; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if ( + is_array($input_value) || + empty($option['value']) + ) { + $value = array(); + + foreach (fw_extract_only_options($option['inner-options']) as $inner_id => $inner_option) { + $value[$inner_id] = fw()->backend->option_type($inner_option['type'])->get_value_from_input( + $inner_option, + isset($input_value[$inner_id]) ? $input_value[$inner_id] : null + ); + } + } else { + $value = $option['value']; + } + + return $value; + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'full'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'inner-options' => array(), + 'value' => array(), + ); + } +} +FW_Option_Type::register('FW_Option_Type_Multi'); diff --git a/scratch-parent/framework/includes/option-types/multi/static/css/styles.css b/scratch-parent/framework/includes/option-types/multi/static/css/styles.css new file mode 100644 index 00000000..c2405483 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/multi/static/css/styles.css @@ -0,0 +1,7 @@ +.fw-backend-option-type-multi { + padding: 0 !important; +} + +.fw-option-type-multi > .fw-backend-option { + border-bottom-width: 0; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/switch/class-fw-option-type-switch.php b/scratch-parent/framework/includes/option-types/switch/class-fw-option-type-switch.php new file mode 100644 index 00000000..13790cf4 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/switch/class-fw-option-type-switch.php @@ -0,0 +1,130 @@ +get_type() .'-adaptive-switch', + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/adaptive-switch/styles.css', + array(), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-'. $this->get_type() .'-adaptive-switch', + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/adaptive-switch/jquery.adaptive-switch.js', + array('jquery'), + fw()->manifest->get_version(), + true + ); + } + + wp_enqueue_style( + 'fw-option-'. $this->get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/css/styles.css', + array('fw-option-'. $this->get_type() .'-adaptive-switch'), + fw()->manifest->get_version() + ); + + wp_enqueue_script( + 'fw-option-'. $this->get_type(), + FW_URI .'/includes/option-types/'. $this->get_type() .'/static/js/scripts.js', + array('fw-events', 'fw-option-'. $this->get_type() .'-adaptive-switch'), + fw()->manifest->get_version(), + true + ); + } + + { + { + $input_attr = array( + 'name' => $option['attr']['name'], + 'id' => $option['attr']['id'] .'--checkbox', + 'data-switch-left' => $option['left-choice']['label'], + 'data-switch-right' => $option['right-choice']['label'], + ); + + foreach (array('left', 'right') as $value_type) { + if (is_bool($option[$value_type .'-choice']['value'])) { + $input_attr['data-switch-'. $value_type .'-bool-value'] = $option[$value_type. '-choice']['value'] + ? 'true' + : 'false'; + } else { + $input_attr['data-switch-'. $value_type .'-value'] = $option[$value_type .'-choice']['value']; + } + } + } + + if ($data['value'] === $option['right-choice']['value']) { + // right choice means checked + $input_attr['checked'] = 'checked'; + } + + unset( + $option['attr']['name'], + $option['attr']['value'], + $option['attr']['checked'], + $option['attr']['type'] + ); + } + + return '
            '. + ''. + '
            '; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if ($input_value) { + return $option['right-choice']['value']; + } else { + return $option['left-choice']['value']; + } + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => false, + 'left-choice' => array( + 'value' => false, + 'label' => __('No', 'fw'), + ), + 'right-choice' => array( + 'value' => true, + 'label' => __('Yes', 'fw'), + ), + ); + } +} +FW_Option_Type::register('FW_Option_Type_Switch'); diff --git a/scratch-parent/framework/includes/option-types/switch/static/adaptive-switch/jquery.adaptive-switch.js b/scratch-parent/framework/includes/option-types/switch/static/adaptive-switch/jquery.adaptive-switch.js new file mode 100644 index 00000000..a452f72b --- /dev/null +++ b/scratch-parent/framework/includes/option-types/switch/static/adaptive-switch/jquery.adaptive-switch.js @@ -0,0 +1,79 @@ +(function(){ + var template = + '
            '+ + '
            '+ + '
            '+ + ''+ + '
            '+ + '
            '+ + '
            '+ + ''+ + ''+ + '
            '+ + '
            '+ + '
            '+ + '
            '; + + function renderTemplate(switchLeft, switchRight, isRight, inputLeftId, inputRightId) { + switchLeft = String(switchLeft); + switchRight = String(switchRight); + + return template + .split('{{switch_left}}' ).join(switchLeft) + .split('{{switch_right}}' ).join(switchRight) + .split('{{biggest_text}}' ).join(switchLeft.length > switchRight.length ? switchLeft : switchRight) + .split('{{id_left}}' ).join(inputLeftId) + .split('{{id_right}}' ).join(inputRightId) + .split('{{wrapper_class}}' ).join(isRight ? ' switch-right' : ''); + } + + { + var increment = 0; + + function getUniqueId() { + return 'switch--'+ (++increment); + } + } + + jQuery.fn.adaptiveSwitch = function() { + var $ = jQuery; + + this.filter('input[type="checkbox"]').each(function(){ + var $this = $(this); + + if (!$this.attr('id')) { + $this.attr('id', getUniqueId()); + } + + var switchId = getUniqueId(); + + $( + renderTemplate( + $this.attr('data-switch-left') ? $this.attr('data-switch-left') : 'No', + $this.attr('data-switch-right') ? $this.attr('data-switch-right') : 'Yes', + $this.prop('checked'), + $this.attr('id'), + $this.attr('id') + ) + ) + .attr('id', switchId) + .addClass('input-type--checkbox') + .addClass('input-id--'+ $this.attr('id')) + .addClass( + $this.attr('class') + ? $.map($this.attr('class').split(/\s+/), function(c){ return c.length ? 'input-class--'+ c : ''; }).join(' ') + : '' + ) + .insertAfter($this); + + $this + .attr('data-switch-id', switchId) + .addClass('adaptive-switch-input') + .on('change', function(){ + $('#'+ $(this).attr('data-switch-id') )[ $(this).prop('checked') ? 'addClass' : 'removeClass' ]('switch-right'); + }); + }); + + return this; + }; +})(); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/switch/static/adaptive-switch/styles.css b/scratch-parent/framework/includes/option-types/switch/static/adaptive-switch/styles.css new file mode 100644 index 00000000..f710e099 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/switch/static/adaptive-switch/styles.css @@ -0,0 +1,153 @@ +.adaptive-switch { + display: inline-block; + white-space: nowrap; + line-height: 200%; +} + +.adaptive-switch .switch-clear { + clear: both; +} + +.adaptive-switch .switch-inner { + position: relative; + overflow: hidden; + height: 2em; +} +.adaptive-switch, +.adaptive-switch .switch-inner { + -webkit-border-radius: 1000px; + -moz-border-radius: 1000px; + border-radius: 1000px; +} + +.adaptive-switch label.switch-label { + display: block;; + padding: 0 2em; + color: #00709f; +} +.adaptive-switch label.switch-label span { + padding: 0 1em; +} +.adaptive-switch label.switch-label-right { + padding-left: 0; +} +.adaptive-switch label.switch-label-left { + padding-right: 0; +} + +.adaptive-switch .switch-switcher { + position: absolute; + top: 0; + height: 100%; + width: 200%; + + left: -100%; + -webkit-transition: left 0.2s linear; + transition: left 0.2s linear; +} +.adaptive-switch.switch-right .switch-switcher { + left: 0; +} +.adaptive-switch .switch-switcher label.switch-label { + width: 50%; + height: 100%; + float: left; + text-align: center; + cursor: pointer; +} + +.adaptive-switch .switch-dot { + background-color: #FFF; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; +} +.adaptive-switch .switch-dot div { + width: 2em; + height: 100%; + text-align: right; + + -webkit-transition: width 0.2s linear; + transition: width 0.2s linear; +} +.adaptive-switch.switch-right .switch-dot div { + width: 100%; +} +.adaptive-switch .switch-dot div span { + height: 2em; + width: 2em; + display: inline-block; + + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; +} + +.adaptive-switch .switch-dot, +.adaptive-switch .switch-switcher label.switch-label { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.adaptive-switch ::-moz-selection { + background: transparent; +} +.adaptive-switch ::selection { + background: transparent; +} + +input.adaptive-switch-input { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + width: 0 !important; + min-width: 0 !important; + height: 0 !important; + min-height: 0 !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; +} +input.adaptive-switch-input, +input.adaptive-switch-input:before, +input.adaptive-switch-input:checked:before, +input.adaptive-switch-input:after, +input.adaptive-switch-input:checked:after { + content: none !important; + visibility: hidden; + + width: 0 !important; + min-width: 0 !important; + height: 0 !important; + min-height: 0 !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; +} + +/* Customize */ + +.adaptive-switch { + font-size: 11px; +} + +.adaptive-switch { + border: 1px solid #ddd; + padding: 2px; + + -moz-box-shadow: inset 0 1px 2px rgba(0,0,0,.07); + -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.07); + box-shadow: inset 0 1px 2px rgba(0,0,0,.07); +} + +.adaptive-switch .switch-dot span { + background-color: #00709f; +} + +.adaptive-switch .switch-switcher label.switch-label { + color: #00709f; +} diff --git a/scratch-parent/framework/includes/option-types/switch/static/css/styles.css b/scratch-parent/framework/includes/option-types/switch/static/css/styles.css new file mode 100644 index 00000000..3cf7a282 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/switch/static/css/styles.css @@ -0,0 +1,18 @@ +.fw-option-type-switch .adaptive-switch { + font-size: 11px; +} + +.fw-backend-option-input-type-switch .fw-option-help-in-input { + top: 3px !important; +} + +.fw-option-type-switch .adaptive-switch label.switch-label span { + text-transform: uppercase; + padding: 0 0.8em; +} + +@media (max-width: 782px) { + .fw-option-type-switch .adaptive-switch { + font-size: 14px; + } +} diff --git a/scratch-parent/framework/includes/option-types/switch/static/js/scripts.js b/scratch-parent/framework/includes/option-types/switch/static/js/scripts.js new file mode 100644 index 00000000..46391dc8 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/switch/static/js/scripts.js @@ -0,0 +1,39 @@ +jQuery(document).ready(function ($) { + var optionTypeClass = 'fw-option-type-switch'; + var customEventPrefix = 'fw:option-type:switch:'; + + fwEvents.on('fw:options:init', function (data) { + var $elements = data.$elements.find('.'+ optionTypeClass +':not(.fw-option-initialized)'); + + $elements.find('input[type="checkbox"]') + .on('change', function(){ + var $this = $(this); + + var value; + if ($this.prop('checked')) { + value = $this.attr('data-switch-right-bool-value'); + + if (value) { + value = value == 'true'; + } else { + value = $this.attr('data-switch-right-value') + } + } else { + value = $this.attr('data-switch-left-bool-value'); + + if (value) { + value = value == 'true'; + } else { + value = $this.attr('data-switch-left-value'); + } + } + + $this.closest('.'+ optionTypeClass).trigger(customEventPrefix +'change', { + value: value + }); + }) + .adaptiveSwitch(); + + $elements.addClass('fw-option-initialized'); + }); +}); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/typography/class-fw-option-type-typography.php b/scratch-parent/framework/includes/option-types/typography/class-fw-option-type-typography.php new file mode 100644 index 00000000..ea0856bf --- /dev/null +++ b/scratch-parent/framework/includes/option-types/typography/class-fw-option-type-typography.php @@ -0,0 +1,125 @@ + array( + "Arial", + "Verdana", + "Trebuchet", + "Georgia", + "Times New Roman", + "Tohama", + "Palatino", + "Helvetica", + "Calibri", + "Myriad Pro", + "Lucida", + "Arial Black", + "Gill Sans", + "Geneva", + "Impact", + "Serif" + ), + 'google' => fw_get_google_fonts() + ); + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + //static + { + wp_enqueue_style( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/css/styles.css', + array('fw-selectize'), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-' . $this->get_type(), + FW_URI . '/includes/option-types/' . $this->get_type() . '/static/js/scripts.js', + array('jquery', 'underscore', 'fw', 'fw-selectize'), + fw()->manifest->get_version() + ); + + if(!self::$googleFontsPrinted) { + wp_localize_script('fw-option-' . $this->get_type(), 'googleFonts', self::$fonts['google']); + self::$googleFontsPrinted = true; + } + } + + return fw_render_view(FW_DIR . '/includes/option-types/' . $this->get_type() . '/view.php', array( + 'id' => $id, + 'option' => $option, + 'data' => $data, + 'fonts' => self::$fonts + )); + } + + public function get_type() + { + return 'typography'; + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (!is_array($input_value)) { + return $option['value']; + } + + $components = (isset($option['components']) && is_array($option['components'])) ? $option['components'] : array(); + $components = array_merge(array( + 'size' => true, + 'family' => true, + 'color' => true, + ), $components); + + $values = array( + 'size' => ($components['size']) ? (isset($input_value['size'])) ? intval($input_value['size']) : intval($option['value']['size']) : false, + 'family' => ($components['family']) ? (isset($input_value['family'])) ? $input_value['family'] : $option['value']['family'] : false, + 'style' => ($components['family']) ? (isset($input_value['style'])) ? $input_value['style'] : $option['value']['style'] : false, + 'color' => ($components['color']) ? (isset($input_value['color']) && preg_match('/^#[a-f0-9]{6}$/i', $input_value['color'])) ? $input_value['color'] : $option['value']['color'] : false, + ); + + return $values; + } + + /** + * @internal + */ + protected function _get_defaults() + { + return array( + 'value' => array( + 'size' => 12, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000' + ) + ); + } +} + +FW_Option_Type::register('FW_Option_Type_Typography'); diff --git a/scratch-parent/framework/includes/option-types/typography/static/css/styles.css b/scratch-parent/framework/includes/option-types/typography/static/css/styles.css new file mode 100644 index 00000000..1178182c --- /dev/null +++ b/scratch-parent/framework/includes/option-types/typography/static/css/styles.css @@ -0,0 +1,250 @@ +.fw-backend-option-input-type-typography .fw-option-help-in-input { + top: 4px !important; +} + +@media (max-width: 782px) { + .fw-option-type-typography .fw-option-typography-option { + padding-top: 5px; + } + + .fw-option-type-typography .fw-option-typography-option:first-child { + padding-top: 0; + } +} + +@media (min-width: 783px) { + .fw-option-type-typography .fw-option-typography-option { + padding-right: 5px; + } + + .fw-option-type-typography .fw-option-typography-option:last-child, + .fw-force-xs .fw-option-type-typography .fw-option-typography-option { + padding-right: 0; + } + + .fw-force-xs .fw-option-type-typography .fw-option-typography-option { + padding-top: 5px; + } +} + +.fw-option-type-typography .fw-option-typography-option input, +.fw-option-type-typography .fw-option-typography-option select { + display: inline-block; + margin: 0; + width: 100%; +} + + +/* Color */ + +@media (min-width: 783px) { + .fw-option-type-typography .fw-option-typography-option-color input { + height: 28px; + } +} + + +/* Size */ + +.fw-option-typography-option-size-input { + width: 62px; +} + + +/* Style */ + +select.fw-option-typography-option-style-input { + width: 98px; +} + + +/* Family */ + +.fw-option-type-typography .fw-option-typography-option-family-input { + background: #fff; +} + +.fw-option-type-typography .fw-option-typography-option-family-input .selectize-input { + height: 32px; +} + +.fw-option-type-typography .fw-option-typography-option-family-input .selectize-input.dropdown-active::before { + background: none; + height: 0; +} + +.fw-option-type-typography .fw-option-typography-option-family .selectize-control.single .selectize-input:after { + right: 8px; + margin-top: -2px; + border-width: 6px 3px 0 3px; + border-color: #000000 transparent transparent transparent; +} + +@media (max-width: 782px) { + .fw-option-type-typography .fw-option-typography-option-family .selectize-control.single .selectize-input:after { + right: 6px; + } + + .fw-option-typography-option.fw-option-typography-option-family, + .fw-option-type-typography .fw-option-typography-option-family-input { + width: 100%; + margin-right: 0; + } +} + +.fw-option-type-typography .fw-option-typography-option-family-input:focus, +.fw-option-type-typography .fw-option-typography-option-family-input.single .selectize-input.focus { + /*border: 1px solid #5b9dd9; + + -webkit-box-shadow: 0 0 2px rgba(30,140,190,.8); + box-shadow: 0 0 2px rgba(30,140,190,.8);*/ + + -webkit-transition: .05s border-color ease-in-out; + transition: .05s border-color ease-in-out; +} + +.fw-option-type-typography .selectize-dropdown.fw-option-typography-option-family-input { + width: 335px !important; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07); + border: 1px solid #ddd; +} + +.fw-option-type-typography .selectize-dropdown .selectize-dropdown-content div { + height: 30px; + background-color: #fff; + cursor: pointer; + border-bottom: 1px solid #ddd; + line-height: 30px; +} + +.fw-option-type-typography .selectize-dropdown .selectize-dropdown-content div div.preview { + display: block; + font-size: 15px; + padding-left: 10px; + height: 30px; + width: 125px; + float: right; + border: none; + background: transparent url(../images/google-fonts.png); +} + +.fw-option-type-typography .selectize-dropdown .selectize-dropdown-content div.option span { + border: none; + background: none; + color: red; +} + +.fw-option-type-typography .selectize-dropdown .selectize-dropdown-content div:hover, +.fw-option-type-typography .selectize-dropdown .selectize-dropdown-content div div.preview:hover { + background-color: #f0f0f0; +} + +.fw-option-type-typography .selectize-dropdown.single { + border: 1px solid #ddd; +} + +.fw-option-type-typography .selectize-control.single .selectize-input { + background: none; + margin: 0; + vertical-align: middle; + border: 1px solid #dddddd; + color: #333333; + height: 28px; + line-height: 27px; + font-size: 14px; + padding: 0 6px; + + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07); + + border-radius: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; +} + +@media (max-width: 782px) { + .fw-option-type-typography .selectize-dropdown.fw-option-typography-option-family-input { + width: 100%!important; + } + + .fw-option-type-typography .selectize-dropdown .selectize-dropdown-content div div.preview { + width: 165px; + } + + .fw-option-type-typography .selectize-control.single .selectize-input { + height: 36px; + font-size: 16px; + line-height: 34px; + } + + #edittag .fw-option-type-typography .selectize-control.single .selectize-input { + padding: 0 14px; + } +} + +.fw-option-type-typography div.selectize-input.items.full.has-options.has-items { + background: none; +} + +.fw-option-type-typography .selectize-dropdown .selectize-dropdown-content { + border: 1px solid #ddd; +} + +.fw-option-type-typography .selectize-control .selectize-dropdown { + border: none; + top: 33px !important; +} + +@media (max-width: 782px) { + .fw-option-type-typography .selectize-control .selectize-dropdown { + top: 41px !important; + } +} + + +.fw-force-xs .fw-option-type-typography .fw-option-typography-option-style, +.fw-force-xs .fw-option-type-typography .fw-option-typography-option-color, +.fw-force-xs .fw-option-type-typography .fw-option-typography-option-color .fw-option-type-color-picker { + width: 100% !important; +} + +@media (max-width: 782px) { + .fw-option-type-typography .fw-option-typography-option-style, + .fw-option-type-typography .fw-option-typography-option-color, + .fw-option-type-typography .fw-option-typography-option-color .fw-option-type-color-picker { + width: 100% !important; + } +} + + +/* +Fix: for color picker width too small or too big +Solution: Set color fixed size, and font-style to calculate it's width + +font-style: fw-col-sm-3 = 25% +color: fw-col-sm-2 = 16.66666667% + +25% + 16.66666667% = 41.66666667% +*/ + +@media (min-width: 783px) { + .fw-option-type-typography .fw-option-typography-option-color { + width: 70px; /* should be same width as option type color-picker */ + } + + .fw-option-type-typography .fw-option-typography-option-style { + width: calc(41.66666667% - 70px); /* minus width of option type color-picker */ + } +} + + +/* Disable Selectize search */ + +.fw-option-type-typography .fw-option-typography-option .selectize-control.single .selectize-input input { + display: none; +} + +.fw-option-type-typography .fw-option-typography-option .selectize-control.single .selectize-input.input-active { + cursor: default; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/typography/static/images/google-fonts.png b/scratch-parent/framework/includes/option-types/typography/static/images/google-fonts.png new file mode 100644 index 00000000..9c5cdabf Binary files /dev/null and b/scratch-parent/framework/includes/option-types/typography/static/images/google-fonts.png differ diff --git a/scratch-parent/framework/includes/option-types/typography/static/js/scripts.js b/scratch-parent/framework/includes/option-types/typography/static/js/scripts.js new file mode 100644 index 00000000..3b4cc206 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/typography/static/js/scripts.js @@ -0,0 +1,34 @@ +/*global googleFonts */ +( function ($) { + $(document).ready(function () { + var fontsHTML = ''; + fwEvents.on('fw:options:init', function (data) { + setTimeout(function () { + data.$elements.find('.fw-option-typography-option-family select[data-type="family"]:not(.initialized)').each(function () { + $(this).html(fontsHTML).val($(this).attr('data-value')).selectize({ + render: { + option: function (item) { + if (googleFonts.hasOwnProperty(item.value)) + return '
            ' + item.text + '
            '; + else + return '
            ' + item.text + '
            ' + item.value + '
            '; + } + }, + onChange: function (selected) { + var html = ''; + if (googleFonts.hasOwnProperty(selected)) { + var font = googleFonts[selected]; + _.each(font.variants, function (variant) { + html += ''; + }); + } else { + html += ''; + } + this.$dropdown.closest('.fw-option-typography-option-family').next('.fw-option-typography-option-style').find('select[data-type="style"]').html(html); + } + }).addClass('initialized'); + }); + }, 1500); + }); + }); +}(jQuery)); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/typography/view.php b/scratch-parent/framework/includes/option-types/typography/view.php new file mode 100644 index 00000000..297e1451 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/typography/view.php @@ -0,0 +1,90 @@ + 12, + 'family' => 'Arial', + 'style' => '400', + 'color' => '#000000', + ), (array)$option['value']); + + $data['value'] = array_merge($option['value'], array_filter((array)$data['value'])); +} +?> +
            > + +
            + +
            + +
            + +
            + +
            + +
            + +
            + backend->option_type('color-picker')->render( + 'color', + array( + 'label' => false, + 'desc' => false, + 'type' => 'color-picker', + 'value' => $option['value']['color'] + ), + array( + 'value' => $data['value']['color'], + 'id_prefix' => 'fw-option-' . $id . '-typography-option-', + 'name_prefix' => $data['name_prefix'] . '[' . $id . ']', + ) + ) + ?> +
            + +
            diff --git a/scratch-parent/framework/includes/option-types/upload/class-fw-option-type-upload.php b/scratch-parent/framework/includes/option-types/upload/class-fw-option-type-upload.php new file mode 100644 index 00000000..c3fa83c5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/class-fw-option-type-upload.php @@ -0,0 +1,189 @@ + true, + 'texts' => array(), + 'value' => '', + ); + } + + /** + * @internal + */ + public function _get_backend_width_type() + { + return 'auto'; + } + + /** + * @internal + */ + protected function _init() + { + $this->views_path = dirname(__FILE__) . '/views/'; + $static_uri = FW_URI . '/includes/option-types/' . $this->get_type() . '/static/'; + $this->js_uri = $static_uri . 'js/'; + $this->css_uri = $static_uri . 'css/'; + } + + /** + * @internal + */ + protected function _render($id, $option, $data) + { + // separate attributes for the hidden input + $input_attr = array(); + $input_attr['name'] = $option['attr']['name']; + $input_attr['value'] = !empty($data['value']['attachment_id']) + ? $data['value']['attachment_id'] + : $option['value']; + unset($option['attr']['name'], $option['attr']['value']); + $wrapper_attr = $option['attr']; + + $l10n = $option['texts']; + + if ($option['images_only']) { + return $this->render_images_only($input_attr, $wrapper_attr, $l10n); + } else { + return $this->render_any_files($input_attr, $wrapper_attr, $l10n); + } + } + + private function render_images_only($input_attr, $wrapper_attr, $l10n) + { + $l10n = array_merge( + array( + 'button_add' => __('Add Image', 'fw'), // TODO: add context ? + 'button_edit' => __('Edit', 'fw') // TODO: add context ? + ), + $l10n + ); + $wrapper_attr = array_merge($wrapper_attr, array( + 'data-l10n-button-add' => $l10n['button_add'], + 'data-l10n-button-edit' => $l10n['button_edit'], + )); + + wp_enqueue_media(); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-modal', + $this->css_uri . 'modal.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-images-only', + $this->css_uri . 'images-only.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-type-'. $this->get_type() . '-images-only', + $this->js_uri . 'images-only.js', + array('jquery', 'fw-events', 'underscore'), + fw()->manifest->get_version(), + true + ); + + $wrapper_attr['class'] .= ' images-only'; + $is_empty = empty($input_attr['value']); + $wrapper_attr['class'] .= $is_empty ? ' empty' : ''; + + return fw_render_view($this->views_path . 'images-only.php', array( + 'wrapper_attr' => $wrapper_attr, + 'input_attr' => $input_attr, + 'is_empty' => $is_empty, + 'l10n' => $l10n + )); + } + + private function render_any_files($input_attr, $wrapper_attr, $l10n) + { + $l10n = array_merge( + array( + 'button_add' => __('Upload', 'fw'), // TODO: add context ? + 'button_edit' => __('Edit', 'fw') // TODO: add context ? + ), + $l10n + ); + $wrapper_attr = array_merge($wrapper_attr, array( + 'data-l10n-button-add' => $l10n['button_add'], + 'data-l10n-button-edit' => $l10n['button_edit'], + )); + + wp_enqueue_media(); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-modal', + $this->css_uri . 'modal.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_style( + 'fw-option-type-'. $this->get_type() . '-any-files', + $this->css_uri . 'any-files.css', + array(), + fw()->manifest->get_version() + ); + wp_enqueue_script( + 'fw-option-type-'. $this->get_type() . '-any-files', + $this->js_uri . 'any-files.js', + array('jquery', 'fw-events'), + fw()->manifest->get_version(), + true + ); + + $wrapper_attr['class'] .= ' any-files'; + $is_empty = empty($input_attr['value']);; + $wrapper_attr['class'] .= $is_empty ? ' empty' : ''; + + return fw_render_view($this->views_path . 'any-files.php', array( + 'wrapper_attr' => $wrapper_attr, + 'input_attr' => $input_attr, + 'is_empty' => $is_empty, + 'l10n' => $l10n + )); + } + + /** + * @internal + */ + protected function _get_value_from_input($option, $input_value) + { + if (empty($input_value)) { + $defaults = $this->get_defaults(); + return $defaults['value']; + } else { + return $this->get_attachment_info($input_value); + } + } + + private function get_attachment_info($attachment_id) + { + $url = wp_get_attachment_url($attachment_id); + if ($url) { + return array( + 'attachment_id' => $attachment_id, + 'url' => preg_replace('/^https?:\/\//', '//', $url) + ); + } else { + $defaults = $this->get_defaults(); + return $defaults['value']; + } + } +} +FW_Option_Type::register('FW_Option_Type_Upload'); diff --git a/scratch-parent/framework/includes/option-types/upload/static/css/any-files.css b/scratch-parent/framework/includes/option-types/upload/static/css/any-files.css new file mode 100644 index 00000000..d1eab433 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/static/css/any-files.css @@ -0,0 +1,17 @@ +.fw-option-type-upload.any-files.empty span { + display: none; +} +.fw-option-type-upload.any-files span { + display: inline-block; + vertical-align: middle; + margin-right: 5px; +} +.fw-option-type-upload.any-files em { + font-style: normal; +} +.fw-option-type-upload.any-files a { + outline: none; +} +.fw-option-type-upload.any-files button { + vertical-align: middle; +} diff --git a/scratch-parent/framework/includes/option-types/upload/static/css/images-only.css b/scratch-parent/framework/includes/option-types/upload/static/css/images-only.css new file mode 100644 index 00000000..07f5ec05 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/static/css/images-only.css @@ -0,0 +1,42 @@ +/* thumb */ +.fw-option-type-upload.images-only .thumb { + position: relative; + display: inline-block; + width: 50px; + height: 50px; + margin-right: 5px; + text-align: center; +} +.fw-option-type-upload.images-only .thumb:last-of-type { + margin-right: 0; +} + +/* Non empty thumb */ +.fw-option-type-upload.images-only .thumb img { + display: block; + width: 100%; + height: 100%; +} +.fw-option-type-upload.images-only .thumb a { + position: absolute; + display: none; + width: 12px; + height: 12px; + top: -6px; + right: -6px; + font-size: 14px; + outline: none; +} +.fw-option-type-upload.images-only .thumb:hover a { + display: block; + background-color: #fff; + border-radius: 50%; +} +.fw-option-type-upload.images-only .thumb a:before { + margin-left: -1px; +} + +/* Upload link */ +.fw-option-type-upload.images-only p { + margin-bottom: 0; +} diff --git a/scratch-parent/framework/includes/option-types/upload/static/css/modal.css b/scratch-parent/framework/includes/option-types/upload/static/css/modal.css new file mode 100644 index 00000000..db5543a0 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/static/css/modal.css @@ -0,0 +1,9 @@ +.fw-option-type-upload .media-modal { + z-index: 170001; +} +.fw-option-type-upload .media-modal-backdrop { + z-index: 170000; +} +.fw-option-type-upload .delete-attachment { + display: none; +} \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/upload/static/js/any-files.js b/scratch-parent/framework/includes/option-types/upload/static/js/any-files.js new file mode 100644 index 00000000..8b7becc5 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/static/js/any-files.js @@ -0,0 +1,82 @@ +(function($, fwe) { + + var init = function() { + var $this = $(this), + elements = { + $container: $this, + $input: $this.find('input[type="hidden"]'), + $uploadButton: $this.find('button'), + $deleteButton: $this.find('a'), // it 'clears' the input + $textField: $this.find('em') // for the name of the attachment + }, + l10n = { + buttonAdd: elements.$container.attr('data-l10n-button-add'), + buttonEdit: elements.$container.attr('data-l10n-button-edit') + }, + frame, + createFrame = function() { + frame = wp.media(); + + frame.on('ready', function() { + frame.modal.$el.addClass('fw-option-type-upload'); + }); + + // opens the modal with the correct attachment already selected + frame.on('open', function() { + var selection = frame.state().get('selection'), + attatchmentId = elements.$input.val(), + attachment = wp.media.attachment(attatchmentId); + + frame.reset(); + if (attachment.id) { + selection.add(attachment); + } + }); + + frame.on('select', function() { + var attachment = frame.state().get('selection').first(); + + elements.$input.val(attachment.id); + elements.$textField.text(attachment.get('filename')); + elements.$uploadButton.text(l10n.buttonEdit); + elements.$container.removeClass('empty'); + + fwe.trigger('fw:option-type:upload:change', { + $element: elements.$container, + attachment: attachment + }); + elements.$container.trigger('fw:option-type:upload:change', { + attachment: attachment + }); + }); + }; + + elements.$uploadButton.on('click', function(e) { + e.preventDefault(); + + if (!frame) { + createFrame(); + } + frame.open(); + }); + + elements.$deleteButton.on('click', function(e) { + elements.$input.val(''); + elements.$textField.text(''); + elements.$uploadButton.text(l10n.buttonAdd); + elements.$container.addClass('empty'); + + fwe.trigger('fw:option-type:upload:clear', {$element: elements.$container}); + elements.$container.trigger('fw:option-type:upload:clear'); + + e.preventDefault(); + }); + }; + + fwe.on('fw:options:init', function(data) { + data.$elements + .find('.fw-option-type-upload.any-files:not(.fw-option-initialized)').each(init) + .addClass('fw-option-initialized'); + }); + +})(jQuery, fwEvents); \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/upload/static/js/images-only.js b/scratch-parent/framework/includes/option-types/upload/static/js/images-only.js new file mode 100644 index 00000000..d022d98f --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/static/js/images-only.js @@ -0,0 +1,105 @@ +(function($, _, fwe) { + + var init = function() { + var $this = $(this), + elements = { + $container: $this, + $input: $this.find('input[type="hidden"]'), + $uploadButton: $this.find('p a'), + $thumb: $this.find('.thumb') + }, + templates = { + thumb: { + empty: $this.find('.thumb-template-empty').attr('data-template'), + notEmpty: $this.find('.thumb-template-not-empty').attr('data-template') + } + }, + l10n = { + buttonAdd: elements.$container.attr('data-l10n-button-add'), + buttonEdit: elements.$container.attr('data-l10n-button-edit') + }, + frame, + createFrame = function() { + frame = wp.media({ + library: { + type: 'image' + } + }); + + frame.on('ready', function() { + frame.modal.$el.addClass('fw-option-type-upload'); + }); + + // opens the modal with the correct attachment selected + frame.on('open', function() { + var selection = frame.state().get('selection'), + attatchmentId = elements.$input.val(), + attachment = wp.media.attachment(attatchmentId); + + frame.reset(); + if (attachment.id) { + selection.add(attachment); + } + }); + + frame.on('select', function() { + var attachment = frame.state().get('selection').first(), + url = attachment.get('sizes').thumbnail.url, + filename = attachment.get('filename'), + compiled = _.template( + templates.thumb.notEmpty, + {src: url, alt: filename}, + {variable: 'data'} + ); + + elements.$input.val(attachment.id); + elements.$uploadButton.text(l10n.buttonEdit); + elements.$thumb + .html(compiled) + .attr({ + 'data-attid': attachment.id, + 'data-origsrc': attachment.get('url') + }); + elements.$container.removeClass('empty'); + + fwe.trigger('fw:option-type:upload:change', { + $element: elements.$container, + attachment: attachment + }); + elements.$container.trigger('fw:option-type:upload:change', { + attachment: attachment + }); + }); + }; + + elements.$uploadButton.on('click', function(e) { + e.preventDefault(); + + if (!frame) { + createFrame(); + } + frame.open(); + }); + + elements.$thumb.on('click', '.clear-uploads-thumb', function(e) { + elements.$input.val(''); + elements.$uploadButton.text(l10n.buttonAdd); + elements.$thumb + .html(templates.thumb.empty) + .removeAttr('data-attid data-origsrc'); + elements.$container.addClass('empty'); + + fwe.trigger('fw:option-type:upload:clear', {$element: elements.$container}); + elements.$container.trigger('fw:option-type:upload:clear'); + + e.preventDefault(); + }); + }; + + fwe.on('fw:options:init', function(data) { + data.$elements + .find('.fw-option-type-upload.images-only:not(.fw-option-initialized)').each(init) + .addClass('fw-option-initialized'); + }); + +})(jQuery, _, fwEvents); diff --git a/scratch-parent/framework/includes/option-types/upload/views/any-files.php b/scratch-parent/framework/includes/option-types/upload/views/any-files.php new file mode 100644 index 00000000..c89521dc --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/views/any-files.php @@ -0,0 +1,19 @@ + + +
            > + /> + + + + + +
            \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/upload/views/images-only.php b/scratch-parent/framework/includes/option-types/upload/views/images-only.php new file mode 100644 index 00000000..097b3213 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/upload/views/images-only.php @@ -0,0 +1,35 @@ + +
            > + /> + +
            + no-image.png +
            + + +
            + <?php echo $attachment_filename; ?> + +
            + +

            +
            " alt="no-image.png"/> + "> +
            " alt="<%= data.alt %>"/> + + "> +
            \ No newline at end of file diff --git a/scratch-parent/framework/includes/option-types/wp-editor/class-fw-option-type-wp-editor.php b/scratch-parent/framework/includes/option-types/wp-editor/class-fw-option-type-wp-editor.php new file mode 100644 index 00000000..602f5a10 --- /dev/null +++ b/scratch-parent/framework/includes/option-types/wp-editor/class-fw-option-type-wp-editor.php @@ -0,0 +1,280 @@ + true, + /** + * boolean + */ + 'media_buttons' => true, + /** + * boolean + */ + 'teeny' => false, + /** + * boolean + */ + 'wpautop' => true, + /** + * string + * Additional CSS styling applied for both visual and HTML editors buttons, needs to include + + + +
            + +

            Genericons Usage

            + +

            Copy the font folder and the genericons.css file together into your project. Link the CSS in your HTML:

            + +

            <link href="path/to/genericons.css" rel="stylesheet">

            + +

            Drop in the following HTML with the name of the icon you want to display:

            + +

            <div class="genericon genericon-standard"></div>

            + +
            + + +
            +
            +
            + +
            +
            +
            + +
            +
            + + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            + + +
            +
            +
            +
            +
            +
            +
            +
            +
            + + + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            + + +
            +
            +
            +
            + +
            + +

            If you want to insert an icon manually using the :before selector, you can setup CSS rules like the following example. Make sure to set the size to a multiple of 16px or the icons could end up looking fuzzy:

            + +

            + +

            Add a matching class to your HTML:

            + +

            <div class="my-icon">You're a Star!</div>

            + +

            Here's the result: You're a Star!

            + +

            Examples

            + +

            Turn every icon a Salmon color:

            + +

            + +

            Or turn the stars Gold:

            + +

            + +

            Use icons for bulleted lists:

            + +
              +
            • One
            • +
            • Two
            • +
            • Three
            • +
            • Four
            • +
            + +

            + +

            + +

            Use icons to style blockquotes:

            + +
            Sometimes I've believed as many as six impossible things before breakfast. —Lewis Carroll
            +
            `Twas brillig, and the slithy toves Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe. "Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!"
            + +

            + +

            + +

            Use icons to style buttons:

            + + View + Listen + +

            + +

            /

            + +

            CSS Preprocessors

            + +

            Preprocessing extensions such as Sass (SCSS Syntax) or LESS can make it easier to manage CSS for a lot of things at once using things like variables and mixins.

            + +

            This example will seup the basic genericon rules and sets a color you can use for all icons using Sass:

            + +

            + +

            Here is a similar example for LESS:

            + +

            + +

            Fallback images for IE7 and below

            + +

            Genericons does not come with fallback icons by default -- therefore you have to create them yourself. If you are using HTML similar to this example: + +

            <span class="genericon genericon-warning"></span>

            + +

            You can use the asterisk hack to serve a different icon to IE7 once you have saved the fallback icons to your project:

            + + + +
            + + + diff --git a/scratch-parent/genericons/font/genericons-regular-webfont.eot b/scratch-parent/genericons/font/genericons-regular-webfont.eot new file mode 100644 index 00000000..6e715677 Binary files /dev/null and b/scratch-parent/genericons/font/genericons-regular-webfont.eot differ diff --git a/scratch-parent/genericons/font/genericons-regular-webfont.svg b/scratch-parent/genericons/font/genericons-regular-webfont.svg new file mode 100644 index 00000000..d9f0c82e --- /dev/null +++ b/scratch-parent/genericons/font/genericons-regular-webfont.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scratch-parent/genericons/font/genericons-regular-webfont.ttf b/scratch-parent/genericons/font/genericons-regular-webfont.ttf new file mode 100644 index 00000000..7be71af3 Binary files /dev/null and b/scratch-parent/genericons/font/genericons-regular-webfont.ttf differ diff --git a/scratch-parent/genericons/font/genericons-regular-webfont.woff b/scratch-parent/genericons/font/genericons-regular-webfont.woff new file mode 100644 index 00000000..4d72659c Binary files /dev/null and b/scratch-parent/genericons/font/genericons-regular-webfont.woff differ diff --git a/scratch-parent/genericons/genericons.css b/scratch-parent/genericons/genericons.css new file mode 100644 index 00000000..5a36281a --- /dev/null +++ b/scratch-parent/genericons/genericons.css @@ -0,0 +1,194 @@ +/** + + Genericons Helper CSS + +*/ + + +/** + * The font was graciously generated by Font Squirrel (http://www.fontsquirrel.com). We love those guys. + */ + +@font-face { + font-family: 'Genericons'; + src: url('font/genericons-regular-webfont.eot'); +} + +@font-face { + font-family: 'Genericons'; + src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAACs4AA4AAAAARowAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABRAAAABwAAAAcaW/Oz0dERUYAAAFgAAAAHQAAACAAqwAET1MvMgAAAYAAAABCAAAAYFFfaIVjbWFwAAABxAAAAJcAAAGyqWOQYWdhc3AAAAJcAAAACAAAAAgAAAAQZ2x5ZgAAAmQAACOsAAA47IE+VnJoZWFkAAAmEAAAACsAAAA2BFJrzGhoZWEAACY8AAAAHAAAACQQAwfdaG10eAAAJlgAAACGAAABBlHsRCBsb2NhAAAm4AAAAP4AAAD+AbXzmG1heHAAACfgAAAAHgAAACAA0ADAbmFtZQAAKAAAAAFhAAAC2ELRXhRwb3N0AAApZAAAAcwAAAT2hTWbEXdlYmYAACswAAAABgAAAAZeqFJzAAAAAQAAAADMPaLPAAAAAM6ZHNoAAAAAzpkPJXjaY2BkYGDgA2IJBhBgYmAEwlogZgHzGAAJqQCwAAAAeNpjYGb/zDiBgZWBhdWY5QwDA8NMCM10hsEIzAdKYQeh3uF+DA4PGL4ys6X9S2Ng4GBg0AAKMyIpUWBgBACHZguVAAB42mNgYGBmgGAZBkYGEFgD5DGC+SwME4C0AhCyMDA8YPjI+Ynzk+Qnlc8cXzi/SH7R/GL5xfNL5JfML8Vfmf//B6tg+MTwSeCTwmeGLwxfBL4ofDH44vAl4EvCl4KvDP//KzDzs/Dx8XHwMfGq8xjwaPGo8MjxSPAI8fDwsHFXQW3HCxjZGODKGJmABBO6AoZhDwAl3ijmAAABAAH//wAPeNqNWwlglNW1vudfE8g2mS0LSWYymZlAkgmZycwkLGEAMZAAgoGwBBFUoAQEwqIgLn9VKoJA6xKtoKBVodiqbUVr0z5T6wJ15RF91u0ZfBVFfc+2tkWYubxz7j8TEsAlk3+/89/tnO9859wzTGX4B19Jv2cy01g6y2DZjNVY3BbZ6rY6LeAeDBYrfHVyP//Fwf18O8zYf3C/9PvEBbCVneY9p4En3mSnoZJL7DQD1u+vhjFNYhK+VDXw3TobjG+2MifWZneHwR12h9x2d+qo4qaxOJOMhCEZBuDbuHijQXe4IbMEvsfAM8M4zXBnYBUSYAEdP/huK167lNwcSXGVSTm5LBip9ZVqNrkaHoSFr73Gd/P5fPdrr8HBns7Onk6dnbmzkErEX+ukB4wpzABDNzRDtNjOirC9OBpeHA2vGnZDkOUwTynucl2OHM3ly9GNr7GXBv7HDWqwxH4HGj/5u2f416DXwqCuLv6vLtWIM9ns1oLYnlPdoMNq0PnXfDv/WmZUogsGUd0SS+s/XszqtripfqAjboaM1ei4xRngYEhir+IGeE82OKMzjoMD9EijfkiMpYNFM04ZCksYNN8gYSHVwHHLxAubpltUSwDCtRGXQzV2dJxmHTt6oaFXNa59vjzxiSHdU/78tbt7e3G8cTb0VPsYYIvSwW2lWcbpwjfSHg8JRtMlCzGQqB2irnwWojly2C1YYzgSttAE4YXTjnVbaq3hYqBHLh9eRKJ2euQIUjEZx6arvTW2as+qWGt7d2s7jZd5rbOuTdxYuNt7d/1MMKatWjWNGzPr7/buXgjGJn4rnXBjU1fXJkgW4qIQGDNF23Dr1qltucxD/QmKxnlwxD2lohlgMW9VAM5A1B2MAE7Sgj17FvAYjxl4on5IVwZeduOY7ntbZ/gMH/AYdO9ZAHiWwPtn7hlvY50ypOZGRbl1ifnByfVGcQRsWaD7G6DWp0eLZTuOlD9SK4k55YbS3jb78kDLiLbGiy6KtxUMLcoZGW5rVvFlp3CTWHvbnOM3znpk28i2xq43ula0FY6eMNk/9bZIW3OP0M3aNJQutgR7GlRYrj2HqZoPZz1c629QaCf5/AHIknSfX9MDcjZoTs1uK5admp4FAfAHFP8wyAKHs1hxFuuRqM2B7fOXMUttLitT2GHYCLkP8g385bJSmDBlg9EaXaoNSsu2KpmhUZdHr9qy5aroZQ3VgwaNGL402mpsmBzOGDJm9iyXlF5UGilSMvLTLQVyelFBaSbImbklZZHRFwegtIy/zDc8CFbYmMYe5P/LNx3mv0p8tkQvyVeen37jyPSSie2PrX6gI7t84qU1ICm5NV63JLm9NRZNkm6/bs3u1Y+1T3SlVc/NzIK6qJLpKcyT9MEFudi3kjq3nFaQX5LvGCQPCq5X8lzaEskBF70B12I/SD502okxy0Yc8LIga2CNbJpAGoZQwxBrGIGNt1TzOKwNStRXpmpMd5RFJRXHsVhyRhSnhJOa64ywqM+fARDJjZapxZALwagkU1k5CLtw5KwPPcS/4Jv4Fbh98dBDYJUmuQzX4j9re6ZsXTr0ev504thz/G/Vz8FXW7bJ2xqf+vcoR5Ff2w+Tryn4umDt8uvgF8dyYvxj3qHcuuuVPP4578ka0caLDnS5H/+Ab25/O42d9X6sU9RblvMIf0Qa4WoYV3b97bGZvOstx8QAFDTVX9peXBSakeHWCqGI/yO2l7++/lWITBlutAbjJ5bDjO5AoPAe/md+aBpUws1N/PBL3YQtiJ+ViJ/vkbaDppOQZMmKx+V1hFxRlCJHKIiH0ShGBDlRh+IkGQwFnZGopkd0Y9IKaFj31FH+l4f46zwxvBzYwat/X+Yvrg7esG/arMmzg1tgy9FBb9+zZ7mxdNjVV2rDV07TXWnXnDj+8j2zHlbvk3as1DML/nyzWiEHH5y/aMb+lwf7q+75r7UFY25uzDTbxxBAdYP5+2u8xW11jwZshzPq85RmSUXgsYQs7iQKIGq2d3a2848hK4N/XDHuEW3q0vm3z67kPFGJD3Sjs/0UlpBeAqU7Y1QU/j4oOn/dBZ/zeKK+s52+KzCXGeoxrDcfL2Ss0EI11DZIoaCjBGRPqVYkqcey+Au8+4MPahc/emW0vaBA/+PkkHKCH44/LU+CapCmblkR02SZfxybkPU6okeqL9lsKpvN5rPFQjYdKJsayqYPZTMC1gYpXEvqm07j7PSVeUoVPRSMjIGIQ9M1Hawyqn3E6TDvFQPd9OK06XIkN1yrovCChuLq8w8Gh9wEy2Hyl9u3f8mf5HfyJ+lMvnN6HsJ4nk2yqjlahpomy1NHDFrBP935Ot+1ota73FNqt2bZKmvA98R1M23ZNtumi3zLPJ4cK2TnVNRIM9TR/3r6na+fPPkqv+FC2bflRkU68fdVutG/Dpgs6j3lg4yL6ue5A3PCpUrxoMLBeVkOi21QfSssWvn8PlWSoaRUVqX43ZIFZutSqQsG0U1rvkNSpbTyYbfcm6hvhzXvvv7653zjFUrRrnggoKnS3sRYNxO2PzmeYTaWTWeLyPZ7LEhNSBaEnCBYIkim4UhGxWko6i5Fa4YDi6JUBASTvoizGJwOTUZQKNUtJO8EowA0pChRiO5OxFBVMwRfQFKAkqWql+yQPdll1iKLJS0w+cm5LXtuSTxww1+nmfJz8tnrDtntOzZu+IPDblyfO8n69N3XvVpc5CoogX06JJ6cuTmv/h1jRpO1tWxUUZHGiGiIt8fxy0McOx5bJhVkDLEU2vLsg2ovHLnt6Y6nh2+/rGUsSbWR+Lnyxv0P/EVR/vqzPd38LmiBv94gj653j/Lym4q8OWmLps1cCpCfOTK/prSGCfuFBkmbqjmRLXqEHqHohAOAMmy3OQANO6mQHiYhr4024FO7IDBSLoxvkaaNG3/xdOW6vbcGp9eV5vATkJaWMyG0KTGdCJOqXjRi1JSpI0dcFN8ILz3+VF6lL39V/Bh0VVnL637DZ8v58WP95imbDUGcifbXZFNlrd+vRSnNJu3tjH9n61KKbk5KYtP3aCuwR9GQTEMbMlbYXUeu3SYpSC/8EqqZ3xe1mvDnEJZfIyVEpWPUXLsNBUkn4+v3oQo3SGVKzRNQ/cra/fzgS5c/Xjopp/SSu/SiB8u3LW6Z7R2d5dywaN0zl/PjJ7Z+cd/sllxdz0nXPY4bbmq86zBUpLENh/ip2/7Fr+q9JMY/qN94R2TvRumJ6Vdv7Vp2cej25+ov//FvoeaptyDr8r3vrr/jCntB3ujyvJz0EKj7r3zvtfsvFdiZsoetSQ5BNtBT6o9ErcVgtjwgYdORuDicjggOdDTi8/vCJspRD7HjUcIjnzkzJYCj4DyLQphm/o4dTUUTh2yf9mBiy/xH/r19299/fk19+5LcIkXKkVU164JGo7vjUO+0zvkXX24dXFPcOP7iNTlp6R3WPA3t3GP9GQPy/E38fx8ctnYJFISbn4YxB1f3/OyyKT985DdzthwZlpZlTY+lWx2Wqdcs/PUt09997M5/37VuWuD+q4aNm3VPR8V0q5V7WxZuWQ9xiCSpgcT2SAv0BeoeZAjI0VmOz6XlOFxlyaP84Vd831dfwWxlbfJEngGzv0qei6NpJ5l+A1IMRB7I9ZbJKAQ42YgZsk8m2dB0J94qhNxQkErmoE3fevOE2OactFUddZNG2WprDs954oZbZmywzZv+4+X3JWAFLFTvg7a0DN5SdM+8J56A7ItgIlRb0+7puGr5DN6b+Afvhf+CP5G7kvRxspH5nqM7yEZxWhky/t1x2islCSzbu5uLWxLuidMm8IvwNjO0ctTDUrzwaKLR9pDFJgAQcS8StWB//CQCqHhuZfxpS9XwSU3LXiwouPnSS65b0TZ7/Y9unTyq0mKB/bxVN7bOuWR0zJNIbN0wbuxqV4nDVgcFs8vyqwL3wiuQP0DvSxB3Rp7bdqQUvgpAWwo2x0gIRhQxI5Ec1Y3ih1QbGQcCuQPROhIeoPzq8eawEW4Wu8Ru/lwveUBIu7/M4T18Nu/J4V82h1UWbh6IAejvJL/U3NxrfqtkXEMP74HKnoZxCUYPWRryfdCZxpmN5SFiuRA1fWwYCxDzp+brQMME1IMoRILg9FqsahSsft3pjfrdulP16ungVy2KV/qPoqLEOIst15oYV1Qk/YelPPHwMSi+GYqPJU7tO/7pp4mbH35YOfHww4lx/OgxtHq3HuNHtX/wqrwSXuVy8MrBg6HH4YIjJXlwZHDis3ufhRB/9dl7YXbi2V27dgVW4N+eZ3fyfTB757P8lQFjHmaz2O/PwzCCZWQMA5Kfph1FV/H7yvy+3GikLIq2T0Egy1XAp+iaJARDiWJvifyNkSNloSASQCxvdZD0EDtko4UVLaNrUT5CIBIAcY2wIlCFZCr5GNlkNfgIbOhKJxTFh4gyzmJJYCddABY9H3eRpM9h8+KRszoPrVn7hD8yafVK/tTeffx4Y1PmrNlQ9WvJ/Qbfe/BdWA+R+/ibV155hc3yyLXrwbVx8sS7EnfeLmfBZZC762dQfFlZ6Q/4ezu0Wa1bV69vafsT2Actm7GYf3Xl2tGj09PuvXLFf48c7Wi+8N2LZtrsoeC8edN8tWmWUO2MlpH1GVpFSXl1YGKmlJVud0yY3GgN+HIbKyra3E2a1Lpp3AWLivK8R1eurkNqevyHN/32vMzo6w/+/crmG9cd3tVuG/7chrv5Y+s3rioq/GD3Lrjypzv/s1jL+ZDfdeR9vvldrUBft3IZ/8tdd56e1Jhdb7+T3/XWbuzHauO2jfX+6+9KDNq+Zs0wz5BSsP9JWvZswxTbyIaly669+vlid8slbUebpthGNVx62YwZec4aZ+PQ2Y0TVW1UtMU7JseuQl2FXNxUVOxWKkonX+yPpqXnl1ywaOyy6tycK29rWrakomLNug0bbnNa30lyrTSGcjUVeVYH24q6HHW7cMLI5UTssGURa5KcWbJO9qQYLUiDjFKmVENAqkUZIJ8VXVI5Cy1OAJ8Is04+s2onbu0OE2uDYhWdVPLmaxvkaAO+WLnhbl7IT9w3aYpr/LzrJ1nr0kCTFIBBhVnW0U23bQwFJ5Xnxja8cO26l3+yJJjpKoqUuWdarc48q9NbOcqVl1NSHMizXZ5bO3rIiCvGD7eHhrQF6i6/IOhURiY5lxG/MNQwtqwk46mHuj4qrRhbludpmViV4dErZv4wtndG3bL5jcNUyaJk61mDs/WCyoA1X9EdFa6i5qmNpeOuvrQu2NphjC+fMLoqWlI0LttaMbza4SjyjWuYE6yYOgYvchKPWoty6+d2rKhZEfMMq5+3Zm1tx09SbPI043eXBaLDgqHijm17bqiePnxYdvpgiy7j4x+hLtfhmM/F0S5WbXqWSspjyTI9fDwrlhCz3ZbhqFaodgHN7xkuUD0LiuUS0AMKDbxcLDvV+zPKr7xkUbS8YvnK9St/MGusJRekwRZX+Rhv7YoZE6y57gvG1+VA3djXNi51Sp4xF7fNa4nZrOP+sr2+vDBfthTmpaf36s4RQ4cMbhx/4d69v3rgno3zCvShqnXizB8/+NF1c25tiVrVzExd45/JGaWlVf7yTKuUX5yRCXmlFVllVfKvEx9nuuZNfXjyjW1NVe7sNJByrguOrVowbcqIysEZh9JdS1c8/MCL86auHumSsobkD6J4zzbs/xrsv5utxxFw6IKR+FE+yohhRUlKgFzRkEnUgGIjvv4fLES+qoM+ZOCSj5Ho4yghYXOkPsj1k6Yv9dx8Sl/Sx4bgpt6bNy6/aPKj/ODRTZbxN/Vu2nb1hOZHoe7oJr54ZKln9IiZU1bMKfS43Ra0avMWVla4iu351eHS0vy8EfUXt67cunxZfX20dt6l11+CVN3dMHbp1KpqZ6HDPsRVUespi9TOuvrpzo6V8rj2lZt6bxqR9aOjUPdoa8vam/CqOWPTUX7w0QX81ZlLZo9u8PkL8/Nsaem52U5bUaC0zOVqGG51lHnmBaurqvILyv1NkxYuvmBseXkBWp2S4mBsaKXD4SqtrXEWuN2B5qmTq8cEAiKMjH4B0yieFjTjihQgErsKCDqEkQ5IFWBBTSY+i8pIAS8tm4y4Zgz3OfC/ORwjm8ljY9c2zh1mdNesWBgDPaMg1z3nwpy0NNgTblbY0HGZbr/YYdn25vLh5ZIx/4ETt6qWKveQGfdePHOP19dMVPVV2K6H9DWshtWziejRzWWXs2XsujOtIxuGcyqinyIGYUWxd6okBQ6BG36v7CB5cEilGsUja9HakedHXjTeUMCGXyI2q0YEq9Udik0r9dHbXPQKPHVG8MSUhtpIkERAD9UFsl7gj/HV/Jcv5FSGr2q5YtTTf52n5ubaoT6vZXjT0qVNjYtVfnLKB4+PWtKy7kisqipWlVj1KHj27+fvP/oL/v7+/eBJHC2vnllUOXSEurKifmhVSUsic9y8sWMD1XDz/LHj5o1rzB5WnN36TFdrdvGw7LodP1F+HG0rDNbc8vGmTX+9JRgpnBNuuaplYToccgzOUCcOrVl659KFjaP49RkLWq+ShlVRpafs7QeWLX+qvf2pt55ql3ZWD2luKKtfXzK8fIR/9JZ548Yl/+PZxRXZra3ZFcXZdSIuLyE1Rn5ZRByHOBmyfVmw/9Hgtptx3QZwOZx2nfDZ5fOHnVFxfzQo06svqAY4tG37IdDxVH0JHC+p90kXHuL/c1Baeh/eUg7PKw0ESnnJlude3Hr4NXd1tRuObf7Ds5uXVd1weOuLf9r6n8MDPXT3bbFGYIg1gmxW1scXxSqByXV9qJo2J0QdwagTImIKif22d6ZWCDqldv6ud3mZzwftine7V4V2b1Mk7NXJbzcOm2sIh8FAhzAMPq/X2+7jnUospkC7r73JK/SC4sxMYwPZdl+U2awP30ZBZTzRxJuRXMagu7Od3ix0S8IR1WitA1kjsmmn2+6WQ1ENcZ8WA7BswjCMmGIkDDSutErCUmskGtWtoLfOwJIu5SbXRjSWYJzJ7OV2UiINzxM4bzLjRjPd6YtTi7ErYd5zmR9DRUbeh76qrRjSQUfVlmuQhql/WLnyD/wUP8pP0RmUHH9zZ1vbzjfNA2yBYXP5E/jeAYVU8cVTK/vK0UFi/K02mAbv9K0laEyszVjwmtQMVcscUXTsI0q7WN3hCEO7e+OsVzHEqg4/3rubjOPu3v59GswKWaW5uuMOh+y0WSlQ4BarEsJFIBSguaJp8lBtmnHSEGtShtEcjgvqL5PDEDMKfL5aXwz3mnGKAnP4R6tZVCJBe+mAr4AzfF4A3VjyrHZEvqMdIyXktkWyTUclQioctYrWhL6hOTwmgexwy5KhVRUUDNGXP0b1fmPDJJdTkkBSB2H7huj4FfgVtZCxjAFtLBGxngpWLSIuI9kYNv67Rs/u8SY3td/52dffNKiMFszMrf/52dff2C/j3D/So1Zo1a/RrxEre7qvNBtQ/XU/oN/QIEXBj0AwBnHAH9WvOYCqfMDrPfARX3dB2/gMW91w2PrRAe8y3wGf74DaRnsqcRQfB3Oraqebj70HfO3eA2zA+qTVrI3cPCKvUrAYnSJd7VtM1JnBLT/97bozarKSV/dbRwTs6v/104x1v/3pyv5riKZcn6nL/a21yYgc31XjLbTu+l3VSibGDKx7KOHTwKoBKw2Z1cMZbu7WzmkC/B+Kgv5Msh3wdYpRUwVnt4RbZNGIZINYH/1FpGNQmca0HpaJcutBmWUWiJS5FCc2DLHLLyPUBCNRBH803HokuZKrJHERTi6CwVAJg6+AU1xbxP/Je/g/r/gMVk954e3nJ8M6vu3+D5e/0Pw+NPSSyw8mfioMTi5Zs2YxV7m6ZPWaJXCSb5va0jIF1sKaBy6empGMDuxOYqva10ZaFS/ENoaEPFKDwInePrnGqh+wyWaAkJqOFCJKEUISU4ocEENRF+9Ysgqbw2/7cjPfLNre+Uf4fO4pNlc6wCuzendXyj2iG51/fJiKUhf+tjnhgB56pq3bEbh4Kn0ZfVzswA/pi0oJr4xU7u7lBvXl0h0B6sbfbqHv0G1mriFLhrArwh5ReCIdsFFOpRtiBu+m9VCxKBrDSyU24JJTkdRajIgnnvMOOWbEu+PdhhwTO5neMeAyTkX6YtFkEwYzJ6syswu8ZjzerrppSgmTbA61L0oU6vfR2CmUmeYwCNgEAdCnaS/NNXHExA1KPTADPYiM+N+dECxVwuOZjew8FKOdv4ulYzu8IKeDDKosT048Ce89De/Cu0/De4kDB5TrgT+V+BQm8yclJzSB5GRibZ2JNWGNDSJJQGD1Ay3/awRshI4k4IphcDPdIGHwGDvDtUjqqVZ7OoTTCZV1tOa0CC+zk/hUZAgYiRgYoqVYWoxbt9aN30tDZpBjsgocfPA7UeokhI/uONYhG4lfLpBaFuwRhwTxCkDpjRvQLRvxL/o/AtLWPr6Db6ep9VL2Am2qoCkkNt3QLXVTS4iyDMCPTJZH6+FgCaLtKcCpzJFYGV7RcrW7VirLFQrqCAI7DNthOgx5ccVp9jL/OffxuBk8Pk2ZHY+v2rNq1R5aBlnxIv8f/jhffRgUeAdmvczxnhlfPgwLX0uIcqsEhjE7+oaf6QEcizxzTd4h5CUKDeCQU8kKyFClJEwob0r/nr1679ef7Vs9WzpRv3NnoVDt5gMmnXr8VMX2V17Zrrx5yfjx8bUgpIfTnoeTEIB1puKwDlbMwpTtEYyIMIbTIXxLWsBQdDdL9ZrWmoTHapJWirmXRd0G/LhqwiD36zffu9a3FAno7E9vfI4/18xfTtIf2cFXmQV2dfjascCcT258DhqaIayw6LDrHlzt86HFmnNFzy+4KN8J4vYab+q2qe+pPA5/KouDwqmoQjaH60wyh2D2oSRlMjM3TFNh0CmONSqPkUzcSBjC0jxDwEA5GpKZwGGSpOf5KLqS2CahG3C7RvKRhSPFGPpu6RAAYV6AuSIi7q6xOdP4Ur502hzTSiQ6U7k34eNHpvF26Jx2xDQeiau6zEdmvxYQjqkfkgqlgwfQCyAqbPAPjQ+hm5JZYI/RLZkygtKTRu0w83OI/eQTFadPGjvBUpsujFFC5MOc7s8DLKYPYvFniaQAiw+9kNrcKNgk3em2lKCohWslv8Wh5KJaG59MnPaXvU/y9/atX6YWrV/2UcKwvtk4HW9B2T5Ub+OTxmd+8AT/ooKfLH4LJnTtBOeyxEc7+afLPpKo5O+WPAHWCtBL3uS/I/9Bxn4qhugFNpiQTxGYksQeGgAzryeZbyRKsLj4Xhxh4jRWiYcWKZbG1P8Wax+FZt4MmXQEjuSB4azYsqAUZyiS8jWgCu4wuBXWrVIPmkf+z8S1j93R2noH7Xbe39Fxf4fcTcxd2t3AS/pOwDBL4I63dlCx/nihC9vJKH3G3M5VUx3nICHSomTsQX8VVfvu02rGeTQ03bQtgv86xYpDheC+Z5hv0s6YFiYkrI3qQQOEA8GS3r+XMtu+6byf9ek+bQo+7cGH5AvHPWFaGxBZXu98w7nJf6nxZmlBhGWWujjryEy7izaDfMlCsXZrhmbQoRiZ5BpOEf9AerHU2bdA0q7rXZt+NL+6a/XuXoWZQFHk2dS1YNHG3t0NQkfJz1bMHD9ET1s2cmo/Cgf4fbVIqYNWZGrqPVDc1PRp0+FmXs8/hJcAL5p7bj/N9qCX+jt+tPlI86eTpIm8Hlz0sKf506bE58D2mHaFrJlK1Ikyc5LjKJtNUc0miRjUEfUL9Zdke9Kp/rAbouoX3DoLZokUuZ/PQjmztsIsA2a1ov5b4YhmpMpHRXk/3vxiFv85JdvBrIHlUVdiGrUB/9MlZCvoRncnkNmgVUPfu1tCfoOGLRkPE9gSE2yP6A2QJSYvX4oR+HeLM3NdVca2UUbaULDIIpcPv4Lais0y7wNBTFzk/5m+heALIhdPM1kP2m+SBbKwp0SypFBYWp+U8KZqaGxAHub5PDrW32fz2j1h+Ba/7XzXUn9H7dv9tvNdayzlqZ1mxvn/aKgkEdMQcQlT/89eBXST/iUzQHHwRHCF9tJxokTcRAEK4MTFMwq/nKZoSCrykcQYUYcTbbPv7DrQ47W4cXxqI0TRcOhzz1OdyFo16NzM03z5rGpxgFAKKHDEBHWinNc+btAXSyWczRcoS9EO+5mjjRFJ9KF8CFyTTHiLo7Dx998/zd7n76t9qJY8smP8gSr+D8isgkspHo6jKXCgRPQwiQQEbOdDA5HtiWbBBAUukk3pTNP6gIHoFWUq0uAJkCB/DA8uVwooEg3UGDNT+AwOlfavXdTyLXB0phIxp/3rT9ZJg31Wvcn4UZJjp4lIHNorARBASx5u3eTaiXfmSj4+l5ZxKKn3NKqORq7wI4l32iQvSSynVF7SrDPxKEVwdksySdeSTGU2mykLtoyTgoXjLKm7ybm1COn1kPUYiSpsSm8IX+KrjQqbohnC0Yil5BSRPRgMxl+jAAcJq2EK70kjensUL2lO97A9+gJ9AQuIqJLu1XSrTkscft1v9flVP61yRP1RNRKVo85I0Bl1yg6n10nhcD3lAusLRvDXK8c4th4an542/tBWe12Ivz7ik7S0T0ZATfUoO97PGX/oNkddCGrodqJYgLD0Od06U7L/G0ZVm0U/6f/mA8ms6/42fbCp0/2zuYESYnSIeG0sFIyCdnZWtxLkPT2bN0pdE9HFqOy55drEhInnpHgnXuuByomJCRs39/CeiVLX9efWiVNAek1pQpCyL2XJo0TQS7xOsKa4CSFy8oC4pDCBt0kIaU7p8RkZ6eNW9JEpnZeljDdtJsfu42FJjhZnJvdKxbG1FN6Lt6ATzgU5S71G6ov5mmUlk9WKwqp4GU9mgSerTOaJszN54qI6M09cBpEEm/a9cDYVxBaSqrSLt5iAl4aAd9LUVIGzpwbgrMAgquO8OJsk15Y+nD1fdYQ1NDWdx1NIC81n1UwDpQq2194ZT6FtIom2yoA4N1nEb490p0TDGbJ4vk+8u3RaXd20OpfxvSLe8oQ6Kn4QvfuB7fJ8Z7tADskpevl92iU5/uBcJdr2fRoGD8P9/LIFonXsrLaNYY3f1TaxIkqfIvDQKmpUZFCKpVE/Yrz0/dstsWhefqQie/AtuTkBlzU7x1I4ds7oFVddtvd790V2D2vGussKczLsDt+w4qIiG7pj1kGDq69uSHyd7KKIJ5r+udA48ZHFrxsU7Dx8yF0oUi74kGzB+coqggDEzymr9MVsNPRoc8mnJc8zZCXTRwer2+/RaSPTTv+tMEN+iwQWxHlrfFmFUSG/hTtVBHlASLN5TMW5UxiQSW+P5PrKspGIK1quU2HS5lU5f+ZHVj3wwCp+5M85q5BLLmqHUZ9b2n/603bL5/z5dnzXYujV79VK8CydstzQUjq9stWfLutW2anET5xmJ/jKw4ff5G/AcE3hh99844031d6GOGv4GOqhfjsS/Hrk8C9t5y/xl7YzZsZlUdOTsap8WlFKh7CbKA36h+diS1/qLQ0jOeVx0UUYGOY/EyOmWTHIbKMfaXQnC4SpMDf6MmLP046ib2+H/dvrpx8sfVvNxjn1laTqo9iYenZ9fvDrYNaYEBm86oD6/jmXdx5ogxyzSnQ8eEzqjg2o8gUqMpd/mfyNS1Iu6bcmhPD4j3Uyu4XCSxTxo5gsdYJYNZrIzqbfX0GWjHpFcVzyJ3h3DC0s7+lsmsxFCE/4WX3yBQPep5z9HpT8gV8esDYi03iA+Tun0oBM6aMeS1BkB8ghECKt4XbhyubmlRc2Lm8I1Xs89aGG5Y3mHZ2dZOTJk/NMm9x3lrLvwmbSb7lELWrSooDbby5GO80fLIFYRz3N1IUJtqpDZh20sCriAkTh4qyj437DuL9jIH8zfx9mHziDoXAtcyVXvYvQ46N5iYs9VMI+qBTMVGVG/zkzcMB4D/+FINRJH0diwmfLTNYiciWIHxMVVkNkB0UuhTgqL7Us7tqE3iflJDIzVN1NAbRuZaF/1/xNXciM22cNRXuHvaOIJ8XvzfdTHEsO6e5oyOqJunXl7S+Nch4rN/AA3eWq8NHITUnF2o3keFpMFsKSeRGqH2TTAQUzvCIZKJrdp1HmTXaSDL78szuxAFw8Ff8n/7abpDSUDobcTZ94LJlrjNdpQoLR7tNt8dz8nhIT6wb4zJr8HjrHMXwKSiy5poDPvOlg3hYl/h9VXAj9eNpjYGRgYGBmaPaTOnEpnt/mKwM3BwMInJvJr4ZMczBwQCgmEAUABy0HjgB42mNgZGDgYPh/A0QyMPz/DySBIiiAFQBj/AP1eNotj7ERAkEIRR94gbljP/bgzMUXWQeR2fVwsdZibiEWIB9gZz/wYfms/SjzF1jGZxyDIBwPS0S5TFwITfhO5qjsm7eqPNmz9jHqhNCZbG1fWjVjOqqLq/RSbaNfBnd59Z3EX4pjqY1qZsyOio5Waq3ef9SiIx6MtZ7N77KePcvtD516IYIAAAAAACYAJgAmAC4AXgCIAMYA7AD6ARYBMAF+AboB9AKOAygDeAO0A94EhgUaBVoFsAYWBpoGvAb6Bx4HVgeyCBAJPAn2CnYLJgtuDCoMcAyyDNQM8A0ODVYNeA28Dg4OeA6uDuQPIg9qD7wQHBA+EGAQphDEEOAQ/BEqEUIRhBG+EhQSUhKAEpYSshL0EwITGBNaE44T+hQkFFYUaBSAFJgUrhTCFM4U3BTyFVoVjBXMFf4WPhZ2Fp4WuhboF0QXfhewF8YX1BfqGAAYDhhAGIIYzhkcGY4ZpBm6GewaDBo2GnoashrwGxwbPBtuG5obzBv8HBYcPhxMHFocaBx2AAB42mNgZGBgqGPYyyDAAAJMQMzIABJzAPMZACNoAZEAAHjajZK9TgJBFIXPAppgYUUsrDbRQk34cYl/UFmIiRpDNGpngmYBI7AIq2Dj8+kLWPoQllZ+MwyRAIWZzOy555577p0BSUt6U1JeKi3piz3CnjJEI5zQsr4dTqrkjTUprXslhxc09G4dXoT/dDitVe/H4XetJDIOf6iQ2NKxqjqTrxeF6qmvB0XqEAfsCMZXjfiVbwsUW9WsegCK1QTVLRODQg11z9klGus20MSsrkrKswZ25dQg+8zXdGzAt6gwtR16hOw8bBc2i39NTyiNTxtmTRXX8Wim3ya3Mx5mVuMXWb8L4gbdzH16KuJVYAUq60qnutE5aF5ddqpynsaf0lxPvdNkt6ouYUw0yTZRxs7vhfy2zeW0x1nmxjU94mk0dVjzTnfU5bRj9z5egQ7+Nf8JfGinOiTbhu/b1+7wBiGuf7/kaIaKdfN5n8hOZnjfTl+i8y5nADb/nAKZ4i+dtXAXAAAAeNpt0tVyG0EYBWG1Ag4zMzNoZ/7ZtUMO2WFmZnDAQYcrj5hXClhtX2WrVOdG9e1O17TardHn969Wav3v+fn3R6tNmwlMZBKT6WEKU5nGdGYwk1nMZg5zmcd8FrCQRSxmCUtZxnJWsJJVrGYNa1nHejawkU1sZgtb2cZ2drCTXeymQ0UiExRqGnrpYw972cd+DtDPQQ5xmCMcZYBBjnGcE5zkFKc5w1nOcZ4LXOQSl7nCVa5xnRvc5Ba3ucNd7nGfBzzkEY95wlOe8ZwhXvCSV7xmmDe85R3v+cBHRvjEZ77wlW9850fPyPDQQKfT+beD1fhWbnKzG25xa7dxe92+0U16SS/pJb2kl/SSXtJLemnMq/QqvUqv0qv0Kr1Kr9Kr9Cq9pJf0kl7SS10ve47sObLnyJ4jd8b+V9zabdzue0MndEIndEIndEIndGLc6X5/2CPsEfYIe4Q9wh5hj7BH2CPsEfYIe4Q9wh5hj0h6SS/pJb2kl/WyXtbLelkv62W9rJf1sl7ohV7ohV7ohV7ohV7ohV7RK3pFr+gVvaJX9Ipe0St6tV6tV+vVerVerVfr1Xq1Xq3X6DV6jV7T9Yr3qXifivepdPIfY1AvlQABUnNepwAA) format('woff'), + url('font/genericons-regular-webfont.ttf') format('truetype'), + url('font/genericons-regular-webfont.svg#genericonsregular') format('svg'); + font-weight: normal; + font-style: normal; +} + + +/** + * All Genericons + */ + +.genericon { + display: inline-block; + width: 16px; + height: 16px; + -webkit-font-smoothing: antialiased; + font-size: 16px; + line-height: 1; + font-family: 'Genericons'; + text-decoration: inherit; + font-weight: normal; + font-style: normal; + vertical-align: top; +} + +/** + * IE7 and IE6 hacks + */ + +.genericon { + *overflow: auto; + *zoom: 1; + *display: inline; +} + +/** + * Individual icons + */ + +/* Post formats */ +.genericon-standard:before { content: '\f100'; } +.genericon-aside:before { content: '\f101'; } +.genericon-image:before { content: '\f102'; } +.genericon-gallery:before { content: '\f103'; } +.genericon-video:before { content: '\f104'; } +.genericon-status:before { content: '\f105'; } +.genericon-quote:before { content: '\f106'; } +.genericon-link:before { content: '\f107'; } +.genericon-chat:before { content: '\f108'; } +.genericon-audio:before { content: '\f109'; } + +/* Social icons */ +.genericon-github:before { content: '\f200'; } +.genericon-dribbble:before { content: '\f201'; } +.genericon-twitter:before { content: '\f202'; } +.genericon-facebook:before { content: '\f203'; } +.genericon-facebook-alt:before { content: '\f204'; } +.genericon-wordpress:before { content: '\f205'; } +.genericon-googleplus:before { content: '\f206'; } +.genericon-linkedin:before { content: '\f207'; } +.genericon-linkedin-alt:before { content: '\f208'; } +.genericon-pinterest:before { content: '\f209'; } +.genericon-pinterest-alt:before { content: '\f210'; } +.genericon-flickr:before { content: '\f211'; } +.genericon-vimeo:before { content: '\f212'; } +.genericon-youtube:before { content: '\f213'; } +.genericon-tumblr:before { content: '\f214'; } +.genericon-instagram:before { content: '\f215'; } +.genericon-codepen:before { content: '\f216'; } +.genericon-polldaddy:before { content: '\f217'; } +.genericon-googleplus-alt:before { content: '\f218'; } +.genericon-path:before { content: '\f219'; } +.genericon-skype:before { content: '\f220'; } +.genericon-digg:before { content: '\f221'; } +.genericon-reddit:before { content: '\f222'; } +.genericon-stumbleupon:before { content: '\f223'; } +.genericon-pocket:before { content: '\f224'; } + +/* Meta icons */ +.genericon-comment:before { content: '\f300'; } +.genericon-category:before { content: '\f301'; } +.genericon-tag:before { content: '\f302'; } +.genericon-time:before { content: '\f303'; } +.genericon-user:before { content: '\f304'; } +.genericon-day:before { content: '\f305'; } +.genericon-week:before { content: '\f306'; } +.genericon-month:before { content: '\f307'; } +.genericon-pinned:before { content: '\f308'; } + +/* Other icons */ +.genericon-search:before { content: '\f400'; } +.genericon-unzoom:before { content: '\f401'; } +.genericon-zoom:before { content: '\f402'; } +.genericon-show:before { content: '\f403'; } +.genericon-hide:before { content: '\f404'; } +.genericon-close:before { content: '\f405'; } +.genericon-close-alt:before { content: '\f406'; } +.genericon-trash:before { content: '\f407'; } +.genericon-star:before { content: '\f408'; } +.genericon-home:before { content: '\f409'; } +.genericon-mail:before { content: '\f410'; } +.genericon-edit:before { content: '\f411'; } +.genericon-reply:before { content: '\f412'; } +.genericon-feed:before { content: '\f413'; } +.genericon-warning:before { content: '\f414'; } +.genericon-share:before { content: '\f415'; } +.genericon-attachment:before { content: '\f416'; } +.genericon-location:before { content: '\f417'; } +.genericon-checkmark:before { content: '\f418'; } +.genericon-menu:before { content: '\f419'; } +.genericon-refresh:before { content: '\f420'; } +.genericon-minimize:before { content: '\f421'; } +.genericon-maximize:before { content: '\f422'; } +.genericon-404:before { content: '\f423'; } +.genericon-spam:before { content: '\f424'; } +.genericon-summary:before { content: '\f425'; } +.genericon-cloud:before { content: '\f426'; } +.genericon-key:before { content: '\f427'; } +.genericon-dot:before { content: '\f428'; } +.genericon-next:before { content: '\f429'; } +.genericon-previous:before { content: '\f430'; } +.genericon-expand:before { content: '\f431'; } +.genericon-collapse:before { content: '\f432'; } +.genericon-dropdown:before { content: '\f433'; } +.genericon-dropdown-left:before { content: '\f434'; } +.genericon-top:before { content: '\f435'; } +.genericon-draggable:before { content: '\f436'; } +.genericon-phone:before { content: '\f437'; } +.genericon-send-to-phone:before { content: '\f438'; } +.genericon-plugin:before { content: '\f439'; } +.genericon-cloud-download:before { content: '\f440'; } +.genericon-cloud-upload:before { content: '\f441'; } +.genericon-external:before { content: '\f442'; } +.genericon-document:before { content: '\f443'; } +.genericon-book:before { content: '\f444'; } +.genericon-cog:before { content: '\f445'; } +.genericon-unapprove:before { content: '\f446'; } +.genericon-cart:before { content: '\f447'; } +.genericon-pause:before { content: '\f448'; } +.genericon-stop:before { content: '\f449'; } +.genericon-skip-back:before { content: '\f450'; } +.genericon-skip-ahead:before { content: '\f451'; } +.genericon-play:before { content: '\f452'; } +.genericon-tablet:before { content: '\f453'; } +.genericon-send-to-tablet:before { content: '\f454'; } +.genericon-info:before { content: '\f455'; } +.genericon-notice:before { content: '\f456'; } +.genericon-help:before { content: '\f457'; } +.genericon-fastforward:before { content: '\f458'; } +.genericon-rewind:before { content: '\f459'; } +.genericon-portfolio:before { content: '\f460'; } +.genericon-heart:before { content: '\f461'; } +.genericon-code:before { content: '\f462'; } +.genericon-subscribe:before { content: '\f463'; } +.genericon-unsubscribe:before { content: '\f464'; } +.genericon-subscribed:before { content: '\f465'; } +.genericon-reply-alt:before { content: '\f466'; } +.genericon-reply-single:before { content: '\f467'; } +.genericon-flag:before { content: '\f468'; } +.genericon-print:before { content: '\f469'; } +.genericon-lock:before { content: '\f470'; } +.genericon-bold:before { content: '\f471'; } +.genericon-italic:before { content: '\f472'; } +.genericon-picture:before { content: '\f473'; } + +/* Generic shapes */ +.genericon-uparrow:before { content: '\f500'; } +.genericon-rightarrow:before { content: '\f501'; } +.genericon-downarrow:before { content: '\f502'; } +.genericon-leftarrow:before { content: '\f503'; } + + + + + diff --git a/scratch-parent/header.php b/scratch-parent/header.php new file mode 100644 index 00000000..f5615646 --- /dev/null +++ b/scratch-parent/header.php @@ -0,0 +1,73 @@ + section and everything up till
            + */ +?> + + + +> + + + + + <?php wp_title( '|', true, 'right' ); ?> + + + + + + + + + + + +> +
            + + + + + +
            diff --git a/scratch-parent/image.php b/scratch-parent/image.php new file mode 100644 index 00000000..567d9d30 --- /dev/null +++ b/scratch-parent/image.php @@ -0,0 +1,75 @@ + + +
            +
            + + +
            > +
            + ', '' ); ?> + + +
            + +
            +
            +
            + +
            + + +
            + +
            + +
            + + '', + 'link_before' => '', + 'link_after' => '', + ) ); + ?> +
            +
            + +
            ' ); ?> +
            + + + + + + +
            + + + + + + + + + + + + + + + + + diff --git a/scratch-parent/images/pattern-light.svg b/scratch-parent/images/pattern-light.svg new file mode 100644 index 00000000..55a48f1b --- /dev/null +++ b/scratch-parent/images/pattern-light.svg @@ -0,0 +1,6 @@ + + + diff --git a/scratch-parent/images/patterns/diagonal_bottom_to_top_pattern.png b/scratch-parent/images/patterns/diagonal_bottom_to_top_pattern.png new file mode 100644 index 00000000..08273451 Binary files /dev/null and b/scratch-parent/images/patterns/diagonal_bottom_to_top_pattern.png differ diff --git a/scratch-parent/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg b/scratch-parent/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg new file mode 100644 index 00000000..245781fd Binary files /dev/null and b/scratch-parent/images/patterns/diagonal_bottom_to_top_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/diagonal_top_to_bottom_pattern.png b/scratch-parent/images/patterns/diagonal_top_to_bottom_pattern.png new file mode 100644 index 00000000..2fcc54d6 Binary files /dev/null and b/scratch-parent/images/patterns/diagonal_top_to_bottom_pattern.png differ diff --git a/scratch-parent/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg b/scratch-parent/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg new file mode 100644 index 00000000..df001483 Binary files /dev/null and b/scratch-parent/images/patterns/diagonal_top_to_bottom_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/dots_pattern.png b/scratch-parent/images/patterns/dots_pattern.png new file mode 100644 index 00000000..d64b3190 Binary files /dev/null and b/scratch-parent/images/patterns/dots_pattern.png differ diff --git a/scratch-parent/images/patterns/dots_pattern_preview.jpg b/scratch-parent/images/patterns/dots_pattern_preview.jpg new file mode 100644 index 00000000..9fe354e2 Binary files /dev/null and b/scratch-parent/images/patterns/dots_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/no_pattern.jpg b/scratch-parent/images/patterns/no_pattern.jpg new file mode 100644 index 00000000..393a4d3d Binary files /dev/null and b/scratch-parent/images/patterns/no_pattern.jpg differ diff --git a/scratch-parent/images/patterns/noise_pattern.png b/scratch-parent/images/patterns/noise_pattern.png new file mode 100644 index 00000000..312ee416 Binary files /dev/null and b/scratch-parent/images/patterns/noise_pattern.png differ diff --git a/scratch-parent/images/patterns/noise_pattern_preview.jpg b/scratch-parent/images/patterns/noise_pattern_preview.jpg new file mode 100644 index 00000000..5190e96b Binary files /dev/null and b/scratch-parent/images/patterns/noise_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/romb_pattern.png b/scratch-parent/images/patterns/romb_pattern.png new file mode 100644 index 00000000..c447c3f2 Binary files /dev/null and b/scratch-parent/images/patterns/romb_pattern.png differ diff --git a/scratch-parent/images/patterns/romb_pattern_preview.jpg b/scratch-parent/images/patterns/romb_pattern_preview.jpg new file mode 100644 index 00000000..4e621998 Binary files /dev/null and b/scratch-parent/images/patterns/romb_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/square_pattern.png b/scratch-parent/images/patterns/square_pattern.png new file mode 100644 index 00000000..3bff4f3c Binary files /dev/null and b/scratch-parent/images/patterns/square_pattern.png differ diff --git a/scratch-parent/images/patterns/square_pattern_preview.jpg b/scratch-parent/images/patterns/square_pattern_preview.jpg new file mode 100644 index 00000000..a0237b1c Binary files /dev/null and b/scratch-parent/images/patterns/square_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/vertical_lines_pattern.png b/scratch-parent/images/patterns/vertical_lines_pattern.png new file mode 100644 index 00000000..b14996e7 Binary files /dev/null and b/scratch-parent/images/patterns/vertical_lines_pattern.png differ diff --git a/scratch-parent/images/patterns/vertical_lines_pattern_preview.jpg b/scratch-parent/images/patterns/vertical_lines_pattern_preview.jpg new file mode 100644 index 00000000..8e9eab86 Binary files /dev/null and b/scratch-parent/images/patterns/vertical_lines_pattern_preview.jpg differ diff --git a/scratch-parent/images/patterns/waves_pattern.png b/scratch-parent/images/patterns/waves_pattern.png new file mode 100644 index 00000000..e64b1e80 Binary files /dev/null and b/scratch-parent/images/patterns/waves_pattern.png differ diff --git a/scratch-parent/images/patterns/waves_pattern_preview.jpg b/scratch-parent/images/patterns/waves_pattern_preview.jpg new file mode 100644 index 00000000..36a50822 Binary files /dev/null and b/scratch-parent/images/patterns/waves_pattern_preview.jpg differ diff --git a/scratch-parent/images/plus-accordion.png b/scratch-parent/images/plus-accordion.png new file mode 100644 index 00000000..3fc0527a Binary files /dev/null and b/scratch-parent/images/plus-accordion.png differ diff --git a/scratch-parent/index.php b/scratch-parent/index.php new file mode 100644 index 00000000..8c502378 --- /dev/null +++ b/scratch-parent/index.php @@ -0,0 +1,58 @@ + + + + +
            + + + +
            +
            + + +
            +
            + +
            + +
            '); + + $error.text(error); + + var $input = $form.find('[name="'+ name +'"]'); + + if ($input.length) { + $error.insertAfter($input); + + $input.one('focus', function(){ + $(this).next().slideUp(function(){ $(this).remove() }); + }); + } else { + $form.prepend($error); + } + }); + }); +})(_localized_form_errors); diff --git a/scratch-parent/js/functions.js b/scratch-parent/js/functions.js new file mode 100644 index 00000000..5a5d7d48 --- /dev/null +++ b/scratch-parent/js/functions.js @@ -0,0 +1,165 @@ +/** + * Theme functions file + * + * Contains handlers for navigation, accessibility, header sizing + * footer widgets and Featured Content slider + * + */ +( function( $ ) { + var body = $( 'body' ), + _window = $( window ); + + // Enable menu toggle for small screens. + ( function() { + var nav = $( '#primary-navigation' ), button, menu; + if ( ! nav ) { + return; + } + + button = nav.find( '.menu-toggle' ); + if ( ! button ) { + return; + } + + // Hide button if menu is missing or empty. + menu = nav.find( '.nav-menu' ); + if ( ! menu || ! menu.children().length ) { + button.hide(); + return; + } + + $( '.menu-toggle' ).on( 'click.fw_theme', function() { + nav.toggleClass( 'toggled-on' ); + } ); + } )(); + + /* + * Makes "skip to content" link work correctly in IE9 and Chrome for better + * accessibility. + * + * @link http://www.nczonline.net/blog/2013/01/15/fixing-skip-to-content-links/ + */ + _window.on( 'hashchange.fw_theme', function() { + var element = document.getElementById( location.hash.substring( 1 ) ); + + if ( element ) { + if ( ! /^(?:a|select|input|button|textarea)$/i.test( element.tagName ) ) { + element.tabIndex = -1; + } + + element.focus(); + + // Repositions the window on jump-to-anchor to account for header height. + window.scrollBy( 0, -80 ); + } + } ); + + $( function() { + // Search toggle. + $( '.search-toggle' ).on( 'click.fw_theme', function( event ) { + var that = $( this ), + wrapper = $( '.search-box-wrapper' ); + + that.toggleClass( 'active' ); + wrapper.toggleClass( 'hide' ); + + if ( that.is( '.active' ) || $( '.search-toggle .screen-reader-text' )[0] === event.target ) { + wrapper.find( '.search-field' ).focus(); + } + } ); + + /* + * Fixed header for large screen. + * If the header becomes more than 48px tall, unfix the header. + * + * The callback on the scroll event is only added if there is a header + * image and we are not on mobile. + */ + if ( _window.width() > 781 ) { + var mastheadHeight = $( '#masthead' ).height(), + toolbarOffset, mastheadOffset; + + if ( mastheadHeight > 48 ) { + body.removeClass( 'masthead-fixed' ); + } + + if ( body.is( '.header-image' ) ) { + toolbarOffset = body.is( '.admin-bar' ) ? $( '#wpadminbar' ).height() : 0; + mastheadOffset = $( '#masthead' ).offset().top - toolbarOffset; + + _window.on( 'scroll.fw_theme', function() { + if ( ( window.scrollY > mastheadOffset ) && ( mastheadHeight < 49 ) ) { + body.addClass( 'masthead-fixed' ); + } else { + body.removeClass( 'masthead-fixed' ); + } + } ); + } + } + + // Focus styles for menus. + $( '.primary-navigation, .secondary-navigation' ).find( 'a' ).on( 'focus.fw_theme blur.fw_theme', function() { + $( this ).parents().toggleClass( 'focus' ); + } ); + } ); + + _window.load( function() { + // Arrange footer widgets vertically. + if ( $.isFunction( $.fn.masonry ) ) { + $( '#footer-sidebar' ).masonry( { + itemSelector: '.widget', + columnWidth: function( containerWidth ) { + return containerWidth / 4; + }, + gutterWidth: 0, + isResizable: true, + isRTL: $( 'body' ).is( '.rtl' ) + } ); + } + + // Initialize Featured Content slider. + if ( body.is( '.slider' ) ) { + $( '.featured-content' ).featuredslider( { + selector: '.featured-content-inner > article', + controlsContainer: '.featured-content' + } ); + } + } ); +} )( jQuery ); + +/** + * Mega Menu + */ +jQuery(function ($) { + + function hoverIn() { + var a = $(this); + var nav = a.closest('.nav-menu'); + var mega = a.find('.mega-menu'); + var offset = rightSide(nav) - leftSide(a); + mega.width(Math.min(rightSide(nav), columns(mega)*325)); + mega.css('left', Math.min(0, offset - mega.width())); + } + + function hoverOut() { + } + + function columns(mega) { + var columns = 0; + mega.children('.mega-menu-row').each(function () { + columns = Math.max(columns, $(this).children('.mega-menu-col').length); + }); + return columns; + } + + function leftSide(elem) { + return elem.offset().left; + } + + function rightSide(elem) { + return elem.offset().left + elem.width(); + } + + $('.primary-navigation .menu-item-has-mega-menu').hover(hoverIn, hoverOut); + +}); diff --git a/scratch-parent/js/html5.js b/scratch-parent/js/html5.js new file mode 100644 index 00000000..6168aacd --- /dev/null +++ b/scratch-parent/js/html5.js @@ -0,0 +1,8 @@ +/* + HTML5 Shiv v3.7.0 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); +a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/[\w\-]+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; +c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| +"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:"3.7.0",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f); +if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d
            + value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + }, + + uniqueId: function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + (++uuid); + } + }); + }, + + removeUniqueId: function() { + return this.each(function() { + if ( runiqueId.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + }); + } +}); + +// selectors +function focusable( element, isTabIndexNotNaN ) { + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap=#" + mapName + "]" )[0]; + return !!img && visible( img ); + } + return ( /input|select|textarea|button|object/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible( element ); +} + +function visible( element ) { + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; +} + +$.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + isTabIndexNaN = isNaN( tabIndex ); + return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); + } +}); + +// support: jQuery <1.8 +if ( !$( "" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; + }); +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} + + + + + +// deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.support.selectstart = "onselectstart" in document.createElement( "div" ); +$.fn.extend({ + disableSelection: function() { + return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }, + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + } +}); + +$.extend( $.ui, { + // $.ui.plugin is deprecated. Use $.widget() extensions instead. + plugin: { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args ) { + var i, + set = instance.plugins[ name ]; + if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } + }, + + // only used by resizable + hasScroll: function( el, a ) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ( $( el ).css( "overflow" ) === "hidden") { + return false; + } + + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", + has = false; + + if ( el[ scroll ] > 0 ) { + return true; + } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[ scroll ] = 1; + has = ( el[ scroll ] > 0 ); + el[ scroll ] = 0; + return has; + } +}); + +})( jQuery ); +(function( $, undefined ) { + +var uuid = 0, + slice = Array.prototype.slice, + _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 ); +}; + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); +}; + +$.widget.extend = function( target ) { + var input = slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.widget.extend.apply( null, [ options ].concat(args) ) : + options; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} )._init(); + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
            ", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +})( jQuery ); +(function( $, undefined ) { + +var mouseHandled = false; +$( document ).mouseup( function() { + mouseHandled = false; +}); + +$.widget("ui.mouse", { + version: "1.10.4", + options: { + cancel: "input,textarea,button,select,option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .bind("mousedown."+this.widgetName, function(event) { + return that._mouseDown(event); + }) + .bind("click."+this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); + event.stopImmediatePropagation(); + return false; + } + }); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind("."+this.widgetName); + if ( this._mouseMoveDelegate ) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + } + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + if( mouseHandled ) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = (event.which === 1), + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + that.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return that._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return that._mouseUp(event); + }; + $(document) + .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .bind("mouseup."+this.widgetName, this._mouseUpDelegate); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); + } + + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(/* event */) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } +}); + +})(jQuery); +(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+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( 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 = $( "
            " ), + 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.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + 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: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; + return { + element: withinElement, + isWindow: isWindow, + isDocument: isDocument, + 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 ) ); +(function( $, undefined ) { + +$.widget("ui.draggable", $.ui.mouse, { + version: "1.10.4", + widgetEventPrefix: "drag", + options: { + addClasses: true, + appendTo: "parent", + axis: false, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null + }, + _create: function() { + + if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { + this.element[0].style.position = "relative"; + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } + + this._mouseInit(); + + }, + + _destroy: function() { + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + + var o = this.options; + + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { + return false; + } + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) { + return false; + } + + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $("
            ") + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + + return true; + + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + this.helper.addClass("ui-draggable-dragging"); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css( "position" ); + this.scrollParent = this.helper.scrollParent(); + this.offsetParent = this.helper.offsetParent(); + this.offsetParentCssPosition = this.offsetParent.css( "position" ); + + //The element's absolute position on the page minus margins + this.offset = this.positionAbs = this.element.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + //Reset scroll cache + this.offset.scroll = false; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this.position = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Set a containment if given in the options + this._setContainment(); + + //Trigger event + callbacks + if(this._trigger("start", event) === false) { + this._clear(); + return false; + } + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } + + return true; + }, + + _mouseDrag: function(event, noPropagation) { + // reset any necessary cached properties (see #5009) + if ( this.offsetParentCssPosition === "fixed" ) { + this.offset.parent = this._getParentOffset(); + } + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + if(this._trigger("drag", event, ui) === false) { + this._mouseUp({}); + return false; + } + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var that = this, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { + dropped = $.ui.ddmanager.drop(this, event); + } + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + //if the original element is no longer in the DOM don't bother to continue (see #8269) + if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) { + return false; + } + + if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + if(that._trigger("stop", event) !== false) { + that._clear(); + } + }); + } else { + if(this._trigger("stop", event) !== false) { + this._clear(); + } + } + + return false; + }, + + _mouseUp: function(event) { + //Remove frame helpers + $("div.ui-draggable-iframeFix").each(function() { + this.parentNode.removeChild(this); + }); + + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) + if( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } + + return $.ui.mouse.prototype._mouseUp.call(this, event); + }, + + cancel: function() { + + if(this.helper.is(".ui-draggable-dragging")) { + this._mouseUp({}); + } else { + this._clear(); + } + + return this; + + }, + + _getHandle: function(event) { + return this.options.handle ? + !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : + true; + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); + + if(!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } + + if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { + helper.css("position", "absolute"); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + //This needs to be actually done for all browsers, since pageX/pageY includes this information + //Ugly IE fix + if((this.offsetParent[0] === document.body) || + (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0), + right: (parseInt(this.element.css("marginRight"),10) || 0), + bottom: (parseInt(this.element.css("marginBottom"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var over, c, ce, + o = this.options; + + if ( !o.containment ) { + this.containment = null; + return; + } + + if ( o.containment === "window" ) { + this.containment = [ + $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, + $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, + $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top + ]; + return; + } + + if ( o.containment === "document") { + this.containment = [ + 0, + 0, + $( document ).width() - this.helperProportions.width - this.margins.left, + ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top + ]; + return; + } + + if ( o.containment.constructor === Array ) { + this.containment = o.containment; + return; + } + + if ( o.containment === "parent" ) { + o.containment = this.helper[ 0 ].parentNode; + } + + c = $( o.containment ); + ce = c[ 0 ]; + + if( !ce ) { + return; + } + + over = c.css( "overflow" ) !== "hidden"; + + this.containment = [ + ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), + ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) , + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right, + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom + ]; + this.relative_container = c; + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent; + + //Cache the scroll + if (!this.offset.scroll) { + this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; + } + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod ) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod ) + ) + }; + + }, + + _generatePosition: function(event) { + + var containment, co, top, left, + o = this.options, + scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent, + pageX = event.pageX, + pageY = event.pageY; + + //Cache the scroll + if (!this.offset.scroll) { + this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + // If we are not dragging yet, we won't check for options + if ( this.originalPosition ) { + if ( this.containment ) { + if ( this.relative_container ){ + co = this.relative_container.offset(); + containment = [ + this.containment[ 0 ] + co.left, + this.containment[ 1 ] + co.top, + this.containment[ 2 ] + co.left, + this.containment[ 3 ] + co.top + ]; + } + else { + containment = this.containment; + } + + if(event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + //The absolute position has to be recalculated after plugins + if(type === "drag") { + this.positionAbs = this._convertPositionTo("absolute"); + } + return $.Widget.prototype._trigger.call(this, type, event, ui); + }, + + plugins: {}, + + _uiHash: function() { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs + }; + } + +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { + + var inst = $(this).data("ui-draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, "ui-sortable"); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). + sortable._trigger("activate", event, uiSortable); + } + }); + + }, + stop: function(event, ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("ui-draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + + this.instance.isOver = 0; + + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" + if(this.shouldRevert) { + this.instance.options.revert = this.shouldRevert; + } + + //Trigger the stop of the sortable + this.instance._mouseStop(event); + + this.instance.options.helper = this.instance.options._helper; + + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper === "original") { + this.instance.currentItem.css({ top: "auto", left: "auto" }); + } + + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } + + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("ui-draggable"), that = this; + + $.each(inst.sortables, function() { + + var innermostIntersecting = false, + thisSortable = this; + + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + + if(this.instance._intersectsWith(this.instance.containerCache)) { + innermostIntersecting = true; + $.each(inst.sortables, function () { + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + if (this !== thisSortable && + this.instance._intersectsWith(this.instance.containerCache) && + $.contains(thisSortable.instance.element[0], this.instance.element[0]) + ) { + innermostIntersecting = false; + } + return innermostIntersecting; + }); + } + + + if(innermostIntersecting) { + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) { + this.instance._mouseDrag(event); + } + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + + //Prevent reverting on this forced stop + this.instance.options.revert = false; + + // The out event needs to be triggered independently + this.instance._trigger("out", event, this.instance._uiHash(this.instance)); + + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) { + this.instance.placeholder.remove(); + } + + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } + + } + + }); + + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function() { + var t = $("body"), o = $(this).data("ui-draggable").options; + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } + t.css("cursor", o.cursor); + }, + stop: function() { + var o = $(this).data("ui-draggable").options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function() { + var i = $(this).data("ui-draggable"); + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + i.overflowOffset = i.scrollParent.offset(); + } + }, + drag: function( event ) { + + var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; + + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + + if(!o.axis || o.axis !== "x") { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } + } + + if(!o.axis || o.axis !== "y") { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } + } + + } else { + + if(!o.axis || o.axis !== "x") { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + } + + if(!o.axis || o.axis !== "y") { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(i, event); + } + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function() { + + var i = $(this).data("ui-draggable"), + o = i.options; + + i.snapElements = []; + + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if(this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } + }); + + }, + drag: function(event, ui) { + + var ts, bs, ls, rs, l, r, t, b, i, first, + inst = $(this).data("ui-draggable"), + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (i = inst.snapElements.length - 1; i >= 0; i--){ + + l = inst.snapElements[i].left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top; + b = t + inst.snapElements[i].height; + + if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { + if(inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + } + + first = (ts || bs || ls || rs); + + if(o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + } + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function() { + var min, + o = this.data("ui-draggable").options, + group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); + + if (!group.length) { return; } + + min = parseInt($(group[0]).css("zIndex"), 10) || 0; + $(group).each(function(i) { + $(this).css("zIndex", min + i); + }); + this.css("zIndex", (min + group.length)); + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } + } +}); + +})(jQuery); +(function( $, undefined ) { + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +$.widget("ui.droppable", { + version: "1.10.4", + widgetEventPrefix: "drop", + options: { + accept: "*", + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null + }, + _create: function() { + + var proportions, + o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; + + this.accept = $.isFunction(accept) ? accept : function(d) { + return d.is(accept); + }; + + this.proportions = function( /* valueToWrite */ ) { + if ( arguments.length ) { + // Store the droppable's proportions + proportions = arguments[ 0 ]; + } else { + // Retrieve or derive the droppable's proportions + return proportions ? + proportions : + proportions = { + width: this.element[ 0 ].offsetWidth, + height: this.element[ 0 ].offsetHeight + }; + } + }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; + $.ui.ddmanager.droppables[o.scope].push(this); + + (o.addClasses && this.element.addClass("ui-droppable")); + + }, + + _destroy: function() { + var i = 0, + drop = $.ui.ddmanager.droppables[this.options.scope]; + + for ( ; i < drop.length; i++ ) { + if ( drop[i] === this ) { + drop.splice(i, 1); + } + } + + this.element.removeClass("ui-droppable ui-droppable-disabled"); + }, + + _setOption: function(key, value) { + + if(key === "accept") { + this.accept = $.isFunction(value) ? value : function(d) { + return d.is(value); + }; + } + $.Widget.prototype._setOption.apply(this, arguments); + }, + + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.addClass(this.options.activeClass); + } + if(draggable){ + this._trigger("activate", event, this.ui(draggable)); + } + }, + + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(draggable){ + this._trigger("deactivate", event, this.ui(draggable)); + } + }, + + _over: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.addClass(this.options.hoverClass); + } + this._trigger("over", event, this.ui(draggable)); + } + + }, + + _out: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("out", event, this.ui(draggable)); + } + + }, + + _drop: function(event,custom) { + + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return false; + } + + this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, "ui-droppable"); + if( + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && + $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + ) { childrenIntersection = true; return false; } + }); + if(childrenIntersection) { + return false; + } + + if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("drop", event, this.ui(draggable)); + return this.element; + } + + return false; + + }, + + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + } + +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) { + return false; + } + + var draggableLeft, draggableTop, + x1 = (draggable.positionAbs || draggable.position.absolute).left, + y1 = (draggable.positionAbs || draggable.position.absolute).top, + x2 = x1 + draggable.helperProportions.width, + y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, + t = droppable.offset.top, + r = l + droppable.proportions().width, + b = t + droppable.proportions().height; + + switch (toleranceMode) { + case "fit": + return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); + case "intersect": + return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half + x2 - (draggable.helperProportions.width / 2) < r && // Left Half + t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half + y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + case "pointer": + draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); + return isOverAxis( draggableTop, t, droppable.proportions().height ) && isOverAxis( draggableLeft, l, droppable.proportions().width ); + case "touch": + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + default: + return false; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { "default": [] }, + prepareOffsets: function(t, event) { + + var i, j, + m = $.ui.ddmanager.droppables[t.options.scope] || [], + type = event ? event.type : null, // workaround for #2317 + list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); + + droppablesLoop: for (i = 0; i < m.length; i++) { + + //No disabled and non-accepted + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { + continue; + } + + // Filter out elements in the current dragged item + for (j=0; j < list.length; j++) { + if(list[j] === m[i].element[0]) { + m[i].proportions().height = 0; + continue droppablesLoop; + } + } + + m[i].visible = m[i].element.css("display") !== "none"; + if(!m[i].visible) { + continue; + } + + //Activate the droppable if used directly from draggables + if(type === "mousedown") { + m[i]._activate.call(m[i], event); + } + + m[ i ].offset = m[ i ].element.offset(); + m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight }); + + } + + }, + drop: function(draggable, event) { + + var dropped = false; + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { + + if(!this.options) { + return; + } + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { + dropped = this._drop.call(this, event) || dropped; + } + + if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = true; + this.isover = false; + this._deactivate.call(this, event); + } + + }); + return dropped; + + }, + dragStart: function( draggable, event ) { + //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + }); + }, + drag: function(draggable, event) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) { + $.ui.ddmanager.prepareOffsets(draggable, event); + } + + //Run through all droppables and check their positions based on specific tolerance options + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) { + return; + } + + var parentInstance, scope, parent, + intersects = $.ui.intersect(draggable, this, this.options.tolerance), + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + if(!c) { + return; + } + + if (this.options.greedy) { + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents(":data(ui-droppable)").filter(function () { + return $.data(this, "ui-droppable").options.scope === scope; + }); + + if (parent.length) { + parentInstance = $.data(parent[0], "ui-droppable"); + parentInstance.greedyChild = (c === "isover"); + } + } + + // we just moved into a greedy child + if (parentInstance && c === "isover") { + parentInstance.isover = false; + parentInstance.isout = true; + parentInstance._out.call(parentInstance, event); + } + + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call(this, event); + + // we just moved out of a greedy child + if (parentInstance && c === "isout") { + parentInstance.isout = false; + parentInstance.isover = true; + parentInstance._over.call(parentInstance, event); + } + }); + + }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); + //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } +}; + +})(jQuery); +(function( $, undefined ) { + +function num(v) { + return parseInt(v, 10) || 0; +} + +function isNumber(value) { + return !isNaN(parseInt(value, 10)); +} + +$.widget("ui.resizable", $.ui.mouse, { + version: "1.10.4", + widgetEventPrefix: "resize", + options: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + containment: false, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + // See #7960 + zIndex: 90, + + // callbacks + resize: null, + start: null, + stop: null + }, + _create: function() { + + var n, i, handle, axis, hname, + that = this, + o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null + }); + + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { + + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $("
            ").css({ + position: this.element.css("position"), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css("top"), + left: this.element.css("left") + }) + ); + + //Overwrite the original this.element + this.element = this.element.parent().data( + "ui-resizable", this.element.data("ui-resizable") + ); + + this.elementIsWrapper = true; + + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css("resize"); + this.originalElement.css("resize", "none"); + + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); + + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css("margin") }); + + // fix handlers offset + this._proportionallyResize(); + + } + + this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); + if(this.handles.constructor === String) { + + if ( this.handles === "all") { + this.handles = "n,e,s,w,se,sw,ne,nw"; + } + + n = this.handles.split(","); + this.handles = {}; + + for(i = 0; i < n.length; i++) { + + handle = $.trim(n[i]); + hname = "ui-resizable-"+handle; + axis = $("
            "); + + // Apply zIndex to all handles - see #7960 + axis.css({ zIndex: o.zIndex }); + + //TODO : What's going on here? + if ("se" === handle) { + axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); + } + + //Insert into internal handles object and append to element + this.handles[handle] = ".ui-resizable-"+handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + var i, axis, padPos, padWrapper; + + target = target || this.element; + + for(i in this.handles) { + + if(this.handles[i].constructor === String) { + this.handles[i] = $(this.handles[i], this.element).show(); + } + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + axis = $(this.handles[i], this.element); + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + padPos = [ "padding", + /ne|nw|n/.test(i) ? "Top" : + /se|sw|s/.test(i) ? "Bottom" : + /^e$/.test(i) ? "Right" : "Left" ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + + } + + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) { + continue; + } + } + }; + + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = $(".ui-resizable-handle", this.element) + .disableSelection(); + + //Matching axis name + this._handles.mouseover(function() { + if (!that.resizing) { + if (this.className) { + axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + } + //Axis, default = se + that.axis = axis && axis[1] ? axis[1] : "se"; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .mouseenter(function() { + if (o.disabled) { + return; + } + $(this).removeClass("ui-resizable-autohide"); + that._handles.show(); + }) + .mouseleave(function(){ + if (o.disabled) { + return; + } + if (!that.resizing) { + $(this).addClass("ui-resizable-autohide"); + that._handles.hide(); + } + }); + } + + //Initialize the mouse interaction + this._mouseInit(); + + }, + + _destroy: function() { + + this._mouseDestroy(); + + var wrapper, + _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + wrapper = this.element; + this.originalElement.css({ + position: wrapper.css("position"), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css("top"), + left: wrapper.css("left") + }).insertAfter( wrapper ); + wrapper.remove(); + } + + this.originalElement.css("resize", this.originalResizeStyle); + _destroy(this.originalElement); + + return this; + }, + + _mouseCapture: function(event) { + var i, handle, + capture = false; + + for (i in this.handles) { + handle = $(this.handles[i])[0]; + if (handle === event.target || $.contains(handle, event.target)) { + capture = true; + } + } + + return !this.options.disabled && capture; + }, + + _mouseStart: function(event) { + + var curleft, curtop, cursor, + o = this.options, + iniPos = this.element.position(), + el = this.element; + + this.resizing = true; + + // bugfix for http://dev.jquery.com/ticket/1749 + if ( (/absolute/).test( el.css("position") ) ) { + el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); + } else if (el.is(".ui-draggable")) { + el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); + } + + this._renderProxy(); + + curleft = num(this.helper.css("left")); + curtop = num(this.helper.css("top")); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + + cursor = $(".ui-resizable-" + this.axis).css("cursor"); + $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var data, + el = this.helper, props = {}, + smp = this.originalMousePosition, + a = this.axis, + prevTop = this.position.top, + prevLeft = this.position.left, + prevWidth = this.size.width, + prevHeight = this.size.height, + dx = (event.pageX-smp.left)||0, + dy = (event.pageY-smp.top)||0, + trigger = this._change[a]; + + if (!trigger) { + return false; + } + + // Calculate the attrs that will be change + data = trigger.apply(this, [event, dx, dy]); + + // Put this in the mouseDrag handler since the user can start pressing shift while resizing + this._updateVirtualBoundaries(event.shiftKey); + if (this._aspectRatio || event.shiftKey) { + data = this._updateRatio(data, event); + } + + data = this._respectSize(data, event); + + this._updateCache(data); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + if (this.position.top !== prevTop) { + props.top = this.position.top + "px"; + } + if (this.position.left !== prevLeft) { + props.left = this.position.left + "px"; + } + if (this.size.width !== prevWidth) { + props.width = this.size.width + "px"; + } + if (this.size.height !== prevHeight) { + props.height = this.size.height + "px"; + } + el.css(props); + + if (!this._helper && this._proportionallyResizeElements.length) { + this._proportionallyResize(); + } + + // Call the user callback if the element was resized + if ( ! $.isEmptyObject(props) ) { + this._trigger("resize", event, this.ui()); + } + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var pr, ista, soffseth, soffsetw, s, left, top, + o = this.options, that = this; + + if(this._helper) { + + pr = this._proportionallyResizeElements; + ista = pr.length && (/textarea/i).test(pr[0].nodeName); + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; + soffsetw = ista ? 0 : that.sizeDiff.width; + + s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) { + this.element.css($.extend(s, { top: top, left: left })); + } + + that.helper.height(that.size.height); + that.helper.width(that.size.width); + + if (this._helper && !o.animate) { + this._proportionallyResize(); + } + } + + $("body").css("cursor", "auto"); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) { + this.helper.remove(); + } + + return false; + + }, + + _updateVirtualBoundaries: function(forceAspectRatio) { + var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, + o = this.options; + + b = { + minWidth: isNumber(o.minWidth) ? o.minWidth : 0, + maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, + minHeight: isNumber(o.minHeight) ? o.minHeight : 0, + maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity + }; + + if(this._aspectRatio || forceAspectRatio) { + // We want to create an enclosing box whose aspect ration is the requested one + // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension + pMinWidth = b.minHeight * this.aspectRatio; + pMinHeight = b.minWidth / this.aspectRatio; + pMaxWidth = b.maxHeight * this.aspectRatio; + pMaxHeight = b.maxWidth / this.aspectRatio; + + if(pMinWidth > b.minWidth) { + b.minWidth = pMinWidth; + } + if(pMinHeight > b.minHeight) { + b.minHeight = pMinHeight; + } + if(pMaxWidth < b.maxWidth) { + b.maxWidth = pMaxWidth; + } + if(pMaxHeight < b.maxHeight) { + b.maxHeight = pMaxHeight; + } + } + this._vBoundaries = b; + }, + + _updateCache: function(data) { + this.offset = this.helper.offset(); + if (isNumber(data.left)) { + this.position.left = data.left; + } + if (isNumber(data.top)) { + this.position.top = data.top; + } + if (isNumber(data.height)) { + this.size.height = data.height; + } + if (isNumber(data.width)) { + this.size.width = data.width; + } + }, + + _updateRatio: function( data ) { + + var cpos = this.position, + csize = this.size, + a = this.axis; + + if (isNumber(data.height)) { + data.width = (data.height * this.aspectRatio); + } else if (isNumber(data.width)) { + data.height = (data.width / this.aspectRatio); + } + + if (a === "sw") { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a === "nw") { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function( data ) { + + var o = this._vBoundaries, + a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), + dw = this.originalPosition.left + this.originalSize.width, + dh = this.position.top + this.size.height, + cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + if (isminw) { + data.width = o.minWidth; + } + if (isminh) { + data.height = o.minHeight; + } + if (ismaxw) { + data.width = o.maxWidth; + } + if (ismaxh) { + data.height = o.maxHeight; + } + + if (isminw && cw) { + data.left = dw - o.minWidth; + } + if (ismaxw && cw) { + data.left = dw - o.maxWidth; + } + if (isminh && ch) { + data.top = dh - o.minHeight; + } + if (ismaxh && ch) { + data.top = dh - o.maxHeight; + } + + // fixing jump error on top/left - bug #2330 + if (!data.width && !data.height && !data.left && data.top) { + data.top = null; + } else if (!data.width && !data.height && !data.top && data.left) { + data.left = null; + } + + return data; + }, + + _proportionallyResize: function() { + + if (!this._proportionallyResizeElements.length) { + return; + } + + var i, j, borders, paddings, prel, + element = this.helper || this.element; + + for ( i=0; i < this._proportionallyResizeElements.length; i++) { + + prel = this._proportionallyResizeElements[i]; + + if (!this.borderDif) { + this.borderDif = []; + borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; + paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; + + for ( j = 0; j < borders.length; j++ ) { + this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); + } + } + + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); + + } + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(this._helper) { + + this.helper = this.helper || $("
            "); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: "absolute", + left: this.elementOffset.left +"px", + top: this.elementOffset.top +"px", + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx) { + var cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n !== "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "animate", { + + stop: function( event ) { + var that = $(this).data("ui-resizable"), + o = that.options, + pr = that._proportionallyResizeElements, + ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width, + style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + that.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(that.element.css("width"), 10), + height: parseInt(that.element.css("height"), 10), + top: parseInt(that.element.css("top"), 10), + left: parseInt(that.element.css("left"), 10) + }; + + if (pr && pr.length) { + $(pr[0]).css({ width: data.width, height: data.height }); + } + + // propagating resize, and updating values for each animation step + that._updateCache(data); + that._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "containment", { + + start: function() { + var element, p, co, ch, cw, width, height, + that = $(this).data("ui-resizable"), + o = that.options, + el = that.element, + oc = o.containment, + ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + + if (!ce) { + return; + } + + that.containerElement = $(ce); + + if (/document/.test(oc) || oc === document) { + that.containerOffset = { left: 0, top: 0 }; + that.containerPosition = { left: 0, top: 0 }; + + that.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + // i'm a node, so compute top, left, right, bottom + else { + element = $(ce); + p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); + + that.containerOffset = element.offset(); + that.containerPosition = element.position(); + that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + co = that.containerOffset; + ch = that.containerSize.height; + cw = that.containerSize.width; + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); + height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + that.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function( event ) { + var woset, hoset, isParent, isOffsetRelative, + that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, + cop = { top:0, left:0 }, ce = that.containerElement; + + if (ce[0] !== document && (/static/).test(ce.css("position"))) { + cop = co; + } + + if (cp.left < (that._helper ? co.left : 0)) { + that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + that.position.left = o.helper ? co.left : 0; + } + + if (cp.top < (that._helper ? co.top : 0)) { + that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + that.position.top = that._helper ? co.top : 0; + } + + that.offset.left = that.parentData.left+that.position.left; + that.offset.top = that.parentData.top+that.position.top; + + woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); + hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); + + isParent = that.containerElement.get(0) === that.element.parent().get(0); + isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); + + if ( isParent && isOffsetRelative ) { + woset -= Math.abs( that.parentData.left ); + } + + if (woset + that.size.width >= that.parentData.width) { + that.size.width = that.parentData.width - woset; + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + } + + if (hoset + that.size.height >= that.parentData.height) { + that.size.height = that.parentData.height - hoset; + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + } + }, + + stop: function(){ + var that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, + cop = that.containerPosition, + ce = that.containerElement, + helper = $(that.helper), + ho = helper.offset(), + w = helper.outerWidth() - that.sizeDiff.width, + h = helper.outerHeight() - that.sizeDiff.height; + + if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + } +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function () { + var that = $(this).data("ui-resizable"), + o = that.options, + _store = function (exp) { + $(exp).each(function() { + var el = $(this); + el.data("ui-resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) + }); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function (exp) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function (event, ui) { + var that = $(this).data("ui-resizable"), + o = that.options, + os = that.originalSize, + op = that.originalPosition, + delta = { + height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 + }, + + _alsoResize = function (exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, + css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; + + $.each(css, function (i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) { + style[prop] = sum || null; + } + }); + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function () { + $(this).removeData("resizable-alsoresize"); + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function() { + + var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; + + that.ghost = that.originalElement.clone(); + that.ghost + .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass("ui-resizable-ghost") + .addClass(typeof o.ghost === "string" ? o.ghost : ""); + + that.ghost.appendTo(that.helper); + + }, + + resize: function(){ + var that = $(this).data("ui-resizable"); + if (that.ghost) { + that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); + } + }, + + stop: function() { + var that = $(this).data("ui-resizable"); + if (that.ghost && that.helper) { + that.helper.get(0).removeChild(that.ghost.get(0)); + } + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function() { + var that = $(this).data("ui-resizable"), + o = that.options, + cs = that.size, + os = that.originalSize, + op = that.originalPosition, + a = that.axis, + grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, + gridX = (grid[0]||1), + gridY = (grid[1]||1), + ox = Math.round((cs.width - os.width) / gridX) * gridX, + oy = Math.round((cs.height - os.height) / gridY) * gridY, + newWidth = os.width + ox, + newHeight = os.height + oy, + isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), + isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), + isMinWidth = o.minWidth && (o.minWidth > newWidth), + isMinHeight = o.minHeight && (o.minHeight > newHeight); + + o.grid = grid; + + if (isMinWidth) { + newWidth = newWidth + gridX; + } + if (isMinHeight) { + newHeight = newHeight + gridY; + } + if (isMaxWidth) { + newWidth = newWidth - gridX; + } + if (isMaxHeight) { + newHeight = newHeight - gridY; + } + + if (/^(se|s|e)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + } else if (/^(ne)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + } else if (/^(sw)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.left = op.left - ox; + } else { + if ( newHeight - gridY > 0 ) { + that.size.height = newHeight; + that.position.top = op.top - oy; + } else { + that.size.height = gridY; + that.position.top = op.top + os.height - gridY; + } + if ( newWidth - gridX > 0 ) { + that.size.width = newWidth; + that.position.left = op.left - ox; + } else { + that.size.width = gridX; + that.position.left = op.left + os.width - gridX; + } + } + } + +}); + +})(jQuery); +(function( $, undefined ) { + +$.widget("ui.selectable", $.ui.mouse, { + version: "1.10.4", + options: { + appendTo: "body", + autoRefresh: true, + distance: 0, + filter: "*", + tolerance: "touch", + + // callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null + }, + _create: function() { + var selectees, + that = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + this.refresh = function() { + selectees = $(that.options.filter, that.element[0]); + selectees.addClass("ui-selectee"); + selectees.each(function() { + var $this = $(this), + pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass("ui-selected"), + selecting: $this.hasClass("ui-selecting"), + unselecting: $this.hasClass("ui-unselecting") + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $("
            "); + }, + + _destroy: function() { + this.selectees + .removeClass("ui-selectee") + .removeData("selectable-item"); + this.element + .removeClass("ui-selectable ui-selectable-disabled"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var that = this, + options = this.options; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) { + return; + } + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "left": event.pageX, + "top": event.pageY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter(".ui-selected").each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey && !event.ctrlKey) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().addBack().each(function() { + var doSelect, + selectee = $.data(this, "selectable-item"); + if (selectee) { + doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); + selectee.$element + .removeClass(doSelect ? "ui-unselecting" : "ui-selected") + .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + // selectable (UN)SELECTING callback + if (doSelect) { + that._trigger("selecting", event, { + selecting: selectee.element + }); + } else { + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + return false; + } + }); + + }, + + _mouseDrag: function(event) { + + this.dragged = true; + + if (this.options.disabled) { + return; + } + + var tmp, + that = this, + options = this.options, + x1 = this.opos[0], + y1 = this.opos[1], + x2 = event.pageX, + y2 = event.pageY; + + if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"), + hit = false; + + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element === that.element[0]) { + return; + } + + if (options.tolerance === "touch") { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance === "fit") { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass("ui-selecting"); + selectee.selecting = true; + // selectable SELECTING callback + that._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if ((event.metaKey || event.ctrlKey) && selectee.startselected) { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + selectee.$element.addClass("ui-selected"); + selectee.selected = true; + } else { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var that = this; + + this.dragged = false; + + $(".ui-unselecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $(".ui-selecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +}); + +})(jQuery); +(function( $, undefined ) { + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +function isFloating(item) { + return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); +} + +$.widget("ui.sortable", $.ui.mouse, { + version: "1.10.4", + widgetEventPrefix: "sort", + ready: false, + options: { + appendTo: "parent", + axis: false, + connectWith: false, + containment: false, + cursor: "auto", + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: "> *", + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000, + + // callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null + }, + _create: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are being displayed horizontally + this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + //We're ready to go + this.ready = true; + + }, + + _destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) { + this.items[i].item.removeData(this.widgetName + "-item"); + } + + return this; + }, + + _setOption: function(key, value){ + if ( key === "disabled" ) { + this.options[ key ] = value; + + this.widget().toggleClass( "ui-sortable-disabled", !!value ); + } else { + // Don't call widget base _setOption for disable as it adds ui-state-disabled class + $.Widget.prototype._setOption.apply(this, arguments); + } + }, + + _mouseCapture: function(event, overrideHandle) { + var currentItem = null, + validHandle = false, + that = this; + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type === "static") { + return false; + } + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + $(event.target).parents().each(function() { + if($.data(this, that.widgetName + "-item") === that) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, that.widgetName + "-item") === that) { + currentItem = $(event.target); + } + + if(!currentItem) { + return false; + } + if(this.options.handle && !overrideHandle) { + $(this.options.handle, currentItem).find("*").addBack().each(function() { + if(this === event.target) { + validHandle = true; + } + }); + if(!validHandle) { + return false; + } + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var i, body, + o = this.options; + + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] !== this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + if( o.cursor && o.cursor !== "auto" ) { // cursor option + body = this.document.find( "body" ); + + // support: IE + this.storedCursor = body.css( "cursor" ); + body.css( "cursor", o.cursor ); + + this.storedStylesheet = $( "" ).appendTo( body ); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) { + this._storedOpacity = this.helper.css("opacity"); + } + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) { + this._storedZIndex = this.helper.css("zIndex"); + } + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + this.overflowOffset = this.scrollParent.offset(); + } + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) { + this._cacheHelperProportions(); + } + + + //Post "activate" events to possible containers + if( !noActivation ) { + for ( i = this.containers.length - 1; i >= 0; i-- ) { + this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); + } + } + + //Prepare possible droppables + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + var i, item, itemElement, intersection, + o = this.options, + scrolled = false; + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + + //Rearrange + for (i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } + + // Only put the placeholder inside the current Container, skip all + // items from other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this, moving items in "sub-sortables" can cause + // the placeholder to jitter beetween the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } + + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection === 1 ? "down" : "up"; + + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + //Call callbacks + this._trigger("sort", event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) { + return; + } + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) { + $.ui.ddmanager.drop(this, event); + } + + if(this.options.revert) { + var that = this, + cur = this.placeholder.offset(), + axis = this.options.axis, + animation = {}; + + if ( !axis || axis === "x" ) { + animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); + } + if ( !axis || axis === "y" ) { + animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); + } + this.reverting = true; + $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { + that._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + if(this.dragging) { + + this._mouseUp({ target: null }); + + if(this.options.helper === "original") { + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, this._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + if (this.placeholder) { + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { + this.helper.remove(); + } + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); + } + }); + + if(!str.length && o.key) { + str.push(o.key + "="); + } + + return str.join("&"); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height, + l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), + isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), + isOverElement = isOverElementHeight && isOverElementWidth; + + if ( this.options.tolerance === "pointer" || + this.options.forcePointerForContainers || + (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) && // Right Half + x2 - (this.helperProportions.width / 2) < r && // Left Half + t < y1 + (this.helperProportions.height / 2) && // Bottom Half + y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) { + return false; + } + + return this.floating ? + ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta !== 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta !== 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + return this; + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var i, j, cur, inst, + items = [], + queries = [], + connectWith = this._connectWith(); + + if(connectWith && connected) { + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for ( j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); + } + } + } + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); + + function addItems() { + items.push( this ); + } + for (i = queries.length - 1; i >= 0; i--){ + queries[i][0].each( addItems ); + } + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); + + this.items = $.grep(this.items, function (item) { + for (var j=0; j < list.length; j++) { + if(list[j] === item.item[0]) { + return false; + } + } + return true; + }); + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + + var i, j, cur, inst, targetData, _queries, item, queriesLength, + items = this.items, + queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], + connectWith = this._connectWith(); + + if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for (j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + } + } + } + + for (i = queries.length - 1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; + + for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); + + item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + } + } + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + var i, item, t, p; + + for (i = this.items.length - 1; i >= 0; i--){ + item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { + continue; + } + + t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + p = t.offset(); + item.left = p.left; + item.top = p.top; + } + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (i = this.containers.length - 1; i >= 0; i--){ + p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + } + } + + return this; + }, + + _createPlaceholder: function(that) { + that = that || this; + var className, + o = that.options; + + if(!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; + o.placeholder = { + element: function() { + + var nodeName = that.currentItem[0].nodeName.toLowerCase(), + element = $( "<" + nodeName + ">", that.document[0] ) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper"); + + if ( nodeName === "tr" ) { + that.currentItem.children().each(function() { + $( " ", that.document[0] ) + .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) + .appendTo( element ); + }); + } else if ( nodeName === "img" ) { + element.attr( "src", that.currentItem.attr( "src" ) ); + } + + if ( !className ) { + element.css( "visibility", "hidden" ); + } + + return element; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) { + return; + } + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } + } + }; + } + + //Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + //Append it after the actual current item + that.currentItem.after(that.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); + + }, + + _contactContainers: function(event) { + var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, + innermostContainer = null, + innermostIndex = null; + + // get innermost container that intersects with item + for (i = this.containers.length - 1; i >= 0; i--) { + + // never consider a container that's located within the item itself + if($.contains(this.currentItem[0], this.containers[i].element[0])) { + continue; + } + + if(this._intersectsWith(this.containers[i].containerCache)) { + + // if we've already found a container and it's more "inner" than this, then continue + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { + continue; + } + + innermostContainer = this.containers[i]; + innermostIndex = i; + + } else { + // container doesn't intersect. trigger "out" event if necessary + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + // if no intersecting containers found, return + if(!innermostContainer) { + return; + } + + // move the item into the container if it's not there already + if(this.containers.length === 1) { + if (!this.containers[innermostIndex].containerCache.over) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + } else { + + //When entering a new container, we will find the item with the least distance and append our item near it + dist = 10000; + itemWithLeastDistance = null; + floating = innermostContainer.floating || isFloating(this.currentItem); + posProperty = floating ? "left" : "top"; + sizeProperty = floating ? "width" : "height"; + base = this.positionAbs[posProperty] + this.offset.click[posProperty]; + for (j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { + continue; + } + if(this.items[j].item[0] === this.currentItem[0]) { + continue; + } + if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { + continue; + } + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; + if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ + nearBottom = true; + cur += this.items[j][sizeProperty]; + } + + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + this.direction = nearBottom ? "up": "down"; + } + } + + //Check if dropOnEmpty is enabled + if(!itemWithLeastDistance && !this.options.dropOnEmpty) { + return; + } + + if(this.currentContainer === this.containers[innermostIndex]) { + return; + } + + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); + this.currentContainer = this.containers[innermostIndex]; + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + + + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); + + //Add the helper to the DOM if that didn't happen already + if(!helper.parents("body").length) { + $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + } + + if(helper[0] === this.currentItem[0]) { + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + } + + if(!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if(!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + // This needs to be actually done for all browsers, since pageX/pageY includes this information + // with an ugly IE fix + if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var ce, co, over, + o = this.options; + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment)) { + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var top, left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) { + pageX = this.containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < this.containment[1]) { + pageY = this.containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > this.containment[2]) { + pageX = this.containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > this.containment[3]) { + pageY = this.containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if(counter === this.counter) { + this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + } + }); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var i, + delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } + this._noFinalSort = null; + + if(this.helper[0] === this.currentItem[0]) { + for(i in this._storedCSS) { + if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { + this._storedCSS[i] = ""; + } + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + } + if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + } + + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if(!noPropagation) { + delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + } + } + + + //Post events to containers + function delayEvent( type, instance, container ) { + return function( event ) { + container._trigger( type, event, instance._uiHash( instance ) ); + }; + } + for (i = this.containers.length - 1; i >= 0; i--){ + if (!noPropagation) { + delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); + } + if(this.containers[i].containerCache.over) { + delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if ( this.storedCursor ) { + this.document.find( "body" ).css( "cursor", this.storedCursor ); + this.storedStylesheet.remove(); + } + if(this._storedOpacity) { + this.helper.css("opacity", this._storedOpacity); + } + if(this._storedZIndex) { + this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); + } + + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return false; + } + + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] !== this.currentItem[0]) { + this.helper.remove(); + } + this.helper = null; + + if(!noPropagation) { + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return true; + + }, + + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null + }; + } + +}); + +})(jQuery); +(function( $, undefined ) { + +var uid = 0, + hideProps = {}, + showProps = {}; + +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; + +$.widget( "ui.accordion", { + version: "1.10.4", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + _create: function() { + var options = this.options; + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + + this._processPanels(); + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next(), + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } else if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter(":not(.ui-accordion-content-active)") + .hide(); + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(), + accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) + .removeClass( "ui-corner-all" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr({ + "tabIndex": -1, + "aria-expanded": "false" + }); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr( "aria-hidden", "false" ) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0, + "aria-expanded": "true" + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } + this._trigger( "activate", null, data ); + } +}); + +})( jQuery ); +(function( $, undefined ) { + +$.widget( "ui.autocomplete", { + version: "1.10.4", + defaultElement: "", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + requestIndex: 0, + pending: 0, + + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[0].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + this.isMultiLine = + // Textareas are always multi-line + isTextarea ? true : + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + isInput ? false : + // All other element types are determined by whether or not they're contentEditable + this.element.prop( "isContentEditable" ); + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + case keyCode.NUMPAD_ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + this._value( this.term ); + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + event.preventDefault(); + } + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + }); + + this._initSource(); + this.menu = $( "
              " ) + .addClass( "ui-autocomplete ui-front" ) + .appendTo( this._appendTo() ) + .menu({ + // disable ARIA support, the live region takes care of that + role: null + }) + .hide() + .data( "ui-menu" ); + + this._on( this.menu.element, { + mousedown: function( event ) { + // prevent moving focus out of the text field + event.preventDefault(); + + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + }); + + // clicking on the scrollbar causes focus to shift to the body + // but we can't detect a mouseup or a click immediately afterward + // so we have to track the next mousedown and close the menu if + // the user clicks somewhere outside of the autocomplete + var menuElement = this.menu.element[ 0 ]; + if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { + this._delay(function() { + var that = this; + this.document.one( "mousedown", function( event ) { + if ( event.target !== that.element[ 0 ] && + event.target !== menuElement && + !$.contains( menuElement, event.target ) ) { + that.close(); + } + }); + }); + } + }, + menufocus: function( event, ui ) { + // support: Firefox + // Prevent accidental activation of menu items in Firefox (#7024 #9118) + if ( this.isNewMenu ) { + this.isNewMenu = false; + if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { + this.menu.blur(); + + this.document.one( "mousemove", function() { + $( event.target ).trigger( event.originalEvent ); + }); + + return; + } + } + + var item = ui.item.data( "ui-autocomplete-item" ); + if ( false !== this._trigger( "focus", event, { item: item } ) ) { + // use value to match what will end up in the input, if it was a key event + if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { + this._value( item.value ); + } + } else { + // Normally the input is populated with the item's value as the + // menu is navigated, causing screen readers to notice a change and + // announce the item. Since the focus event was canceled, this doesn't + // happen, so we update the live region so that screen readers can + // still notice the change and announce it. + this.liveRegion.text( item.value ); + } + }, + menuselect: function( event, ui ) { + var item = ui.item.data( "ui-autocomplete-item" ), + previous = this.previous; + + // only trigger when focus was lost (click on menu) + if ( this.element[0] !== this.document[0].activeElement ) { + this.element.focus(); + this.previous = previous; + // #6109 - IE triggers two focus events and the second + // is asynchronous, so we need to reset the previous + // term synchronously and asynchronously :-( + this._delay(function() { + this.previous = previous; + this.selectedItem = item; + }); + } + + if ( false !== this._trigger( "select", event, { item: item } ) ) { + this._value( item.value ); + } + // reset the term after the select event + // this allows custom select handling to work properly + this.term = this._value(); + + this.close( event ); + this.selectedItem = item; + } + }); + + this.liveRegion = $( "", { + role: "status", + "aria-live": "polite" + }) + .addClass( "ui-helper-hidden-accessible" ) + .insertBefore( this.element ); + + // turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + }); + }, + + _destroy: function() { + clearTimeout( this.searching ); + this.element + .removeClass( "ui-autocomplete-input" ) + .removeAttr( "autocomplete" ); + this.menu.element.remove(); + this.liveRegion.remove(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "source" ) { + this._initSource(); + } + if ( key === "appendTo" ) { + this.menu.element.appendTo( this._appendTo() ); + } + if ( key === "disabled" && value && this.xhr ) { + this.xhr.abort(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); + } + + if ( !element ) { + element = this.element.closest( ".ui-front" ); + } + + if ( !element.length ) { + element = this.document[0].body; + } + + return element; + }, + + _initSource: function() { + var array, url, + that = this; + if ( $.isArray(this.options.source) ) { + array = this.options.source; + this.source = function( request, response ) { + response( $.ui.autocomplete.filter( array, request.term ) ); + }; + } else if ( typeof this.options.source === "string" ) { + url = this.options.source; + this.source = function( request, response ) { + if ( that.xhr ) { + that.xhr.abort(); + } + that.xhr = $.ajax({ + url: url, + data: request, + dataType: "json", + success: function( data ) { + response( data ); + }, + error: function() { + response( [] ); + } + }); + }; + } else { + this.source = this.options.source; + } + }, + + _searchTimeout: function( event ) { + clearTimeout( this.searching ); + this.searching = this._delay(function() { + // only search if the value has changed + if ( this.term !== this._value() ) { + this.selectedItem = null; + this.search( null, event ); + } + }, this.options.delay ); + }, + + search: function( value, event ) { + value = value != null ? value : this._value(); + + // always save the actual value, not the one passed as an argument + this.term = this._value(); + + if ( value.length < this.options.minLength ) { + return this.close( event ); + } + + if ( this._trigger( "search", event ) === false ) { + return; + } + + return this._search( value ); + }, + + _search: function( value ) { + this.pending++; + this.element.addClass( "ui-autocomplete-loading" ); + this.cancelSearch = false; + + this.source( { term: value }, this._response() ); + }, + + _response: function() { + var index = ++this.requestIndex; + + return $.proxy(function( content ) { + if ( index === this.requestIndex ) { + this.__response( content ); + } + + this.pending--; + if ( !this.pending ) { + this.element.removeClass( "ui-autocomplete-loading" ); + } + }, this ); + }, + + __response: function( content ) { + if ( content ) { + content = this._normalize( content ); + } + this._trigger( "response", null, { content: content } ); + if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { + this._suggest( content ); + this._trigger( "open" ); + } else { + // use ._close() instead of .close() so we don't cancel future searches + this._close(); + } + }, + + close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, + + _close: function( event ) { + if ( this.menu.element.is( ":visible" ) ) { + this.menu.element.hide(); + this.menu.blur(); + this.isNewMenu = true; + this._trigger( "close", event ); + } + }, + + _change: function( event ) { + if ( this.previous !== this._value() ) { + this._trigger( "change", event, { item: this.selectedItem } ); + } + }, + + _normalize: function( items ) { + // assume all items have the right format when the first item is complete + if ( items.length && items[0].label && items[0].value ) { + return items; + } + return $.map( items, function( item ) { + if ( typeof item === "string" ) { + return { + label: item, + value: item + }; + } + return $.extend({ + label: item.label || item.value, + value: item.value || item.label + }, item ); + }); + }, + + _suggest: function( items ) { + var ul = this.menu.element.empty(); + this._renderMenu( ul, items ); + this.isNewMenu = true; + this.menu.refresh(); + + // size and position menu + ul.show(); + this._resizeMenu(); + ul.position( $.extend({ + of: this.element + }, this.options.position )); + + if ( this.options.autoFocus ) { + this.menu.next(); + } + }, + + _resizeMenu: function() { + var ul = this.menu.element; + ul.outerWidth( Math.max( + // Firefox wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping (#7513) + ul.width( "" ).outerWidth() + 1, + this.element.outerWidth() + ) ); + }, + + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ); + }); + }, + + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); + }, + + _renderItem: function( ul, item ) { + return $( "
            • " ) + .append( $( "" ).text( item.label ) ) + .appendTo( ul ); + }, + + _move: function( direction, event ) { + if ( !this.menu.element.is( ":visible" ) ) { + this.search( null, event ); + return; + } + if ( this.menu.isFirstItem() && /^previous/.test( direction ) || + this.menu.isLastItem() && /^next/.test( direction ) ) { + this._value( this.term ); + this.menu.blur(); + return; + } + this.menu[ direction ]( event ); + }, + + widget: function() { + return this.menu.element; + }, + + _value: function() { + return this.valueMethod.apply( this.element, arguments ); + }, + + _keyEvent: function( keyEvent, event ) { + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + this._move( keyEvent, event ); + + // prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); + } + } +}); + +$.extend( $.ui.autocomplete, { + escapeRegex: function( value ) { + return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); + }, + filter: function(array, term) { + var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); + return $.grep( array, function(value) { + return matcher.test( value.label || value.value || value ); + }); + } +}); + + +// live region extension, adding a `messages` option +// NOTE: This is an experimental API. We are still investigating +// a full solution for string manipulation and internationalization. +$.widget( "ui.autocomplete", $.ui.autocomplete, { + options: { + messages: { + noResults: "No search results.", + results: function( amount ) { + return amount + ( amount > 1 ? " results are" : " result is" ) + + " available, use up and down arrow keys to navigate."; + } + } + }, + + __response: function( content ) { + var message; + this._superApply( arguments ); + if ( this.options.disabled || this.cancelSearch ) { + return; + } + if ( content && content.length ) { + message = this.options.messages.results( content.length ); + } else { + message = this.options.messages.noResults; + } + this.liveRegion.text( message ); + } +}); + +}( jQuery )); +(function( $, undefined ) { + +var lastActive, + baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", + typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", + formResetHandler = function() { + var form = $( this ); + setTimeout(function() { + form.find( ":ui-button" ).button( "refresh" ); + }, 1 ); + }, + radioGroup = function( radio ) { + var name = radio.name, + form = radio.form, + radios = $( [] ); + if ( name ) { + name = name.replace( /'/g, "\\'" ); + if ( form ) { + radios = $( form ).find( "[name='" + name + "']" ); + } else { + radios = $( "[name='" + name + "']", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } + } + return radios; + }; + +$.widget( "ui.button", { + version: "1.10.4", + defaultElement: "").addClass(this._triggerClass). + html(!buttonImage ? buttonText : $("").attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? "before" : "after"](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { + $.datepicker._hideDatepicker(); + } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { + $.datepicker._hideDatepicker(); + $.datepicker._showDatepicker(input[0]); + } else { + $.datepicker._showDatepicker(input[0]); + } + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, "autoSize") && !inst.inline) { + var findMax, max, maxI, i, + date = new Date(2009, 12 - 1, 20), // Ensure double digits + dateFormat = this._get(inst, "dateFormat"); + + if (dateFormat.match(/[DM]/)) { + findMax = function(names) { + max = 0; + maxI = 0; + for (i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + "monthNames" : "monthNamesShort")))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); + } + inst.input.attr("size", this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) { + return; + } + divSpan.addClass(this.markerClassName).append(inst.dpDiv); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + //If disabled option is true, disable the datepicker before showing it (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements + // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height + inst.dpDiv.css( "display", "block" ); + }, + + /* Pop-up the date picker in a "dialog" box. + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var id, browserWidth, browserHeight, scrollX, scrollY, + inst = this._dialogInst; // internal instance + + if (!inst) { + this.uuid += 1; + id = "dp" + this.uuid; + this._dialogInput = $(""); + this._dialogInput.keydown(this._doKeyDown); + $("body").append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + browserWidth = document.documentElement.clientWidth; + browserHeight = document.documentElement.clientHeight; + scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) { + $.blockUI(this.dpDiv); + } + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + * @param target element - the target input field or division or span + */ + _destroyDatepicker: function(target) { + var nodeName, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName === "input") { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind("focus", this._showDatepicker). + unbind("keydown", this._doKeyDown). + unbind("keypress", this._doKeyPress). + unbind("keyup", this._doKeyUp); + } else if (nodeName === "div" || nodeName === "span") { + $target.removeClass(this.markerClassName).empty(); + } + }, + + /* Enable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _enableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img").css({opacity: "1.0", cursor: ""}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().removeClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", false); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _disableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, PROP_NAME); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img").css({opacity: "0.5", cursor: "default"}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().addClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", true); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] === target) { + return true; + } + } + return false; + }, + + /* Retrieve the instance data for the target control. + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw "Missing instance data for this datepicker"; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also "all" for all instance settings or + * "defaults" for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ + _optionDatepicker: function(target, name, value) { + var settings, date, minDate, maxDate, + inst = this._getInst(target); + + if (arguments.length === 2 && typeof name === "string") { + return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : + (inst ? (name === "all" ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + + settings = name || {}; + if (typeof name === "string") { + settings = {}; + settings[name] = value; + } + + if (inst) { + if (this._curInst === inst) { + this._hideDatepicker(); + } + + date = this._getDateDatepicker(target, true); + minDate = this._getMinMaxDate(inst, "min"); + maxDate = this._getMinMaxDate(inst, "max"); + extendRemove(inst.settings, settings); + // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { + inst.settings.minDate = this._formatDate(inst, minDate); + } + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { + inst.settings.maxDate = this._formatDate(inst, maxDate); + } + if ( "disabled" in settings ) { + if ( settings.disabled ) { + this._disableDatepicker(target); + } else { + this._enableDatepicker(target); + } + } + this._attachments($(target), inst); + this._autoSize(inst); + this._setDate(inst, date); + this._updateAlternate(inst); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + * @param target element - the target input field or division or span + */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + * @param target element - the target input field or division or span + * @param date Date - the new date + */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) { + this._setDateFromField(inst, noDefault); + } + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var onSelect, dateStr, sel, + inst = $.datepicker._getInst(event.target), + handled = true, + isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); + + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) { + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + + $.datepicker._currentClass + ")", inst.dpDiv); + if (sel[0]) { + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + } + + onSelect = $.datepicker._get(inst, "onSelect"); + if (onSelect) { + dateStr = $.datepicker._formatDate(inst); + + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } else { + $.datepicker._hideDatepicker(); + } + + return false; // don't submit the form + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) { + $.datepicker._clearDate(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) { + $.datepicker._gotoToday(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, -7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, +7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + } else { + handled = false; + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var chars, chr, + inst = $.datepicker._getInst(event.target); + + if ($.datepicker._get(inst, "constrainInput")) { + chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); + chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var date, + inst = $.datepicker._getInst(event.target); + + if (inst.input.val() !== inst.lastVal) { + try { + date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (err) { + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger + input = $("input", input.parentNode)[0]; + } + + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here + return; + } + + var inst, beforeShow, beforeShowSettings, isFixed, + offset, showAnim, duration; + + inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst !== inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + if ( inst && $.datepicker._datepickerShowing ) { + $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); + } + } + + beforeShow = $.datepicker._get(inst, "beforeShow"); + beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + if(beforeShowSettings === false){ + return; + } + extendRemove(inst.settings, beforeShowSettings); + + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + + if ($.datepicker._inDialog) { // hide cursor + input.value = ""; + } + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + + isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css("position") === "fixed"; + return !isFixed; + }); + + offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + //to avoid flashes on Firefox + inst.dpDiv.empty(); + // determine sizing offscreen + inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + "static" : (isFixed ? "fixed" : "absolute")), display: "none", + left: offset.left + "px", top: offset.top + "px"}); + + if (!inst.inline) { + showAnim = $.datepicker._get(inst, "showAnim"); + duration = $.datepicker._get(inst, "duration"); + inst.dpDiv.zIndex($(input).zIndex()+1); + $.datepicker._datepickerShowing = true; + + if ( $.effects && $.effects.effect[ showAnim ] ) { + inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); + } else { + inst.dpDiv[showAnim || "show"](showAnim ? duration : null); + } + + if ( $.datepicker._shouldFocusInput( inst ) ) { + inst.input.focus(); + } + + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) + instActive = inst; // for delegate hover events + inst.dpDiv.empty().append(this._generateHTML(inst)); + this._attachHandlers(inst); + inst.dpDiv.find("." + this._dayOverClass + " a").mouseover(); + + var origyearshtml, + numMonths = this._getNumberOfMonths(inst), + cols = numMonths[1], + width = 17; + + inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); + if (cols > 1) { + inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); + } + inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + + "Class"]("ui-datepicker-multi"); + inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + + "Class"]("ui-datepicker-rtl"); + + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { + inst.input.focus(); + } + + // deffered render of the years select (to avoid flashes on Firefox) + if( inst.yearshtml ){ + origyearshtml = inst.yearshtml; + setTimeout(function(){ + //assure that inst.yearshtml didn't change. + if( origyearshtml === inst.yearshtml && inst.yearshtml ){ + inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); + } + origyearshtml = inst.yearshtml = null; + }, 0); + } + }, + + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + // Support: IE and jQuery <1.9 + _shouldFocusInput: function( inst ) { + return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(), + dpHeight = inst.dpDiv.outerHeight(), + inputWidth = inst.input ? inst.input.outerWidth() : 0, + inputHeight = inst.input ? inst.input.outerHeight() : 0, + viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), + viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); + + offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var position, + inst = this._getInst(obj), + isRTL = this._get(inst, "isRTL"); + + while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? "previousSibling" : "nextSibling"]; + } + + position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + * @param input element - the input field attached to the date picker + */ + _hideDatepicker: function(input) { + var showAnim, duration, postProcess, onClose, + inst = this._curInst; + + if (!inst || (input && inst !== $.data(input, PROP_NAME))) { + return; + } + + if (this._datepickerShowing) { + showAnim = this._get(inst, "showAnim"); + duration = this._get(inst, "duration"); + postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); + } else { + inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : + (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); + } + + if (!showAnim) { + postProcess(); + } + this._datepickerShowing = false; + + onClose = this._get(inst, "onClose"); + if (onClose) { + onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); + } + + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); + if ($.blockUI) { + $.unblockUI(); + $("body").append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) { + return; + } + + var $target = $(event.target), + inst = $.datepicker._getInst($target[0]); + + if ( ( ( $target[0].id !== $.datepicker._mainDivId && + $target.parents("#" + $.datepicker._mainDivId).length === 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.closest("." + $.datepicker._triggerClass).length && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { + $.datepicker._hideDatepicker(); + } + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id), + inst = this._getInst(target[0]); + + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var date, + target = $(id), + inst = this._getInst(target[0]); + + if (this._get(inst, "gotoCurrent") && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } else { + date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id), + inst = this._getInst(target[0]); + + inst["selected" + (period === "M" ? "Month" : "Year")] = + inst["draw" + (period === "M" ? "Month" : "Year")] = + parseInt(select.options[select.selectedIndex].value,10); + + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var inst, + target = $(id); + + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + + inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $("a", td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + this._selectDate(target, ""); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var onSelect, + target = $(id), + inst = this._getInst(target[0]); + + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) { + inst.input.val(dateStr); + } + this._updateAlternate(inst); + + onSelect = this._get(inst, "onSelect"); + if (onSelect) { + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + } else if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + + if (inst.inline){ + this._updateDatepicker(inst); + } else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) !== "object") { + inst.input.focus(); // restore focus + } + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altFormat, date, dateStr, + altField = this._get(inst, "altField"); + + if (altField) { // update alternate field too + altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); + date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), ""]; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ + iso8601Week: function(date) { + var time, + checkDate = new Date(date.getTime()); + + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + + time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ + parseDate: function (format, value, settings) { + if (format == null || value == null) { + throw "Invalid arguments"; + } + + value = (typeof value === "object" ? value.toString() : value + ""); + if (value === "") { + return null; + } + + var iFormat, dim, extra, + iValue = 0, + shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, + shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : + new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Extract a number from the string value + getNumber = function(match) { + var isDoubled = lookAhead(match), + size = (match === "@" ? 14 : (match === "!" ? 20 : + (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), + digits = new RegExp("^\\d{1," + size + "}"), + num = value.substring(iValue).match(digits); + if (!num) { + throw "Missing number at position " + iValue; + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + // Extract a name from the string value and convert to an index + getName = function(match, shortNames, longNames) { + var index = -1, + names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index !== -1) { + return index + 1; + } else { + throw "Unknown name at position " + iValue; + } + }, + // Confirm that a literal character matches the string value + checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw "Unexpected literal at position " + iValue; + } + iValue++; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + checkLiteral(); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + day = getNumber("d"); + break; + case "D": + getName("D", dayNamesShort, dayNames); + break; + case "o": + doy = getNumber("o"); + break; + case "m": + month = getNumber("m"); + break; + case "M": + month = getName("M", monthNamesShort, monthNames); + break; + case "y": + year = getNumber("y"); + break; + case "@": + date = new Date(getNumber("@")); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "!": + date = new Date((getNumber("!") - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")){ + checkLiteral(); + } else { + literal = true; + } + break; + default: + checkLiteral(); + } + } + } + + if (iValue < value.length){ + extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw "Extra/unparsed characters found in date: " + extra; + } + } + + if (year === -1) { + year = new Date().getFullYear(); + } else if (year < 100) { + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + } + + if (doy > -1) { + month = 1; + day = doy; + do { + dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) { + break; + } + month++; + day -= dim; + } while (true); + } + + date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw "Invalid date"; // E.g. 31/02/00 + } + return date; + }, + + /* Standard date formats. */ + ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) + COOKIE: "D, dd M yy", + ISO_8601: "yy-mm-dd", + RFC_822: "D, d M y", + RFC_850: "DD, dd-M-y", + RFC_1036: "D, d M y", + RFC_1123: "D, d M yy", + RFC_2822: "D, d M yy", + RSS: "D, d M y", // RFC 822 + TICKS: "!", + TIMESTAMP: "@", + W3C: "yy-mm-dd", // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * "..." - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ + formatDate: function (format, date, settings) { + if (!date) { + return ""; + } + + var iFormat, + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Format a number, with leading zero if necessary + formatNumber = function(match, value, len) { + var num = "" + value; + if (lookAhead(match)) { + while (num.length < len) { + num = "0" + num; + } + } + return num; + }, + // Format a name, short or long as requested + formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }, + output = "", + literal = false; + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + output += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + output += formatNumber("d", date.getDate(), 2); + break; + case "D": + output += formatName("D", date.getDay(), dayNamesShort, dayNames); + break; + case "o": + output += formatNumber("o", + Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case "m": + output += formatNumber("m", date.getMonth() + 1, 2); + break; + case "M": + output += formatName("M", date.getMonth(), monthNamesShort, monthNames); + break; + case "y": + output += (lookAhead("y") ? date.getFullYear() : + (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); + break; + case "@": + output += date.getTime(); + break; + case "!": + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) { + output += "'"; + } else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); + } + } + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var iFormat, + chars = "", + literal = false, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + chars += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": case "m": case "y": case "@": + chars += "0123456789"; + break; + case "D": case "M": + return null; // Accept anything + case "'": + if (lookAhead("'")) { + chars += "'"; + } else { + literal = true; + } + break; + default: + chars += format.charAt(iFormat); + } + } + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() === inst.lastVal) { + return; + } + + var dateFormat = this._get(inst, "dateFormat"), + dates = inst.lastVal = inst.input ? inst.input.val() : null, + defaultDate = this._getDefaultDate(inst), + date = defaultDate, + settings = this._getFormatConfig(inst); + + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + dates = (noDefault ? "" : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }, + offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(), + year = date.getFullYear(), + month = date.getMonth(), + day = date.getDate(), + pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, + matches = pattern.exec(offset); + + while (matches) { + switch (matches[2] || "d") { + case "d" : case "D" : + day += parseInt(matches[1],10); break; + case "w" : case "W" : + day += parseInt(matches[1],10) * 7; break; + case "m" : case "M" : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case "y": case "Y" : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }, + newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : + (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + + newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); + if (newDate) { + newDate.setHours(0); + newDate.setMinutes(0); + newDate.setSeconds(0); + newDate.setMilliseconds(0); + } + return this._daylightSavingAdjust(newDate); + }, + + /* Handle switch to/from daylight saving. + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ + _daylightSavingAdjust: function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !date, + origMonth = inst.selectedMonth, + origYear = inst.selectedYear, + newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + + inst.selectedDay = inst.currentDay = newDate.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); + if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { + this._notifyChange(inst); + } + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? "" : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Attach the onxxx handlers. These are declared statically so + * they work with static code transformers like Caja. + */ + _attachHandlers: function(inst) { + var stepMonths = this._get(inst, "stepMonths"), + id = "#" + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find("[data-handler]").map(function () { + var handler = { + prev: function () { + $.datepicker._adjustDate(id, -stepMonths, "M"); + }, + next: function () { + $.datepicker._adjustDate(id, +stepMonths, "M"); + }, + hide: function () { + $.datepicker._hideDatepicker(); + }, + today: function () { + $.datepicker._gotoToday(id); + }, + selectDay: function () { + $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); + return false; + }, + selectMonth: function () { + $.datepicker._selectMonthYear(id, this, "M"); + return false; + }, + selectYear: function () { + $.datepicker._selectMonthYear(id, this, "Y"); + return false; + } + }; + $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); + }); + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, + controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, + monthNames, monthNamesShort, beforeShowDay, showOtherMonths, + selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, + cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, + printDate, dRow, tbody, daySettings, otherMonth, unselectable, + tempDate = new Date(), + today = this._daylightSavingAdjust( + new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time + isRTL = this._get(inst, "isRTL"), + showButtonPanel = this._get(inst, "showButtonPanel"), + hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), + navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), + numMonths = this._getNumberOfMonths(inst), + showCurrentAtPos = this._get(inst, "showCurrentAtPos"), + stepMonths = this._get(inst, "stepMonths"), + isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), + currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + drawMonth = inst.drawMonth - showCurrentAtPos, + drawYear = inst.drawYear; + + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + + prevText = this._get(inst, "prevText"); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + + prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + "" + prevText + "" : + (hideIfNoPrevNext ? "" : "" + prevText + "")); + + nextText = this._get(inst, "nextText"); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + + next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + "" + nextText + "" : + (hideIfNoPrevNext ? "" : "" + nextText + "")); + + currentText = this._get(inst, "currentText"); + gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + + controls = (!inst.inline ? "" : ""); + + buttonPanel = (showButtonPanel) ? "
              " + (isRTL ? controls : "") + + (this._isInRange(inst, gotoDate) ? "" : "") + (isRTL ? "" : controls) + "
              " : ""; + + firstDay = parseInt(this._get(inst, "firstDay"),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + + showWeek = this._get(inst, "showWeek"); + dayNames = this._get(inst, "dayNames"); + dayNamesMin = this._get(inst, "dayNamesMin"); + monthNames = this._get(inst, "monthNames"); + monthNamesShort = this._get(inst, "monthNamesShort"); + beforeShowDay = this._get(inst, "beforeShowDay"); + showOtherMonths = this._get(inst, "showOtherMonths"); + selectOtherMonths = this._get(inst, "selectOtherMonths"); + defaultDate = this._getDefaultDate(inst); + html = ""; + dow; + for (row = 0; row < numMonths[0]; row++) { + group = ""; + this.maxRows = 4; + for (col = 0; col < numMonths[1]; col++) { + selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + cornerClass = " ui-corner-all"; + calender = ""; + if (isMultiMonth) { + calender += "
              "; + } + calender += "
              " + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + "
              " + + ""; + thead = (showWeek ? "" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += "= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "" + dayNamesMin[day] + ""; + } + calender += thead + ""; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ""; + tbody = (!showWeek ? "" : ""); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ""; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ""; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += "
              " + this._get(inst, "weekHeader") + "
              " + + this._get(inst, "calculateWeek")(printDate) + "" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "" + printDate.getDate() + "" : "" + printDate.getDate() + "")) + "
              " + (isMultiMonth ? "
              " + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "
              " : "") : ""); + group += calender; + } + html += group; + } + html += buttonPanel; + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "
              ", + monthHtml = ""; + + // month selection + if (secondary || !changeMonth) { + monthHtml += "" + monthNames[drawMonth] + ""; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += ""; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "" + drawYear + ""; + } else { + // determine range of years to display + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += ""; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "
              "; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period === "M" || period === "Y") { + this._notifyChange(inst); + } + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + } + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + + if (offset < 0) { + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10); + maxYear = parseInt(yearSplit[1], 10); + if ( yearSplit[0].match(/[+\-].*/) ) { + minYear += currentYear; + } + if ( yearSplit[1].match(/[+\-].*/) ) { + maxYear += currentYear; + } + } + + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day === "object" ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function bindHover(dpDiv) { + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } + }) + .delegate(selector, "mouseover", function(){ + if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } + } + }); +} + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) { + if (props[name] == null) { + target[name] = props[name]; + } + } + return target; +} + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + return this.each(function() { + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.10.4"; + +})(jQuery); +(function( $, undefined ) { + +var sizeRelatedOptions = { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + resizableRelatedOptions = { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }; + +$.widget( "ui.dialog", { + version: "1.10.4", + options: { + appendTo: "body", + autoOpen: true, + buttons: [], + closeOnEscape: true, + closeText: "close", + dialogClass: "", + draggable: true, + hide: null, + height: "auto", + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + // Ensure the titlebar is always visible + using: function( pos ) { + var topOffset = $( this ).css( pos ).offset().top; + if ( topOffset < 0 ) { + $( this ).css( "top", pos.top - topOffset ); + } + } + }, + resizable: true, + show: null, + title: null, + width: 300, + + // callbacks + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + }, + + _create: function() { + this.originalCss = { + display: this.element[0].style.display, + width: this.element[0].style.width, + minHeight: this.element[0].style.minHeight, + maxHeight: this.element[0].style.maxHeight, + height: this.element[0].style.height + }; + this.originalPosition = { + parent: this.element.parent(), + index: this.element.parent().children().index( this.element ) + }; + this.originalTitle = this.element.attr("title"); + this.options.title = this.options.title || this.originalTitle; + + this._createWrapper(); + + this.element + .show() + .removeAttr("title") + .addClass("ui-dialog-content ui-widget-content") + .appendTo( this.uiDialog ); + + this._createTitlebar(); + this._createButtonPane(); + + if ( this.options.draggable && $.fn.draggable ) { + this._makeDraggable(); + } + if ( this.options.resizable && $.fn.resizable ) { + this._makeResizable(); + } + + this._isOpen = false; + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + if ( element && (element.jquery || element.nodeType) ) { + return $( element ); + } + return this.document.find( element || "body" ).eq( 0 ); + }, + + _destroy: function() { + var next, + originalPosition = this.originalPosition; + + this._destroyOverlay(); + + this.element + .removeUniqueId() + .removeClass("ui-dialog-content ui-widget-content") + .css( this.originalCss ) + // Without detaching first, the following becomes really slow + .detach(); + + this.uiDialog.stop( true, true ).remove(); + + if ( this.originalTitle ) { + this.element.attr( "title", this.originalTitle ); + } + + next = originalPosition.parent.children().eq( originalPosition.index ); + // Don't try to place the dialog next to itself (#8613) + if ( next.length && next[0] !== this.element[0] ) { + next.before( this.element ); + } else { + originalPosition.parent.append( this.element ); + } + }, + + widget: function() { + return this.uiDialog; + }, + + disable: $.noop, + enable: $.noop, + + close: function( event ) { + var activeElement, + that = this; + + if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { + return; + } + + this._isOpen = false; + this._destroyOverlay(); + + if ( !this.opener.filter(":focusable").focus().length ) { + + // support: IE9 + // IE9 throws an "Unspecified error" accessing document.activeElement from an