diff --git a/.htaccess b/.htaccess new file mode 100644 index 00000000..13e5791d --- /dev/null +++ b/.htaccess @@ -0,0 +1,29 @@ +Options -Indexes -MultiViews + +RewriteEngine On +#RewriteBase / + +# Page parser +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^([A-Za-z0-9-_']+)\.png/?$ tools/signature/index.php?name=$1 [L] +RewriteRule ^images/items/([0-9]+)\.gif$ tools/item.php?id=$1 +RewriteRule ^characters/([A-Za-z0-9-_+']+)$ index.php?subtopic=characters&name=$1 +RewriteRule ^guilds/([A-Za-z0-9-_+']+)$ index.php?subtopic=guilds&action=show&guild=$1 +RewriteRule ^forum/board/([0-9]+)$ index.php?subtopic=forum&action=show_board&id=$1 +RewriteRule ^account/manage$ index.php?subtopic=accountmanagement +RewriteRule ^account/create$ index.php?subtopic=createaccount +RewriteRule ^account/lost$ index.php?subtopic=lostaccount +RewriteRule ^account/logout$ index.php?subtopic=accountmanagement&action=logout +RewriteRule ^news/archive/([0-9]+)$ index.php?subtopic=news&archive=true&id=$1 +RewriteRule ^news/archive$ index.php?subtopic=news&archive=true +RewriteRule ^highscores/([A-Za-z0-9-_]+)/([A-Za-z0-9-_]+)?$ index.php?subtopic=highscores&list=$1&vocation=$2 +RewriteRule ^highscores/([A-Za-z0-9-_']+)$ index.php?subtopic=highscores&list=$1 +RewriteRule ^admin/$ admin/index.php +RewriteRule ^install/$ install/index.php + +# temp solution >.> +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^([A-Za-z0-9-_]+)/?$ index.php?p=$1 [L] +RewriteRule ^([A-Za-z0-9-_]+)/([A-Za-z0-9-_]+)?$ index.php?p=$1&action=$2 [L] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..94a9ed02 --- /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. + + + Copyright (C) + + 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: + + Copyright (C) + 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 b/README new file mode 100644 index 00000000..c188c405 --- /dev/null +++ b/README @@ -0,0 +1,41 @@ +MyAAC 0.0.1 - http://www.myaac.net/ + +REQUIREMENTS +===================================== + - PHP 5.1.0 or later + - MySQL database + - (optional) mod_rewrite to use friendly_urls + +INSTALLATION AND CONFIGURATION +===================================== + Just decompress and untar the source (which you should have done by now, + if you're reading this), into your webserver's document root. + + MyAAC needs proper permissions to handle files correctly. + If you're using apache2, then your directory needs to have owner set to: www-data, you can do it by using following command: + chown -R www-data.www-data /var/www/* + (or any other path your MyAAC installation is located at..) + +-------------------------- + Note: Linux only + If you're under linux use these commands to set proper permissions: + chmod 660 config.local.php + chmod 660 images/guilds + chmod 660 images/houses + chmod 660 images/screenshots +-------------------------- + + Visit http://your_domain/install (http://localhost/install) and follow instructions in the browser. + +KNOWN PROBLEMS +===================================== + - none - + +OTHER NOTES +===================================== + If you have a great idea or want contribute to the project - visit our website at http://www.my-aac.org + +LICENSING +===================================== + This program and all associated files are released under the GNU Public + License, see LICENSE for details. diff --git a/admin/.htaccess b/admin/.htaccess new file mode 100644 index 00000000..4beb9e61 --- /dev/null +++ b/admin/.htaccess @@ -0,0 +1,4 @@ +# uncomment if you want to restrict access only for your ip +#order deny,allow +#deny from all +#allow from 127.0.0.1 \ No newline at end of file diff --git a/admin/includes/functions.php b/admin/includes/functions.php new file mode 100644 index 00000000..ab604f76 --- /dev/null +++ b/admin/includes/functions.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 00000000..d0a16a2e --- /dev/null +++ b/admin/index.php @@ -0,0 +1 @@ +install/ directory exists. Please visit this url to start MyAAC Installation.
Delete install/ directory if you already installed MyAAC.
Remember to REFRESH this page when you\'re done!'); } $content = ''; // validate page $page = isset($_GET['p']) ? $_GET['p'] : ''; if(empty($page) || preg_match("/[^a-zA-Z0-9_\-]/", $page)) $page = 'dashboard'; $page = strtolower($page); define('PAGE', $page); require(SYSTEM . 'functions.php'); require(SYSTEM . 'init.php'); require(SYSTEM . 'status.php'); require(SYSTEM . 'login.php'); require(ADMIN . 'includes/functions.php'); // if we're not logged in - show login box if(!$logged || !admin()) { $page = 'login'; } // include our page $file = SYSTEM . 'pages/admin/' . $page . '.php'; if(!@file_exists($file)) { $page = '404'; $file = SYSTEM . 'pages/404.php'; } ob_start(); include($file); $content .= ob_get_contents(); ob_end_clean(); // template $template_path = 'templates/clean/'; require(ADMIN . $template_path . 'template.php'); ?> \ No newline at end of file diff --git a/admin/templates/clean/style.css b/admin/templates/clean/style.css new file mode 100644 index 00000000..c2f5da37 --- /dev/null +++ b/admin/templates/clean/style.css @@ -0,0 +1,136 @@ +*{ + margin:0; + padding:0; +} +body { + font-family: Helvetica; + color: #313334; + background: /*#f9f9f9 #EEEEEE*/#F7F6F1; +} + +img {border: none;} + +a:link {color: #000; text-decoration: none;} +a:visited {color: #000; text-decoration: none;} +a:focus {color: #000; text-decoration: none;} +a:active {color: #000; text-decoration: underline;} +a:hover {color: #000; text-decoration: underline;} +a.current {font-weight: bold;} + +h5.blue {color: #6b7b95;} +h5.red {color: #c17878;} +h5.green {color: #78ba91;} +h5.purple {color: #a87aad;} + +h1, h2, h3, h4, h5, h6 {color: #313334; font-weight: bold;} +.separator {color:#BCE} +.margin-left{ + margin-left:5px; +} + +.button { background:#eee url(images/button.gif) repeat-x 0 0; border:solid 1px #b1a874; color:#7f7f7f; font-size:11px; padding:2px 6px 2px 6px; cursor:pointer; line-height:14px !important; } +.button:hover { color:#333; border-color:#857b42; } + +.field, .button { -moz-border-radius:4px; -webkit-border-radius:4px; } +.small-field, .button, .pagging a { -moz-border-radius:3px; -webkit-border-radius:3px; } + +.table th { + background-color: #4CAF50; + color: white; + text-align: left; +} + +.table tr:nth-child(odd) {background-color: #d1d1d1} + +a.ico { color:#9d9c9a; font-size:10px; text-decoration: none; padding:0 0 0 14px; background-repeat:no-repeat; background-position:0 0; } +a.ico:hover { color:#333;} + +#container{ + width:960px; + margin-left:auto; + margin-right:auto; +} +#header { + /*width: 960px;*/ + padding-left: auto; + padding-right: auto; + border-bottom: 1px dotted black; + margin-top: 40px; +} +#header h1 { + margin: 0; + padding-top: 20px; + text-align: center; +} +#sidebar{ + background: #FFF; + width: 170px; + float: left; + margin: 10px 0 10px 0; + padding: 10px; + border: 1px solid #CCC; +} +#content { + width: 740px; + float: right; + margin: 20px 0 10px 0; + padding: 10px; +} +#footer { + margin-top: 20px; + border-top: 1px dotted black; + text-align: center; + clear: both; +} +/********************* + Sidebar +*********************/ +#sidebar ul{ + list-style:none; + line-height:22px; +} +#sidebar ul li a,#sidebar ul li a:visited{ + padding-left:19px; + text-decoration:none; + margin:0 3px; + display:block; +} +#sidebar ul li a:hover{ + text-decoration:underline; +} +#sidebar ul li ul{ + margin-left:10px; +} +#sidebar h3{ + padding:2px; + font-size:14px; +} +/********************* + Status & version boxes +*********************/ +#status { + position: absolute; top: 10px; left: 10px; + margin: 0px; + float: right; + font-size: 12px; +} +#status .success { + margin: 0px: +} +#version { + position: absolute; top: 10px; right: 10px; + float: right; + text-align: right; + font-size: 12px; +} +/********************* + Infobox +*********************/ +#infobox{ + border:1px solid #e9e8e3; +} +#infobox h3{ + background:#f7f6f1; + border-bottom:1px solid #e9e8e3; + color:#654322; +} \ No newline at end of file diff --git a/admin/templates/clean/template.php b/admin/templates/clean/template.php new file mode 100644 index 00000000..dfc6e5c7 --- /dev/null +++ b/admin/templates/clean/template.php @@ -0,0 +1,95 @@ + + + + + + <?php echo $title . $config['title_separator'] . $config['lua']['serverName']; ?> - Powered by MyAAC + + + + +
+ +
+ + + +
+
+ +
+ + + diff --git a/admin/templates/stylish/Kopia index.html b/admin/templates/stylish/Kopia index.html new file mode 100644 index 00000000..4662068f --- /dev/null +++ b/admin/templates/stylish/Kopia index.html @@ -0,0 +1,281 @@ + + + + +Dashboard - Admin Template + + + + + + + +
+ + +
+
+
+

+ Right Now + Add New Product + Some Action +
+

+

You have 19 new orders, 12 new users and 5 new reviews, today you made $1523.63 in sales and a total of $328.24 profit +

+
+
+
+

Sales for July

+

+
+
+

Traffic for July

+

a

+
+
+

Last 5 Orders

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CustomerItemsGrand Total
Jennifer Kyrnin114.95 €
Mark Kyrnin234.27 €
Virgílio Cezar261.39 €
Todd Simonides51472.56 €
Carol Elihu19.95 €
+
+
+

Bestsellers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Product NamePriceOrders
Apple iPhone 3G 8GB199.00 €24
Fuji FinePix S5800365.24 €19
Canon PIXMA MP14059.50 €12
Apple iPhone 3G 16GB199.00 €10
Prenosnik HP 530 1,6GHz499.00 €6
+
+
+

New Customers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CustomerOrdersAverageTotal
Jennifer Kyrnin15.6€14.95 €
Mark Kyrnin214.97€34.27 €
Virgílio Cezar215.31€61.39 €
Todd Simonides5502.61€1472.56 €
Carol Elihu15.1€9.95 €
+
+
+

Last 5 Reviews

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReviewerProductAction
Jennifer KyrninApple iPhone 3G 8GB
Mark KyrninPrenosnik HP 530 1,6GHz
Virgílio CezarFuji FinePix S5800
Todd SimonidesCanon PIXMA MP140
Carol ElihuPrenosnik HP 530 1,6GHz
+
+
+
+ +
+ +
+ + diff --git a/admin/templates/stylish/blank.html b/admin/templates/stylish/blank.html new file mode 100644 index 00000000..01b09cf0 --- /dev/null +++ b/admin/templates/stylish/blank.html @@ -0,0 +1,100 @@ + + + + +Dashboard - Admin Template + + + + + + + +
+ + + + +
+ + diff --git a/admin/templates/stylish/css/Copy of theme.css b/admin/templates/stylish/css/Copy of theme.css new file mode 100644 index 00000000..9a5f2f88 --- /dev/null +++ b/admin/templates/stylish/css/Copy of theme.css @@ -0,0 +1,121 @@ +body{ + background:#f7f6f0 url(../img/bg.jpg) repeat-x top; + color: #202020; +} +a, a:visited{ + color:#993300; +} +input{ + border:1px solid #e8e7e1; +} +select{ + border:1px solid #e8e7e1; +} +#header h2{ + color:#FFF; +} +#content{ + background:#FFF; +} +#sidebar{ + background:#FFF; +} +#sidebar h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; +} +#topmenu a,#topmenu a:visited{ + color:#f7f6f0; + background:#cc3300; +} +#topmenu a:hover{ + color: #FFF; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + color:#993400; + background: #FFF url(../img/bg_menu_red.jpg) repeat-x top; + border-left: #FFF 1px solid; + border-right: #FFF 1px solid; +} +#top-panel{ + background:#FFF; +} +table{ + background:none; +} +td, th{ + border:1px solid #e8e7e1; +} +thead{ + background:#f7f6f0; +} +#styleswitcher{ + background:#FFFFFF; +} +#footer{ + background:#FFF; +} +#box{ + border:1px solid #e8e7e1; +} +#box h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; + color:#993300; +} +/*************** + Forms +***************/ +form#form fieldset { + border:1px solid #e8e7e1; +} +form#form legend { + border:1px solid #e8e7e1; + background:#fff url(../img/form_red.gif) repeat-x center left; + color:#993300; +} +form#form input { + border:1px solid #e8e7e1; + background:#fff url(../img/form_red.gif) repeat-x top left; +} +form#form textarea { + border:1px solid #e8e7e1; + background:#fff url(../img/form_red.gif) repeat-x bottom left; +} +form#form option { + background:#FFF; +} +form#form optgroup { + background:#e8e7e1; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + color:#c00; +} +form#form #button1:hover, form#form #button2:hover { + color:#000; +} +/*************** + Home +***************/ +#infobox{ + border:1px solid #e8e7e1; +} +#infobox h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; + color:#993300; +} +#rightnow { + border:1px solid #e8e7e1; +} +#rightnow .reallynow { + background:#f7f6f0; + color:#993300; +} +#rightnow h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; +} \ No newline at end of file diff --git a/admin/templates/stylish/css/ie-sucks.css b/admin/templates/stylish/css/ie-sucks.css new file mode 100644 index 00000000..27a6c23a --- /dev/null +++ b/admin/templates/stylish/css/ie-sucks.css @@ -0,0 +1,21 @@ +#content{ + width:740px; +} +#topmenu{ + margin-top:26px; +} +#sidebar{ + width:160px; +} +#sidebar ul{ + width:150px; +} +#sidebar ul li ul{ + width:140px; +} +#sidebar h3{ + margin-bottom:5px; +} +#rightnow .reallynow a { + padding:0 0 0 10px; +} \ No newline at end of file diff --git a/admin/templates/stylish/css/iepngfix.htc b/admin/templates/stylish/css/iepngfix.htc new file mode 100644 index 00000000..a8c5d312 --- /dev/null +++ b/admin/templates/stylish/css/iepngfix.htc @@ -0,0 +1,68 @@ + + + + + \ No newline at end of file diff --git a/admin/templates/stylish/css/style.css b/admin/templates/stylish/css/style.css new file mode 100644 index 00000000..345f94e3 --- /dev/null +++ b/admin/templates/stylish/css/style.css @@ -0,0 +1,397 @@ +/********************* + HTML Elements +*********************/ +*{ + margin:0; + padding:0; +} +img, div,a { behavior: url(css/iepngfix.htc) } +body{ + font-size: 12px; + font-family: Arial, Tahoma, Verdana; +} +a, a:visited{ + text-decoration:none; +} +img{ + border:0; + margin:1px; +} +p{ + padding:3px; +} +h2{ + +} +input{ + padding:2px; +} +select{ + padding:2px; +} +/********************* + Status +*********************/ +#status { + position: absolute; top: 10px; left: 10px; + margin: 0px; + float: right; + font-size: 12px; +} +#status .success { + margin: 0px: +} +#version { + position: absolute; top: 10px; right: 10px; + float: right; + text-align: right; + font-size: 12px; +} +/********************* + Structure +*********************/ +#container{ + width:960px; + margin-left:auto; + margin-right:auto; +} +#header{ + width:960px; +} +#header h2{ + margin-top:20px; +} +#content{ + width:740px; + float:left; + margin:10px 0 10px 0; + padding:10px; +} +#sidebar{ + background:#FFF; + width:170px; + float:right; + margin:10px 0 10px 0; + padding:10px; +} +#footer{ + clear:both; + padding:5px; + margin-top:10px; +} +#box h3{ + padding:5px; + font-size:14px; +} +/********************* + Sidebar +*********************/ +#sidebar ul{ + list-style:none; + line-height:22px; +} +#sidebar ul li a,#sidebar ul li a:visited{ + padding-left:19px; + text-decoration:none; + margin:0 3px; + display:block; +} +#sidebar ul li a:hover{ + text-decoration:underline; +} +#sidebar ul li ul{ + margin-left:10px; +} +#sidebar h3{ + padding:2px; + font-size:14px; +} +/********************* + TopMenu, Top-Panel +*********************/ +#topmenu{ + margin-top:33px; + width:700px; + float:left; + voice-family:inherit; +} +#topmenu ul{ + list-style:none; + line-height:25px; +} +#topmenu li{ + display:inline; +} +#topmenu a,#topmenu a:visited{ + padding:5px 12px 5px 12px; + text-decoration:none; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + padding:5px 12px 5px 12px; + font-weight:bold; + +} +#top-panel{ + background:#FFF; + padding:5px; + height:20px; + float:left; + width:950px; +} +#top-panel ul{ + list-style:none; +} +#top-panel ul li{ + display:inline; + line-height:20px; +} +#top-panel ul li a{ + padding-left:19px; + text-decoration:none; + margin:0 3px; + display:inline-block; +} +#top-panel a:hover{ + text-decoration:underline; +} +/********************* + Other +*********************/ +.a-right{text-align:right;} +.a-left{text-align:left;} +.a-center{text-align:center;} +#pager{ + margin:5px; + height:25px; +} +#styleswitcher{ + float:right; +} +#styleswitcher ul{ + list-style:none; + line-height:10px; +} +#styleswitcher li{ + height:12px; + display:inline; +} +#footer ul { + list-style:none; +} +#footer li { + display:inline; +} +a#defswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#bd3f09; + font-size: 8px; + color:#bd3f09; + display:inline-block; +} +a#blueswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#375b91; + font-size: 8px; + color:#375b91; + display:inline-block; +} +a#greenswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#d0e0b8; + font-size: 8px; + color:#d0e0b8; + display:inline-block; +} +a#brownswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#654322; + font-size: 8px; + color:#654322; + display:inline-block; +} +a#mixswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#294145; + font-size: 8px; + color:#294145; + display:inline-block; +} +#credits{ + clear:both; + width:250px; + float:left; +} +/********************* + Tables +*********************/ +table{ + margin:5px; + border-collapse: collapse; + table-layout:automatic; + width:98%; +} +td, th{ + padding: 2px; +} +thead{ + +} +/********************* + Home +*********************/ +#infowrap li{ + display:inline: +} +#infobox{ + width:365px; + float:left; + margin-top:10px; +} +#infobox h3{ + padding:5px; + font-size:14px; +} +.margin-left{ + margin-left:5px; +} +#rightnow .reallynow { + padding: 5px; + font-size:14px; +} +#rightnow h3{ + padding:2px; + padding: 0 10px; + font-size:14px; +} +#rightnow .reallynow span { + display: block; + text-align: left; + float: left; + padding:0 2px; + font-size:14px +} +#rightnow .reallynow a { + text-decoration:none; + display: block; + text-align: right; + float: right; + padding:0 0 0 18px; + margin-left:4px; + font-weight:normal; + font-size:12px; +} +#rightnow .reallynow a:hover{ + text-decoration:underline; +} +#rightnow .youhave { + font-size: 12px; + padding: 10px; +} +#rightnow a { + font-weight: bold; +} +/********************* + Forms +*********************/ +form{ + padding:10px; + margin:0 auto; +} +form#form fieldset { + display:block; + padding:5px 10px 5px 10px; + line-height:20px; + margin-bottom:10px; +} +form#form legend { + font-size:12px; + font-weight:bold; + margin-bottom:5px; + padding:3px; + width:254px; +} +form#form label { + clear:left; + display:block; + float:left; + width:100px; + text-align:right; + padding-right:10px; + margin-bottom:5px; +} +form#form input { + padding:3px; + margin-bottom:5px; +} +form#form select { + margin-left:5px; +} +form#form textarea { + width:410px; + height:200px; + padding:5px; + overflow:auto; +} +form#form option { + background:#FFF; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + padding-right:5px; + cursor:pointer; + width:205px; + margin-left:8px; + font-weight:bold; +} +form#form #button1:hover, form#form #button2:hover { + background-position:center left; +} + +/********************* + Icons +*********************/ +.icon{ + padding-left:19px; + text-decoration:none; + height:20px; + font-size:12x; + margin:0 3px; + display:inline-block; + line-height:20px; +} +.user{background:transparent url(../img/icons/user.png) no-repeat left;} +.useradd{background:transparent url(../img/icons/user_add.png) no-repeat left;} +.group{background:transparent url(../img/icons/group.png) no-repeat left;} +.search{background:transparent url(../img/icons/magnifier.png) no-repeat left;} +.online{background:transparent url(../img/icons/world.png) no-repeat left;} +.pagenew{background:transparent url(../img/icons/page_add.png) no-repeat left;} +.rss{background:transparent url(../img/icons/rss.png) no-repeat left;} +.feed{background:transparent url(../img/icons/feed.png) no-repeat left;} +.report{background:transparent url(../img/icons/report.png) no-repeat left;} +.house{background:transparent url(../img/icons/house.png) no-repeat left;} +.manage{background:transparent url(../img/icons/cog.png) no-repeat left;} +.manage_page{background:transparent url(../img/icons/page_gear.png) no-repeat left;} +.folder{background:transparent url(../img/icons/folder.png) no-repeat left;} +.promotions{background:transparent url(../img/icons/coins.png) no-repeat left;} +.cart{background:transparent url(../img/icons/cart.png) no-repeat left;} +.folder_table{background:transparent url(../img/icons/folder_page.png) no-repeat left;} +.shipping{background:transparent url(../img/icons/car.png) no-repeat left;} +.invoices{background:transparent url(../img/icons/page_white_text_width.png) no-repeat left;} +.addorder{background:transparent url(../img/icons/folder_page_add.png) no-repeat left;} +.add{background:transparent url(../img/icons/add.png) no-repeat left;} +.app_add{background:transparent url(../img/icons/application_add.png) no-repeat left;} +.report_seo{background:transparent url(../img/icons/report_link.png) no-repeat left;} +.modules{background:transparent url(../img/icons/bricks.png) no-repeat left;} +.modules_manage{background:transparent url(../img/icons/bricks_gear.png) no-repeat left;} \ No newline at end of file diff --git a/admin/templates/stylish/css/switch.css b/admin/templates/stylish/css/switch.css new file mode 100644 index 00000000..544d9a5a --- /dev/null +++ b/admin/templates/stylish/css/switch.css @@ -0,0 +1,51 @@ +#footer ul { + list-style:none; +} +#footer li { + display:inline; +} +a#defswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#bd3f09; + font-size: 8px; + color:#bd3f09; + display:inline-block; +} +a#blueswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#375b91; + font-size: 8px; + color:#375b91; + display:inline-block; +} +a#greenswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#d0e0b8; + font-size: 8px; + color:#d0e0b8; + display:inline-block; +} +a#brownswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#654322; + font-size: 8px; + color:#654322; + display:inline-block; +} +a#mixswitch { + width:15px; + height:10px; + margin: 3px 0 3px 0; + background-color:#294145; + font-size: 8px; + color:#294145; + display:inline-block; +} diff --git a/admin/templates/stylish/css/theme.css b/admin/templates/stylish/css/theme.css new file mode 100644 index 00000000..6d341e82 --- /dev/null +++ b/admin/templates/stylish/css/theme.css @@ -0,0 +1,121 @@ +body{ + background:#f7f6f0 url(../img/bg.jpg) repeat-x top; + color: #202020; +} +a, a:visited{ + color:#a43708; +} +input{ + border:1px solid #e8e7e1; +} +select{ + border:1px solid #e8e7e1; +} +#header h2{ + color:#FFF; +} +#content{ + background:#FFF; +} +#sidebar{ + background:#FFF; +} +#sidebar h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; +} +#topmenu a,#topmenu a:visited{ + color:#f7f6f0; + background:#bd3f09; +} +#topmenu a:hover{ + color: #FFF; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + color:#993400; + background: #FFF url(../img/bg_menu_red.jpg) repeat-x top; + border-left: #FFF 1px solid; + border-right: #FFF 1px solid; +} +#top-panel{ + background:#FFF; +} +table{ + background:none; +} +td, th{ + border:1px solid #e8e7e1; +} +thead{ + background:#f7f6f0; +} +#styleswitcher{ + background:#FFFFFF; +} +#footer{ + background:#FFF; +} +#box{ + border:1px solid #e8e7e1; +} +#box h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; + color:#a43708; +} +/*************** + Forms +***************/ +form#form fieldset { + border:1px solid #e8e7e1; +} +form#form legend { + border:1px solid #e8e7e1; + background:#fff url(../img/form_red.gif) repeat-x center left; + color:#a43708; +} +form#form input { + border:1px solid #e8e7e1; + background:#fff url(../img/form_red.gif) repeat-x top left; +} +form#form textarea { + border:1px solid #e8e7e1; + background:#fff url(../img/form_red.gif) repeat-x bottom left; +} +form#form option { + background:#FFF; +} +form#form optgroup { + background:#e8e7e1; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + color:#c00; +} +form#form #button1:hover, form#form #button2:hover { + color:#000; +} +/*************** + Home +***************/ +#infobox{ + border:1px solid #e8e7e1; +} +#infobox h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; + color:#a43708; +} +#rightnow { + border:1px solid #e8e7e1; +} +#rightnow .reallynow { + background:#f7f6f0; + color:#a43708; +} +#rightnow h3{ + background:#f7f6f0; + border-bottom:1px solid #e8e7e1; +} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme1.css b/admin/templates/stylish/css/theme1.css new file mode 100644 index 00000000..0e2803e4 --- /dev/null +++ b/admin/templates/stylish/css/theme1.css @@ -0,0 +1,121 @@ +body{ + background:#f3f9ff url(../img/bg_blue.jpg) repeat-x top; + color: #202020; +} +a, a:visited{ + color:#375b91; +} +input{ + border:1px solid #d9e6f0; +} +select{ + border:1px solid #d9e6f0; +} +#header h2{ + color:#FFF; +} +#content{ + background:#FFF; +} +#sidebar{ + background:#FFF; +} +#sidebar h3{ + background:#f3f9ff; + border-bottom:1px solid #d9e6f0; +} +#topmenu a,#topmenu a:visited{ + color:#FFF; + background:#7e9dcc; +} +#topmenu a:hover{ + color: #FFF; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + color:#375b91; + background: #FFF url(../img/bg_menu_blue.jpg) repeat-x top; + border-left: #FFF 1px solid; + border-right: #FFF 1px solid; +} +#top-panel{ + background:#FFF; +} +table{ + background:none; +} +td, th{ + border:1px solid #d9e6f0; +} +thead{ + background:#f3f9ff; +} +#styleswitcher{ + background:#FFFFFF; +} +#footer{ + background:#FFF; +} +#box{ + border:1px solid #d9e6f0; +} +#box h3{ + background:#f3f9ff; + border-bottom:1px solid #d9e6f0; + color:#375b91; +} +/*************** + Forms +***************/ +form#form fieldset { + border:1px solid #d9e6f0; +} +form#form legend { + border:1px solid #d9e6f0; + background:#fff url(../img/form_blue.gif) repeat-x center left; + color:#375b91; +} +form#form input { + border:1px solid #d9e6f0; + background:#fff url(../img/form_blue.gif) repeat-x top left; +} +form#form textarea { + border:1px solid #d9e6f0; + background:#fff url(../img/form_blue.gif) repeat-x bottom left; +} +form#form option { + background:#FFF; +} +form#form optgroup { + background:#d9e6f0; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + color:#375b91; +} +form#form #button1:hover, form#form #button2:hover { + color:#000; +} +/*************** + Home +***************/ +#infobox{ + border:1px solid #d9e6f0; +} +#infobox h3{ + background:#f3f9ff; + border-bottom:1px solid #d9e6f0; + color:#375b91; +} +#rightnow { + border:1px solid #d9e6f0; +} +#rightnow .reallynow { + background:#f3f9ff; + color:#375b91; +} +#rightnow h3{ + background:#f3f9ff; + border-bottom:1px solid #d9e6f0; +} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme2.css b/admin/templates/stylish/css/theme2.css new file mode 100644 index 00000000..1876b9fc --- /dev/null +++ b/admin/templates/stylish/css/theme2.css @@ -0,0 +1,121 @@ +body{ + background:#f0f7e8 url(../img/bg_light_green.jpg) repeat-x top; + color: #202020; +} +a, a:visited{ + color:#93ad7e; +} +input{ + border:1px solid #e7eedf; +} +select{ + border:1px solid #e7eedf; +} +#header h2{ + color:#FFF; +} +#content{ + background:#FFF; +} +#sidebar{ + background:#FFF; +} +#sidebar h3{ + background:#f0f7e8; + border-bottom:1px solid #e7eedf; +} +#topmenu a,#topmenu a:visited{ + color:#93ad7e; + background:#e7eedc; +} +#topmenu a:hover{ + color: #93ad7e; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + color:#93ad7e; + background: #FFF url(../img/bg_menu_green.jpg) repeat-x top; + border-left: #FFF 1px solid; + border-right: #FFF 1px solid; +} +#top-panel{ + background:#FFF; +} +table{ + background:none; +} +td, th{ + border:1px solid #e7eedf; +} +thead{ + background:#f0f7e8; +} +#styleswitcher{ + background:#FFFFFF; +} +#footer{ + background:#FFF; +} +#box{ + border:1px solid #e7eedf; +} +#box h3{ + background:#f0f7e8; + border-bottom:1px solid #e7eedf; + color:#93ad7e; +} +/*************** + Forms +***************/ +form#form fieldset { + border:1px solid #e7eedf; +} +form#form legend { + border:1px solid #e7eedf; + background:#fff url(../img/form_green.gif) repeat-x center left; + color:#93ad7e; +} +form#form input { + border:1px solid #e7eedf; + background:#fff url(../img/form_green.gif) repeat-x top left; +} +form#form textarea { + border:1px solid #e7eedf; + background:#fff url(../img/form_green.gif) repeat-x bottom left; +} +form#form option { + background:#FFF; +} +form#form optgroup { + background:#e7eedf; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + color:#93ad7e; +} +form#form #button1:hover, form#form #button2:hover { + color:#000; +} +/*************** + Home +***************/ +#infobox{ + border:1px solid #e7eedf; +} +#infobox h3{ + background:#f0f7e8; + border-bottom:1px solid #e7eedf; + color:#93ad7e; +} +#rightnow { + border:1px solid #e7eedf; +} +#rightnow .reallynow { + background:#f0f7e8; + color:#93ad7e; +} +#rightnow h3{ + background:#f0f7e8; + border-bottom:1px solid #e7eedf; +} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme3.css b/admin/templates/stylish/css/theme3.css new file mode 100644 index 00000000..9fb95faa --- /dev/null +++ b/admin/templates/stylish/css/theme3.css @@ -0,0 +1,121 @@ +body{ + background:#f7f6f1 url(../img/bg_brown.jpg) repeat-x top; + color: #202020; +} +a, a:visited{ + color:#654322; +} +input{ + border:1px solid #e9e8e3; +} +select{ + border:1px solid #e9e8e3; +} +#header h2{ + color:#FFF; +} +#content{ + background:#FFF; +} +#sidebar{ + background:#FFF; +} +#sidebar h3{ + background:#f7f6f1; + border-bottom:1px solid #e9e8e3; +} +#topmenu a,#topmenu a:visited{ + color:#FFF; + background:#8f6831; +} +#topmenu a:hover{ + color: #654322; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + color:#654322; + background: #FFF url(../img/bg_menu_brown.jpg) repeat-x top; + border-left: #FFF 1px solid; + border-right: #FFF 1px solid; +} +#top-panel{ + background:#FFF; +} +table{ + background:none; +} +td, th{ + border:1px solid #e9e8e3; +} +thead{ + background:#f7f6f1; +} +#styleswitcher{ + background:#FFFFFF; +} +#footer{ + background:#FFF; +} +#box{ + border:1px solid #e9e8e3; +} +#box h3{ + background:#f7f6f1; + border-bottom:1px solid #e9e8e3; + color:#654322; +} +/*************** + Forms +***************/ +form#form fieldset { + border:1px solid #e9e8e3; +} +form#form legend { + border:1px solid #e9e8e3; + background:#fff url(../img/form_brown.gif) repeat-x center left; + color:#654322; +} +form#form input { + border:1px solid #e9e8e3; + background:#fff url(../img/form_brown.gif) repeat-x top left; +} +form#form textarea { + border:1px solid #e9e8e3; + background:#fff url(../img/form_brown.gif) repeat-x bottom left; +} +form#form option { + background:#FFF; +} +form#form optgroup { + background:#e9e8e3; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + color:#654322; +} +form#form #button1:hover, form#form #button2:hover { + color:#000; +} +/*************** + Home +***************/ +#infobox{ + border:1px solid #e9e8e3; +} +#infobox h3{ + background:#f7f6f1; + border-bottom:1px solid #e9e8e3; + color:#654322; +} +#rightnow { + border:1px solid #e9e8e3; +} +#rightnow .reallynow { + background:#f7f6f1; + color:#654322; +} +#rightnow h3{ + background:#f7f6f1; + border-bottom:1px solid #e9e8e3; +} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme4.css b/admin/templates/stylish/css/theme4.css new file mode 100644 index 00000000..ce4bba24 --- /dev/null +++ b/admin/templates/stylish/css/theme4.css @@ -0,0 +1,122 @@ +body{ + background:#d9eaed url(../img/bg_mix.jpg) repeat-x top; + color: #202020; +} +a, a:visited{ + color:#294145; + text-decoration:underline; +} +input{ + border:1px solid #c3d7db; +} +select{ + border:1px solid #c3d7db; +} +#header h2{ + color:#FFF; +} +#content{ + background:#FFF; +} +#sidebar{ + background:#FFF; +} +#sidebar h3{ + background:#d9eaed; + border-bottom:1px solid #c3d7db; +} +#topmenu a,#topmenu a:visited{ + color:#FFF; + background:#5d99a3; +} +#topmenu a:hover{ + color: #294145; +} +#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ + color:#294145; + background: #FFF url(../img/bg_menu_mix.jpg) repeat-x top; + border-left: #FFF 1px solid; + border-right: #FFF 1px solid; +} +#top-panel{ + background:#FFF; +} +table{ + background:none; +} +td, th{ + border:1px solid #c3d7db; +} +thead{ + background:#d9eaed; +} +#styleswitcher{ + background:#FFFFFF; +} +#footer{ + background:#FFF; +} +#box{ + border:1px solid #c3d7db; +} +#box h3{ + background:#d9eaed; + border-bottom:1px solid #c3d7db; + color:#294145; +} +/*************** + Forms +***************/ +form#form fieldset { + border:1px solid #c3d7db; +} +form#form legend { + border:1px solid #c3d7db; + background:#fff url(../img/form_mix.gif) repeat-x center left; + color:#294145; +} +form#form input { + border:1px solid #c3d7db; + background:#fff url(../img/form_mix.gif) repeat-x top left; +} +form#form textarea { + border:1px solid #c3d7db; + background:#fff url(../img/form_mix.gif) repeat-x bottom left; +} +form#form option { + background:#FFF; +} +form#form optgroup { + background:#c3d7db; +} +form#form optgroup option { + +} +form#form #button1, form#form #button2 { + color:#294145; +} +form#form #button1:hover, form#form #button2:hover { + color:#000; +} +/*************** + Home +***************/ +#infobox{ + border:1px solid #c3d7db; +} +#infobox h3{ + background:#d9eaed; + border-bottom:1px solid #c3d7db; + color:#294145; +} +#rightnow { + border:1px solid #c3d7db; +} +#rightnow .reallynow { + background:#d9eaed; + color:#294145; +} +#rightnow h3{ + background:#d9eaed; + border-bottom:1px solid #c3d7db; +} \ No newline at end of file diff --git a/admin/templates/stylish/img/bg.jpg b/admin/templates/stylish/img/bg.jpg new file mode 100644 index 00000000..1980c13f Binary files /dev/null and b/admin/templates/stylish/img/bg.jpg differ diff --git a/admin/templates/stylish/img/bg_blue.jpg b/admin/templates/stylish/img/bg_blue.jpg new file mode 100644 index 00000000..ad55db4d Binary files /dev/null and b/admin/templates/stylish/img/bg_blue.jpg differ diff --git a/admin/templates/stylish/img/bg_brown.jpg b/admin/templates/stylish/img/bg_brown.jpg new file mode 100644 index 00000000..5c2af288 Binary files /dev/null and b/admin/templates/stylish/img/bg_brown.jpg differ diff --git a/admin/templates/stylish/img/bg_light_green.jpg b/admin/templates/stylish/img/bg_light_green.jpg new file mode 100644 index 00000000..b091ebdf Binary files /dev/null and b/admin/templates/stylish/img/bg_light_green.jpg differ diff --git a/admin/templates/stylish/img/bg_menu_blue.jpg b/admin/templates/stylish/img/bg_menu_blue.jpg new file mode 100644 index 00000000..0a406082 Binary files /dev/null and b/admin/templates/stylish/img/bg_menu_blue.jpg differ diff --git a/admin/templates/stylish/img/bg_menu_green.jpg b/admin/templates/stylish/img/bg_menu_green.jpg new file mode 100644 index 00000000..503f7198 Binary files /dev/null and b/admin/templates/stylish/img/bg_menu_green.jpg differ diff --git a/admin/templates/stylish/img/bg_menu_mix.jpg b/admin/templates/stylish/img/bg_menu_mix.jpg new file mode 100644 index 00000000..c006525b Binary files /dev/null and b/admin/templates/stylish/img/bg_menu_mix.jpg differ diff --git a/admin/templates/stylish/img/bg_menu_red.jpg b/admin/templates/stylish/img/bg_menu_red.jpg new file mode 100644 index 00000000..f774a4d0 Binary files /dev/null and b/admin/templates/stylish/img/bg_menu_red.jpg differ diff --git a/admin/templates/stylish/img/bg_mix.jpg b/admin/templates/stylish/img/bg_mix.jpg new file mode 100644 index 00000000..f328fb3c Binary files /dev/null and b/admin/templates/stylish/img/bg_mix.jpg differ diff --git a/admin/templates/stylish/img/form_blue.gif b/admin/templates/stylish/img/form_blue.gif new file mode 100644 index 00000000..8952f383 Binary files /dev/null and b/admin/templates/stylish/img/form_blue.gif differ diff --git a/admin/templates/stylish/img/form_brown.gif b/admin/templates/stylish/img/form_brown.gif new file mode 100644 index 00000000..8e1efcc7 Binary files /dev/null and b/admin/templates/stylish/img/form_brown.gif differ diff --git a/admin/templates/stylish/img/form_green.gif b/admin/templates/stylish/img/form_green.gif new file mode 100644 index 00000000..ce0ceb0b Binary files /dev/null and b/admin/templates/stylish/img/form_green.gif differ diff --git a/admin/templates/stylish/img/form_mix.gif b/admin/templates/stylish/img/form_mix.gif new file mode 100644 index 00000000..b7fd05b6 Binary files /dev/null and b/admin/templates/stylish/img/form_mix.gif differ diff --git a/admin/templates/stylish/img/form_red.gif b/admin/templates/stylish/img/form_red.gif new file mode 100644 index 00000000..b5a7a729 Binary files /dev/null and b/admin/templates/stylish/img/form_red.gif differ diff --git a/admin/templates/stylish/img/graph.jpg b/admin/templates/stylish/img/graph.jpg new file mode 100644 index 00000000..56b1469d Binary files /dev/null and b/admin/templates/stylish/img/graph.jpg differ diff --git a/admin/templates/stylish/img/graph2.jpg b/admin/templates/stylish/img/graph2.jpg new file mode 100644 index 00000000..c25ad0d5 Binary files /dev/null and b/admin/templates/stylish/img/graph2.jpg differ diff --git a/admin/templates/stylish/img/icons/add.png b/admin/templates/stylish/img/icons/add.png new file mode 100644 index 00000000..6332fefe Binary files /dev/null and b/admin/templates/stylish/img/icons/add.png differ diff --git a/admin/templates/stylish/img/icons/application_add.png b/admin/templates/stylish/img/icons/application_add.png new file mode 100644 index 00000000..2e945076 Binary files /dev/null and b/admin/templates/stylish/img/icons/application_add.png differ diff --git a/admin/templates/stylish/img/icons/arrow_down.png b/admin/templates/stylish/img/icons/arrow_down.png new file mode 100644 index 00000000..2c4e2793 Binary files /dev/null and b/admin/templates/stylish/img/icons/arrow_down.png differ diff --git a/admin/templates/stylish/img/icons/arrow_down_mini.gif b/admin/templates/stylish/img/icons/arrow_down_mini.gif new file mode 100644 index 00000000..f0bb6a4e Binary files /dev/null and b/admin/templates/stylish/img/icons/arrow_down_mini.gif differ diff --git a/admin/templates/stylish/img/icons/arrow_left.gif b/admin/templates/stylish/img/icons/arrow_left.gif new file mode 100644 index 00000000..932ade16 Binary files /dev/null and b/admin/templates/stylish/img/icons/arrow_left.gif differ diff --git a/admin/templates/stylish/img/icons/arrow_right.gif b/admin/templates/stylish/img/icons/arrow_right.gif new file mode 100644 index 00000000..780431c2 Binary files /dev/null and b/admin/templates/stylish/img/icons/arrow_right.gif differ diff --git a/admin/templates/stylish/img/icons/brick.png b/admin/templates/stylish/img/icons/brick.png new file mode 100644 index 00000000..7851cf34 Binary files /dev/null and b/admin/templates/stylish/img/icons/brick.png differ diff --git a/admin/templates/stylish/img/icons/brick_edit.png b/admin/templates/stylish/img/icons/brick_edit.png new file mode 100644 index 00000000..eb06df3b Binary files /dev/null and b/admin/templates/stylish/img/icons/brick_edit.png differ diff --git a/admin/templates/stylish/img/icons/bricks.png b/admin/templates/stylish/img/icons/bricks.png new file mode 100644 index 00000000..0905f933 Binary files /dev/null and b/admin/templates/stylish/img/icons/bricks.png differ diff --git a/admin/templates/stylish/img/icons/bricks_gear.png b/admin/templates/stylish/img/icons/bricks_gear.png new file mode 100644 index 00000000..9dda1f3b Binary files /dev/null and b/admin/templates/stylish/img/icons/bricks_gear.png differ diff --git a/admin/templates/stylish/img/icons/car.png b/admin/templates/stylish/img/icons/car.png new file mode 100644 index 00000000..4f3a770f Binary files /dev/null and b/admin/templates/stylish/img/icons/car.png differ diff --git a/admin/templates/stylish/img/icons/cart.png b/admin/templates/stylish/img/icons/cart.png new file mode 100644 index 00000000..1baf7b9f Binary files /dev/null and b/admin/templates/stylish/img/icons/cart.png differ diff --git a/admin/templates/stylish/img/icons/cart_add.png b/admin/templates/stylish/img/icons/cart_add.png new file mode 100644 index 00000000..45c29000 Binary files /dev/null and b/admin/templates/stylish/img/icons/cart_add.png differ diff --git a/admin/templates/stylish/img/icons/cog.png b/admin/templates/stylish/img/icons/cog.png new file mode 100644 index 00000000..67de2c6c Binary files /dev/null and b/admin/templates/stylish/img/icons/cog.png differ diff --git a/admin/templates/stylish/img/icons/coins.png b/admin/templates/stylish/img/icons/coins.png new file mode 100644 index 00000000..0ca9074d Binary files /dev/null and b/admin/templates/stylish/img/icons/coins.png differ diff --git a/admin/templates/stylish/img/icons/color_swatch.png b/admin/templates/stylish/img/icons/color_swatch.png new file mode 100644 index 00000000..6e6e8521 Binary files /dev/null and b/admin/templates/stylish/img/icons/color_swatch.png differ diff --git a/admin/templates/stylish/img/icons/expand.jpg b/admin/templates/stylish/img/icons/expand.jpg new file mode 100644 index 00000000..e7e129fb Binary files /dev/null and b/admin/templates/stylish/img/icons/expand.jpg differ diff --git a/admin/templates/stylish/img/icons/feed.png b/admin/templates/stylish/img/icons/feed.png new file mode 100644 index 00000000..315c4f4f Binary files /dev/null and b/admin/templates/stylish/img/icons/feed.png differ diff --git a/admin/templates/stylish/img/icons/folder.png b/admin/templates/stylish/img/icons/folder.png new file mode 100644 index 00000000..784e8fa4 Binary files /dev/null and b/admin/templates/stylish/img/icons/folder.png differ diff --git a/admin/templates/stylish/img/icons/folder_page.png b/admin/templates/stylish/img/icons/folder_page.png new file mode 100644 index 00000000..1ef6e114 Binary files /dev/null and b/admin/templates/stylish/img/icons/folder_page.png differ diff --git a/admin/templates/stylish/img/icons/folder_page_add.png b/admin/templates/stylish/img/icons/folder_page_add.png new file mode 100644 index 00000000..c1e90af4 Binary files /dev/null and b/admin/templates/stylish/img/icons/folder_page_add.png differ diff --git a/admin/templates/stylish/img/icons/folder_table.png b/admin/templates/stylish/img/icons/folder_table.png new file mode 100644 index 00000000..473cee35 Binary files /dev/null and b/admin/templates/stylish/img/icons/folder_table.png differ diff --git a/admin/templates/stylish/img/icons/group.png b/admin/templates/stylish/img/icons/group.png new file mode 100644 index 00000000..7fb4e1f1 Binary files /dev/null and b/admin/templates/stylish/img/icons/group.png differ diff --git a/admin/templates/stylish/img/icons/house.png b/admin/templates/stylish/img/icons/house.png new file mode 100644 index 00000000..fed62219 Binary files /dev/null and b/admin/templates/stylish/img/icons/house.png differ diff --git a/admin/templates/stylish/img/icons/magnifier.png b/admin/templates/stylish/img/icons/magnifier.png new file mode 100644 index 00000000..cf3d97f7 Binary files /dev/null and b/admin/templates/stylish/img/icons/magnifier.png differ diff --git a/admin/templates/stylish/img/icons/page_add.png b/admin/templates/stylish/img/icons/page_add.png new file mode 100644 index 00000000..d5bfa071 Binary files /dev/null and b/admin/templates/stylish/img/icons/page_add.png differ diff --git a/admin/templates/stylish/img/icons/page_gear.png b/admin/templates/stylish/img/icons/page_gear.png new file mode 100644 index 00000000..8e83281c Binary files /dev/null and b/admin/templates/stylish/img/icons/page_gear.png differ diff --git a/admin/templates/stylish/img/icons/page_white_delete.png b/admin/templates/stylish/img/icons/page_white_delete.png new file mode 100644 index 00000000..af1ecaf2 Binary files /dev/null and b/admin/templates/stylish/img/icons/page_white_delete.png differ diff --git a/admin/templates/stylish/img/icons/page_white_edit.png b/admin/templates/stylish/img/icons/page_white_edit.png new file mode 100644 index 00000000..b93e7760 Binary files /dev/null and b/admin/templates/stylish/img/icons/page_white_edit.png differ diff --git a/admin/templates/stylish/img/icons/page_white_link.png b/admin/templates/stylish/img/icons/page_white_link.png new file mode 100644 index 00000000..bf7bd1c9 Binary files /dev/null and b/admin/templates/stylish/img/icons/page_white_link.png differ diff --git a/admin/templates/stylish/img/icons/page_white_text_width.png b/admin/templates/stylish/img/icons/page_white_text_width.png new file mode 100644 index 00000000..d9cf1325 Binary files /dev/null and b/admin/templates/stylish/img/icons/page_white_text_width.png differ diff --git a/admin/templates/stylish/img/icons/report.png b/admin/templates/stylish/img/icons/report.png new file mode 100644 index 00000000..779ad58e Binary files /dev/null and b/admin/templates/stylish/img/icons/report.png differ diff --git a/admin/templates/stylish/img/icons/report_link.png b/admin/templates/stylish/img/icons/report_link.png new file mode 100644 index 00000000..23f2611e Binary files /dev/null and b/admin/templates/stylish/img/icons/report_link.png differ diff --git a/admin/templates/stylish/img/icons/rss.png b/admin/templates/stylish/img/icons/rss.png new file mode 100644 index 00000000..1dc6ff30 Binary files /dev/null and b/admin/templates/stylish/img/icons/rss.png differ diff --git a/admin/templates/stylish/img/icons/user.png b/admin/templates/stylish/img/icons/user.png new file mode 100644 index 00000000..79f35ccb Binary files /dev/null and b/admin/templates/stylish/img/icons/user.png differ diff --git a/admin/templates/stylish/img/icons/user_add.png b/admin/templates/stylish/img/icons/user_add.png new file mode 100644 index 00000000..deae99bc Binary files /dev/null and b/admin/templates/stylish/img/icons/user_add.png differ diff --git a/admin/templates/stylish/img/icons/user_delete.png b/admin/templates/stylish/img/icons/user_delete.png new file mode 100644 index 00000000..acbb5630 Binary files /dev/null and b/admin/templates/stylish/img/icons/user_delete.png differ diff --git a/admin/templates/stylish/img/icons/user_edit.png b/admin/templates/stylish/img/icons/user_edit.png new file mode 100644 index 00000000..c1974cda Binary files /dev/null and b/admin/templates/stylish/img/icons/user_edit.png differ diff --git a/admin/templates/stylish/img/icons/world.png b/admin/templates/stylish/img/icons/world.png new file mode 100644 index 00000000..68f21d30 Binary files /dev/null and b/admin/templates/stylish/img/icons/world.png differ diff --git a/admin/templates/stylish/psd/template.psd b/admin/templates/stylish/psd/template.psd new file mode 100644 index 00000000..d9004ae8 Binary files /dev/null and b/admin/templates/stylish/psd/template.psd differ diff --git a/admin/templates/stylish/template.php b/admin/templates/stylish/template.php new file mode 100644 index 00000000..a064b847 --- /dev/null +++ b/admin/templates/stylish/template.php @@ -0,0 +1,296 @@ + + + + + + <?php echo $title . $config['title_separator'] . $config['lua']['serverName']; ?> - Powered by MyAAC + + + + + + + +
+ + +
+
+
+

+ Right Now + Add New Product + Some Action +
+

+

You have 19 new orders, 12 new users and 5 new reviews, today you made $1523.63 in sales and a total of $328.24 profit +

+
+
+
+

Sales for July

+

+
+
+

Traffic for July

+

a

+
+
+

Last 5 Orders

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CustomerItemsGrand Total
Jennifer Kyrnin114.95 €
Mark Kyrnin234.27 €
Virgílio Cezar261.39 €
Todd Simonides51472.56 €
Carol Elihu19.95 €
+
+
+

Bestsellers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Product NamePriceOrders
Apple iPhone 3G 8GB199.00 €24
Fuji FinePix S5800365.24 €19
Canon PIXMA MP14059.50 €12
Apple iPhone 3G 16GB199.00 €10
Prenosnik HP 530 1,6GHz499.00 €6
+
+
+

New Customers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CustomerOrdersAverageTotal
Jennifer Kyrnin15.6€14.95 €
Mark Kyrnin214.97€34.27 €
Virgílio Cezar215.31€61.39 €
Todd Simonides5502.61€1472.56 €
Carol Elihu15.1€9.95 €
+
+
+

Last 5 Reviews

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReviewerProductAction
Jennifer KyrninApple iPhone 3G 8GB
Mark KyrninPrenosnik HP 530 1,6GHz
Virgílio CezarFuji FinePix S5800
Todd SimonidesCanon PIXMA MP140
Carol ElihuPrenosnik HP 530 1,6GHz
+
+
+
+ +
+ +
+ + diff --git a/admin/templates/stylish/users.html b/admin/templates/stylish/users.html new file mode 100644 index 00000000..30694291 --- /dev/null +++ b/admin/templates/stylish/users.html @@ -0,0 +1,309 @@ + + + + +Users - Admin Template + + + + + + + +
+ + +
+
+
+

Users

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDFull NameEmailGroupZIPRegisteredAction
232Jennifer Hodesjennifer.hodes@gmail.comGeneral1000July 2, 2008
231Mark Kyrninmark.kyrnin@hotmail.comAffiliate8310June 17, 2008
230Virgílio Cezarvirgilio@somecompany.czGeneral6200June 31, 2008
229Todd Simonidestodd.simonides@gmail.comWholesale2010June 5, 2008
228Carol Elihucarol@herbusiness.comGeneral3120May 23, 2008
232Jennifer Hodesjennifer.hodes@gmail.comGeneral1000July 2, 2008
231Mark Kyrninmark.kyrnin@hotmail.comAffiliate8310June 17, 2008
230Virgílio Cezarvirgilio@somecompany.czGeneral6200June 31, 2008
229Todd Simonidestodd.simonides@gmail.comWholesale2010June 5, 2008
228Carol Elihucarol@herbusiness.comGeneral3120May 23, 2008
+
+ Page + + of 42 + pages | View + per page | Total 420 records found +
+
+
+
+

Add user

+
+
+ PERSONAL INFORMATION + + +
+ + +
+ + +
+

Send auto generated password +

+ + +
+ + +
+
+
+ Address + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+ OPTIONS + + +
+
+ + +
+
+ +
+
+ +
+ +
+ + diff --git a/admin/tools/phpinfo.php b/admin/tools/phpinfo.php new file mode 100644 index 00000000..0ebd694b --- /dev/null +++ b/admin/tools/phpinfo.php @@ -0,0 +1,14 @@ + diff --git a/admin/tools/status.php b/admin/tools/status.php new file mode 100644 index 00000000..5e992979 --- /dev/null +++ b/admin/tools/status.php @@ -0,0 +1,21 @@ + +Server:
+Version:

+ +Monsters:
+Map: , author: , size:
+MOTD:

+ +Last check: diff --git a/common.php b/common.php new file mode 100644 index 00000000..9f6b680e --- /dev/null +++ b/common.php @@ -0,0 +1,86 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +session_start(); + +define('MYAAC', true); +define('MYAAC_VERSION', '0.0.1'); +define('TABLE_PREFIX', 'myaac_'); +define('START_TIME', microtime(true)); +define('MYAAC_OS', (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? 'WINDOWS' : 'LINUX'); + +// account flags +define('FLAG_ADMIN', 1); +define('FLAG_SUPER_ADMIN', 2); +define('FLAG_CONTENT_PAGES', 4); +define('FLAG_CONTENT_MAILER', 8); +define('FLAG_CONTENT_NEWS', 16); +define('FLAG_CONTENT_FORUM', 32); +define('FLAG_CONTENT_COMMANDS', 64); +define('FLAG_CONTENT_SPELLS', 128); +define('FLAG_CONTENT_MONSTERS', 256); + +// directories +define('BASE', dirname(__FILE__) . '/'); +define('ADMIN', BASE . 'admin/'); +define('SYSTEM', BASE . 'system/'); +define('CACHE', SYSTEM . 'cache/'); +define('LOCALE', SYSTEM . 'locale/'); +define('LIBS', SYSTEM . 'libs/'); +define('LOGS', SYSTEM . 'logs/'); +define('PLUGINS', BASE . 'plugins/'); +define('TEMPLATES', BASE . 'templates/'); + +// otserv versions +define('OTSERV', 1); +define('OTSERV_06', 2); +define('OTSERV_FIRST', OTSERV); +define('OTSERV_LAST', OTSERV_06); +define('TFS_02', 3); +define('TFS_03', 4); +define('TFS_FIRST', TFS_02); +define('TFS_LAST', TFS_03); + +// basedir +$basedir = ''; +$tmp = explode('/', $_SERVER['SCRIPT_NAME']); +$size = sizeof($tmp) - 1; +for($i = 1; $i < $size; $i++) + $basedir .= '/' . $tmp[$i]; + +$basedir = str_replace('/admin', '', $basedir); +$basedir = str_replace('/install', '', $basedir); +define('BASE_DIR', $basedir); + +if(isset($_SERVER['HTTPS'][0]) && $_SERVER['HTTPS'] == 'on') + define('SERVER_URL', 'https://' . $_SERVER['HTTP_HOST']); +else + define('SERVER_URL', 'http://' . $_SERVER['HTTP_HOST']); + +define('BASE_URL', SERVER_URL . BASE_DIR . '/'); +define('ADMIN_URL', SERVER_URL . BASE_DIR . '/admin/'); +//define('CURRENT_URL', BASE_URL . $_SERVER['REQUEST_URI']); +?> diff --git a/config.local.php b/config.local.php new file mode 100644 index 00000000..dc941cc7 --- /dev/null +++ b/config.local.php @@ -0,0 +1,3 @@ + diff --git a/config.php b/config.php new file mode 100644 index 00000000..abd4d9c0 --- /dev/null +++ b/config.php @@ -0,0 +1,225 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ + +$config = array( + // directories & files + 'server_path' => '', // path to the server directory (same directory where config file is located) + + 'template' => 'kathrine', // template used by website (kathrine, tibiacom) + 'template_allow_change' => true, // allow users to choose their own template while browsing website? + + // what client version are you using on this OT? + // used for the Downloads page and some templates aswell + 'client' => 1098, // 954 = client 9.54 + + 'friendly_urls' => false, // mod_rewrite is required for this, it makes links looks more elegant to eye, and also are SEO friendly (example: http://my-aac.org/guilds/Testing instead of http://my-aac.org/?subtopic=guilds&name=Testing) + 'gzip_output' => false, // gzip page content before sending it to the browser, uses less bandwidth but more cpu cycles + + // gesior backward support (templates & pages) + // allows using gesior templates and pages with myaac + 'backward_support' => true, + + // head options (html) + 'meta_description' => 'Tibia is a free massive multiplayer online role playing game (MMORPG).', // description of the site + 'meta_keywords' => 'free online game, free multiplayer game, ots, open tibia server', // keywords list separated by commas + 'title_separator' => ' - ', + + // footer + 'footer' => ''/*'
Your Server © 2016. All rights reserved.'*/, + + // site closed + 'site_closed' => false, + 'site_closed_title' => 'Closed', + 'site_closed_message' => 'Server is under maintance, please visit later.

', + + 'debug_level' => 0, // 0 - disabled, 1 - show load time, 2 - show db query counter, 3 - both + + 'language' => 'en', // default language (currently only 'en' available) + 'language_allow_change' => false, + + 'visitors_counter' => true, + 'visitors_counter_ttl' => 10, // how long visitor will be marked as online (in minutes) + 'views_counter' => true, + + // cache system. by default file cache is used + 'cache_engine' => 'auto', // apc, eaccelerator, xcache, file, auto, or blank to disable. + 'cache_prefix' => 'myaac_', // have to be unique if running more MyAAC instances on the same server, ignored when using file cache. + + // database details (leave blank for auto detect from config.lua) + 'database_host' => '', + 'database_port' => '', // leave blank to default 3306 + 'database_user' => '', + 'database_password' => '', + 'database_name' => '', + + // multiworld system + 'multiworld' => false, // use multiworld system? + 'worlds' => array( // list of worlds + //'1' => 'Your World Name', + //'2' => 'Your Second World Name' + ), + + // account + 'account_management' => true, // disable if you're using other method to manage users (fe. tfs account manager) + 'account_mail_verify' => false, // force users to confirm their email addresses when registering account + 'account_mail_unique' => true, // email addresses cannot be duplicated? (one account = one email) + 'account_premium_days' => 0, // default premium days on new account + 'account_premium_points' => 0, // default premium points on new account + 'account_welcome_mail' => true, // send welcome email when user registers + 'account_mail_change' => 2, // how many days user need to change email to account - block hackers + 'account_country' => true, // user will be able to set country of origin when registering account, this information will be viewable in others places aswell + + // mail + 'mail_enabled' => false, // is aac maker configured to send e-mails? + 'mail_address' => 'no-reply@your-server.org', // server e-mail address (from:) + 'mail_admin' => 'your-address@your-server.org', // admin email address, where mails from contact form will be sent + 'mail_signature' => array( // signature that will be included at the end of every message sent using _mail function + 'plain' => "--\nMy Server,\nhttp://www.myserver.com", + 'html' => '
My Server,\nmyserver.com' + ), + 'smtp_enabled' => false, // send by smtp or mail function (set false if use mail function) + 'smtp_host' => '', // mail host + 'smtp_port' => 25, // 25 (default) / 465 (ssl, e.g. gmail) + 'smtp_auth' => true, // need authorization? + 'smtp_user' => 'admin@example.org', + 'smtp_pass' => '', + + // reCAPTCHA (prevent spam bots) + 'recaptcha_enabled' => false, // enable recaptcha verification code + 'recaptcha_site_key' => '', // get your own public and private keys at https://www.google.com/recaptcha + 'recaptcha_secret_key' => '', + 'recaptcha_theme' => 'light', // light, dark + + // + 'generate_new_reckey' => true, // let player generate new recovery key, he will receive e-mail with new rec key (not display on page, hacker can't generate rec key) + 'generate_new_reckey_price' => 20, // price for new recovery key + 'send_mail_when_change_password' => true, // send e-mail with new password when change password to account + 'send_mail_when_generate_reckey' => true, // send e-mail with rec key (key is displayed on page anyway when generate) + + // new character config + 'character_samples' => array( // vocations, format: ID_of_vocation => 'Name of Character to copy' + //0 => 'Rook Sample', + 1 => 'Sorcerer Sample', + 2 => 'Druid Sample', + 3 => 'Paladin Sample', + 4 => 'Knight Sample' + ), + + // town list used when creating character + // won't be displayed if there is only one item (rookgaard for example) + 'character_towns' => array(1), + + // list of towns + 'towns' => array( + 0 => 'No town', + 1 => 'Sample town' + ), + + 'characters_per_account' => 10, // max. number of characters per account + + // guilds + 'guild_management' => true, // enable guild management system on the site? + 'guild_need_level' => 1, // min. level to form a guild + 'guild_need_premium' => true, // require premium account to form a guild? + 'guild_image_size_kb' => 80, // maximum size of the guild logo image in KB (kilobytes) + 'guild_description_chars_limit' => 1000, // limit of guild description + 'guild_description_lines_limit' => 6, // limit of lines, if description has more lines it will be showed as long text, without 'enters' + 'guild_motd_chars_limit' => 150, // limit of MOTD (message of the day) that is shown later in the game on the guild channel + + 'quests' => array(), // quests list (displayed in character view), name => storage + + 'signature_enabled' => true, + 'signature_type' => 'tibian', // signature engine to use: tibian, mango, gesior + 'signature_cache_time' => 5, // how long to store cached file (in minutes) + + // online page + 'online_record' => true, // display players record? + 'online_vocations' => false, // display vocation statistics? + 'online_vocations_images' => false, // display vocation images? + 'online_skulls' => false, // display skull images + 'online_afk' => false, + + // support list page + 'team_style' => 2, // 1/2 (1 - normal table, 2 - in boxes, grouped by group id) + 'team_display_status' => true, + 'team_display_lastlogin' => true, + 'team_display_world' => false, + + // bans page + 'bans_limit' => 50, + 'bans_display_all' => true, // should all bans be displayed? (sorted page by page) + + // highscores page + 'highscores_vocation_box' => true, // show 'Choose a vocation' box on the highscores (allowing peoples to sort highscores by vocation)? + 'highscores_vocation' => true, // show player vocation under his nickname? + 'highscores_frags' => false, // show 'Frags' tab (best fraggers on the server)? Only 0.3 + 'highscores_country_box' => false, // doesnt work yet! (not implemented) + 'highscores_groups_hidden' => 4, // this group id and higher won't be shown on the highscores + + // characters page + 'characters' => array( // what things to display on character view page (true/false in each option) + 'level' => true, + 'experience' => false, + 'magic_level' => false, + 'balance' => false, + 'marriage_info' => true, // only 0.3 + 'creation_date' => true, + 'quests' => true, + 'skills' => true, + 'equipment' => true, + 'frags' => false + ), + + // news page + 'news_limit' => 5, // limit of news on latest news page + 'news_ticker_limit' => 5, // limit of news in tickers (mini news) (0 to disable) + 'news_date_format' => 'j.n.Y', // check php manual date() function for more info about this + 'news_author' => true, + + // gifts/shop system + 'gifts_system' => false, + + // forum + 'forum' => 'site', // link to the server forum, set to "site" if you want to use build in forum system, otherwise leave empty if you aren't going to use any forum + 'forum_level_required' => 0, // level required to post, 0 to disable + 'forum_post_interval' => 30, // in seconds + 'forum_posts_per_page' => 20, + 'forum_threads_per_page' => 20, + + // last kills + 'last_kills_limit' => 50, // max. number of deaths shown on the last kills page + + // status, took automatically from config file if empty + 'status_ip' => '', + 'status_port' => '', + + // other + 'email_lai_sec_interval' => 60, // time in seconds between e-mails to one account from lost account interface, block spam + 'google_analytics_id' => '', // e.g.: UA-XXXXXXX-X + 'experiencetable_columns' => 5, // how many columns to display in experience table page. * 100, 5 = 500 (will show up to 500 level) + + 'monsters' => array(), + 'npc' => array() +); + +// download link to client. +$config['client_download'] = 'http://clients.halfaway.net/windows.php?tibia='. $config['client'] .''; +$config['client_download_linux'] = 'http://clients.halfaway.net/linux.php?tibia='. $config['client'] .''; + +?> diff --git a/images/.htaccess b/images/.htaccess new file mode 100644 index 00000000..5a928f6d --- /dev/null +++ b/images/.htaccess @@ -0,0 +1 @@ +Options -Indexes diff --git a/images/addons/Female_Assassin_1.gif b/images/addons/Female_Assassin_1.gif new file mode 100644 index 00000000..4eb2ee94 Binary files /dev/null and b/images/addons/Female_Assassin_1.gif differ diff --git a/images/addons/Female_Assassin_2.gif b/images/addons/Female_Assassin_2.gif new file mode 100644 index 00000000..ae4056f0 Binary files /dev/null and b/images/addons/Female_Assassin_2.gif differ diff --git a/images/addons/Female_Barbarian_1.gif b/images/addons/Female_Barbarian_1.gif new file mode 100644 index 00000000..79ddc015 Binary files /dev/null and b/images/addons/Female_Barbarian_1.gif differ diff --git a/images/addons/Female_Barbarian_2.gif b/images/addons/Female_Barbarian_2.gif new file mode 100644 index 00000000..9b2e56db Binary files /dev/null and b/images/addons/Female_Barbarian_2.gif differ diff --git a/images/addons/Female_Beggar_1.gif b/images/addons/Female_Beggar_1.gif new file mode 100644 index 00000000..14ca0dde Binary files /dev/null and b/images/addons/Female_Beggar_1.gif differ diff --git a/images/addons/Female_Beggar_2.gif b/images/addons/Female_Beggar_2.gif new file mode 100644 index 00000000..28b1b20f Binary files /dev/null and b/images/addons/Female_Beggar_2.gif differ diff --git a/images/addons/Female_Brotherhood_1.gif b/images/addons/Female_Brotherhood_1.gif new file mode 100644 index 00000000..dfe273c3 Binary files /dev/null and b/images/addons/Female_Brotherhood_1.gif differ diff --git a/images/addons/Female_Brotherhood_2.gif b/images/addons/Female_Brotherhood_2.gif new file mode 100644 index 00000000..d83a7f8f Binary files /dev/null and b/images/addons/Female_Brotherhood_2.gif differ diff --git a/images/addons/Female_Citizen_1.gif b/images/addons/Female_Citizen_1.gif new file mode 100644 index 00000000..f5a7ac30 Binary files /dev/null and b/images/addons/Female_Citizen_1.gif differ diff --git a/images/addons/Female_Citizen_2.gif b/images/addons/Female_Citizen_2.gif new file mode 100644 index 00000000..b831e032 Binary files /dev/null and b/images/addons/Female_Citizen_2.gif differ diff --git a/images/addons/Female_Demonhunter_1.gif b/images/addons/Female_Demonhunter_1.gif new file mode 100644 index 00000000..601a1e67 Binary files /dev/null and b/images/addons/Female_Demonhunter_1.gif differ diff --git a/images/addons/Female_Demonhunter_2.gif b/images/addons/Female_Demonhunter_2.gif new file mode 100644 index 00000000..1d6ac363 Binary files /dev/null and b/images/addons/Female_Demonhunter_2.gif differ diff --git a/images/addons/Female_Druid_1.gif b/images/addons/Female_Druid_1.gif new file mode 100644 index 00000000..756778bb Binary files /dev/null and b/images/addons/Female_Druid_1.gif differ diff --git a/images/addons/Female_Druid_2.gif b/images/addons/Female_Druid_2.gif new file mode 100644 index 00000000..475a8ebe Binary files /dev/null and b/images/addons/Female_Druid_2.gif differ diff --git a/images/addons/Female_Hunter_1.gif b/images/addons/Female_Hunter_1.gif new file mode 100644 index 00000000..90c802d3 Binary files /dev/null and b/images/addons/Female_Hunter_1.gif differ diff --git a/images/addons/Female_Hunter_2.gif b/images/addons/Female_Hunter_2.gif new file mode 100644 index 00000000..2bd4c5b4 Binary files /dev/null and b/images/addons/Female_Hunter_2.gif differ diff --git a/images/addons/Female_Jester_1.gif b/images/addons/Female_Jester_1.gif new file mode 100644 index 00000000..6709a90c Binary files /dev/null and b/images/addons/Female_Jester_1.gif differ diff --git a/images/addons/Female_Jester_2.gif b/images/addons/Female_Jester_2.gif new file mode 100644 index 00000000..68eb48e8 Binary files /dev/null and b/images/addons/Female_Jester_2.gif differ diff --git a/images/addons/Female_Knight_1.gif b/images/addons/Female_Knight_1.gif new file mode 100644 index 00000000..67ba682f Binary files /dev/null and b/images/addons/Female_Knight_1.gif differ diff --git a/images/addons/Female_Knight_2.gif b/images/addons/Female_Knight_2.gif new file mode 100644 index 00000000..6f0feaa5 Binary files /dev/null and b/images/addons/Female_Knight_2.gif differ diff --git a/images/addons/Female_Mage_1.gif b/images/addons/Female_Mage_1.gif new file mode 100644 index 00000000..866a02e1 Binary files /dev/null and b/images/addons/Female_Mage_1.gif differ diff --git a/images/addons/Female_Mage_2.gif b/images/addons/Female_Mage_2.gif new file mode 100644 index 00000000..a0a44fd8 Binary files /dev/null and b/images/addons/Female_Mage_2.gif differ diff --git a/images/addons/Female_Nightmare_1.gif b/images/addons/Female_Nightmare_1.gif new file mode 100644 index 00000000..26fecde4 Binary files /dev/null and b/images/addons/Female_Nightmare_1.gif differ diff --git a/images/addons/Female_Nightmare_2.gif b/images/addons/Female_Nightmare_2.gif new file mode 100644 index 00000000..0fe68ba2 Binary files /dev/null and b/images/addons/Female_Nightmare_2.gif differ diff --git a/images/addons/Female_Nobleman_1.gif b/images/addons/Female_Nobleman_1.gif new file mode 100644 index 00000000..89c508cb Binary files /dev/null and b/images/addons/Female_Nobleman_1.gif differ diff --git a/images/addons/Female_Nobleman_2.gif b/images/addons/Female_Nobleman_2.gif new file mode 100644 index 00000000..59e87382 Binary files /dev/null and b/images/addons/Female_Nobleman_2.gif differ diff --git a/images/addons/Female_Norseman_1.gif b/images/addons/Female_Norseman_1.gif new file mode 100644 index 00000000..ed558ff5 Binary files /dev/null and b/images/addons/Female_Norseman_1.gif differ diff --git a/images/addons/Female_Norseman_2.gif b/images/addons/Female_Norseman_2.gif new file mode 100644 index 00000000..ecc8a602 Binary files /dev/null and b/images/addons/Female_Norseman_2.gif differ diff --git a/images/addons/Female_Oriental_1.gif b/images/addons/Female_Oriental_1.gif new file mode 100644 index 00000000..a7dfbb1b Binary files /dev/null and b/images/addons/Female_Oriental_1.gif differ diff --git a/images/addons/Female_Oriental_2.gif b/images/addons/Female_Oriental_2.gif new file mode 100644 index 00000000..a7217b29 Binary files /dev/null and b/images/addons/Female_Oriental_2.gif differ diff --git a/images/addons/Female_Pirate_1.gif b/images/addons/Female_Pirate_1.gif new file mode 100644 index 00000000..5377746c Binary files /dev/null and b/images/addons/Female_Pirate_1.gif differ diff --git a/images/addons/Female_Pirate_2.gif b/images/addons/Female_Pirate_2.gif new file mode 100644 index 00000000..e1ac50f1 Binary files /dev/null and b/images/addons/Female_Pirate_2.gif differ diff --git a/images/addons/Female_Shaman_1.gif b/images/addons/Female_Shaman_1.gif new file mode 100644 index 00000000..609ad678 Binary files /dev/null and b/images/addons/Female_Shaman_1.gif differ diff --git a/images/addons/Female_Shaman_2.gif b/images/addons/Female_Shaman_2.gif new file mode 100644 index 00000000..e71dd2a4 Binary files /dev/null and b/images/addons/Female_Shaman_2.gif differ diff --git a/images/addons/Female_Summoner_1.gif b/images/addons/Female_Summoner_1.gif new file mode 100644 index 00000000..952e42eb Binary files /dev/null and b/images/addons/Female_Summoner_1.gif differ diff --git a/images/addons/Female_Summoner_2.gif b/images/addons/Female_Summoner_2.gif new file mode 100644 index 00000000..eb135bb9 Binary files /dev/null and b/images/addons/Female_Summoner_2.gif differ diff --git a/images/addons/Female_Warrior_1.gif b/images/addons/Female_Warrior_1.gif new file mode 100644 index 00000000..d126fb4b Binary files /dev/null and b/images/addons/Female_Warrior_1.gif differ diff --git a/images/addons/Female_Warrior_2.gif b/images/addons/Female_Warrior_2.gif new file mode 100644 index 00000000..0ecd5a38 Binary files /dev/null and b/images/addons/Female_Warrior_2.gif differ diff --git a/images/addons/Female_Wizard_1.gif b/images/addons/Female_Wizard_1.gif new file mode 100644 index 00000000..544fc8a3 Binary files /dev/null and b/images/addons/Female_Wizard_1.gif differ diff --git a/images/addons/Female_Wizard_2.gif b/images/addons/Female_Wizard_2.gif new file mode 100644 index 00000000..9b9d7c77 Binary files /dev/null and b/images/addons/Female_Wizard_2.gif differ diff --git a/images/addons/Male_Assassin_1.gif b/images/addons/Male_Assassin_1.gif new file mode 100644 index 00000000..99c3bfdb Binary files /dev/null and b/images/addons/Male_Assassin_1.gif differ diff --git a/images/addons/Male_Assassin_2.gif b/images/addons/Male_Assassin_2.gif new file mode 100644 index 00000000..f9b333b1 Binary files /dev/null and b/images/addons/Male_Assassin_2.gif differ diff --git a/images/addons/Male_Barbarian_1.gif b/images/addons/Male_Barbarian_1.gif new file mode 100644 index 00000000..15a9dd95 Binary files /dev/null and b/images/addons/Male_Barbarian_1.gif differ diff --git a/images/addons/Male_Barbarian_2.gif b/images/addons/Male_Barbarian_2.gif new file mode 100644 index 00000000..f85e05a8 Binary files /dev/null and b/images/addons/Male_Barbarian_2.gif differ diff --git a/images/addons/Male_Beggar_1.gif b/images/addons/Male_Beggar_1.gif new file mode 100644 index 00000000..0b315c4e Binary files /dev/null and b/images/addons/Male_Beggar_1.gif differ diff --git a/images/addons/Male_Beggar_2.gif b/images/addons/Male_Beggar_2.gif new file mode 100644 index 00000000..a752ca21 Binary files /dev/null and b/images/addons/Male_Beggar_2.gif differ diff --git a/images/addons/Male_Brotherhood_1.gif b/images/addons/Male_Brotherhood_1.gif new file mode 100644 index 00000000..cef9b046 Binary files /dev/null and b/images/addons/Male_Brotherhood_1.gif differ diff --git a/images/addons/Male_Brotherhood_2.gif b/images/addons/Male_Brotherhood_2.gif new file mode 100644 index 00000000..cb7f99b5 Binary files /dev/null and b/images/addons/Male_Brotherhood_2.gif differ diff --git a/images/addons/Male_Citizen_1.gif b/images/addons/Male_Citizen_1.gif new file mode 100644 index 00000000..b560b15f Binary files /dev/null and b/images/addons/Male_Citizen_1.gif differ diff --git a/images/addons/Male_Citizen_2.gif b/images/addons/Male_Citizen_2.gif new file mode 100644 index 00000000..ca542bfb Binary files /dev/null and b/images/addons/Male_Citizen_2.gif differ diff --git a/images/addons/Male_Demonhunter_1.gif b/images/addons/Male_Demonhunter_1.gif new file mode 100644 index 00000000..65b2bc7d Binary files /dev/null and b/images/addons/Male_Demonhunter_1.gif differ diff --git a/images/addons/Male_Demonhunter_2.gif b/images/addons/Male_Demonhunter_2.gif new file mode 100644 index 00000000..5eb7cf2c Binary files /dev/null and b/images/addons/Male_Demonhunter_2.gif differ diff --git a/images/addons/Male_Druid_1.gif b/images/addons/Male_Druid_1.gif new file mode 100644 index 00000000..dcf022ef Binary files /dev/null and b/images/addons/Male_Druid_1.gif differ diff --git a/images/addons/Male_Druid_2.gif b/images/addons/Male_Druid_2.gif new file mode 100644 index 00000000..c73da4a5 Binary files /dev/null and b/images/addons/Male_Druid_2.gif differ diff --git a/images/addons/Male_Hunter_1.gif b/images/addons/Male_Hunter_1.gif new file mode 100644 index 00000000..505823df Binary files /dev/null and b/images/addons/Male_Hunter_1.gif differ diff --git a/images/addons/Male_Hunter_2.gif b/images/addons/Male_Hunter_2.gif new file mode 100644 index 00000000..f3bc5136 Binary files /dev/null and b/images/addons/Male_Hunter_2.gif differ diff --git a/images/addons/Male_Jester_1.gif b/images/addons/Male_Jester_1.gif new file mode 100644 index 00000000..1719e0c2 Binary files /dev/null and b/images/addons/Male_Jester_1.gif differ diff --git a/images/addons/Male_Jester_2.gif b/images/addons/Male_Jester_2.gif new file mode 100644 index 00000000..5a6a69c9 Binary files /dev/null and b/images/addons/Male_Jester_2.gif differ diff --git a/images/addons/Male_Knight_1.gif b/images/addons/Male_Knight_1.gif new file mode 100644 index 00000000..e79fd012 Binary files /dev/null and b/images/addons/Male_Knight_1.gif differ diff --git a/images/addons/Male_Knight_2.gif b/images/addons/Male_Knight_2.gif new file mode 100644 index 00000000..8b2670ed Binary files /dev/null and b/images/addons/Male_Knight_2.gif differ diff --git a/images/addons/Male_Mage_1.gif b/images/addons/Male_Mage_1.gif new file mode 100644 index 00000000..c6f89cdc Binary files /dev/null and b/images/addons/Male_Mage_1.gif differ diff --git a/images/addons/Male_Mage_2.gif b/images/addons/Male_Mage_2.gif new file mode 100644 index 00000000..9c19eb8f Binary files /dev/null and b/images/addons/Male_Mage_2.gif differ diff --git a/images/addons/Male_Nightmare_1.gif b/images/addons/Male_Nightmare_1.gif new file mode 100644 index 00000000..520453d7 Binary files /dev/null and b/images/addons/Male_Nightmare_1.gif differ diff --git a/images/addons/Male_Nightmare_2.gif b/images/addons/Male_Nightmare_2.gif new file mode 100644 index 00000000..028ec3e3 Binary files /dev/null and b/images/addons/Male_Nightmare_2.gif differ diff --git a/images/addons/Male_Nobleman_1.gif b/images/addons/Male_Nobleman_1.gif new file mode 100644 index 00000000..410370ef Binary files /dev/null and b/images/addons/Male_Nobleman_1.gif differ diff --git a/images/addons/Male_Nobleman_2.gif b/images/addons/Male_Nobleman_2.gif new file mode 100644 index 00000000..05ee40a1 Binary files /dev/null and b/images/addons/Male_Nobleman_2.gif differ diff --git a/images/addons/Male_Norseman_1.gif b/images/addons/Male_Norseman_1.gif new file mode 100644 index 00000000..7f788631 Binary files /dev/null and b/images/addons/Male_Norseman_1.gif differ diff --git a/images/addons/Male_Norseman_2.gif b/images/addons/Male_Norseman_2.gif new file mode 100644 index 00000000..a641f728 Binary files /dev/null and b/images/addons/Male_Norseman_2.gif differ diff --git a/images/addons/Male_Oriental_1.gif b/images/addons/Male_Oriental_1.gif new file mode 100644 index 00000000..76e97710 Binary files /dev/null and b/images/addons/Male_Oriental_1.gif differ diff --git a/images/addons/Male_Oriental_2.gif b/images/addons/Male_Oriental_2.gif new file mode 100644 index 00000000..e694a97c Binary files /dev/null and b/images/addons/Male_Oriental_2.gif differ diff --git a/images/addons/Male_Pirate_1.gif b/images/addons/Male_Pirate_1.gif new file mode 100644 index 00000000..f28289b0 Binary files /dev/null and b/images/addons/Male_Pirate_1.gif differ diff --git a/images/addons/Male_Pirate_2.gif b/images/addons/Male_Pirate_2.gif new file mode 100644 index 00000000..6f75eb7c Binary files /dev/null and b/images/addons/Male_Pirate_2.gif differ diff --git a/images/addons/Male_Shaman_1.gif b/images/addons/Male_Shaman_1.gif new file mode 100644 index 00000000..840b57be Binary files /dev/null and b/images/addons/Male_Shaman_1.gif differ diff --git a/images/addons/Male_Shaman_2.gif b/images/addons/Male_Shaman_2.gif new file mode 100644 index 00000000..c532dac5 Binary files /dev/null and b/images/addons/Male_Shaman_2.gif differ diff --git a/images/addons/Male_Summoner_1.gif b/images/addons/Male_Summoner_1.gif new file mode 100644 index 00000000..0cad1dcc Binary files /dev/null and b/images/addons/Male_Summoner_1.gif differ diff --git a/images/addons/Male_Summoner_2.gif b/images/addons/Male_Summoner_2.gif new file mode 100644 index 00000000..de917f25 Binary files /dev/null and b/images/addons/Male_Summoner_2.gif differ diff --git a/images/addons/Male_Warrior_1.gif b/images/addons/Male_Warrior_1.gif new file mode 100644 index 00000000..d1ef88be Binary files /dev/null and b/images/addons/Male_Warrior_1.gif differ diff --git a/images/addons/Male_Warrior_2.gif b/images/addons/Male_Warrior_2.gif new file mode 100644 index 00000000..2f341481 Binary files /dev/null and b/images/addons/Male_Warrior_2.gif differ diff --git a/images/addons/Male_Wizard_1.gif b/images/addons/Male_Wizard_1.gif new file mode 100644 index 00000000..3d4f550b Binary files /dev/null and b/images/addons/Male_Wizard_1.gif differ diff --git a/images/addons/Male_Wizard_2.gif b/images/addons/Male_Wizard_2.gif new file mode 100644 index 00000000..996b53d7 Binary files /dev/null and b/images/addons/Male_Wizard_2.gif differ diff --git a/images/arrow_left.gif b/images/arrow_left.gif new file mode 100644 index 00000000..8b2988d8 Binary files /dev/null and b/images/arrow_left.gif differ diff --git a/images/arrow_right.gif b/images/arrow_right.gif new file mode 100644 index 00000000..6239eba2 Binary files /dev/null and b/images/arrow_right.gif differ diff --git a/images/arrow_up.gif b/images/arrow_up.gif new file mode 100644 index 00000000..8ea2c8f6 Binary files /dev/null and b/images/arrow_up.gif differ diff --git a/images/blackskull.gif b/images/blackskull.gif new file mode 100644 index 00000000..c9c769ee Binary files /dev/null and b/images/blackskull.gif differ diff --git a/images/changelog/added.png b/images/changelog/added.png new file mode 100644 index 00000000..33b069bc Binary files /dev/null and b/images/changelog/added.png differ diff --git a/images/changelog/changed.png b/images/changelog/changed.png new file mode 100644 index 00000000..33b069bc Binary files /dev/null and b/images/changelog/changed.png differ diff --git a/images/changelog/fixed.png b/images/changelog/fixed.png new file mode 100644 index 00000000..a5ae9f11 Binary files /dev/null and b/images/changelog/fixed.png differ diff --git a/images/changelog/removed.png b/images/changelog/removed.png new file mode 100644 index 00000000..33b069bc Binary files /dev/null and b/images/changelog/removed.png differ diff --git a/images/changelog/server.png b/images/changelog/server.png new file mode 100644 index 00000000..8e8dd843 Binary files /dev/null and b/images/changelog/server.png differ diff --git a/images/changelog/website.png b/images/changelog/website.png new file mode 100644 index 00000000..578d29d8 Binary files /dev/null and b/images/changelog/website.png differ diff --git a/images/del.png b/images/del.png new file mode 100644 index 00000000..a3260d71 Binary files /dev/null and b/images/del.png differ diff --git a/images/druid.png b/images/druid.png new file mode 100644 index 00000000..2f2de82c Binary files /dev/null and b/images/druid.png differ diff --git a/images/edit.png b/images/edit.png new file mode 100644 index 00000000..0bfecd50 Binary files /dev/null and b/images/edit.png differ diff --git a/images/error.png b/images/error.png new file mode 100644 index 00000000..8a1ba4c6 Binary files /dev/null and b/images/error.png differ diff --git a/images/false.png b/images/false.png new file mode 100644 index 00000000..9bfb378c Binary files /dev/null and b/images/false.png differ diff --git a/images/flags/ad.gif b/images/flags/ad.gif new file mode 100644 index 00000000..57b49973 Binary files /dev/null and b/images/flags/ad.gif differ diff --git a/images/flags/ae.gif b/images/flags/ae.gif new file mode 100644 index 00000000..78d15b67 Binary files /dev/null and b/images/flags/ae.gif differ diff --git a/images/flags/af.gif b/images/flags/af.gif new file mode 100644 index 00000000..98894082 Binary files /dev/null and b/images/flags/af.gif differ diff --git a/images/flags/ag.gif b/images/flags/ag.gif new file mode 100644 index 00000000..48f8e7bc Binary files /dev/null and b/images/flags/ag.gif differ diff --git a/images/flags/ai.gif b/images/flags/ai.gif new file mode 100644 index 00000000..1cbc5795 Binary files /dev/null and b/images/flags/ai.gif differ diff --git a/images/flags/al.gif b/images/flags/al.gif new file mode 100644 index 00000000..c44fe0a0 Binary files /dev/null and b/images/flags/al.gif differ diff --git a/images/flags/am.gif b/images/flags/am.gif new file mode 100644 index 00000000..2915e30c Binary files /dev/null and b/images/flags/am.gif differ diff --git a/images/flags/an.gif b/images/flags/an.gif new file mode 100644 index 00000000..cb570c67 Binary files /dev/null and b/images/flags/an.gif differ diff --git a/images/flags/ao.gif b/images/flags/ao.gif new file mode 100644 index 00000000..8c854fa1 Binary files /dev/null and b/images/flags/ao.gif differ diff --git a/images/flags/aq.gif b/images/flags/aq.gif new file mode 100644 index 00000000..84503388 Binary files /dev/null and b/images/flags/aq.gif differ diff --git a/images/flags/ar.gif b/images/flags/ar.gif new file mode 100644 index 00000000..a9f71f7d Binary files /dev/null and b/images/flags/ar.gif differ diff --git a/images/flags/as.gif b/images/flags/as.gif new file mode 100644 index 00000000..d776ec27 Binary files /dev/null and b/images/flags/as.gif differ diff --git a/images/flags/at.gif b/images/flags/at.gif new file mode 100644 index 00000000..87e12173 Binary files /dev/null and b/images/flags/at.gif differ diff --git a/images/flags/au.gif b/images/flags/au.gif new file mode 100644 index 00000000..5269c6a0 Binary files /dev/null and b/images/flags/au.gif differ diff --git a/images/flags/aw.gif b/images/flags/aw.gif new file mode 100644 index 00000000..27fdb4d1 Binary files /dev/null and b/images/flags/aw.gif differ diff --git a/images/flags/ax.gif b/images/flags/ax.gif new file mode 100644 index 00000000..0ceb6849 Binary files /dev/null and b/images/flags/ax.gif differ diff --git a/images/flags/az.gif b/images/flags/az.gif new file mode 100644 index 00000000..d7716184 Binary files /dev/null and b/images/flags/az.gif differ diff --git a/images/flags/ba.gif b/images/flags/ba.gif new file mode 100644 index 00000000..9bf5f0ac Binary files /dev/null and b/images/flags/ba.gif differ diff --git a/images/flags/bb.gif b/images/flags/bb.gif new file mode 100644 index 00000000..b7d08e57 Binary files /dev/null and b/images/flags/bb.gif differ diff --git a/images/flags/bd.gif b/images/flags/bd.gif new file mode 100644 index 00000000..0fd27eca Binary files /dev/null and b/images/flags/bd.gif differ diff --git a/images/flags/be.gif b/images/flags/be.gif new file mode 100644 index 00000000..ae09bfbe Binary files /dev/null and b/images/flags/be.gif differ diff --git a/images/flags/bf.gif b/images/flags/bf.gif new file mode 100644 index 00000000..9d6772cd Binary files /dev/null and b/images/flags/bf.gif differ diff --git a/images/flags/bg.gif b/images/flags/bg.gif new file mode 100644 index 00000000..11cf8ff3 Binary files /dev/null and b/images/flags/bg.gif differ diff --git a/images/flags/bh.gif b/images/flags/bh.gif new file mode 100644 index 00000000..56aa72b2 Binary files /dev/null and b/images/flags/bh.gif differ diff --git a/images/flags/bi.gif b/images/flags/bi.gif new file mode 100644 index 00000000..6e2cbe12 Binary files /dev/null and b/images/flags/bi.gif differ diff --git a/images/flags/bj.gif b/images/flags/bj.gif new file mode 100644 index 00000000..e676116f Binary files /dev/null and b/images/flags/bj.gif differ diff --git a/images/flags/bm.gif b/images/flags/bm.gif new file mode 100644 index 00000000..9feb87bc Binary files /dev/null and b/images/flags/bm.gif differ diff --git a/images/flags/bn.gif b/images/flags/bn.gif new file mode 100644 index 00000000..b7b6b0f9 Binary files /dev/null and b/images/flags/bn.gif differ diff --git a/images/flags/bo.gif b/images/flags/bo.gif new file mode 100644 index 00000000..4844f856 Binary files /dev/null and b/images/flags/bo.gif differ diff --git a/images/flags/br.gif b/images/flags/br.gif new file mode 100644 index 00000000..8c866162 Binary files /dev/null and b/images/flags/br.gif differ diff --git a/images/flags/bs.gif b/images/flags/bs.gif new file mode 100644 index 00000000..c0a741e5 Binary files /dev/null and b/images/flags/bs.gif differ diff --git a/images/flags/bt.gif b/images/flags/bt.gif new file mode 100644 index 00000000..abe2f3cc Binary files /dev/null and b/images/flags/bt.gif differ diff --git a/images/flags/bv.gif b/images/flags/bv.gif new file mode 100644 index 00000000..6202d1f3 Binary files /dev/null and b/images/flags/bv.gif differ diff --git a/images/flags/bw.gif b/images/flags/bw.gif new file mode 100644 index 00000000..986ab63c Binary files /dev/null and b/images/flags/bw.gif differ diff --git a/images/flags/by.gif b/images/flags/by.gif new file mode 100644 index 00000000..43ffcd4c Binary files /dev/null and b/images/flags/by.gif differ diff --git a/images/flags/bz.gif b/images/flags/bz.gif new file mode 100644 index 00000000..791737f0 Binary files /dev/null and b/images/flags/bz.gif differ diff --git a/images/flags/ca.gif b/images/flags/ca.gif new file mode 100644 index 00000000..457d9662 Binary files /dev/null and b/images/flags/ca.gif differ diff --git a/images/flags/catalonia.gif b/images/flags/catalonia.gif new file mode 100644 index 00000000..73df9a04 Binary files /dev/null and b/images/flags/catalonia.gif differ diff --git a/images/flags/cc.gif b/images/flags/cc.gif new file mode 100644 index 00000000..3f783270 Binary files /dev/null and b/images/flags/cc.gif differ diff --git a/images/flags/cd.gif b/images/flags/cd.gif new file mode 100644 index 00000000..1df717ae Binary files /dev/null and b/images/flags/cd.gif differ diff --git a/images/flags/cf.gif b/images/flags/cf.gif new file mode 100644 index 00000000..35787ca4 Binary files /dev/null and b/images/flags/cf.gif differ diff --git a/images/flags/cg.gif b/images/flags/cg.gif new file mode 100644 index 00000000..e0a62a51 Binary files /dev/null and b/images/flags/cg.gif differ diff --git a/images/flags/ch.gif b/images/flags/ch.gif new file mode 100644 index 00000000..d5c0e5b7 Binary files /dev/null and b/images/flags/ch.gif differ diff --git a/images/flags/ci.gif b/images/flags/ci.gif new file mode 100644 index 00000000..844120a5 Binary files /dev/null and b/images/flags/ci.gif differ diff --git a/images/flags/ck.gif b/images/flags/ck.gif new file mode 100644 index 00000000..2edb7399 Binary files /dev/null and b/images/flags/ck.gif differ diff --git a/images/flags/cl.gif b/images/flags/cl.gif new file mode 100644 index 00000000..cbc370e6 Binary files /dev/null and b/images/flags/cl.gif differ diff --git a/images/flags/cm.gif b/images/flags/cm.gif new file mode 100644 index 00000000..1fb102b2 Binary files /dev/null and b/images/flags/cm.gif differ diff --git a/images/flags/cn.gif b/images/flags/cn.gif new file mode 100644 index 00000000..b0525309 Binary files /dev/null and b/images/flags/cn.gif differ diff --git a/images/flags/co.gif b/images/flags/co.gif new file mode 100644 index 00000000..d0e15caf Binary files /dev/null and b/images/flags/co.gif differ diff --git a/images/flags/cr.gif b/images/flags/cr.gif new file mode 100644 index 00000000..0728dd6a Binary files /dev/null and b/images/flags/cr.gif differ diff --git a/images/flags/cs.gif b/images/flags/cs.gif new file mode 100644 index 00000000..101db649 Binary files /dev/null and b/images/flags/cs.gif differ diff --git a/images/flags/cu.gif b/images/flags/cu.gif new file mode 100644 index 00000000..291255ca Binary files /dev/null and b/images/flags/cu.gif differ diff --git a/images/flags/cv.gif b/images/flags/cv.gif new file mode 100644 index 00000000..43c6c6cb Binary files /dev/null and b/images/flags/cv.gif differ diff --git a/images/flags/cx.gif b/images/flags/cx.gif new file mode 100644 index 00000000..a5b43089 Binary files /dev/null and b/images/flags/cx.gif differ diff --git a/images/flags/cy.gif b/images/flags/cy.gif new file mode 100644 index 00000000..35c661e1 Binary files /dev/null and b/images/flags/cy.gif differ diff --git a/images/flags/cz.gif b/images/flags/cz.gif new file mode 100644 index 00000000..0a605e58 Binary files /dev/null and b/images/flags/cz.gif differ diff --git a/images/flags/de.gif b/images/flags/de.gif new file mode 100644 index 00000000..75728ddf Binary files /dev/null and b/images/flags/de.gif differ diff --git a/images/flags/dj.gif b/images/flags/dj.gif new file mode 100644 index 00000000..212406d9 Binary files /dev/null and b/images/flags/dj.gif differ diff --git a/images/flags/dk.gif b/images/flags/dk.gif new file mode 100644 index 00000000..03e75bd2 Binary files /dev/null and b/images/flags/dk.gif differ diff --git a/images/flags/dm.gif b/images/flags/dm.gif new file mode 100644 index 00000000..2f87f3ca Binary files /dev/null and b/images/flags/dm.gif differ diff --git a/images/flags/do.gif b/images/flags/do.gif new file mode 100644 index 00000000..f7d0bad3 Binary files /dev/null and b/images/flags/do.gif differ diff --git a/images/flags/dz.gif b/images/flags/dz.gif new file mode 100644 index 00000000..ed580a7c Binary files /dev/null and b/images/flags/dz.gif differ diff --git a/images/flags/ec.gif b/images/flags/ec.gif new file mode 100644 index 00000000..9e41e0ec Binary files /dev/null and b/images/flags/ec.gif differ diff --git a/images/flags/ee.gif b/images/flags/ee.gif new file mode 100644 index 00000000..9397a2d0 Binary files /dev/null and b/images/flags/ee.gif differ diff --git a/images/flags/eg.gif b/images/flags/eg.gif new file mode 100644 index 00000000..6857c7dd Binary files /dev/null and b/images/flags/eg.gif differ diff --git a/images/flags/eh.gif b/images/flags/eh.gif new file mode 100644 index 00000000..dd0391c2 Binary files /dev/null and b/images/flags/eh.gif differ diff --git a/images/flags/england.gif b/images/flags/england.gif new file mode 100644 index 00000000..933a4f0b Binary files /dev/null and b/images/flags/england.gif differ diff --git a/images/flags/er.gif b/images/flags/er.gif new file mode 100644 index 00000000..3d4d612c Binary files /dev/null and b/images/flags/er.gif differ diff --git a/images/flags/es.gif b/images/flags/es.gif new file mode 100644 index 00000000..c27d65e5 Binary files /dev/null and b/images/flags/es.gif differ diff --git a/images/flags/et.gif b/images/flags/et.gif new file mode 100644 index 00000000..f77995d0 Binary files /dev/null and b/images/flags/et.gif differ diff --git a/images/flags/europeanunion.gif b/images/flags/europeanunion.gif new file mode 100644 index 00000000..28a762a5 Binary files /dev/null and b/images/flags/europeanunion.gif differ diff --git a/images/flags/fam.gif b/images/flags/fam.gif new file mode 100644 index 00000000..7d528852 Binary files /dev/null and b/images/flags/fam.gif differ diff --git a/images/flags/fi.gif b/images/flags/fi.gif new file mode 100644 index 00000000..8d3a1918 Binary files /dev/null and b/images/flags/fi.gif differ diff --git a/images/flags/fj.gif b/images/flags/fj.gif new file mode 100644 index 00000000..486151cb Binary files /dev/null and b/images/flags/fj.gif differ diff --git a/images/flags/fk.gif b/images/flags/fk.gif new file mode 100644 index 00000000..37b5ecf3 Binary files /dev/null and b/images/flags/fk.gif differ diff --git a/images/flags/fm.gif b/images/flags/fm.gif new file mode 100644 index 00000000..7f8723b7 Binary files /dev/null and b/images/flags/fm.gif differ diff --git a/images/flags/fo.gif b/images/flags/fo.gif new file mode 100644 index 00000000..4a90fc04 Binary files /dev/null and b/images/flags/fo.gif differ diff --git a/images/flags/fr.gif b/images/flags/fr.gif new file mode 100644 index 00000000..43d0b801 Binary files /dev/null and b/images/flags/fr.gif differ diff --git a/images/flags/ga.gif b/images/flags/ga.gif new file mode 100644 index 00000000..23fd5f0d Binary files /dev/null and b/images/flags/ga.gif differ diff --git a/images/flags/gb.gif b/images/flags/gb.gif new file mode 100644 index 00000000..3c6bce15 Binary files /dev/null and b/images/flags/gb.gif differ diff --git a/images/flags/gd.gif b/images/flags/gd.gif new file mode 100644 index 00000000..25ea3123 Binary files /dev/null and b/images/flags/gd.gif differ diff --git a/images/flags/ge.gif b/images/flags/ge.gif new file mode 100644 index 00000000..faa7f126 Binary files /dev/null and b/images/flags/ge.gif differ diff --git a/images/flags/gf.gif b/images/flags/gf.gif new file mode 100644 index 00000000..43d0b801 Binary files /dev/null and b/images/flags/gf.gif differ diff --git a/images/flags/gh.gif b/images/flags/gh.gif new file mode 100644 index 00000000..273fb7d1 Binary files /dev/null and b/images/flags/gh.gif differ diff --git a/images/flags/gi.gif b/images/flags/gi.gif new file mode 100644 index 00000000..7b1984bc Binary files /dev/null and b/images/flags/gi.gif differ diff --git a/images/flags/gl.gif b/images/flags/gl.gif new file mode 100644 index 00000000..ef445be0 Binary files /dev/null and b/images/flags/gl.gif differ diff --git a/images/flags/gm.gif b/images/flags/gm.gif new file mode 100644 index 00000000..6847c5a8 Binary files /dev/null and b/images/flags/gm.gif differ diff --git a/images/flags/gn.gif b/images/flags/gn.gif new file mode 100644 index 00000000..a982ac6f Binary files /dev/null and b/images/flags/gn.gif differ diff --git a/images/flags/gp.gif b/images/flags/gp.gif new file mode 100644 index 00000000..31166db6 Binary files /dev/null and b/images/flags/gp.gif differ diff --git a/images/flags/gq.gif b/images/flags/gq.gif new file mode 100644 index 00000000..8b4e0cc4 Binary files /dev/null and b/images/flags/gq.gif differ diff --git a/images/flags/gr.gif b/images/flags/gr.gif new file mode 100644 index 00000000..b4c8c04e Binary files /dev/null and b/images/flags/gr.gif differ diff --git a/images/flags/gs.gif b/images/flags/gs.gif new file mode 100644 index 00000000..ccc96ec0 Binary files /dev/null and b/images/flags/gs.gif differ diff --git a/images/flags/gt.gif b/images/flags/gt.gif new file mode 100644 index 00000000..7e94d1dd Binary files /dev/null and b/images/flags/gt.gif differ diff --git a/images/flags/gu.gif b/images/flags/gu.gif new file mode 100644 index 00000000..eafef683 Binary files /dev/null and b/images/flags/gu.gif differ diff --git a/images/flags/gw.gif b/images/flags/gw.gif new file mode 100644 index 00000000..55f75711 Binary files /dev/null and b/images/flags/gw.gif differ diff --git a/images/flags/gy.gif b/images/flags/gy.gif new file mode 100644 index 00000000..1cb4cd71 Binary files /dev/null and b/images/flags/gy.gif differ diff --git a/images/flags/hk.gif b/images/flags/hk.gif new file mode 100644 index 00000000..798af96d Binary files /dev/null and b/images/flags/hk.gif differ diff --git a/images/flags/hm.gif b/images/flags/hm.gif new file mode 100644 index 00000000..5269c6a0 Binary files /dev/null and b/images/flags/hm.gif differ diff --git a/images/flags/hn.gif b/images/flags/hn.gif new file mode 100644 index 00000000..6c4ffe8e Binary files /dev/null and b/images/flags/hn.gif differ diff --git a/images/flags/hr.gif b/images/flags/hr.gif new file mode 100644 index 00000000..557c6602 Binary files /dev/null and b/images/flags/hr.gif differ diff --git a/images/flags/ht.gif b/images/flags/ht.gif new file mode 100644 index 00000000..059604ab Binary files /dev/null and b/images/flags/ht.gif differ diff --git a/images/flags/hu.gif b/images/flags/hu.gif new file mode 100644 index 00000000..6142d868 Binary files /dev/null and b/images/flags/hu.gif differ diff --git a/images/flags/id.gif b/images/flags/id.gif new file mode 100644 index 00000000..865161b0 Binary files /dev/null and b/images/flags/id.gif differ diff --git a/images/flags/ie.gif b/images/flags/ie.gif new file mode 100644 index 00000000..506ad285 Binary files /dev/null and b/images/flags/ie.gif differ diff --git a/images/flags/il.gif b/images/flags/il.gif new file mode 100644 index 00000000..c8483ae5 Binary files /dev/null and b/images/flags/il.gif differ diff --git a/images/flags/in.gif b/images/flags/in.gif new file mode 100644 index 00000000..1cd80272 Binary files /dev/null and b/images/flags/in.gif differ diff --git a/images/flags/io.gif b/images/flags/io.gif new file mode 100644 index 00000000..de7e7ab3 Binary files /dev/null and b/images/flags/io.gif differ diff --git a/images/flags/iq.gif b/images/flags/iq.gif new file mode 100644 index 00000000..c34fe3c4 Binary files /dev/null and b/images/flags/iq.gif differ diff --git a/images/flags/ir.gif b/images/flags/ir.gif new file mode 100644 index 00000000..156040fc Binary files /dev/null and b/images/flags/ir.gif differ diff --git a/images/flags/is.gif b/images/flags/is.gif new file mode 100644 index 00000000..b42502de Binary files /dev/null and b/images/flags/is.gif differ diff --git a/images/flags/it.gif b/images/flags/it.gif new file mode 100644 index 00000000..d79e90e9 Binary files /dev/null and b/images/flags/it.gif differ diff --git a/images/flags/jm.gif b/images/flags/jm.gif new file mode 100644 index 00000000..0bed67c2 Binary files /dev/null and b/images/flags/jm.gif differ diff --git a/images/flags/jo.gif b/images/flags/jo.gif new file mode 100644 index 00000000..03daf8af Binary files /dev/null and b/images/flags/jo.gif differ diff --git a/images/flags/jp.gif b/images/flags/jp.gif new file mode 100644 index 00000000..444c1d05 Binary files /dev/null and b/images/flags/jp.gif differ diff --git a/images/flags/ke.gif b/images/flags/ke.gif new file mode 100644 index 00000000..c2b5d45c Binary files /dev/null and b/images/flags/ke.gif differ diff --git a/images/flags/kg.gif b/images/flags/kg.gif new file mode 100644 index 00000000..72a4d412 Binary files /dev/null and b/images/flags/kg.gif differ diff --git a/images/flags/kh.gif b/images/flags/kh.gif new file mode 100644 index 00000000..30a18315 Binary files /dev/null and b/images/flags/kh.gif differ diff --git a/images/flags/ki.gif b/images/flags/ki.gif new file mode 100644 index 00000000..4a0751a2 Binary files /dev/null and b/images/flags/ki.gif differ diff --git a/images/flags/km.gif b/images/flags/km.gif new file mode 100644 index 00000000..5859595e Binary files /dev/null and b/images/flags/km.gif differ diff --git a/images/flags/kn.gif b/images/flags/kn.gif new file mode 100644 index 00000000..bb9cc34a Binary files /dev/null and b/images/flags/kn.gif differ diff --git a/images/flags/kp.gif b/images/flags/kp.gif new file mode 100644 index 00000000..6e0ca09e Binary files /dev/null and b/images/flags/kp.gif differ diff --git a/images/flags/kr.gif b/images/flags/kr.gif new file mode 100644 index 00000000..1cddbe75 Binary files /dev/null and b/images/flags/kr.gif differ diff --git a/images/flags/kw.gif b/images/flags/kw.gif new file mode 100644 index 00000000..1efc7347 Binary files /dev/null and b/images/flags/kw.gif differ diff --git a/images/flags/ky.gif b/images/flags/ky.gif new file mode 100644 index 00000000..d3d02ee4 Binary files /dev/null and b/images/flags/ky.gif differ diff --git a/images/flags/kz.gif b/images/flags/kz.gif new file mode 100644 index 00000000..24baebe0 Binary files /dev/null and b/images/flags/kz.gif differ diff --git a/images/flags/la.gif b/images/flags/la.gif new file mode 100644 index 00000000..d14cf4d8 Binary files /dev/null and b/images/flags/la.gif differ diff --git a/images/flags/lb.gif b/images/flags/lb.gif new file mode 100644 index 00000000..003d83af Binary files /dev/null and b/images/flags/lb.gif differ diff --git a/images/flags/lc.gif b/images/flags/lc.gif new file mode 100644 index 00000000..f5fe5bff Binary files /dev/null and b/images/flags/lc.gif differ diff --git a/images/flags/li.gif b/images/flags/li.gif new file mode 100644 index 00000000..713c58e1 Binary files /dev/null and b/images/flags/li.gif differ diff --git a/images/flags/lk.gif b/images/flags/lk.gif new file mode 100644 index 00000000..1b3ee7f5 Binary files /dev/null and b/images/flags/lk.gif differ diff --git a/images/flags/lr.gif b/images/flags/lr.gif new file mode 100644 index 00000000..435af9e5 Binary files /dev/null and b/images/flags/lr.gif differ diff --git a/images/flags/ls.gif b/images/flags/ls.gif new file mode 100644 index 00000000..427ae957 Binary files /dev/null and b/images/flags/ls.gif differ diff --git a/images/flags/lt.gif b/images/flags/lt.gif new file mode 100644 index 00000000..dee9c601 Binary files /dev/null and b/images/flags/lt.gif differ diff --git a/images/flags/lu.gif b/images/flags/lu.gif new file mode 100644 index 00000000..7d7293ed Binary files /dev/null and b/images/flags/lu.gif differ diff --git a/images/flags/lv.gif b/images/flags/lv.gif new file mode 100644 index 00000000..17e71b7e Binary files /dev/null and b/images/flags/lv.gif differ diff --git a/images/flags/ly.gif b/images/flags/ly.gif new file mode 100644 index 00000000..a654c30a Binary files /dev/null and b/images/flags/ly.gif differ diff --git a/images/flags/ma.gif b/images/flags/ma.gif new file mode 100644 index 00000000..fc784119 Binary files /dev/null and b/images/flags/ma.gif differ diff --git a/images/flags/mc.gif b/images/flags/mc.gif new file mode 100644 index 00000000..02a7c8e1 Binary files /dev/null and b/images/flags/mc.gif differ diff --git a/images/flags/md.gif b/images/flags/md.gif new file mode 100644 index 00000000..e4b8a7e3 Binary files /dev/null and b/images/flags/md.gif differ diff --git a/images/flags/me.gif b/images/flags/me.gif new file mode 100644 index 00000000..a260453c Binary files /dev/null and b/images/flags/me.gif differ diff --git a/images/flags/mg.gif b/images/flags/mg.gif new file mode 100644 index 00000000..a91b577d Binary files /dev/null and b/images/flags/mg.gif differ diff --git a/images/flags/mh.gif b/images/flags/mh.gif new file mode 100644 index 00000000..92f5f485 Binary files /dev/null and b/images/flags/mh.gif differ diff --git a/images/flags/mk.gif b/images/flags/mk.gif new file mode 100644 index 00000000..7aeb8311 Binary files /dev/null and b/images/flags/mk.gif differ diff --git a/images/flags/ml.gif b/images/flags/ml.gif new file mode 100644 index 00000000..53d6f490 Binary files /dev/null and b/images/flags/ml.gif differ diff --git a/images/flags/mm.gif b/images/flags/mm.gif new file mode 100644 index 00000000..9e0a2756 Binary files /dev/null and b/images/flags/mm.gif differ diff --git a/images/flags/mn.gif b/images/flags/mn.gif new file mode 100644 index 00000000..dff8ea5a Binary files /dev/null and b/images/flags/mn.gif differ diff --git a/images/flags/mo.gif b/images/flags/mo.gif new file mode 100644 index 00000000..66cf5b4f Binary files /dev/null and b/images/flags/mo.gif differ diff --git a/images/flags/mp.gif b/images/flags/mp.gif new file mode 100644 index 00000000..73b7147e Binary files /dev/null and b/images/flags/mp.gif differ diff --git a/images/flags/mq.gif b/images/flags/mq.gif new file mode 100644 index 00000000..570bc5dd Binary files /dev/null and b/images/flags/mq.gif differ diff --git a/images/flags/mr.gif b/images/flags/mr.gif new file mode 100644 index 00000000..f52fcf09 Binary files /dev/null and b/images/flags/mr.gif differ diff --git a/images/flags/ms.gif b/images/flags/ms.gif new file mode 100644 index 00000000..5e5a67aa Binary files /dev/null and b/images/flags/ms.gif differ diff --git a/images/flags/mt.gif b/images/flags/mt.gif new file mode 100644 index 00000000..45c709f2 Binary files /dev/null and b/images/flags/mt.gif differ diff --git a/images/flags/mu.gif b/images/flags/mu.gif new file mode 100644 index 00000000..081ab453 Binary files /dev/null and b/images/flags/mu.gif differ diff --git a/images/flags/mv.gif b/images/flags/mv.gif new file mode 100644 index 00000000..46b63875 Binary files /dev/null and b/images/flags/mv.gif differ diff --git a/images/flags/mw.gif b/images/flags/mw.gif new file mode 100644 index 00000000..ad045a09 Binary files /dev/null and b/images/flags/mw.gif differ diff --git a/images/flags/mx.gif b/images/flags/mx.gif new file mode 100644 index 00000000..ddc75d04 Binary files /dev/null and b/images/flags/mx.gif differ diff --git a/images/flags/my.gif b/images/flags/my.gif new file mode 100644 index 00000000..fc7d5236 Binary files /dev/null and b/images/flags/my.gif differ diff --git a/images/flags/mz.gif b/images/flags/mz.gif new file mode 100644 index 00000000..7d635082 Binary files /dev/null and b/images/flags/mz.gif differ diff --git a/images/flags/na.gif b/images/flags/na.gif new file mode 100644 index 00000000..c0babe72 Binary files /dev/null and b/images/flags/na.gif differ diff --git a/images/flags/nc.gif b/images/flags/nc.gif new file mode 100644 index 00000000..b1e91b9a Binary files /dev/null and b/images/flags/nc.gif differ diff --git a/images/flags/ne.gif b/images/flags/ne.gif new file mode 100644 index 00000000..ff4eaf07 Binary files /dev/null and b/images/flags/ne.gif differ diff --git a/images/flags/nf.gif b/images/flags/nf.gif new file mode 100644 index 00000000..c83424c2 Binary files /dev/null and b/images/flags/nf.gif differ diff --git a/images/flags/ng.gif b/images/flags/ng.gif new file mode 100644 index 00000000..bdde7cb3 Binary files /dev/null and b/images/flags/ng.gif differ diff --git a/images/flags/ni.gif b/images/flags/ni.gif new file mode 100644 index 00000000..d05894d0 Binary files /dev/null and b/images/flags/ni.gif differ diff --git a/images/flags/nl.gif b/images/flags/nl.gif new file mode 100644 index 00000000..c1c8f46d Binary files /dev/null and b/images/flags/nl.gif differ diff --git a/images/flags/no.gif b/images/flags/no.gif new file mode 100644 index 00000000..6202d1f3 Binary files /dev/null and b/images/flags/no.gif differ diff --git a/images/flags/np.gif b/images/flags/np.gif new file mode 100644 index 00000000..1096893a Binary files /dev/null and b/images/flags/np.gif differ diff --git a/images/flags/nr.gif b/images/flags/nr.gif new file mode 100644 index 00000000..2e4c0c5c Binary files /dev/null and b/images/flags/nr.gif differ diff --git a/images/flags/nu.gif b/images/flags/nu.gif new file mode 100644 index 00000000..618210a7 Binary files /dev/null and b/images/flags/nu.gif differ diff --git a/images/flags/nz.gif b/images/flags/nz.gif new file mode 100644 index 00000000..028a5dc6 Binary files /dev/null and b/images/flags/nz.gif differ diff --git a/images/flags/om.gif b/images/flags/om.gif new file mode 100644 index 00000000..2b8c7750 Binary files /dev/null and b/images/flags/om.gif differ diff --git a/images/flags/pa.gif b/images/flags/pa.gif new file mode 100644 index 00000000..d518b2f9 Binary files /dev/null and b/images/flags/pa.gif differ diff --git a/images/flags/pe.gif b/images/flags/pe.gif new file mode 100644 index 00000000..3bc76390 Binary files /dev/null and b/images/flags/pe.gif differ diff --git a/images/flags/pf.gif b/images/flags/pf.gif new file mode 100644 index 00000000..849297a5 Binary files /dev/null and b/images/flags/pf.gif differ diff --git a/images/flags/pg.gif b/images/flags/pg.gif new file mode 100644 index 00000000..2d20b078 Binary files /dev/null and b/images/flags/pg.gif differ diff --git a/images/flags/ph.gif b/images/flags/ph.gif new file mode 100644 index 00000000..12b380ac Binary files /dev/null and b/images/flags/ph.gif differ diff --git a/images/flags/pk.gif b/images/flags/pk.gif new file mode 100644 index 00000000..f3f62c2e Binary files /dev/null and b/images/flags/pk.gif differ diff --git a/images/flags/pl.gif b/images/flags/pl.gif new file mode 100644 index 00000000..bf106463 Binary files /dev/null and b/images/flags/pl.gif differ diff --git a/images/flags/pm.gif b/images/flags/pm.gif new file mode 100644 index 00000000..99bf6fdb Binary files /dev/null and b/images/flags/pm.gif differ diff --git a/images/flags/pn.gif b/images/flags/pn.gif new file mode 100644 index 00000000..4bc86a1d Binary files /dev/null and b/images/flags/pn.gif differ diff --git a/images/flags/pr.gif b/images/flags/pr.gif new file mode 100644 index 00000000..6d5d5896 Binary files /dev/null and b/images/flags/pr.gif differ diff --git a/images/flags/ps.gif b/images/flags/ps.gif new file mode 100644 index 00000000..6afa3b71 Binary files /dev/null and b/images/flags/ps.gif differ diff --git a/images/flags/pt.gif b/images/flags/pt.gif new file mode 100644 index 00000000..e735f740 Binary files /dev/null and b/images/flags/pt.gif differ diff --git a/images/flags/pw.gif b/images/flags/pw.gif new file mode 100644 index 00000000..5854510f Binary files /dev/null and b/images/flags/pw.gif differ diff --git a/images/flags/py.gif b/images/flags/py.gif new file mode 100644 index 00000000..f2e66af7 Binary files /dev/null and b/images/flags/py.gif differ diff --git a/images/flags/qa.gif b/images/flags/qa.gif new file mode 100644 index 00000000..2e843ff9 Binary files /dev/null and b/images/flags/qa.gif differ diff --git a/images/flags/re.gif b/images/flags/re.gif new file mode 100644 index 00000000..43d0b801 Binary files /dev/null and b/images/flags/re.gif differ diff --git a/images/flags/ro.gif b/images/flags/ro.gif new file mode 100644 index 00000000..f5d5f125 Binary files /dev/null and b/images/flags/ro.gif differ diff --git a/images/flags/rs.gif b/images/flags/rs.gif new file mode 100644 index 00000000..3bd1fb2f Binary files /dev/null and b/images/flags/rs.gif differ diff --git a/images/flags/ru.gif b/images/flags/ru.gif new file mode 100644 index 00000000..b525c462 Binary files /dev/null and b/images/flags/ru.gif differ diff --git a/images/flags/rw.gif b/images/flags/rw.gif new file mode 100644 index 00000000..0d095f7a Binary files /dev/null and b/images/flags/rw.gif differ diff --git a/images/flags/sa.gif b/images/flags/sa.gif new file mode 100644 index 00000000..179961b6 Binary files /dev/null and b/images/flags/sa.gif differ diff --git a/images/flags/sb.gif b/images/flags/sb.gif new file mode 100644 index 00000000..8f5ff837 Binary files /dev/null and b/images/flags/sb.gif differ diff --git a/images/flags/sc.gif b/images/flags/sc.gif new file mode 100644 index 00000000..31b47677 Binary files /dev/null and b/images/flags/sc.gif differ diff --git a/images/flags/scotland.gif b/images/flags/scotland.gif new file mode 100644 index 00000000..03f3f1de Binary files /dev/null and b/images/flags/scotland.gif differ diff --git a/images/flags/sd.gif b/images/flags/sd.gif new file mode 100644 index 00000000..53ae214f Binary files /dev/null and b/images/flags/sd.gif differ diff --git a/images/flags/se.gif b/images/flags/se.gif new file mode 100644 index 00000000..80f62852 Binary files /dev/null and b/images/flags/se.gif differ diff --git a/images/flags/sg.gif b/images/flags/sg.gif new file mode 100644 index 00000000..5663d39f Binary files /dev/null and b/images/flags/sg.gif differ diff --git a/images/flags/sh.gif b/images/flags/sh.gif new file mode 100644 index 00000000..dcc7f3bc Binary files /dev/null and b/images/flags/sh.gif differ diff --git a/images/flags/si.gif b/images/flags/si.gif new file mode 100644 index 00000000..23852b50 Binary files /dev/null and b/images/flags/si.gif differ diff --git a/images/flags/sj.gif b/images/flags/sj.gif new file mode 100644 index 00000000..6202d1f3 Binary files /dev/null and b/images/flags/sj.gif differ diff --git a/images/flags/sk.gif b/images/flags/sk.gif new file mode 100644 index 00000000..1b3f22ba Binary files /dev/null and b/images/flags/sk.gif differ diff --git a/images/flags/sl.gif b/images/flags/sl.gif new file mode 100644 index 00000000..f0f34923 Binary files /dev/null and b/images/flags/sl.gif differ diff --git a/images/flags/sm.gif b/images/flags/sm.gif new file mode 100644 index 00000000..04d98de5 Binary files /dev/null and b/images/flags/sm.gif differ diff --git a/images/flags/sn.gif b/images/flags/sn.gif new file mode 100644 index 00000000..6dac8709 Binary files /dev/null and b/images/flags/sn.gif differ diff --git a/images/flags/so.gif b/images/flags/so.gif new file mode 100644 index 00000000..f1961694 Binary files /dev/null and b/images/flags/so.gif differ diff --git a/images/flags/sr.gif b/images/flags/sr.gif new file mode 100644 index 00000000..0f7499ad Binary files /dev/null and b/images/flags/sr.gif differ diff --git a/images/flags/st.gif b/images/flags/st.gif new file mode 100644 index 00000000..4f1e6e09 Binary files /dev/null and b/images/flags/st.gif differ diff --git a/images/flags/sv.gif b/images/flags/sv.gif new file mode 100644 index 00000000..2d7b159a Binary files /dev/null and b/images/flags/sv.gif differ diff --git a/images/flags/sy.gif b/images/flags/sy.gif new file mode 100644 index 00000000..dc8bd509 Binary files /dev/null and b/images/flags/sy.gif differ diff --git a/images/flags/sz.gif b/images/flags/sz.gif new file mode 100644 index 00000000..f37aaf80 Binary files /dev/null and b/images/flags/sz.gif differ diff --git a/images/flags/tc.gif b/images/flags/tc.gif new file mode 100644 index 00000000..11a8c232 Binary files /dev/null and b/images/flags/tc.gif differ diff --git a/images/flags/td.gif b/images/flags/td.gif new file mode 100644 index 00000000..7aa8a10d Binary files /dev/null and b/images/flags/td.gif differ diff --git a/images/flags/tf.gif b/images/flags/tf.gif new file mode 100644 index 00000000..51a43250 Binary files /dev/null and b/images/flags/tf.gif differ diff --git a/images/flags/tg.gif b/images/flags/tg.gif new file mode 100644 index 00000000..ca6b4e77 Binary files /dev/null and b/images/flags/tg.gif differ diff --git a/images/flags/th.gif b/images/flags/th.gif new file mode 100644 index 00000000..01307924 Binary files /dev/null and b/images/flags/th.gif differ diff --git a/images/flags/tj.gif b/images/flags/tj.gif new file mode 100644 index 00000000..2fe38d4a Binary files /dev/null and b/images/flags/tj.gif differ diff --git a/images/flags/tk.gif b/images/flags/tk.gif new file mode 100644 index 00000000..3d3a727f Binary files /dev/null and b/images/flags/tk.gif differ diff --git a/images/flags/tl.gif b/images/flags/tl.gif new file mode 100644 index 00000000..df22d582 Binary files /dev/null and b/images/flags/tl.gif differ diff --git a/images/flags/tm.gif b/images/flags/tm.gif new file mode 100644 index 00000000..36d0994f Binary files /dev/null and b/images/flags/tm.gif differ diff --git a/images/flags/tn.gif b/images/flags/tn.gif new file mode 100644 index 00000000..917d4288 Binary files /dev/null and b/images/flags/tn.gif differ diff --git a/images/flags/to.gif b/images/flags/to.gif new file mode 100644 index 00000000..d7ed4d11 Binary files /dev/null and b/images/flags/to.gif differ diff --git a/images/flags/tr.gif b/images/flags/tr.gif new file mode 100644 index 00000000..e407d553 Binary files /dev/null and b/images/flags/tr.gif differ diff --git a/images/flags/tt.gif b/images/flags/tt.gif new file mode 100644 index 00000000..47d3b806 Binary files /dev/null and b/images/flags/tt.gif differ diff --git a/images/flags/tv.gif b/images/flags/tv.gif new file mode 100644 index 00000000..3c338277 Binary files /dev/null and b/images/flags/tv.gif differ diff --git a/images/flags/tw.gif b/images/flags/tw.gif new file mode 100644 index 00000000..cacfd9b7 Binary files /dev/null and b/images/flags/tw.gif differ diff --git a/images/flags/tz.gif b/images/flags/tz.gif new file mode 100644 index 00000000..82b52ca2 Binary files /dev/null and b/images/flags/tz.gif differ diff --git a/images/flags/ua.gif b/images/flags/ua.gif new file mode 100644 index 00000000..5d6cd83f Binary files /dev/null and b/images/flags/ua.gif differ diff --git a/images/flags/ug.gif b/images/flags/ug.gif new file mode 100644 index 00000000..58b731ad Binary files /dev/null and b/images/flags/ug.gif differ diff --git a/images/flags/um.gif b/images/flags/um.gif new file mode 100644 index 00000000..3b4c8483 Binary files /dev/null and b/images/flags/um.gif differ diff --git a/images/flags/us.gif b/images/flags/us.gif new file mode 100644 index 00000000..8f198f73 Binary files /dev/null and b/images/flags/us.gif differ diff --git a/images/flags/uy.gif b/images/flags/uy.gif new file mode 100644 index 00000000..12848c74 Binary files /dev/null and b/images/flags/uy.gif differ diff --git a/images/flags/uz.gif b/images/flags/uz.gif new file mode 100644 index 00000000..dc9daeca Binary files /dev/null and b/images/flags/uz.gif differ diff --git a/images/flags/va.gif b/images/flags/va.gif new file mode 100644 index 00000000..2bd74468 Binary files /dev/null and b/images/flags/va.gif differ diff --git a/images/flags/vc.gif b/images/flags/vc.gif new file mode 100644 index 00000000..48213816 Binary files /dev/null and b/images/flags/vc.gif differ diff --git a/images/flags/ve.gif b/images/flags/ve.gif new file mode 100644 index 00000000..19ce6c14 Binary files /dev/null and b/images/flags/ve.gif differ diff --git a/images/flags/vg.gif b/images/flags/vg.gif new file mode 100644 index 00000000..1fc0f96e Binary files /dev/null and b/images/flags/vg.gif differ diff --git a/images/flags/vi.gif b/images/flags/vi.gif new file mode 100644 index 00000000..66f9e746 Binary files /dev/null and b/images/flags/vi.gif differ diff --git a/images/flags/vn.gif b/images/flags/vn.gif new file mode 100644 index 00000000..f1e20c94 Binary files /dev/null and b/images/flags/vn.gif differ diff --git a/images/flags/vu.gif b/images/flags/vu.gif new file mode 100644 index 00000000..8a8b2b06 Binary files /dev/null and b/images/flags/vu.gif differ diff --git a/images/flags/wales.gif b/images/flags/wales.gif new file mode 100644 index 00000000..901d1750 Binary files /dev/null and b/images/flags/wales.gif differ diff --git a/images/flags/wf.gif b/images/flags/wf.gif new file mode 100644 index 00000000..eaa954b1 Binary files /dev/null and b/images/flags/wf.gif differ diff --git a/images/flags/ws.gif b/images/flags/ws.gif new file mode 100644 index 00000000..a51f939e Binary files /dev/null and b/images/flags/ws.gif differ diff --git a/images/flags/ye.gif b/images/flags/ye.gif new file mode 100644 index 00000000..7b0183d0 Binary files /dev/null and b/images/flags/ye.gif differ diff --git a/images/flags/yt.gif b/images/flags/yt.gif new file mode 100644 index 00000000..a2267c05 Binary files /dev/null and b/images/flags/yt.gif differ diff --git a/images/flags/za.gif b/images/flags/za.gif new file mode 100644 index 00000000..ede52589 Binary files /dev/null and b/images/flags/za.gif differ diff --git a/images/flags/zm.gif b/images/flags/zm.gif new file mode 100644 index 00000000..b2851d2b Binary files /dev/null and b/images/flags/zm.gif differ diff --git a/images/flags/zw.gif b/images/flags/zw.gif new file mode 100644 index 00000000..02901f62 Binary files /dev/null and b/images/flags/zw.gif differ diff --git a/images/forum/post.gif b/images/forum/post.gif new file mode 100644 index 00000000..ce4b06ee Binary files /dev/null and b/images/forum/post.gif differ diff --git a/images/forum/smile/1.gif b/images/forum/smile/1.gif new file mode 100644 index 00000000..f41e41a7 Binary files /dev/null and b/images/forum/smile/1.gif differ diff --git a/images/forum/smile/10.gif b/images/forum/smile/10.gif new file mode 100644 index 00000000..ac97d895 Binary files /dev/null and b/images/forum/smile/10.gif differ diff --git a/images/forum/smile/2.gif b/images/forum/smile/2.gif new file mode 100644 index 00000000..5174ce47 Binary files /dev/null and b/images/forum/smile/2.gif differ diff --git a/images/forum/smile/3.gif b/images/forum/smile/3.gif new file mode 100644 index 00000000..3fb84b90 Binary files /dev/null and b/images/forum/smile/3.gif differ diff --git a/images/forum/smile/4.gif b/images/forum/smile/4.gif new file mode 100644 index 00000000..8d22e981 Binary files /dev/null and b/images/forum/smile/4.gif differ diff --git a/images/forum/smile/5.gif b/images/forum/smile/5.gif new file mode 100644 index 00000000..01542349 Binary files /dev/null and b/images/forum/smile/5.gif differ diff --git a/images/forum/smile/6.gif b/images/forum/smile/6.gif new file mode 100644 index 00000000..d000ca5a Binary files /dev/null and b/images/forum/smile/6.gif differ diff --git a/images/forum/smile/7.gif b/images/forum/smile/7.gif new file mode 100644 index 00000000..993ef075 Binary files /dev/null and b/images/forum/smile/7.gif differ diff --git a/images/forum/smile/8.gif b/images/forum/smile/8.gif new file mode 100644 index 00000000..a4910467 Binary files /dev/null and b/images/forum/smile/8.gif differ diff --git a/images/forum/smile/9.gif b/images/forum/smile/9.gif new file mode 100644 index 00000000..59bdca5a Binary files /dev/null and b/images/forum/smile/9.gif differ diff --git a/images/forum/topic.gif b/images/forum/topic.gif new file mode 100644 index 00000000..7e0bff4c Binary files /dev/null and b/images/forum/topic.gif differ diff --git a/images/green_skull.gif b/images/green_skull.gif new file mode 100644 index 00000000..78740842 Binary files /dev/null and b/images/green_skull.gif differ diff --git a/images/guilds/default.gif b/images/guilds/default.gif new file mode 100644 index 00000000..404a0df8 Binary files /dev/null and b/images/guilds/default.gif differ diff --git a/images/hist.png b/images/hist.png new file mode 100644 index 00000000..8a6b74cc Binary files /dev/null and b/images/hist.png differ diff --git a/images/houses/default.jpg b/images/houses/default.jpg new file mode 100644 index 00000000..f40ee400 Binary files /dev/null and b/images/houses/default.jpg differ diff --git a/images/icons/add.png b/images/icons/add.png new file mode 100644 index 00000000..6332fefe Binary files /dev/null and b/images/icons/add.png differ diff --git a/images/icons/application_add.png b/images/icons/application_add.png new file mode 100644 index 00000000..2e945076 Binary files /dev/null and b/images/icons/application_add.png differ diff --git a/images/icons/arrow_down.gif b/images/icons/arrow_down.gif new file mode 100644 index 00000000..f0bb6a4e Binary files /dev/null and b/images/icons/arrow_down.gif differ diff --git a/images/icons/arrow_down.png b/images/icons/arrow_down.png new file mode 100644 index 00000000..2c4e2793 Binary files /dev/null and b/images/icons/arrow_down.png differ diff --git a/images/icons/arrow_down_mini.gif b/images/icons/arrow_down_mini.gif new file mode 100644 index 00000000..f0bb6a4e Binary files /dev/null and b/images/icons/arrow_down_mini.gif differ diff --git a/images/icons/arrow_left.gif b/images/icons/arrow_left.gif new file mode 100644 index 00000000..932ade16 Binary files /dev/null and b/images/icons/arrow_left.gif differ diff --git a/images/icons/arrow_right.gif b/images/icons/arrow_right.gif new file mode 100644 index 00000000..780431c2 Binary files /dev/null and b/images/icons/arrow_right.gif differ diff --git a/images/icons/arrow_up.gif b/images/icons/arrow_up.gif new file mode 100644 index 00000000..e8234178 Binary files /dev/null and b/images/icons/arrow_up.gif differ diff --git a/images/icons/brick.png b/images/icons/brick.png new file mode 100644 index 00000000..7851cf34 Binary files /dev/null and b/images/icons/brick.png differ diff --git a/images/icons/brick_edit.png b/images/icons/brick_edit.png new file mode 100644 index 00000000..eb06df3b Binary files /dev/null and b/images/icons/brick_edit.png differ diff --git a/images/icons/bricks.png b/images/icons/bricks.png new file mode 100644 index 00000000..0905f933 Binary files /dev/null and b/images/icons/bricks.png differ diff --git a/images/icons/bricks_gear.png b/images/icons/bricks_gear.png new file mode 100644 index 00000000..9dda1f3b Binary files /dev/null and b/images/icons/bricks_gear.png differ diff --git a/images/icons/car.png b/images/icons/car.png new file mode 100644 index 00000000..4f3a770f Binary files /dev/null and b/images/icons/car.png differ diff --git a/images/icons/cart.png b/images/icons/cart.png new file mode 100644 index 00000000..1baf7b9f Binary files /dev/null and b/images/icons/cart.png differ diff --git a/images/icons/cart_add.png b/images/icons/cart_add.png new file mode 100644 index 00000000..45c29000 Binary files /dev/null and b/images/icons/cart_add.png differ diff --git a/images/icons/cog.png b/images/icons/cog.png new file mode 100644 index 00000000..67de2c6c Binary files /dev/null and b/images/icons/cog.png differ diff --git a/images/icons/coins.png b/images/icons/coins.png new file mode 100644 index 00000000..0ca9074d Binary files /dev/null and b/images/icons/coins.png differ diff --git a/images/icons/color_swatch.png b/images/icons/color_swatch.png new file mode 100644 index 00000000..6e6e8521 Binary files /dev/null and b/images/icons/color_swatch.png differ diff --git a/images/icons/error.gif b/images/icons/error.gif new file mode 100644 index 00000000..352875dc Binary files /dev/null and b/images/icons/error.gif differ diff --git a/images/icons/expand.jpg b/images/icons/expand.jpg new file mode 100644 index 00000000..e7e129fb Binary files /dev/null and b/images/icons/expand.jpg differ diff --git a/images/icons/feed.png b/images/icons/feed.png new file mode 100644 index 00000000..315c4f4f Binary files /dev/null and b/images/icons/feed.png differ diff --git a/images/icons/folder.png b/images/icons/folder.png new file mode 100644 index 00000000..784e8fa4 Binary files /dev/null and b/images/icons/folder.png differ diff --git a/images/icons/folder_page.png b/images/icons/folder_page.png new file mode 100644 index 00000000..1ef6e114 Binary files /dev/null and b/images/icons/folder_page.png differ diff --git a/images/icons/folder_page_add.png b/images/icons/folder_page_add.png new file mode 100644 index 00000000..c1e90af4 Binary files /dev/null and b/images/icons/folder_page_add.png differ diff --git a/images/icons/folder_table.png b/images/icons/folder_table.png new file mode 100644 index 00000000..473cee35 Binary files /dev/null and b/images/icons/folder_table.png differ diff --git a/images/icons/group.png b/images/icons/group.png new file mode 100644 index 00000000..7fb4e1f1 Binary files /dev/null and b/images/icons/group.png differ diff --git a/images/icons/house.png b/images/icons/house.png new file mode 100644 index 00000000..fed62219 Binary files /dev/null and b/images/icons/house.png differ diff --git a/images/icons/logout.png b/images/icons/logout.png new file mode 100644 index 00000000..7d44194f Binary files /dev/null and b/images/icons/logout.png differ diff --git a/images/icons/magnifier.png b/images/icons/magnifier.png new file mode 100644 index 00000000..cf3d97f7 Binary files /dev/null and b/images/icons/magnifier.png differ diff --git a/images/icons/note.gif b/images/icons/note.gif new file mode 100644 index 00000000..9fa6bdd0 Binary files /dev/null and b/images/icons/note.gif differ diff --git a/images/icons/page_add.png b/images/icons/page_add.png new file mode 100644 index 00000000..d5bfa071 Binary files /dev/null and b/images/icons/page_add.png differ diff --git a/images/icons/page_gear.png b/images/icons/page_gear.png new file mode 100644 index 00000000..8e83281c Binary files /dev/null and b/images/icons/page_gear.png differ diff --git a/images/icons/page_white_delete.png b/images/icons/page_white_delete.png new file mode 100644 index 00000000..af1ecaf2 Binary files /dev/null and b/images/icons/page_white_delete.png differ diff --git a/images/icons/page_white_edit.png b/images/icons/page_white_edit.png new file mode 100644 index 00000000..b93e7760 Binary files /dev/null and b/images/icons/page_white_edit.png differ diff --git a/images/icons/page_white_link.png b/images/icons/page_white_link.png new file mode 100644 index 00000000..bf7bd1c9 Binary files /dev/null and b/images/icons/page_white_link.png differ diff --git a/images/icons/page_white_text_width.png b/images/icons/page_white_text_width.png new file mode 100644 index 00000000..d9cf1325 Binary files /dev/null and b/images/icons/page_white_text_width.png differ diff --git a/images/icons/report.png b/images/icons/report.png new file mode 100644 index 00000000..779ad58e Binary files /dev/null and b/images/icons/report.png differ diff --git a/images/icons/report_link.png b/images/icons/report_link.png new file mode 100644 index 00000000..23f2611e Binary files /dev/null and b/images/icons/report_link.png differ diff --git a/images/icons/rss.png b/images/icons/rss.png new file mode 100644 index 00000000..1dc6ff30 Binary files /dev/null and b/images/icons/rss.png differ diff --git a/images/icons/success.gif b/images/icons/success.gif new file mode 100644 index 00000000..c5206b56 Binary files /dev/null and b/images/icons/success.gif differ diff --git a/images/icons/user.png b/images/icons/user.png new file mode 100644 index 00000000..79f35ccb Binary files /dev/null and b/images/icons/user.png differ diff --git a/images/icons/user_add.png b/images/icons/user_add.png new file mode 100644 index 00000000..deae99bc Binary files /dev/null and b/images/icons/user_add.png differ diff --git a/images/icons/user_delete.png b/images/icons/user_delete.png new file mode 100644 index 00000000..acbb5630 Binary files /dev/null and b/images/icons/user_delete.png differ diff --git a/images/icons/user_edit.png b/images/icons/user_edit.png new file mode 100644 index 00000000..c1974cda Binary files /dev/null and b/images/icons/user_edit.png differ diff --git a/images/icons/warning.gif b/images/icons/warning.gif new file mode 100644 index 00000000..3a9a3fbc Binary files /dev/null and b/images/icons/warning.gif differ diff --git a/images/icons/world.png b/images/icons/world.png new file mode 100644 index 00000000..68f21d30 Binary files /dev/null and b/images/icons/world.png differ diff --git a/images/info.png b/images/info.png new file mode 100644 index 00000000..a237c178 Binary files /dev/null and b/images/info.png differ diff --git a/images/items/no_ammo.gif b/images/items/no_ammo.gif new file mode 100644 index 00000000..6ae611e4 Binary files /dev/null and b/images/items/no_ammo.gif differ diff --git a/images/items/no_armor.gif b/images/items/no_armor.gif new file mode 100644 index 00000000..b1d51537 Binary files /dev/null and b/images/items/no_armor.gif differ diff --git a/images/items/no_backpack.gif b/images/items/no_backpack.gif new file mode 100644 index 00000000..4693cf9f Binary files /dev/null and b/images/items/no_backpack.gif differ diff --git a/images/items/no_boots.gif b/images/items/no_boots.gif new file mode 100644 index 00000000..a772a430 Binary files /dev/null and b/images/items/no_boots.gif differ diff --git a/images/items/no_handleft.gif b/images/items/no_handleft.gif new file mode 100644 index 00000000..11667b6d Binary files /dev/null and b/images/items/no_handleft.gif differ diff --git a/images/items/no_handright.gif b/images/items/no_handright.gif new file mode 100644 index 00000000..ac87bd59 Binary files /dev/null and b/images/items/no_handright.gif differ diff --git a/images/items/no_helmet.gif b/images/items/no_helmet.gif new file mode 100644 index 00000000..acaf168c Binary files /dev/null and b/images/items/no_helmet.gif differ diff --git a/images/items/no_legs.gif b/images/items/no_legs.gif new file mode 100644 index 00000000..e57510b4 Binary files /dev/null and b/images/items/no_legs.gif differ diff --git a/images/items/no_necklace.gif b/images/items/no_necklace.gif new file mode 100644 index 00000000..512542b3 Binary files /dev/null and b/images/items/no_necklace.gif differ diff --git a/images/items/no_ring.gif b/images/items/no_ring.gif new file mode 100644 index 00000000..bb82663c Binary files /dev/null and b/images/items/no_ring.gif differ diff --git a/images/knight.png b/images/knight.png new file mode 100644 index 00000000..789f6a4d Binary files /dev/null and b/images/knight.png differ diff --git a/images/loading.gif b/images/loading.gif new file mode 100644 index 00000000..240bd88c Binary files /dev/null and b/images/loading.gif differ diff --git a/images/minus.gif b/images/minus.gif new file mode 100644 index 00000000..499a2e2a Binary files /dev/null and b/images/minus.gif differ diff --git a/images/monsters/acidblob.gif b/images/monsters/acidblob.gif new file mode 100644 index 00000000..e3ac9be6 Binary files /dev/null and b/images/monsters/acidblob.gif differ diff --git a/images/monsters/acolyte of the cult.gif b/images/monsters/acolyte of the cult.gif new file mode 100644 index 00000000..7ea9b797 Binary files /dev/null and b/images/monsters/acolyte of the cult.gif differ diff --git a/images/monsters/adept of the cult.gif b/images/monsters/adept of the cult.gif new file mode 100644 index 00000000..39c12a4d Binary files /dev/null and b/images/monsters/adept of the cult.gif differ diff --git a/images/monsters/amazon.gif b/images/monsters/amazon.gif new file mode 100644 index 00000000..92b0b7a0 Binary files /dev/null and b/images/monsters/amazon.gif differ diff --git a/images/monsters/ancient scarab.gif b/images/monsters/ancient scarab.gif new file mode 100644 index 00000000..2ecc3742 Binary files /dev/null and b/images/monsters/ancient scarab.gif differ diff --git a/images/monsters/ancientscarab.gif b/images/monsters/ancientscarab.gif new file mode 100644 index 00000000..dcff35cf Binary files /dev/null and b/images/monsters/ancientscarab.gif differ diff --git a/images/monsters/animated-statue.gif b/images/monsters/animated-statue.gif new file mode 100644 index 00000000..92eff794 Binary files /dev/null and b/images/monsters/animated-statue.gif differ diff --git a/images/monsters/annihilon.gif b/images/monsters/annihilon.gif new file mode 100644 index 00000000..b723ca77 Binary files /dev/null and b/images/monsters/annihilon.gif differ diff --git a/images/monsters/apprentice sheng.gif b/images/monsters/apprentice sheng.gif new file mode 100644 index 00000000..34040f2e Binary files /dev/null and b/images/monsters/apprentice sheng.gif differ diff --git a/images/monsters/ashmunrah.gif b/images/monsters/ashmunrah.gif new file mode 100644 index 00000000..6bde3894 Binary files /dev/null and b/images/monsters/ashmunrah.gif differ diff --git a/images/monsters/assassin.gif b/images/monsters/assassin.gif new file mode 100644 index 00000000..1368da74 Binary files /dev/null and b/images/monsters/assassin.gif differ diff --git a/images/monsters/avalanche.gif b/images/monsters/avalanche.gif new file mode 100644 index 00000000..3b8179c3 Binary files /dev/null and b/images/monsters/avalanche.gif differ diff --git a/images/monsters/axeitus headbanger.gif b/images/monsters/axeitus headbanger.gif new file mode 100644 index 00000000..f30bc6e2 Binary files /dev/null and b/images/monsters/axeitus headbanger.gif differ diff --git a/images/monsters/azure frog.gif b/images/monsters/azure frog.gif new file mode 100644 index 00000000..4105cb5b Binary files /dev/null and b/images/monsters/azure frog.gif differ diff --git a/images/monsters/badger.gif b/images/monsters/badger.gif new file mode 100644 index 00000000..718dc4ec Binary files /dev/null and b/images/monsters/badger.gif differ diff --git a/images/monsters/bandit.gif b/images/monsters/bandit.gif new file mode 100644 index 00000000..f362e587 Binary files /dev/null and b/images/monsters/bandit.gif differ diff --git a/images/monsters/banshee.gif b/images/monsters/banshee.gif new file mode 100644 index 00000000..6fbcea05 Binary files /dev/null and b/images/monsters/banshee.gif differ diff --git a/images/monsters/barbaria.gif b/images/monsters/barbaria.gif new file mode 100644 index 00000000..d2ed0827 Binary files /dev/null and b/images/monsters/barbaria.gif differ diff --git a/images/monsters/barbarian brutetamer.gif b/images/monsters/barbarian brutetamer.gif new file mode 100644 index 00000000..8d022ade Binary files /dev/null and b/images/monsters/barbarian brutetamer.gif differ diff --git a/images/monsters/barbarian headsplitter.gif b/images/monsters/barbarian headsplitter.gif new file mode 100644 index 00000000..6812479b Binary files /dev/null and b/images/monsters/barbarian headsplitter.gif differ diff --git a/images/monsters/barbarian skullhunter.gif b/images/monsters/barbarian skullhunter.gif new file mode 100644 index 00000000..13ce5c1b Binary files /dev/null and b/images/monsters/barbarian skullhunter.gif differ diff --git a/images/monsters/barbarianbloodwalker.gif b/images/monsters/barbarianbloodwalker.gif new file mode 100644 index 00000000..9bd876b1 Binary files /dev/null and b/images/monsters/barbarianbloodwalker.gif differ diff --git a/images/monsters/barbarianbrutetamer.gif b/images/monsters/barbarianbrutetamer.gif new file mode 100644 index 00000000..0807861b Binary files /dev/null and b/images/monsters/barbarianbrutetamer.gif differ diff --git a/images/monsters/barbarianheadsplitter.gif b/images/monsters/barbarianheadsplitter.gif new file mode 100644 index 00000000..8b1c4a59 Binary files /dev/null and b/images/monsters/barbarianheadsplitter.gif differ diff --git a/images/monsters/barbarianskullhunter.gif b/images/monsters/barbarianskullhunter.gif new file mode 100644 index 00000000..6f2284aa Binary files /dev/null and b/images/monsters/barbarianskullhunter.gif differ diff --git a/images/monsters/bat.gif b/images/monsters/bat.gif new file mode 100644 index 00000000..11ecffed Binary files /dev/null and b/images/monsters/bat.gif differ diff --git a/images/monsters/bear.gif b/images/monsters/bear.gif new file mode 100644 index 00000000..4249b050 Binary files /dev/null and b/images/monsters/bear.gif differ diff --git a/images/monsters/behemoth.gif b/images/monsters/behemoth.gif new file mode 100644 index 00000000..4c0668c7 Binary files /dev/null and b/images/monsters/behemoth.gif differ diff --git a/images/monsters/beholder.gif b/images/monsters/beholder.gif new file mode 100644 index 00000000..58d4b9ce Binary files /dev/null and b/images/monsters/beholder.gif differ diff --git a/images/monsters/betrayed wraith.gif b/images/monsters/betrayed wraith.gif new file mode 100644 index 00000000..bce51bc7 Binary files /dev/null and b/images/monsters/betrayed wraith.gif differ diff --git a/images/monsters/big boss trolliver.gif b/images/monsters/big boss trolliver.gif new file mode 100644 index 00000000..355c3bf0 Binary files /dev/null and b/images/monsters/big boss trolliver.gif differ diff --git a/images/monsters/black sheep.gif b/images/monsters/black sheep.gif new file mode 100644 index 00000000..64b6cde4 Binary files /dev/null and b/images/monsters/black sheep.gif differ diff --git a/images/monsters/blackknight.gif b/images/monsters/blackknight.gif new file mode 100644 index 00000000..248f32b2 Binary files /dev/null and b/images/monsters/blackknight.gif differ diff --git a/images/monsters/blazing fire elemental.gif b/images/monsters/blazing fire elemental.gif new file mode 100644 index 00000000..071c1607 Binary files /dev/null and b/images/monsters/blazing fire elemental.gif differ diff --git a/images/monsters/blightwalker.gif b/images/monsters/blightwalker.gif new file mode 100644 index 00000000..ff9aaaf8 Binary files /dev/null and b/images/monsters/blightwalker.gif differ diff --git a/images/monsters/blistering fire elemental.gif b/images/monsters/blistering fire elemental.gif new file mode 100644 index 00000000..2443d306 Binary files /dev/null and b/images/monsters/blistering fire elemental.gif differ diff --git a/images/monsters/blood crab.gif b/images/monsters/blood crab.gif new file mode 100644 index 00000000..d2d17b4c Binary files /dev/null and b/images/monsters/blood crab.gif differ diff --git a/images/monsters/bloodcrab.gif b/images/monsters/bloodcrab.gif new file mode 100644 index 00000000..d2d17b4c Binary files /dev/null and b/images/monsters/bloodcrab.gif differ diff --git a/images/monsters/bloodpaw.gif b/images/monsters/bloodpaw.gif new file mode 100644 index 00000000..d7eebb15 Binary files /dev/null and b/images/monsters/bloodpaw.gif differ diff --git a/images/monsters/blue djinn.gif b/images/monsters/blue djinn.gif new file mode 100644 index 00000000..999ba4ed Binary files /dev/null and b/images/monsters/blue djinn.gif differ diff --git a/images/monsters/bluedjinn.gif b/images/monsters/bluedjinn.gif new file mode 100644 index 00000000..999ba4ed Binary files /dev/null and b/images/monsters/bluedjinn.gif differ diff --git a/images/monsters/bog raider.gif b/images/monsters/bog raider.gif new file mode 100644 index 00000000..212d700e Binary files /dev/null and b/images/monsters/bog raider.gif differ diff --git a/images/monsters/bograider.gif b/images/monsters/bograider.gif new file mode 100644 index 00000000..522d1f04 Binary files /dev/null and b/images/monsters/bograider.gif differ diff --git a/images/monsters/bonebeast.gif b/images/monsters/bonebeast.gif new file mode 100644 index 00000000..74beac2d Binary files /dev/null and b/images/monsters/bonebeast.gif differ diff --git a/images/monsters/bones.gif b/images/monsters/bones.gif new file mode 100644 index 00000000..be2aabba Binary files /dev/null and b/images/monsters/bones.gif differ diff --git a/images/monsters/bovinus.gif b/images/monsters/bovinus.gif new file mode 100644 index 00000000..35785d7e Binary files /dev/null and b/images/monsters/bovinus.gif differ diff --git a/images/monsters/braindeath.gif b/images/monsters/braindeath.gif new file mode 100644 index 00000000..4ec481e7 Binary files /dev/null and b/images/monsters/braindeath.gif differ diff --git a/images/monsters/brutus bloodbeard.gif b/images/monsters/brutus bloodbeard.gif new file mode 100644 index 00000000..e1a8ee69 Binary files /dev/null and b/images/monsters/brutus bloodbeard.gif differ diff --git a/images/monsters/bug.gif b/images/monsters/bug.gif new file mode 100644 index 00000000..7ca6c71a Binary files /dev/null and b/images/monsters/bug.gif differ diff --git a/images/monsters/butterfly purple.gif b/images/monsters/butterfly purple.gif new file mode 100644 index 00000000..8ff52cfa Binary files /dev/null and b/images/monsters/butterfly purple.gif differ diff --git a/images/monsters/butterfly.gif b/images/monsters/butterfly.gif new file mode 100644 index 00000000..4bdfe81f Binary files /dev/null and b/images/monsters/butterfly.gif differ diff --git a/images/monsters/butterflypurple.gif b/images/monsters/butterflypurple.gif new file mode 100644 index 00000000..8ff52cfa Binary files /dev/null and b/images/monsters/butterflypurple.gif differ diff --git a/images/monsters/carniphila.gif b/images/monsters/carniphila.gif new file mode 100644 index 00000000..46becba3 Binary files /dev/null and b/images/monsters/carniphila.gif differ diff --git a/images/monsters/carrion worm.gif b/images/monsters/carrion worm.gif new file mode 100644 index 00000000..7ee814cc Binary files /dev/null and b/images/monsters/carrion worm.gif differ diff --git a/images/monsters/carrionworm.gif b/images/monsters/carrionworm.gif new file mode 100644 index 00000000..7ee814cc Binary files /dev/null and b/images/monsters/carrionworm.gif differ diff --git a/images/monsters/cat.gif b/images/monsters/cat.gif new file mode 100644 index 00000000..8e5e13d4 Binary files /dev/null and b/images/monsters/cat.gif differ diff --git a/images/monsters/cave rat.gif b/images/monsters/cave rat.gif new file mode 100644 index 00000000..359cf8cc Binary files /dev/null and b/images/monsters/cave rat.gif differ diff --git a/images/monsters/caverat.gif b/images/monsters/caverat.gif new file mode 100644 index 00000000..d1c25562 Binary files /dev/null and b/images/monsters/caverat.gif differ diff --git a/images/monsters/centipede.gif b/images/monsters/centipede.gif new file mode 100644 index 00000000..3683ae00 Binary files /dev/null and b/images/monsters/centipede.gif differ diff --git a/images/monsters/chakoya toolshaper.gif b/images/monsters/chakoya toolshaper.gif new file mode 100644 index 00000000..cd1431ed Binary files /dev/null and b/images/monsters/chakoya toolshaper.gif differ diff --git a/images/monsters/chakoya tribewarden.gif b/images/monsters/chakoya tribewarden.gif new file mode 100644 index 00000000..93eabf11 Binary files /dev/null and b/images/monsters/chakoya tribewarden.gif differ diff --git a/images/monsters/chakoya windcaller.gif b/images/monsters/chakoya windcaller.gif new file mode 100644 index 00000000..3f4d0617 Binary files /dev/null and b/images/monsters/chakoya windcaller.gif differ diff --git a/images/monsters/chakoyatoolshaper.gif b/images/monsters/chakoyatoolshaper.gif new file mode 100644 index 00000000..c1ce0e45 Binary files /dev/null and b/images/monsters/chakoyatoolshaper.gif differ diff --git a/images/monsters/chakoyatribewarden.gif b/images/monsters/chakoyatribewarden.gif new file mode 100644 index 00000000..7da67f54 Binary files /dev/null and b/images/monsters/chakoyatribewarden.gif differ diff --git a/images/monsters/chakoyawindcaller.gif b/images/monsters/chakoyawindcaller.gif new file mode 100644 index 00000000..9fffcbaf Binary files /dev/null and b/images/monsters/chakoyawindcaller.gif differ diff --git a/images/monsters/charged energy elemental.gif b/images/monsters/charged energy elemental.gif new file mode 100644 index 00000000..f9d3d260 Binary files /dev/null and b/images/monsters/charged energy elemental.gif differ diff --git a/images/monsters/chicken.gif b/images/monsters/chicken.gif new file mode 100644 index 00000000..000bae5a Binary files /dev/null and b/images/monsters/chicken.gif differ diff --git a/images/monsters/cobra.gif b/images/monsters/cobra.gif new file mode 100644 index 00000000..9230cff1 Binary files /dev/null and b/images/monsters/cobra.gif differ diff --git a/images/monsters/cockroach.gif b/images/monsters/cockroach.gif new file mode 100644 index 00000000..ea5854ec Binary files /dev/null and b/images/monsters/cockroach.gif differ diff --git a/images/monsters/colerian the barbarian.gif b/images/monsters/colerian the barbarian.gif new file mode 100644 index 00000000..d92fcec7 Binary files /dev/null and b/images/monsters/colerian the barbarian.gif differ diff --git a/images/monsters/coral frog.gif b/images/monsters/coral frog.gif new file mode 100644 index 00000000..c3c6b122 Binary files /dev/null and b/images/monsters/coral frog.gif differ diff --git a/images/monsters/countess sorrow.gif b/images/monsters/countess sorrow.gif new file mode 100644 index 00000000..7f146090 Binary files /dev/null and b/images/monsters/countess sorrow.gif differ diff --git a/images/monsters/crab.gif b/images/monsters/crab.gif new file mode 100644 index 00000000..dd326d65 Binary files /dev/null and b/images/monsters/crab.gif differ diff --git a/images/monsters/crazed beggar.gif b/images/monsters/crazed beggar.gif new file mode 100644 index 00000000..e111b3d0 Binary files /dev/null and b/images/monsters/crazed beggar.gif differ diff --git a/images/monsters/crimson frog.gif b/images/monsters/crimson frog.gif new file mode 100644 index 00000000..acba329b Binary files /dev/null and b/images/monsters/crimson frog.gif differ diff --git a/images/monsters/crocodile.gif b/images/monsters/crocodile.gif new file mode 100644 index 00000000..09ca2316 Binary files /dev/null and b/images/monsters/crocodile.gif differ diff --git a/images/monsters/crypt shambler.gif b/images/monsters/crypt shambler.gif new file mode 100644 index 00000000..96caeeb6 Binary files /dev/null and b/images/monsters/crypt shambler.gif differ diff --git a/images/monsters/cryptshambler.gif b/images/monsters/cryptshambler.gif new file mode 100644 index 00000000..4a1482b6 Binary files /dev/null and b/images/monsters/cryptshambler.gif differ diff --git a/images/monsters/crystal spider.gif b/images/monsters/crystal spider.gif new file mode 100644 index 00000000..c57899d7 Binary files /dev/null and b/images/monsters/crystal spider.gif differ diff --git a/images/monsters/crystalspider.gif b/images/monsters/crystalspider.gif new file mode 100644 index 00000000..5f5ee167 Binary files /dev/null and b/images/monsters/crystalspider.gif differ diff --git a/images/monsters/cultacolyte.gif b/images/monsters/cultacolyte.gif new file mode 100644 index 00000000..7ea9b797 Binary files /dev/null and b/images/monsters/cultacolyte.gif differ diff --git a/images/monsters/cultadept.gif b/images/monsters/cultadept.gif new file mode 100644 index 00000000..39c12a4d Binary files /dev/null and b/images/monsters/cultadept.gif differ diff --git a/images/monsters/cultnovice.gif b/images/monsters/cultnovice.gif new file mode 100644 index 00000000..cccc5970 Binary files /dev/null and b/images/monsters/cultnovice.gif differ diff --git a/images/monsters/cultpriest.gif b/images/monsters/cultpriest.gif new file mode 100644 index 00000000..c710221e Binary files /dev/null and b/images/monsters/cultpriest.gif differ diff --git a/images/monsters/cursed gladiator.gif b/images/monsters/cursed gladiator.gif new file mode 100644 index 00000000..96caeeb6 Binary files /dev/null and b/images/monsters/cursed gladiator.gif differ diff --git a/images/monsters/cyclops drone.gif b/images/monsters/cyclops drone.gif new file mode 100644 index 00000000..81898d3f Binary files /dev/null and b/images/monsters/cyclops drone.gif differ diff --git a/images/monsters/cyclops.gif b/images/monsters/cyclops.gif new file mode 100644 index 00000000..09e10aba Binary files /dev/null and b/images/monsters/cyclops.gif differ diff --git a/images/monsters/cyclopsdrone.gif b/images/monsters/cyclopsdrone.gif new file mode 100644 index 00000000..c7a85569 Binary files /dev/null and b/images/monsters/cyclopsdrone.gif differ diff --git a/images/monsters/cyclopssmith.gif b/images/monsters/cyclopssmith.gif new file mode 100644 index 00000000..31036b74 Binary files /dev/null and b/images/monsters/cyclopssmith.gif differ diff --git a/images/monsters/damaged worker golem.gif b/images/monsters/damaged worker golem.gif new file mode 100644 index 00000000..7dfc35f6 Binary files /dev/null and b/images/monsters/damaged worker golem.gif differ diff --git a/images/monsters/darakan the executioner.gif b/images/monsters/darakan the executioner.gif new file mode 100644 index 00000000..c79bad7d Binary files /dev/null and b/images/monsters/darakan the executioner.gif differ diff --git a/images/monsters/dark apprentice.gif b/images/monsters/dark apprentice.gif new file mode 100644 index 00000000..8ee98179 Binary files /dev/null and b/images/monsters/dark apprentice.gif differ diff --git a/images/monsters/dark magician.gif b/images/monsters/dark magician.gif new file mode 100644 index 00000000..a77d6e51 Binary files /dev/null and b/images/monsters/dark magician.gif differ diff --git a/images/monsters/dark monk.gif b/images/monsters/dark monk.gif new file mode 100644 index 00000000..407af447 Binary files /dev/null and b/images/monsters/dark monk.gif differ diff --git a/images/monsters/dark torturer.gif b/images/monsters/dark torturer.gif new file mode 100644 index 00000000..a483ad89 Binary files /dev/null and b/images/monsters/dark torturer.gif differ diff --git a/images/monsters/darkapprentice.gif b/images/monsters/darkapprentice.gif new file mode 100644 index 00000000..cc224ece Binary files /dev/null and b/images/monsters/darkapprentice.gif differ diff --git a/images/monsters/darkmagician.gif b/images/monsters/darkmagician.gif new file mode 100644 index 00000000..64ec8ad9 Binary files /dev/null and b/images/monsters/darkmagician.gif differ diff --git a/images/monsters/darkmonk.gif b/images/monsters/darkmonk.gif new file mode 100644 index 00000000..6e21e4f3 Binary files /dev/null and b/images/monsters/darkmonk.gif differ diff --git a/images/monsters/darktorturer.gif b/images/monsters/darktorturer.gif new file mode 100644 index 00000000..a483ad89 Binary files /dev/null and b/images/monsters/darktorturer.gif differ diff --git a/images/monsters/death blob.gif b/images/monsters/death blob.gif new file mode 100644 index 00000000..5e453dc5 Binary files /dev/null and b/images/monsters/death blob.gif differ diff --git a/images/monsters/deathbringer.gif b/images/monsters/deathbringer.gif new file mode 100644 index 00000000..d0cb3520 Binary files /dev/null and b/images/monsters/deathbringer.gif differ diff --git a/images/monsters/deathslicer.gif b/images/monsters/deathslicer.gif new file mode 100644 index 00000000..5282275e Binary files /dev/null and b/images/monsters/deathslicer.gif differ diff --git a/images/monsters/deer.gif b/images/monsters/deer.gif new file mode 100644 index 00000000..2a05d2f2 Binary files /dev/null and b/images/monsters/deer.gif differ diff --git a/images/monsters/defiler.gif b/images/monsters/defiler.gif new file mode 100644 index 00000000..fd266d6d Binary files /dev/null and b/images/monsters/defiler.gif differ diff --git a/images/monsters/demodras.gif b/images/monsters/demodras.gif new file mode 100644 index 00000000..a661cfd7 Binary files /dev/null and b/images/monsters/demodras.gif differ diff --git a/images/monsters/demon skeleton.gif b/images/monsters/demon skeleton.gif new file mode 100644 index 00000000..7e4187e5 Binary files /dev/null and b/images/monsters/demon skeleton.gif differ diff --git a/images/monsters/demon.gif b/images/monsters/demon.gif new file mode 100644 index 00000000..cbc1211f Binary files /dev/null and b/images/monsters/demon.gif differ diff --git a/images/monsters/demonskeleton.gif b/images/monsters/demonskeleton.gif new file mode 100644 index 00000000..d2416b65 Binary files /dev/null and b/images/monsters/demonskeleton.gif differ diff --git a/images/monsters/destroyer.gif b/images/monsters/destroyer.gif new file mode 100644 index 00000000..9e2f6660 Binary files /dev/null and b/images/monsters/destroyer.gif differ diff --git a/images/monsters/dharalion.gif b/images/monsters/dharalion.gif new file mode 100644 index 00000000..21fc94a1 Binary files /dev/null and b/images/monsters/dharalion.gif differ diff --git a/images/monsters/diabelski smok.gif b/images/monsters/diabelski smok.gif new file mode 100644 index 00000000..24819ed4 Binary files /dev/null and b/images/monsters/diabelski smok.gif differ diff --git a/images/monsters/diabolic imp.gif b/images/monsters/diabolic imp.gif new file mode 100644 index 00000000..2cd8b63e Binary files /dev/null and b/images/monsters/diabolic imp.gif differ diff --git a/images/monsters/diabolicimp.gif b/images/monsters/diabolicimp.gif new file mode 100644 index 00000000..a3d72f61 Binary files /dev/null and b/images/monsters/diabolicimp.gif differ diff --git a/images/monsters/dire penguin.gif b/images/monsters/dire penguin.gif new file mode 100644 index 00000000..19432f5f Binary files /dev/null and b/images/monsters/dire penguin.gif differ diff --git a/images/monsters/dog.gif b/images/monsters/dog.gif new file mode 100644 index 00000000..67942659 Binary files /dev/null and b/images/monsters/dog.gif differ diff --git a/images/monsters/dragon hatchling.gif b/images/monsters/dragon hatchling.gif new file mode 100644 index 00000000..a7439bd8 Binary files /dev/null and b/images/monsters/dragon hatchling.gif differ diff --git a/images/monsters/dragon lord hatchling.gif b/images/monsters/dragon lord hatchling.gif new file mode 100644 index 00000000..1cbb1e59 Binary files /dev/null and b/images/monsters/dragon lord hatchling.gif differ diff --git a/images/monsters/dragon lord.gif b/images/monsters/dragon lord.gif new file mode 100644 index 00000000..a661cfd7 Binary files /dev/null and b/images/monsters/dragon lord.gif differ diff --git a/images/monsters/dragon.gif b/images/monsters/dragon.gif new file mode 100644 index 00000000..ac77434c Binary files /dev/null and b/images/monsters/dragon.gif differ diff --git a/images/monsters/dragonhatchling.gif b/images/monsters/dragonhatchling.gif new file mode 100644 index 00000000..09ab1dbf Binary files /dev/null and b/images/monsters/dragonhatchling.gif differ diff --git a/images/monsters/dragonlord.gif b/images/monsters/dragonlord.gif new file mode 100644 index 00000000..24819ed4 Binary files /dev/null and b/images/monsters/dragonlord.gif differ diff --git a/images/monsters/dragonlordhatchling.gif b/images/monsters/dragonlordhatchling.gif new file mode 100644 index 00000000..f7b129e0 Binary files /dev/null and b/images/monsters/dragonlordhatchling.gif differ diff --git a/images/monsters/dreadbeast.gif b/images/monsters/dreadbeast.gif new file mode 100644 index 00000000..c7ea6cb8 Binary files /dev/null and b/images/monsters/dreadbeast.gif differ diff --git a/images/monsters/dwarf geomancer.gif b/images/monsters/dwarf geomancer.gif new file mode 100644 index 00000000..cfef30c8 Binary files /dev/null and b/images/monsters/dwarf geomancer.gif differ diff --git a/images/monsters/dwarf guard.gif b/images/monsters/dwarf guard.gif new file mode 100644 index 00000000..d9d3669c Binary files /dev/null and b/images/monsters/dwarf guard.gif differ diff --git a/images/monsters/dwarf soldier.gif b/images/monsters/dwarf soldier.gif new file mode 100644 index 00000000..f30bc6e2 Binary files /dev/null and b/images/monsters/dwarf soldier.gif differ diff --git a/images/monsters/dwarf.gif b/images/monsters/dwarf.gif new file mode 100644 index 00000000..ee1706df Binary files /dev/null and b/images/monsters/dwarf.gif differ diff --git a/images/monsters/dwarfgeomancer.gif b/images/monsters/dwarfgeomancer.gif new file mode 100644 index 00000000..a3183fcc Binary files /dev/null and b/images/monsters/dwarfgeomancer.gif differ diff --git a/images/monsters/dwarfguard.gif b/images/monsters/dwarfguard.gif new file mode 100644 index 00000000..9842d83e Binary files /dev/null and b/images/monsters/dwarfguard.gif differ diff --git a/images/monsters/dwarfminer.gif b/images/monsters/dwarfminer.gif new file mode 100644 index 00000000..60cf3f0a Binary files /dev/null and b/images/monsters/dwarfminer.gif differ diff --git a/images/monsters/dwarfsoldier.gif b/images/monsters/dwarfsoldier.gif new file mode 100644 index 00000000..e6dbda0e Binary files /dev/null and b/images/monsters/dwarfsoldier.gif differ diff --git a/images/monsters/dworc fleshhunter.gif b/images/monsters/dworc fleshhunter.gif new file mode 100644 index 00000000..20f0d8e8 Binary files /dev/null and b/images/monsters/dworc fleshhunter.gif differ diff --git a/images/monsters/dworc venomsniper.gif b/images/monsters/dworc venomsniper.gif new file mode 100644 index 00000000..49eb0b38 Binary files /dev/null and b/images/monsters/dworc venomsniper.gif differ diff --git a/images/monsters/dworc voodoomaster.gif b/images/monsters/dworc voodoomaster.gif new file mode 100644 index 00000000..abc34251 Binary files /dev/null and b/images/monsters/dworc voodoomaster.gif differ diff --git a/images/monsters/dworcfleshhunter.gif b/images/monsters/dworcfleshhunter.gif new file mode 100644 index 00000000..b75d650a Binary files /dev/null and b/images/monsters/dworcfleshhunter.gif differ diff --git a/images/monsters/dworcvenomsniper.gif b/images/monsters/dworcvenomsniper.gif new file mode 100644 index 00000000..f62ed147 Binary files /dev/null and b/images/monsters/dworcvenomsniper.gif differ diff --git a/images/monsters/dworcvoodoomaster.gif b/images/monsters/dworcvoodoomaster.gif new file mode 100644 index 00000000..8fad0060 Binary files /dev/null and b/images/monsters/dworcvoodoomaster.gif differ diff --git a/images/monsters/earth elemental.gif b/images/monsters/earth elemental.gif new file mode 100644 index 00000000..939bac19 Binary files /dev/null and b/images/monsters/earth elemental.gif differ diff --git a/images/monsters/earth overlord.gif b/images/monsters/earth overlord.gif new file mode 100644 index 00000000..f8e4c6b6 Binary files /dev/null and b/images/monsters/earth overlord.gif differ diff --git a/images/monsters/earthelemental.gif b/images/monsters/earthelemental.gif new file mode 100644 index 00000000..1c2cee06 Binary files /dev/null and b/images/monsters/earthelemental.gif differ diff --git a/images/monsters/efreet.gif b/images/monsters/efreet.gif new file mode 100644 index 00000000..2c0e0aca Binary files /dev/null and b/images/monsters/efreet.gif differ diff --git a/images/monsters/elder beholder.gif b/images/monsters/elder beholder.gif new file mode 100644 index 00000000..2ca3a866 Binary files /dev/null and b/images/monsters/elder beholder.gif differ diff --git a/images/monsters/elderbeholder.gif b/images/monsters/elderbeholder.gif new file mode 100644 index 00000000..ca2ad4ef Binary files /dev/null and b/images/monsters/elderbeholder.gif differ diff --git a/images/monsters/elephant.gif b/images/monsters/elephant.gif new file mode 100644 index 00000000..a21fbc65 Binary files /dev/null and b/images/monsters/elephant.gif differ diff --git a/images/monsters/elf.gif b/images/monsters/elf.gif new file mode 100644 index 00000000..decf4c26 Binary files /dev/null and b/images/monsters/elf.gif differ diff --git a/images/monsters/elfarcanist.gif b/images/monsters/elfarcanist.gif new file mode 100644 index 00000000..e81a1d51 Binary files /dev/null and b/images/monsters/elfarcanist.gif differ diff --git a/images/monsters/elfscout.gif b/images/monsters/elfscout.gif new file mode 100644 index 00000000..b34c35c5 Binary files /dev/null and b/images/monsters/elfscout.gif differ diff --git a/images/monsters/energy elemental.gif b/images/monsters/energy elemental.gif new file mode 100644 index 00000000..98b49a9b Binary files /dev/null and b/images/monsters/energy elemental.gif differ diff --git a/images/monsters/energy overlord.gif b/images/monsters/energy overlord.gif new file mode 100644 index 00000000..090b778e Binary files /dev/null and b/images/monsters/energy overlord.gif differ diff --git a/images/monsters/energyelemental.gif b/images/monsters/energyelemental.gif new file mode 100644 index 00000000..80b9e3d0 Binary files /dev/null and b/images/monsters/energyelemental.gif differ diff --git a/images/monsters/energyelementalmassive.gif b/images/monsters/energyelementalmassive.gif new file mode 100644 index 00000000..d27177f5 Binary files /dev/null and b/images/monsters/energyelementalmassive.gif differ diff --git a/images/monsters/enlightened of the cult.gif b/images/monsters/enlightened of the cult.gif new file mode 100644 index 00000000..2534d6e8 Binary files /dev/null and b/images/monsters/enlightened of the cult.gif differ diff --git a/images/monsters/evileye.gif b/images/monsters/evileye.gif new file mode 100644 index 00000000..ca2ad4ef Binary files /dev/null and b/images/monsters/evileye.gif differ diff --git a/images/monsters/eye of the seven.gif b/images/monsters/eye of the seven.gif new file mode 100644 index 00000000..73457601 Binary files /dev/null and b/images/monsters/eye of the seven.gif differ diff --git a/images/monsters/fernfang.gif b/images/monsters/fernfang.gif new file mode 100644 index 00000000..22a085d7 Binary files /dev/null and b/images/monsters/fernfang.gif differ diff --git a/images/monsters/ferumbras.gif b/images/monsters/ferumbras.gif new file mode 100644 index 00000000..d937faa1 Binary files /dev/null and b/images/monsters/ferumbras.gif differ diff --git a/images/monsters/fire devil.gif b/images/monsters/fire devil.gif new file mode 100644 index 00000000..16534061 Binary files /dev/null and b/images/monsters/fire devil.gif differ diff --git a/images/monsters/fire elemental.gif b/images/monsters/fire elemental.gif new file mode 100644 index 00000000..071c1607 Binary files /dev/null and b/images/monsters/fire elemental.gif differ diff --git a/images/monsters/fire overlord.gif b/images/monsters/fire overlord.gif new file mode 100644 index 00000000..6cbccd0d Binary files /dev/null and b/images/monsters/fire overlord.gif differ diff --git a/images/monsters/firedevil.gif b/images/monsters/firedevil.gif new file mode 100644 index 00000000..e9afb89a Binary files /dev/null and b/images/monsters/firedevil.gif differ diff --git a/images/monsters/fireelemental.gif b/images/monsters/fireelemental.gif new file mode 100644 index 00000000..2adc5269 Binary files /dev/null and b/images/monsters/fireelemental.gif differ diff --git a/images/monsters/flamethrower.gif b/images/monsters/flamethrower.gif new file mode 100644 index 00000000..d938b8f2 Binary files /dev/null and b/images/monsters/flamethrower.gif differ diff --git a/images/monsters/flamingo.gif b/images/monsters/flamingo.gif new file mode 100644 index 00000000..280d61f3 Binary files /dev/null and b/images/monsters/flamingo.gif differ diff --git a/images/monsters/fluffy.gif b/images/monsters/fluffy.gif new file mode 100644 index 00000000..336306f7 Binary files /dev/null and b/images/monsters/fluffy.gif differ diff --git a/images/monsters/foreman kneebiter.gif b/images/monsters/foreman kneebiter.gif new file mode 100644 index 00000000..a98b6862 Binary files /dev/null and b/images/monsters/foreman kneebiter.gif differ diff --git a/images/monsters/frogazure.gif b/images/monsters/frogazure.gif new file mode 100644 index 00000000..41f307e6 Binary files /dev/null and b/images/monsters/frogazure.gif differ diff --git a/images/monsters/frost dragon hatchling.gif b/images/monsters/frost dragon hatchling.gif new file mode 100644 index 00000000..b809ffd3 Binary files /dev/null and b/images/monsters/frost dragon hatchling.gif differ diff --git a/images/monsters/frost dragon.gif b/images/monsters/frost dragon.gif new file mode 100644 index 00000000..f32ee5e8 Binary files /dev/null and b/images/monsters/frost dragon.gif differ diff --git a/images/monsters/frost giant.gif b/images/monsters/frost giant.gif new file mode 100644 index 00000000..a9dc6762 Binary files /dev/null and b/images/monsters/frost giant.gif differ diff --git a/images/monsters/frost giantess.gif b/images/monsters/frost giantess.gif new file mode 100644 index 00000000..9d9eb5f1 Binary files /dev/null and b/images/monsters/frost giantess.gif differ diff --git a/images/monsters/frost troll.gif b/images/monsters/frost troll.gif new file mode 100644 index 00000000..10ee62be Binary files /dev/null and b/images/monsters/frost troll.gif differ diff --git a/images/monsters/frostdragon.gif b/images/monsters/frostdragon.gif new file mode 100644 index 00000000..50aeb05f Binary files /dev/null and b/images/monsters/frostdragon.gif differ diff --git a/images/monsters/frostdragonhatchling.gif b/images/monsters/frostdragonhatchling.gif new file mode 100644 index 00000000..7ef6484e Binary files /dev/null and b/images/monsters/frostdragonhatchling.gif differ diff --git a/images/monsters/frostfur.gif b/images/monsters/frostfur.gif new file mode 100644 index 00000000..d2469997 Binary files /dev/null and b/images/monsters/frostfur.gif differ diff --git a/images/monsters/frostgiant.gif b/images/monsters/frostgiant.gif new file mode 100644 index 00000000..e120cb4a Binary files /dev/null and b/images/monsters/frostgiant.gif differ diff --git a/images/monsters/frostgiantess.gif b/images/monsters/frostgiantess.gif new file mode 100644 index 00000000..483f77ea Binary files /dev/null and b/images/monsters/frostgiantess.gif differ diff --git a/images/monsters/frosttroll.gif b/images/monsters/frosttroll.gif new file mode 100644 index 00000000..bfe41656 Binary files /dev/null and b/images/monsters/frosttroll.gif differ diff --git a/images/monsters/fury.gif b/images/monsters/fury.gif new file mode 100644 index 00000000..c2c29001 Binary files /dev/null and b/images/monsters/fury.gif differ diff --git a/images/monsters/gargoyle.gif b/images/monsters/gargoyle.gif new file mode 100644 index 00000000..bc5c9ab1 Binary files /dev/null and b/images/monsters/gargoyle.gif differ diff --git a/images/monsters/gazer.gif b/images/monsters/gazer.gif new file mode 100644 index 00000000..73457601 Binary files /dev/null and b/images/monsters/gazer.gif differ diff --git a/images/monsters/ghazbaran.gif b/images/monsters/ghazbaran.gif new file mode 100644 index 00000000..8dc175a4 Binary files /dev/null and b/images/monsters/ghazbaran.gif differ diff --git a/images/monsters/ghost.gif b/images/monsters/ghost.gif new file mode 100644 index 00000000..6da14ea7 Binary files /dev/null and b/images/monsters/ghost.gif differ diff --git a/images/monsters/ghoul.gif b/images/monsters/ghoul.gif new file mode 100644 index 00000000..6ca9cb27 Binary files /dev/null and b/images/monsters/ghoul.gif differ diff --git a/images/monsters/giant spider.gif b/images/monsters/giant spider.gif new file mode 100644 index 00000000..5dffef2a Binary files /dev/null and b/images/monsters/giant spider.gif differ diff --git a/images/monsters/giantspider.gif b/images/monsters/giantspider.gif new file mode 100644 index 00000000..a4b51b14 Binary files /dev/null and b/images/monsters/giantspider.gif differ diff --git a/images/monsters/gladiator.gif b/images/monsters/gladiator.gif new file mode 100644 index 00000000..29b5ac1f Binary files /dev/null and b/images/monsters/gladiator.gif differ diff --git a/images/monsters/gnorre chyllson.gif b/images/monsters/gnorre chyllson.gif new file mode 100644 index 00000000..0bf06328 Binary files /dev/null and b/images/monsters/gnorre chyllson.gif differ diff --git a/images/monsters/goblin assassin.gif b/images/monsters/goblin assassin.gif new file mode 100644 index 00000000..f36f3dbf Binary files /dev/null and b/images/monsters/goblin assassin.gif differ diff --git a/images/monsters/goblin leader.gif b/images/monsters/goblin leader.gif new file mode 100644 index 00000000..03f650d8 Binary files /dev/null and b/images/monsters/goblin leader.gif differ diff --git a/images/monsters/goblin.gif b/images/monsters/goblin.gif new file mode 100644 index 00000000..d4a67880 Binary files /dev/null and b/images/monsters/goblin.gif differ diff --git a/images/monsters/goblinassassin.gif b/images/monsters/goblinassassin.gif new file mode 100644 index 00000000..4ad2fc3a Binary files /dev/null and b/images/monsters/goblinassassin.gif differ diff --git a/images/monsters/goblinscavenger.gif b/images/monsters/goblinscavenger.gif new file mode 100644 index 00000000..3a475284 Binary files /dev/null and b/images/monsters/goblinscavenger.gif differ diff --git a/images/monsters/golgordan.gif b/images/monsters/golgordan.gif new file mode 100644 index 00000000..c50b2323 Binary files /dev/null and b/images/monsters/golgordan.gif differ diff --git a/images/monsters/green djinn.gif b/images/monsters/green djinn.gif new file mode 100644 index 00000000..1f598d86 Binary files /dev/null and b/images/monsters/green djinn.gif differ diff --git a/images/monsters/green frog.gif b/images/monsters/green frog.gif new file mode 100644 index 00000000..881616c1 Binary files /dev/null and b/images/monsters/green frog.gif differ diff --git a/images/monsters/greendjinn.gif b/images/monsters/greendjinn.gif new file mode 100644 index 00000000..0e3307b2 Binary files /dev/null and b/images/monsters/greendjinn.gif differ diff --git a/images/monsters/grim reaper.gif b/images/monsters/grim reaper.gif new file mode 100644 index 00000000..a9accab8 Binary files /dev/null and b/images/monsters/grim reaper.gif differ diff --git a/images/monsters/grimreaper.gif b/images/monsters/grimreaper.gif new file mode 100644 index 00000000..3cc4ad56 Binary files /dev/null and b/images/monsters/grimreaper.gif differ diff --git a/images/monsters/grorlam.gif b/images/monsters/grorlam.gif new file mode 100644 index 00000000..56a73439 Binary files /dev/null and b/images/monsters/grorlam.gif differ diff --git a/images/monsters/hairman the huge.gif b/images/monsters/hairman the huge.gif new file mode 100644 index 00000000..aad05772 Binary files /dev/null and b/images/monsters/hairman the huge.gif differ diff --git a/images/monsters/halloweenhare.gif b/images/monsters/halloweenhare.gif new file mode 100644 index 00000000..51f93713 Binary files /dev/null and b/images/monsters/halloweenhare.gif differ diff --git a/images/monsters/hand of cursed fate.gif b/images/monsters/hand of cursed fate.gif new file mode 100644 index 00000000..722b24d9 Binary files /dev/null and b/images/monsters/hand of cursed fate.gif differ diff --git a/images/monsters/handofcursedfate.gif b/images/monsters/handofcursedfate.gif new file mode 100644 index 00000000..b8511dbf Binary files /dev/null and b/images/monsters/handofcursedfate.gif differ diff --git a/images/monsters/haunted treeling.gif b/images/monsters/haunted treeling.gif new file mode 100644 index 00000000..df4ff352 Binary files /dev/null and b/images/monsters/haunted treeling.gif differ diff --git a/images/monsters/hellfire fighter.gif b/images/monsters/hellfire fighter.gif new file mode 100644 index 00000000..6cbccd0d Binary files /dev/null and b/images/monsters/hellfire fighter.gif differ diff --git a/images/monsters/hellfirefighter.gif b/images/monsters/hellfirefighter.gif new file mode 100644 index 00000000..a3c2d001 Binary files /dev/null and b/images/monsters/hellfirefighter.gif differ diff --git a/images/monsters/hellhound.gif b/images/monsters/hellhound.gif new file mode 100644 index 00000000..336306f7 Binary files /dev/null and b/images/monsters/hellhound.gif differ diff --git a/images/monsters/hero.gif b/images/monsters/hero.gif new file mode 100644 index 00000000..5a23ab89 Binary files /dev/null and b/images/monsters/hero.gif differ diff --git a/images/monsters/hornedfox.gif b/images/monsters/hornedfox.gif new file mode 100644 index 00000000..4d62a705 Binary files /dev/null and b/images/monsters/hornedfox.gif differ diff --git a/images/monsters/hunter.gif b/images/monsters/hunter.gif new file mode 100644 index 00000000..ddc3515e Binary files /dev/null and b/images/monsters/hunter.gif differ diff --git a/images/monsters/husky.gif b/images/monsters/husky.gif new file mode 100644 index 00000000..f0fbd5f8 Binary files /dev/null and b/images/monsters/husky.gif differ diff --git a/images/monsters/hyaena.gif b/images/monsters/hyaena.gif new file mode 100644 index 00000000..932ce767 Binary files /dev/null and b/images/monsters/hyaena.gif differ diff --git a/images/monsters/hydra.gif b/images/monsters/hydra.gif new file mode 100644 index 00000000..5536e552 Binary files /dev/null and b/images/monsters/hydra.gif differ diff --git a/images/monsters/ice golem.gif b/images/monsters/ice golem.gif new file mode 100644 index 00000000..4d6f1a14 Binary files /dev/null and b/images/monsters/ice golem.gif differ diff --git a/images/monsters/ice overlord.gif b/images/monsters/ice overlord.gif new file mode 100644 index 00000000..aaaba295 Binary files /dev/null and b/images/monsters/ice overlord.gif differ diff --git a/images/monsters/ice witch.gif b/images/monsters/ice witch.gif new file mode 100644 index 00000000..5b93961b Binary files /dev/null and b/images/monsters/ice witch.gif differ diff --git a/images/monsters/icegolem.gif b/images/monsters/icegolem.gif new file mode 100644 index 00000000..9fb75c2c Binary files /dev/null and b/images/monsters/icegolem.gif differ diff --git a/images/monsters/icewitch.gif b/images/monsters/icewitch.gif new file mode 100644 index 00000000..45275474 Binary files /dev/null and b/images/monsters/icewitch.gif differ diff --git a/images/monsters/island troll.gif b/images/monsters/island troll.gif new file mode 100644 index 00000000..b8aa66d8 Binary files /dev/null and b/images/monsters/island troll.gif differ diff --git a/images/monsters/islandtroll.gif b/images/monsters/islandtroll.gif new file mode 100644 index 00000000..005a688c Binary files /dev/null and b/images/monsters/islandtroll.gif differ diff --git a/images/monsters/jagged earth elemental.gif b/images/monsters/jagged earth elemental.gif new file mode 100644 index 00000000..f8e4c6b6 Binary files /dev/null and b/images/monsters/jagged earth elemental.gif differ diff --git a/images/monsters/juggernaut.gif b/images/monsters/juggernaut.gif new file mode 100644 index 00000000..9a2fba7e Binary files /dev/null and b/images/monsters/juggernaut.gif differ diff --git a/images/monsters/kongra.gif b/images/monsters/kongra.gif new file mode 100644 index 00000000..de54f261 Binary files /dev/null and b/images/monsters/kongra.gif differ diff --git a/images/monsters/larva.gif b/images/monsters/larva.gif new file mode 100644 index 00000000..66fdec69 Binary files /dev/null and b/images/monsters/larva.gif differ diff --git a/images/monsters/latrivan.gif b/images/monsters/latrivan.gif new file mode 100644 index 00000000..c13607c5 Binary files /dev/null and b/images/monsters/latrivan.gif differ diff --git a/images/monsters/lavahole.gif b/images/monsters/lavahole.gif new file mode 100644 index 00000000..c9ecb89c Binary files /dev/null and b/images/monsters/lavahole.gif differ diff --git a/images/monsters/lethal lissy.gif b/images/monsters/lethal lissy.gif new file mode 100644 index 00000000..94cd67f9 Binary files /dev/null and b/images/monsters/lethal lissy.gif differ diff --git a/images/monsters/leviathan.gif b/images/monsters/leviathan.gif new file mode 100644 index 00000000..b02b314e Binary files /dev/null and b/images/monsters/leviathan.gif differ diff --git a/images/monsters/lich.gif b/images/monsters/lich.gif new file mode 100644 index 00000000..4d825e58 Binary files /dev/null and b/images/monsters/lich.gif differ diff --git a/images/monsters/lion.gif b/images/monsters/lion.gif new file mode 100644 index 00000000..c4acf459 Binary files /dev/null and b/images/monsters/lion.gif differ diff --git a/images/monsters/lizard sentinel.gif b/images/monsters/lizard sentinel.gif new file mode 100644 index 00000000..b9b5b025 Binary files /dev/null and b/images/monsters/lizard sentinel.gif differ diff --git a/images/monsters/lizard snakecharmer.gif b/images/monsters/lizard snakecharmer.gif new file mode 100644 index 00000000..40d3d094 Binary files /dev/null and b/images/monsters/lizard snakecharmer.gif differ diff --git a/images/monsters/lizard templar.gif b/images/monsters/lizard templar.gif new file mode 100644 index 00000000..7809b39e Binary files /dev/null and b/images/monsters/lizard templar.gif differ diff --git a/images/monsters/lizardsentinel.gif b/images/monsters/lizardsentinel.gif new file mode 100644 index 00000000..4fb3c5d2 Binary files /dev/null and b/images/monsters/lizardsentinel.gif differ diff --git a/images/monsters/lizardsnakecharmer.gif b/images/monsters/lizardsnakecharmer.gif new file mode 100644 index 00000000..b2fc78d1 Binary files /dev/null and b/images/monsters/lizardsnakecharmer.gif differ diff --git a/images/monsters/lizardtemplar.gif b/images/monsters/lizardtemplar.gif new file mode 100644 index 00000000..62db32ac Binary files /dev/null and b/images/monsters/lizardtemplar.gif differ diff --git a/images/monsters/lord of the elements.gif b/images/monsters/lord of the elements.gif new file mode 100644 index 00000000..a6680987 Binary files /dev/null and b/images/monsters/lord of the elements.gif differ diff --git a/images/monsters/lost soul.gif b/images/monsters/lost soul.gif new file mode 100644 index 00000000..95be577b Binary files /dev/null and b/images/monsters/lost soul.gif differ diff --git a/images/monsters/lostsoul.gif b/images/monsters/lostsoul.gif new file mode 100644 index 00000000..74b14113 Binary files /dev/null and b/images/monsters/lostsoul.gif differ diff --git a/images/monsters/mad scientist.gif b/images/monsters/mad scientist.gif new file mode 100644 index 00000000..e8322c84 Binary files /dev/null and b/images/monsters/mad scientist.gif differ diff --git a/images/monsters/madareth.gif b/images/monsters/madareth.gif new file mode 100644 index 00000000..c4cbfada Binary files /dev/null and b/images/monsters/madareth.gif differ diff --git a/images/monsters/magicthrower.gif b/images/monsters/magicthrower.gif new file mode 100644 index 00000000..d938b8f2 Binary files /dev/null and b/images/monsters/magicthrower.gif differ diff --git a/images/monsters/mammoth.gif b/images/monsters/mammoth.gif new file mode 100644 index 00000000..58db34a4 Binary files /dev/null and b/images/monsters/mammoth.gif differ diff --git a/images/monsters/man in the cave.gif b/images/monsters/man in the cave.gif new file mode 100644 index 00000000..c6a1edab Binary files /dev/null and b/images/monsters/man in the cave.gif differ diff --git a/images/monsters/marid.gif b/images/monsters/marid.gif new file mode 100644 index 00000000..360729c1 Binary files /dev/null and b/images/monsters/marid.gif differ diff --git a/images/monsters/massacre.gif b/images/monsters/massacre.gif new file mode 100644 index 00000000..e7f80f29 Binary files /dev/null and b/images/monsters/massacre.gif differ diff --git a/images/monsters/massive earth elemental.gif b/images/monsters/massive earth elemental.gif new file mode 100644 index 00000000..f8e4c6b6 Binary files /dev/null and b/images/monsters/massive earth elemental.gif differ diff --git a/images/monsters/massive energy elemental.gif b/images/monsters/massive energy elemental.gif new file mode 100644 index 00000000..090b778e Binary files /dev/null and b/images/monsters/massive energy elemental.gif differ diff --git a/images/monsters/massive fire elemental.gif b/images/monsters/massive fire elemental.gif new file mode 100644 index 00000000..e8ba25ba Binary files /dev/null and b/images/monsters/massive fire elemental.gif differ diff --git a/images/monsters/massive water elemental.gif b/images/monsters/massive water elemental.gif new file mode 100644 index 00000000..aaaba295 Binary files /dev/null and b/images/monsters/massive water elemental.gif differ diff --git a/images/monsters/massiveearthelemental.gif b/images/monsters/massiveearthelemental.gif new file mode 100644 index 00000000..77548b2f Binary files /dev/null and b/images/monsters/massiveearthelemental.gif differ diff --git a/images/monsters/medusa.gif b/images/monsters/medusa.gif new file mode 100644 index 00000000..9fb75ff5 Binary files /dev/null and b/images/monsters/medusa.gif differ diff --git a/images/monsters/mercury blob.gif b/images/monsters/mercury blob.gif new file mode 100644 index 00000000..f355f0b8 Binary files /dev/null and b/images/monsters/mercury blob.gif differ diff --git a/images/monsters/merlkin.gif b/images/monsters/merlkin.gif new file mode 100644 index 00000000..8b81cebf Binary files /dev/null and b/images/monsters/merlkin.gif differ diff --git a/images/monsters/mimic.gif b/images/monsters/mimic.gif new file mode 100644 index 00000000..004605c4 Binary files /dev/null and b/images/monsters/mimic.gif differ diff --git a/images/monsters/minishabaal.gif b/images/monsters/minishabaal.gif new file mode 100644 index 00000000..a3d72f61 Binary files /dev/null and b/images/monsters/minishabaal.gif differ diff --git a/images/monsters/minotaur archer.gif b/images/monsters/minotaur archer.gif new file mode 100644 index 00000000..32e9c020 Binary files /dev/null and b/images/monsters/minotaur archer.gif differ diff --git a/images/monsters/minotaur guard.gif b/images/monsters/minotaur guard.gif new file mode 100644 index 00000000..c021316a Binary files /dev/null and b/images/monsters/minotaur guard.gif differ diff --git a/images/monsters/minotaur mage.gif b/images/monsters/minotaur mage.gif new file mode 100644 index 00000000..52e5babc Binary files /dev/null and b/images/monsters/minotaur mage.gif differ diff --git a/images/monsters/minotaur.gif b/images/monsters/minotaur.gif new file mode 100644 index 00000000..ec805ee7 Binary files /dev/null and b/images/monsters/minotaur.gif differ diff --git a/images/monsters/minotaurarcher.gif b/images/monsters/minotaurarcher.gif new file mode 100644 index 00000000..7023e095 Binary files /dev/null and b/images/monsters/minotaurarcher.gif differ diff --git a/images/monsters/minotaurguard.gif b/images/monsters/minotaurguard.gif new file mode 100644 index 00000000..4d62a705 Binary files /dev/null and b/images/monsters/minotaurguard.gif differ diff --git a/images/monsters/minotaurmage.gif b/images/monsters/minotaurmage.gif new file mode 100644 index 00000000..6881e6cd Binary files /dev/null and b/images/monsters/minotaurmage.gif differ diff --git a/images/monsters/monk.gif b/images/monsters/monk.gif new file mode 100644 index 00000000..22a085d7 Binary files /dev/null and b/images/monsters/monk.gif differ diff --git a/images/monsters/morgaroth.gif b/images/monsters/morgaroth.gif new file mode 100644 index 00000000..b2067237 Binary files /dev/null and b/images/monsters/morgaroth.gif differ diff --git a/images/monsters/morguthis.gif b/images/monsters/morguthis.gif new file mode 100644 index 00000000..ce35bb0b Binary files /dev/null and b/images/monsters/morguthis.gif differ diff --git a/images/monsters/mr. punish.gif b/images/monsters/mr. punish.gif new file mode 100644 index 00000000..99c45b7b Binary files /dev/null and b/images/monsters/mr. punish.gif differ diff --git a/images/monsters/muddy earth elemental.gif b/images/monsters/muddy earth elemental.gif new file mode 100644 index 00000000..939bac19 Binary files /dev/null and b/images/monsters/muddy earth elemental.gif differ diff --git a/images/monsters/mummy.gif b/images/monsters/mummy.gif new file mode 100644 index 00000000..3329b9bb Binary files /dev/null and b/images/monsters/mummy.gif differ diff --git a/images/monsters/munster.gif b/images/monsters/munster.gif new file mode 100644 index 00000000..c177de44 Binary files /dev/null and b/images/monsters/munster.gif differ diff --git a/images/monsters/mutated bat.gif b/images/monsters/mutated bat.gif new file mode 100644 index 00000000..dd76bcdb Binary files /dev/null and b/images/monsters/mutated bat.gif differ diff --git a/images/monsters/mutated human.gif b/images/monsters/mutated human.gif new file mode 100644 index 00000000..9863675f Binary files /dev/null and b/images/monsters/mutated human.gif differ diff --git a/images/monsters/mutated rat.gif b/images/monsters/mutated rat.gif new file mode 100644 index 00000000..c659d5e6 Binary files /dev/null and b/images/monsters/mutated rat.gif differ diff --git a/images/monsters/mutated tiger.gif b/images/monsters/mutated tiger.gif new file mode 100644 index 00000000..fda1527d Binary files /dev/null and b/images/monsters/mutated tiger.gif differ diff --git a/images/monsters/necromancer.gif b/images/monsters/necromancer.gif new file mode 100644 index 00000000..6a4ea314 Binary files /dev/null and b/images/monsters/necromancer.gif differ diff --git a/images/monsters/necropharus.gif b/images/monsters/necropharus.gif new file mode 100644 index 00000000..6a4ea314 Binary files /dev/null and b/images/monsters/necropharus.gif differ diff --git a/images/monsters/nightmare scion.gif b/images/monsters/nightmare scion.gif new file mode 100644 index 00000000..b46fa224 Binary files /dev/null and b/images/monsters/nightmare scion.gif differ diff --git a/images/monsters/nightmare.gif b/images/monsters/nightmare.gif new file mode 100644 index 00000000..66882501 Binary files /dev/null and b/images/monsters/nightmare.gif differ diff --git a/images/monsters/nomad.gif b/images/monsters/nomad.gif new file mode 100644 index 00000000..f959be36 Binary files /dev/null and b/images/monsters/nomad.gif differ diff --git a/images/monsters/nophoto.png b/images/monsters/nophoto.png new file mode 100644 index 00000000..e21bf60d Binary files /dev/null and b/images/monsters/nophoto.png differ diff --git a/images/monsters/novice of the cult.gif b/images/monsters/novice of the cult.gif new file mode 100644 index 00000000..f2bc15a5 Binary files /dev/null and b/images/monsters/novice of the cult.gif differ diff --git a/images/monsters/oldwidow.gif b/images/monsters/oldwidow.gif new file mode 100644 index 00000000..a4b51b14 Binary files /dev/null and b/images/monsters/oldwidow.gif differ diff --git a/images/monsters/orc berserker.gif b/images/monsters/orc berserker.gif new file mode 100644 index 00000000..17275562 Binary files /dev/null and b/images/monsters/orc berserker.gif differ diff --git a/images/monsters/orc leader.gif b/images/monsters/orc leader.gif new file mode 100644 index 00000000..2ce5287a Binary files /dev/null and b/images/monsters/orc leader.gif differ diff --git a/images/monsters/orc rider.gif b/images/monsters/orc rider.gif new file mode 100644 index 00000000..bb72c720 Binary files /dev/null and b/images/monsters/orc rider.gif differ diff --git a/images/monsters/orc shaman.gif b/images/monsters/orc shaman.gif new file mode 100644 index 00000000..4425d8a7 Binary files /dev/null and b/images/monsters/orc shaman.gif differ diff --git a/images/monsters/orc spearman.gif b/images/monsters/orc spearman.gif new file mode 100644 index 00000000..dcaa7957 Binary files /dev/null and b/images/monsters/orc spearman.gif differ diff --git a/images/monsters/orc warlord.gif b/images/monsters/orc warlord.gif new file mode 100644 index 00000000..ffe358f8 Binary files /dev/null and b/images/monsters/orc warlord.gif differ diff --git a/images/monsters/orc warrior.gif b/images/monsters/orc warrior.gif new file mode 100644 index 00000000..d09e6289 Binary files /dev/null and b/images/monsters/orc warrior.gif differ diff --git a/images/monsters/orc.gif b/images/monsters/orc.gif new file mode 100644 index 00000000..746134bc Binary files /dev/null and b/images/monsters/orc.gif differ diff --git a/images/monsters/orcberserker.gif b/images/monsters/orcberserker.gif new file mode 100644 index 00000000..efad70f0 Binary files /dev/null and b/images/monsters/orcberserker.gif differ diff --git a/images/monsters/orchid frog.gif b/images/monsters/orchid frog.gif new file mode 100644 index 00000000..9d177dfa Binary files /dev/null and b/images/monsters/orchid frog.gif differ diff --git a/images/monsters/orcleader.gif b/images/monsters/orcleader.gif new file mode 100644 index 00000000..77fc444d Binary files /dev/null and b/images/monsters/orcleader.gif differ diff --git a/images/monsters/orcrider.gif b/images/monsters/orcrider.gif new file mode 100644 index 00000000..85116da1 Binary files /dev/null and b/images/monsters/orcrider.gif differ diff --git a/images/monsters/orcshaman.gif b/images/monsters/orcshaman.gif new file mode 100644 index 00000000..11cda667 Binary files /dev/null and b/images/monsters/orcshaman.gif differ diff --git a/images/monsters/orcspearman.gif b/images/monsters/orcspearman.gif new file mode 100644 index 00000000..5ffdba8d Binary files /dev/null and b/images/monsters/orcspearman.gif differ diff --git a/images/monsters/orcus the cruel.gif b/images/monsters/orcus the cruel.gif new file mode 100644 index 00000000..2ce5287a Binary files /dev/null and b/images/monsters/orcus the cruel.gif differ diff --git a/images/monsters/orcwarlord.gif b/images/monsters/orcwarlord.gif new file mode 100644 index 00000000..d070a23a Binary files /dev/null and b/images/monsters/orcwarlord.gif differ diff --git a/images/monsters/orcwarrior.gif b/images/monsters/orcwarrior.gif new file mode 100644 index 00000000..cf071616 Binary files /dev/null and b/images/monsters/orcwarrior.gif differ diff --git a/images/monsters/orshabaal.gif b/images/monsters/orshabaal.gif new file mode 100644 index 00000000..0176ff59 Binary files /dev/null and b/images/monsters/orshabaal.gif differ diff --git a/images/monsters/overcharged energy element.gif b/images/monsters/overcharged energy element.gif new file mode 100644 index 00000000..090b778e Binary files /dev/null and b/images/monsters/overcharged energy element.gif differ diff --git a/images/monsters/overcharged energy elemental.gif b/images/monsters/overcharged energy elemental.gif new file mode 100644 index 00000000..090b778e Binary files /dev/null and b/images/monsters/overcharged energy elemental.gif differ diff --git a/images/monsters/pajak.gif b/images/monsters/pajak.gif new file mode 100644 index 00000000..01090009 Binary files /dev/null and b/images/monsters/pajak.gif differ diff --git a/images/monsters/panda.gif b/images/monsters/panda.gif new file mode 100644 index 00000000..838703a6 Binary files /dev/null and b/images/monsters/panda.gif differ diff --git a/images/monsters/parrot.gif b/images/monsters/parrot.gif new file mode 100644 index 00000000..7ba06d88 Binary files /dev/null and b/images/monsters/parrot.gif differ diff --git a/images/monsters/penguin.gif b/images/monsters/penguin.gif new file mode 100644 index 00000000..19432f5f Binary files /dev/null and b/images/monsters/penguin.gif differ diff --git a/images/monsters/phantasm mirror.gif b/images/monsters/phantasm mirror.gif new file mode 100644 index 00000000..5fa1a7b3 Binary files /dev/null and b/images/monsters/phantasm mirror.gif differ diff --git a/images/monsters/phantasm.gif b/images/monsters/phantasm.gif new file mode 100644 index 00000000..47ef6822 Binary files /dev/null and b/images/monsters/phantasm.gif differ diff --git a/images/monsters/pig.gif b/images/monsters/pig.gif new file mode 100644 index 00000000..a9ef5c68 Binary files /dev/null and b/images/monsters/pig.gif differ diff --git a/images/monsters/pirate buccaneer.gif b/images/monsters/pirate buccaneer.gif new file mode 100644 index 00000000..80496542 Binary files /dev/null and b/images/monsters/pirate buccaneer.gif differ diff --git a/images/monsters/pirate corsair.gif b/images/monsters/pirate corsair.gif new file mode 100644 index 00000000..e1a8ee69 Binary files /dev/null and b/images/monsters/pirate corsair.gif differ diff --git a/images/monsters/pirate cutthroat.gif b/images/monsters/pirate cutthroat.gif new file mode 100644 index 00000000..fd3508e1 Binary files /dev/null and b/images/monsters/pirate cutthroat.gif differ diff --git a/images/monsters/pirate ghost.gif b/images/monsters/pirate ghost.gif new file mode 100644 index 00000000..4910d89d Binary files /dev/null and b/images/monsters/pirate ghost.gif differ diff --git a/images/monsters/pirate marauder.gif b/images/monsters/pirate marauder.gif new file mode 100644 index 00000000..5a68007f Binary files /dev/null and b/images/monsters/pirate marauder.gif differ diff --git a/images/monsters/pirate skeleton.gif b/images/monsters/pirate skeleton.gif new file mode 100644 index 00000000..34ffa2dd Binary files /dev/null and b/images/monsters/pirate skeleton.gif differ diff --git a/images/monsters/piratebuccaneer.gif b/images/monsters/piratebuccaneer.gif new file mode 100644 index 00000000..4569628e Binary files /dev/null and b/images/monsters/piratebuccaneer.gif differ diff --git a/images/monsters/piratecorsair.gif b/images/monsters/piratecorsair.gif new file mode 100644 index 00000000..53f0aa4c Binary files /dev/null and b/images/monsters/piratecorsair.gif differ diff --git a/images/monsters/piratecutthroat.gif b/images/monsters/piratecutthroat.gif new file mode 100644 index 00000000..e217f76c Binary files /dev/null and b/images/monsters/piratecutthroat.gif differ diff --git a/images/monsters/pirateghost.gif b/images/monsters/pirateghost.gif new file mode 100644 index 00000000..4910d89d Binary files /dev/null and b/images/monsters/pirateghost.gif differ diff --git a/images/monsters/pirateghost_002.gif b/images/monsters/pirateghost_002.gif new file mode 100644 index 00000000..78541b4f Binary files /dev/null and b/images/monsters/pirateghost_002.gif differ diff --git a/images/monsters/piratemarauder.gif b/images/monsters/piratemarauder.gif new file mode 100644 index 00000000..d4722129 Binary files /dev/null and b/images/monsters/piratemarauder.gif differ diff --git a/images/monsters/pirateskeleton.gif b/images/monsters/pirateskeleton.gif new file mode 100644 index 00000000..c716e33d Binary files /dev/null and b/images/monsters/pirateskeleton.gif differ diff --git a/images/monsters/plague smith.gif b/images/monsters/plague smith.gif new file mode 100644 index 00000000..c32d8920 Binary files /dev/null and b/images/monsters/plague smith.gif differ diff --git a/images/monsters/plaguesmith.gif b/images/monsters/plaguesmith.gif new file mode 100644 index 00000000..458d9674 Binary files /dev/null and b/images/monsters/plaguesmith.gif differ diff --git a/images/monsters/plaguethrower.gif b/images/monsters/plaguethrower.gif new file mode 100644 index 00000000..d938b8f2 Binary files /dev/null and b/images/monsters/plaguethrower.gif differ diff --git a/images/monsters/poacher.gif b/images/monsters/poacher.gif new file mode 100644 index 00000000..82789b68 Binary files /dev/null and b/images/monsters/poacher.gif differ diff --git a/images/monsters/poison spider.gif b/images/monsters/poison spider.gif new file mode 100644 index 00000000..b3480a44 Binary files /dev/null and b/images/monsters/poison spider.gif differ diff --git a/images/monsters/poisonspider.gif b/images/monsters/poisonspider.gif new file mode 100644 index 00000000..88a58d87 Binary files /dev/null and b/images/monsters/poisonspider.gif differ diff --git a/images/monsters/polar bear.gif b/images/monsters/polar bear.gif new file mode 100644 index 00000000..e6ea5338 Binary files /dev/null and b/images/monsters/polar bear.gif differ diff --git a/images/monsters/polarbear.gif b/images/monsters/polarbear.gif new file mode 100644 index 00000000..bbeb9786 Binary files /dev/null and b/images/monsters/polarbear.gif differ diff --git a/images/monsters/priestess.gif b/images/monsters/priestess.gif new file mode 100644 index 00000000..79da9b46 Binary files /dev/null and b/images/monsters/priestess.gif differ diff --git a/images/monsters/quara constrictor scout.gif b/images/monsters/quara constrictor scout.gif new file mode 100644 index 00000000..27815538 Binary files /dev/null and b/images/monsters/quara constrictor scout.gif differ diff --git a/images/monsters/quara constrictor.gif b/images/monsters/quara constrictor.gif new file mode 100644 index 00000000..27815538 Binary files /dev/null and b/images/monsters/quara constrictor.gif differ diff --git a/images/monsters/quara hydromancer scout.gif b/images/monsters/quara hydromancer scout.gif new file mode 100644 index 00000000..638be5a7 Binary files /dev/null and b/images/monsters/quara hydromancer scout.gif differ diff --git a/images/monsters/quara hydromancer.gif b/images/monsters/quara hydromancer.gif new file mode 100644 index 00000000..638be5a7 Binary files /dev/null and b/images/monsters/quara hydromancer.gif differ diff --git a/images/monsters/quara mantassin scout.gif b/images/monsters/quara mantassin scout.gif new file mode 100644 index 00000000..b9cf7f11 Binary files /dev/null and b/images/monsters/quara mantassin scout.gif differ diff --git a/images/monsters/quara mantassin.gif b/images/monsters/quara mantassin.gif new file mode 100644 index 00000000..b9cf7f11 Binary files /dev/null and b/images/monsters/quara mantassin.gif differ diff --git a/images/monsters/quara pincher scout.gif b/images/monsters/quara pincher scout.gif new file mode 100644 index 00000000..d16bb681 Binary files /dev/null and b/images/monsters/quara pincher scout.gif differ diff --git a/images/monsters/quara pincher.gif b/images/monsters/quara pincher.gif new file mode 100644 index 00000000..d16bb681 Binary files /dev/null and b/images/monsters/quara pincher.gif differ diff --git a/images/monsters/quara predator scout.gif b/images/monsters/quara predator scout.gif new file mode 100644 index 00000000..06ebd964 Binary files /dev/null and b/images/monsters/quara predator scout.gif differ diff --git a/images/monsters/quara predator.gif b/images/monsters/quara predator.gif new file mode 100644 index 00000000..06ebd964 Binary files /dev/null and b/images/monsters/quara predator.gif differ diff --git a/images/monsters/quaraconstrictor.gif b/images/monsters/quaraconstrictor.gif new file mode 100644 index 00000000..0dbea560 Binary files /dev/null and b/images/monsters/quaraconstrictor.gif differ diff --git a/images/monsters/quarahydromancer.gif b/images/monsters/quarahydromancer.gif new file mode 100644 index 00000000..84ff7d9c Binary files /dev/null and b/images/monsters/quarahydromancer.gif differ diff --git a/images/monsters/quaramantassin.gif b/images/monsters/quaramantassin.gif new file mode 100644 index 00000000..eda1a488 Binary files /dev/null and b/images/monsters/quaramantassin.gif differ diff --git a/images/monsters/quarapincher.gif b/images/monsters/quarapincher.gif new file mode 100644 index 00000000..f30c5508 Binary files /dev/null and b/images/monsters/quarapincher.gif differ diff --git a/images/monsters/quarapredator.gif b/images/monsters/quarapredator.gif new file mode 100644 index 00000000..214b6e60 Binary files /dev/null and b/images/monsters/quarapredator.gif differ diff --git a/images/monsters/rabbit.gif b/images/monsters/rabbit.gif new file mode 100644 index 00000000..5fb4c4e7 Binary files /dev/null and b/images/monsters/rabbit.gif differ diff --git a/images/monsters/rat.gif b/images/monsters/rat.gif new file mode 100644 index 00000000..458f06ec Binary files /dev/null and b/images/monsters/rat.gif differ diff --git a/images/monsters/rift brood.gif b/images/monsters/rift brood.gif new file mode 100644 index 00000000..090b778e Binary files /dev/null and b/images/monsters/rift brood.gif differ diff --git a/images/monsters/rift scythe.gif b/images/monsters/rift scythe.gif new file mode 100644 index 00000000..a9accab8 Binary files /dev/null and b/images/monsters/rift scythe.gif differ diff --git a/images/monsters/rift worm.gif b/images/monsters/rift worm.gif new file mode 100644 index 00000000..ee82a76a Binary files /dev/null and b/images/monsters/rift worm.gif differ diff --git a/images/monsters/roaring water elemental.gif b/images/monsters/roaring water elemental.gif new file mode 100644 index 00000000..aaaba295 Binary files /dev/null and b/images/monsters/roaring water elemental.gif differ diff --git a/images/monsters/rocky.gif b/images/monsters/rocky.gif new file mode 100644 index 00000000..bc5c9ab1 Binary files /dev/null and b/images/monsters/rocky.gif differ diff --git a/images/monsters/ron the ripper.gif b/images/monsters/ron the ripper.gif new file mode 100644 index 00000000..47dc213c Binary files /dev/null and b/images/monsters/ron the ripper.gif differ diff --git a/images/monsters/rotworm queen.gif b/images/monsters/rotworm queen.gif new file mode 100644 index 00000000..dd78aa91 Binary files /dev/null and b/images/monsters/rotworm queen.gif differ diff --git a/images/monsters/rotworm.gif b/images/monsters/rotworm.gif new file mode 100644 index 00000000..5e3ea3da Binary files /dev/null and b/images/monsters/rotworm.gif differ diff --git a/images/monsters/scarab.gif b/images/monsters/scarab.gif new file mode 100644 index 00000000..a1d9c742 Binary files /dev/null and b/images/monsters/scarab.gif differ diff --git a/images/monsters/scorpion.gif b/images/monsters/scorpion.gif new file mode 100644 index 00000000..f51f5fc4 Binary files /dev/null and b/images/monsters/scorpion.gif differ diff --git a/images/monsters/sea serpent.gif b/images/monsters/sea serpent.gif new file mode 100644 index 00000000..b02b314e Binary files /dev/null and b/images/monsters/sea serpent.gif differ diff --git a/images/monsters/seagull.gif b/images/monsters/seagull.gif new file mode 100644 index 00000000..7c9a110d Binary files /dev/null and b/images/monsters/seagull.gif differ diff --git a/images/monsters/seaserpent.gif b/images/monsters/seaserpent.gif new file mode 100644 index 00000000..7dd49ef7 Binary files /dev/null and b/images/monsters/seaserpent.gif differ diff --git a/images/monsters/serpent spawn.gif b/images/monsters/serpent spawn.gif new file mode 100644 index 00000000..f26c0a7d Binary files /dev/null and b/images/monsters/serpent spawn.gif differ diff --git a/images/monsters/serpentspawn.gif b/images/monsters/serpentspawn.gif new file mode 100644 index 00000000..82addbde Binary files /dev/null and b/images/monsters/serpentspawn.gif differ diff --git a/images/monsters/sheep.gif b/images/monsters/sheep.gif new file mode 100644 index 00000000..6c26eb3a Binary files /dev/null and b/images/monsters/sheep.gif differ diff --git a/images/monsters/shredderthrower.gif b/images/monsters/shredderthrower.gif new file mode 100644 index 00000000..d938b8f2 Binary files /dev/null and b/images/monsters/shredderthrower.gif differ diff --git a/images/monsters/sibang.gif b/images/monsters/sibang.gif new file mode 100644 index 00000000..d41f1d8b Binary files /dev/null and b/images/monsters/sibang.gif differ diff --git a/images/monsters/silver rabbit.gif b/images/monsters/silver rabbit.gif new file mode 100644 index 00000000..7ffa53b0 Binary files /dev/null and b/images/monsters/silver rabbit.gif differ diff --git a/images/monsters/silverrabbit.gif b/images/monsters/silverrabbit.gif new file mode 100644 index 00000000..635cea5d Binary files /dev/null and b/images/monsters/silverrabbit.gif differ diff --git a/images/monsters/skeleton warrior.gif b/images/monsters/skeleton warrior.gif new file mode 100644 index 00000000..9463cf38 Binary files /dev/null and b/images/monsters/skeleton warrior.gif differ diff --git a/images/monsters/skeleton.gif b/images/monsters/skeleton.gif new file mode 100644 index 00000000..b5aa1cc9 Binary files /dev/null and b/images/monsters/skeleton.gif differ diff --git a/images/monsters/skeletonwarrior.gif b/images/monsters/skeletonwarrior.gif new file mode 100644 index 00000000..496b9f2b Binary files /dev/null and b/images/monsters/skeletonwarrior.gif differ diff --git a/images/monsters/skunk.gif b/images/monsters/skunk.gif new file mode 100644 index 00000000..f0403215 Binary files /dev/null and b/images/monsters/skunk.gif differ diff --git a/images/monsters/slick water elemental.gif b/images/monsters/slick water elemental.gif new file mode 100644 index 00000000..afffcef4 Binary files /dev/null and b/images/monsters/slick water elemental.gif differ diff --git a/images/monsters/slim.gif b/images/monsters/slim.gif new file mode 100644 index 00000000..38334148 Binary files /dev/null and b/images/monsters/slim.gif differ diff --git a/images/monsters/slime.gif b/images/monsters/slime.gif new file mode 100644 index 00000000..e58c3d2e Binary files /dev/null and b/images/monsters/slime.gif differ diff --git a/images/monsters/slime2.gif b/images/monsters/slime2.gif new file mode 100644 index 00000000..fa9f2505 Binary files /dev/null and b/images/monsters/slime2.gif differ diff --git a/images/monsters/smoczek.gif b/images/monsters/smoczek.gif new file mode 100644 index 00000000..612307f1 Binary files /dev/null and b/images/monsters/smoczek.gif differ diff --git a/images/monsters/smok.gif b/images/monsters/smok.gif new file mode 100644 index 00000000..612307f1 Binary files /dev/null and b/images/monsters/smok.gif differ diff --git a/images/monsters/smuggler.gif b/images/monsters/smuggler.gif new file mode 100644 index 00000000..0fad3bd2 Binary files /dev/null and b/images/monsters/smuggler.gif differ diff --git a/images/monsters/snake.gif b/images/monsters/snake.gif new file mode 100644 index 00000000..056e42e5 Binary files /dev/null and b/images/monsters/snake.gif differ diff --git a/images/monsters/son of verminor.gif b/images/monsters/son of verminor.gif new file mode 100644 index 00000000..fcd92bb6 Binary files /dev/null and b/images/monsters/son of verminor.gif differ diff --git a/images/monsters/sonofverminor.gif b/images/monsters/sonofverminor.gif new file mode 100644 index 00000000..fa9f2505 Binary files /dev/null and b/images/monsters/sonofverminor.gif differ diff --git a/images/monsters/spectre.gif b/images/monsters/spectre.gif new file mode 100644 index 00000000..fceb4891 Binary files /dev/null and b/images/monsters/spectre.gif differ diff --git a/images/monsters/spider.gif b/images/monsters/spider.gif new file mode 100644 index 00000000..3f81791f Binary files /dev/null and b/images/monsters/spider.gif differ diff --git a/images/monsters/spirit of earth.gif b/images/monsters/spirit of earth.gif new file mode 100644 index 00000000..56a73439 Binary files /dev/null and b/images/monsters/spirit of earth.gif differ diff --git a/images/monsters/spirit of fire.gif b/images/monsters/spirit of fire.gif new file mode 100644 index 00000000..da258024 Binary files /dev/null and b/images/monsters/spirit of fire.gif differ diff --git a/images/monsters/spirit of water.gif b/images/monsters/spirit of water.gif new file mode 100644 index 00000000..aaaba295 Binary files /dev/null and b/images/monsters/spirit of water.gif differ diff --git a/images/monsters/spit nettle.gif b/images/monsters/spit nettle.gif new file mode 100644 index 00000000..7ab82813 Binary files /dev/null and b/images/monsters/spit nettle.gif differ diff --git a/images/monsters/spitnettle.gif b/images/monsters/spitnettle.gif new file mode 100644 index 00000000..2a1a4dcf Binary files /dev/null and b/images/monsters/spitnettle.gif differ diff --git a/images/monsters/squirrel.gif b/images/monsters/squirrel.gif new file mode 100644 index 00000000..a8f22707 Binary files /dev/null and b/images/monsters/squirrel.gif differ diff --git a/images/monsters/stalker.gif b/images/monsters/stalker.gif new file mode 100644 index 00000000..c5e68f3a Binary files /dev/null and b/images/monsters/stalker.gif differ diff --git a/images/monsters/stone golem.gif b/images/monsters/stone golem.gif new file mode 100644 index 00000000..56a73439 Binary files /dev/null and b/images/monsters/stone golem.gif differ diff --git a/images/monsters/stonegolem.gif b/images/monsters/stonegolem.gif new file mode 100644 index 00000000..69ac6236 Binary files /dev/null and b/images/monsters/stonegolem.gif differ diff --git a/images/monsters/svoren the mad.gif b/images/monsters/svoren the mad.gif new file mode 100644 index 00000000..e570f949 Binary files /dev/null and b/images/monsters/svoren the mad.gif differ diff --git a/images/monsters/swamp troll.gif b/images/monsters/swamp troll.gif new file mode 100644 index 00000000..0ff0dac5 Binary files /dev/null and b/images/monsters/swamp troll.gif differ diff --git a/images/monsters/swamptroll.gif b/images/monsters/swamptroll.gif new file mode 100644 index 00000000..44d387c7 Binary files /dev/null and b/images/monsters/swamptroll.gif differ diff --git a/images/monsters/tarantula.gif b/images/monsters/tarantula.gif new file mode 100644 index 00000000..cfc08336 Binary files /dev/null and b/images/monsters/tarantula.gif differ diff --git a/images/monsters/terror bird.gif b/images/monsters/terror bird.gif new file mode 100644 index 00000000..99c3edb8 Binary files /dev/null and b/images/monsters/terror bird.gif differ diff --git a/images/monsters/terrorbird.gif b/images/monsters/terrorbird.gif new file mode 100644 index 00000000..8accd10c Binary files /dev/null and b/images/monsters/terrorbird.gif differ diff --git a/images/monsters/thalas.gif b/images/monsters/thalas.gif new file mode 100644 index 00000000..ce35bb0b Binary files /dev/null and b/images/monsters/thalas.gif differ diff --git a/images/monsters/the abomination.gif b/images/monsters/the abomination.gif new file mode 100644 index 00000000..74356b6d Binary files /dev/null and b/images/monsters/the abomination.gif differ diff --git a/images/monsters/the count.gif b/images/monsters/the count.gif new file mode 100644 index 00000000..8485db2b Binary files /dev/null and b/images/monsters/the count.gif differ diff --git a/images/monsters/the dark dancer.gif b/images/monsters/the dark dancer.gif new file mode 100644 index 00000000..79da9b46 Binary files /dev/null and b/images/monsters/the dark dancer.gif differ diff --git a/images/monsters/the evil eye.gif b/images/monsters/the evil eye.gif new file mode 100644 index 00000000..2ca3a866 Binary files /dev/null and b/images/monsters/the evil eye.gif differ diff --git a/images/monsters/the hairy one.gif b/images/monsters/the hairy one.gif new file mode 100644 index 00000000..de54f261 Binary files /dev/null and b/images/monsters/the hairy one.gif differ diff --git a/images/monsters/the halloween hare.gif b/images/monsters/the halloween hare.gif new file mode 100644 index 00000000..effccbb0 Binary files /dev/null and b/images/monsters/the halloween hare.gif differ diff --git a/images/monsters/the handmaiden.gif b/images/monsters/the handmaiden.gif new file mode 100644 index 00000000..722b24d9 Binary files /dev/null and b/images/monsters/the handmaiden.gif differ diff --git a/images/monsters/the imperor.gif b/images/monsters/the imperor.gif new file mode 100644 index 00000000..2cd8b63e Binary files /dev/null and b/images/monsters/the imperor.gif differ diff --git a/images/monsters/the obliverator.gif b/images/monsters/the obliverator.gif new file mode 100644 index 00000000..0176ff59 Binary files /dev/null and b/images/monsters/the obliverator.gif differ diff --git a/images/monsters/the old widow.gif b/images/monsters/the old widow.gif new file mode 100644 index 00000000..ddd32287 Binary files /dev/null and b/images/monsters/the old widow.gif differ diff --git a/images/monsters/the plasmother.gif b/images/monsters/the plasmother.gif new file mode 100644 index 00000000..61909f28 Binary files /dev/null and b/images/monsters/the plasmother.gif differ diff --git a/images/monsters/thornback tortoise.gif b/images/monsters/thornback tortoise.gif new file mode 100644 index 00000000..3850dd9d Binary files /dev/null and b/images/monsters/thornback tortoise.gif differ diff --git a/images/monsters/thornbacktortoise.gif b/images/monsters/thornbacktortoise.gif new file mode 100644 index 00000000..fcef3d54 Binary files /dev/null and b/images/monsters/thornbacktortoise.gif differ diff --git a/images/monsters/thul.gif b/images/monsters/thul.gif new file mode 100644 index 00000000..27815538 Binary files /dev/null and b/images/monsters/thul.gif differ diff --git a/images/monsters/tiger.gif b/images/monsters/tiger.gif new file mode 100644 index 00000000..1bcf42b9 Binary files /dev/null and b/images/monsters/tiger.gif differ diff --git a/images/monsters/tiquandas revenge.gif b/images/monsters/tiquandas revenge.gif new file mode 100644 index 00000000..2edfcdbf Binary files /dev/null and b/images/monsters/tiquandas revenge.gif differ diff --git a/images/monsters/toad.gif b/images/monsters/toad.gif new file mode 100644 index 00000000..6b49ff79 Binary files /dev/null and b/images/monsters/toad.gif differ diff --git a/images/monsters/tortoise.gif b/images/monsters/tortoise.gif new file mode 100644 index 00000000..7d70acfb Binary files /dev/null and b/images/monsters/tortoise.gif differ diff --git a/images/monsters/troll champion.gif b/images/monsters/troll champion.gif new file mode 100644 index 00000000..56d84a0b Binary files /dev/null and b/images/monsters/troll champion.gif differ diff --git a/images/monsters/troll.gif b/images/monsters/troll.gif new file mode 100644 index 00000000..9377600b Binary files /dev/null and b/images/monsters/troll.gif differ diff --git a/images/monsters/trollchampion.gif b/images/monsters/trollchampion.gif new file mode 100644 index 00000000..a66c62f0 Binary files /dev/null and b/images/monsters/trollchampion.gif differ diff --git a/images/monsters/undead dragon.gif b/images/monsters/undead dragon.gif new file mode 100644 index 00000000..be2aabba Binary files /dev/null and b/images/monsters/undead dragon.gif differ diff --git a/images/monsters/undead minion.gif b/images/monsters/undead minion.gif new file mode 100644 index 00000000..7e4187e5 Binary files /dev/null and b/images/monsters/undead minion.gif differ diff --git a/images/monsters/undeaddragon.gif b/images/monsters/undeaddragon.gif new file mode 100644 index 00000000..d50e3442 Binary files /dev/null and b/images/monsters/undeaddragon.gif differ diff --git a/images/monsters/ushuriel.gif b/images/monsters/ushuriel.gif new file mode 100644 index 00000000..2f7e0cf9 Binary files /dev/null and b/images/monsters/ushuriel.gif differ diff --git a/images/monsters/valkyrie.gif b/images/monsters/valkyrie.gif new file mode 100644 index 00000000..9b23b325 Binary files /dev/null and b/images/monsters/valkyrie.gif differ diff --git a/images/monsters/vampire bride.gif b/images/monsters/vampire bride.gif new file mode 100644 index 00000000..3f66c3f2 Binary files /dev/null and b/images/monsters/vampire bride.gif differ diff --git a/images/monsters/vampire.gif b/images/monsters/vampire.gif new file mode 100644 index 00000000..8a1579fd Binary files /dev/null and b/images/monsters/vampire.gif differ diff --git a/images/monsters/vashresamun.gif b/images/monsters/vashresamun.gif new file mode 100644 index 00000000..ce35bb0b Binary files /dev/null and b/images/monsters/vashresamun.gif differ diff --git a/images/monsters/war golem.gif b/images/monsters/war golem.gif new file mode 100644 index 00000000..ded325fe Binary files /dev/null and b/images/monsters/war golem.gif differ diff --git a/images/monsters/war wolf.gif b/images/monsters/war wolf.gif new file mode 100644 index 00000000..5c4b2884 Binary files /dev/null and b/images/monsters/war wolf.gif differ diff --git a/images/monsters/warlock.gif b/images/monsters/warlock.gif new file mode 100644 index 00000000..2ef3574b Binary files /dev/null and b/images/monsters/warlock.gif differ diff --git a/images/monsters/warwolf.gif b/images/monsters/warwolf.gif new file mode 100644 index 00000000..cf9bb5b6 Binary files /dev/null and b/images/monsters/warwolf.gif differ diff --git a/images/monsters/wasp.gif b/images/monsters/wasp.gif new file mode 100644 index 00000000..b518975f Binary files /dev/null and b/images/monsters/wasp.gif differ diff --git a/images/monsters/water elemental.gif b/images/monsters/water elemental.gif new file mode 100644 index 00000000..afffcef4 Binary files /dev/null and b/images/monsters/water elemental.gif differ diff --git a/images/monsters/waterelemental.gif b/images/monsters/waterelemental.gif new file mode 100644 index 00000000..fd6d9c40 Binary files /dev/null and b/images/monsters/waterelemental.gif differ diff --git a/images/monsters/waterelementalmassive.gif b/images/monsters/waterelementalmassive.gif new file mode 100644 index 00000000..1e3f9a0e Binary files /dev/null and b/images/monsters/waterelementalmassive.gif differ diff --git a/images/monsters/webster.gif b/images/monsters/webster.gif new file mode 100644 index 00000000..c57899d7 Binary files /dev/null and b/images/monsters/webster.gif differ diff --git a/images/monsters/werewolf.gif b/images/monsters/werewolf.gif new file mode 100644 index 00000000..cc8ef554 Binary files /dev/null and b/images/monsters/werewolf.gif differ diff --git a/images/monsters/wild warrior.gif b/images/monsters/wild warrior.gif new file mode 100644 index 00000000..f4ac37f2 Binary files /dev/null and b/images/monsters/wild warrior.gif differ diff --git a/images/monsters/wildwarrior.gif b/images/monsters/wildwarrior.gif new file mode 100644 index 00000000..512551d1 Binary files /dev/null and b/images/monsters/wildwarrior.gif differ diff --git a/images/monsters/winter wolf.gif b/images/monsters/winter wolf.gif new file mode 100644 index 00000000..3c066fa2 Binary files /dev/null and b/images/monsters/winter wolf.gif differ diff --git a/images/monsters/winterwolf.gif b/images/monsters/winterwolf.gif new file mode 100644 index 00000000..af27fa9d Binary files /dev/null and b/images/monsters/winterwolf.gif differ diff --git a/images/monsters/wisp.gif b/images/monsters/wisp.gif new file mode 100644 index 00000000..e82f0d2c Binary files /dev/null and b/images/monsters/wisp.gif differ diff --git a/images/monsters/witch.gif b/images/monsters/witch.gif new file mode 100644 index 00000000..4d2958cf Binary files /dev/null and b/images/monsters/witch.gif differ diff --git a/images/monsters/wolf.gif b/images/monsters/wolf.gif new file mode 100644 index 00000000..60c2c313 Binary files /dev/null and b/images/monsters/wolf.gif differ diff --git a/images/monsters/worker golem.gif b/images/monsters/worker golem.gif new file mode 100644 index 00000000..ec3e58c1 Binary files /dev/null and b/images/monsters/worker golem.gif differ diff --git a/images/monsters/wraith.gif b/images/monsters/wraith.gif new file mode 100644 index 00000000..bce51bc7 Binary files /dev/null and b/images/monsters/wraith.gif differ diff --git a/images/monsters/wyrm.gif b/images/monsters/wyrm.gif new file mode 100644 index 00000000..0b13fdf9 Binary files /dev/null and b/images/monsters/wyrm.gif differ diff --git a/images/monsters/wyvern.gif b/images/monsters/wyvern.gif new file mode 100644 index 00000000..9869fddf Binary files /dev/null and b/images/monsters/wyvern.gif differ diff --git a/images/monsters/xenia.gif b/images/monsters/xenia.gif new file mode 100644 index 00000000..916a4975 Binary files /dev/null and b/images/monsters/xenia.gif differ diff --git a/images/monsters/yeti.gif b/images/monsters/yeti.gif new file mode 100644 index 00000000..45c69626 Binary files /dev/null and b/images/monsters/yeti.gif differ diff --git a/images/monsters/young sea serpent.gif b/images/monsters/young sea serpent.gif new file mode 100644 index 00000000..ea179b9a Binary files /dev/null and b/images/monsters/young sea serpent.gif differ diff --git a/images/monsters/zombie.gif b/images/monsters/zombie.gif new file mode 100644 index 00000000..c20c1bc9 Binary files /dev/null and b/images/monsters/zombie.gif differ diff --git a/images/monsters/zugurosh.gif b/images/monsters/zugurosh.gif new file mode 100644 index 00000000..08874c97 Binary files /dev/null and b/images/monsters/zugurosh.gif differ diff --git a/images/news/blank.gif b/images/news/blank.gif new file mode 100644 index 00000000..06926d0a Binary files /dev/null and b/images/news/blank.gif differ diff --git a/images/news/icon_0.gif b/images/news/icon_0.gif new file mode 100644 index 00000000..78e2e8ff Binary files /dev/null and b/images/news/icon_0.gif differ diff --git a/images/news/icon_0_small.gif b/images/news/icon_0_small.gif new file mode 100644 index 00000000..5ffc2b42 Binary files /dev/null and b/images/news/icon_0_small.gif differ diff --git a/images/news/icon_1.gif b/images/news/icon_1.gif new file mode 100644 index 00000000..2b36e957 Binary files /dev/null and b/images/news/icon_1.gif differ diff --git a/images/news/icon_1_small.gif b/images/news/icon_1_small.gif new file mode 100644 index 00000000..284d033f Binary files /dev/null and b/images/news/icon_1_small.gif differ diff --git a/images/news/icon_2.gif b/images/news/icon_2.gif new file mode 100644 index 00000000..5347643b Binary files /dev/null and b/images/news/icon_2.gif differ diff --git a/images/news/icon_2_small.gif b/images/news/icon_2_small.gif new file mode 100644 index 00000000..62deeb8c Binary files /dev/null and b/images/news/icon_2_small.gif differ diff --git a/images/news/icon_3.gif b/images/news/icon_3.gif new file mode 100644 index 00000000..47512fac Binary files /dev/null and b/images/news/icon_3.gif differ diff --git a/images/news/icon_3_small.gif b/images/news/icon_3_small.gif new file mode 100644 index 00000000..b7418840 Binary files /dev/null and b/images/news/icon_3_small.gif differ diff --git a/images/news/icon_4.gif b/images/news/icon_4.gif new file mode 100644 index 00000000..5d7a454e Binary files /dev/null and b/images/news/icon_4.gif differ diff --git a/images/news/icon_4_small.gif b/images/news/icon_4_small.gif new file mode 100644 index 00000000..fad06ef3 Binary files /dev/null and b/images/news/icon_4_small.gif differ diff --git a/images/notify.png b/images/notify.png new file mode 100644 index 00000000..6e0015df Binary files /dev/null and b/images/notify.png differ diff --git a/images/palladin.png b/images/palladin.png new file mode 100644 index 00000000..698b4e7d Binary files /dev/null and b/images/palladin.png differ diff --git a/images/payments/daopay.gif b/images/payments/daopay.gif new file mode 100644 index 00000000..c986cc23 Binary files /dev/null and b/images/payments/daopay.gif differ diff --git a/images/payments/dotpay.png b/images/payments/dotpay.png new file mode 100644 index 00000000..b587080d Binary files /dev/null and b/images/payments/dotpay.png differ diff --git a/images/payments/paypal.gif b/images/payments/paypal.gif new file mode 100644 index 00000000..969a19bf Binary files /dev/null and b/images/payments/paypal.gif differ diff --git a/images/payments/sms.gif b/images/payments/sms.gif new file mode 100644 index 00000000..a1f59774 Binary files /dev/null and b/images/payments/sms.gif differ diff --git a/images/plus.gif b/images/plus.gif new file mode 100644 index 00000000..9306686d Binary files /dev/null and b/images/plus.gif differ diff --git a/images/redskull.gif b/images/redskull.gif new file mode 100644 index 00000000..c7dc2e01 Binary files /dev/null and b/images/redskull.gif differ diff --git a/images/refresh.gif b/images/refresh.gif new file mode 100644 index 00000000..d04bd394 Binary files /dev/null and b/images/refresh.gif differ diff --git a/images/screenshots/demon.jpg b/images/screenshots/demon.jpg new file mode 100644 index 00000000..b2a787f5 Binary files /dev/null and b/images/screenshots/demon.jpg differ diff --git a/images/screenshots/demon_thumb.gif b/images/screenshots/demon_thumb.gif new file mode 100644 index 00000000..52fefa0c Binary files /dev/null and b/images/screenshots/demon_thumb.gif differ diff --git a/images/search.png b/images/search.png new file mode 100644 index 00000000..cf3d97f7 Binary files /dev/null and b/images/search.png differ diff --git a/images/smileys/icon_arrow.gif b/images/smileys/icon_arrow.gif new file mode 100644 index 00000000..2880055c Binary files /dev/null and b/images/smileys/icon_arrow.gif differ diff --git a/images/smileys/icon_biggrin.gif b/images/smileys/icon_biggrin.gif new file mode 100644 index 00000000..d3527723 Binary files /dev/null and b/images/smileys/icon_biggrin.gif differ diff --git a/images/smileys/icon_confused.gif b/images/smileys/icon_confused.gif new file mode 100644 index 00000000..0c49e069 Binary files /dev/null and b/images/smileys/icon_confused.gif differ diff --git a/images/smileys/icon_cool.gif b/images/smileys/icon_cool.gif new file mode 100644 index 00000000..cead0306 Binary files /dev/null and b/images/smileys/icon_cool.gif differ diff --git a/images/smileys/icon_cry.gif b/images/smileys/icon_cry.gif new file mode 100644 index 00000000..7d54b1f9 Binary files /dev/null and b/images/smileys/icon_cry.gif differ diff --git a/images/smileys/icon_doubt.gif b/images/smileys/icon_doubt.gif new file mode 100644 index 00000000..fd7903b1 Binary files /dev/null and b/images/smileys/icon_doubt.gif differ diff --git a/images/smileys/icon_doubt2.gif b/images/smileys/icon_doubt2.gif new file mode 100644 index 00000000..eb4b70b6 Binary files /dev/null and b/images/smileys/icon_doubt2.gif differ diff --git a/images/smileys/icon_eek.gif b/images/smileys/icon_eek.gif new file mode 100644 index 00000000..5d397810 Binary files /dev/null and b/images/smileys/icon_eek.gif differ diff --git a/images/smileys/icon_evil.gif b/images/smileys/icon_evil.gif new file mode 100644 index 00000000..ab1aa8e1 Binary files /dev/null and b/images/smileys/icon_evil.gif differ diff --git a/images/smileys/icon_exclaim.gif b/images/smileys/icon_exclaim.gif new file mode 100644 index 00000000..6e50e2ee Binary files /dev/null and b/images/smileys/icon_exclaim.gif differ diff --git a/images/smileys/icon_frown.gif b/images/smileys/icon_frown.gif new file mode 100644 index 00000000..d2ac78c0 Binary files /dev/null and b/images/smileys/icon_frown.gif differ diff --git a/images/smileys/icon_fun.gif b/images/smileys/icon_fun.gif new file mode 100644 index 00000000..a8bb8a30 Binary files /dev/null and b/images/smileys/icon_fun.gif differ diff --git a/images/smileys/icon_idea.gif b/images/smileys/icon_idea.gif new file mode 100644 index 00000000..a40ae0d7 Binary files /dev/null and b/images/smileys/icon_idea.gif differ diff --git a/images/smileys/icon_kaddi.gif b/images/smileys/icon_kaddi.gif new file mode 100644 index 00000000..1410f7f1 Binary files /dev/null and b/images/smileys/icon_kaddi.gif differ diff --git a/images/smileys/icon_lol.gif b/images/smileys/icon_lol.gif new file mode 100644 index 00000000..374ba150 Binary files /dev/null and b/images/smileys/icon_lol.gif differ diff --git a/images/smileys/icon_mrgreen.gif b/images/smileys/icon_mrgreen.gif new file mode 100644 index 00000000..b54cd0f9 Binary files /dev/null and b/images/smileys/icon_mrgreen.gif differ diff --git a/images/smileys/icon_neutral.gif b/images/smileys/icon_neutral.gif new file mode 100644 index 00000000..4f311567 Binary files /dev/null and b/images/smileys/icon_neutral.gif differ diff --git a/images/smileys/icon_question.gif b/images/smileys/icon_question.gif new file mode 100644 index 00000000..9d072265 Binary files /dev/null and b/images/smileys/icon_question.gif differ diff --git a/images/smileys/icon_razz.gif b/images/smileys/icon_razz.gif new file mode 100644 index 00000000..29da2a2f Binary files /dev/null and b/images/smileys/icon_razz.gif differ diff --git a/images/smileys/icon_redface.gif b/images/smileys/icon_redface.gif new file mode 100644 index 00000000..ad762832 Binary files /dev/null and b/images/smileys/icon_redface.gif differ diff --git a/images/smileys/icon_rolleyes.gif b/images/smileys/icon_rolleyes.gif new file mode 100644 index 00000000..d7f5f2f4 Binary files /dev/null and b/images/smileys/icon_rolleyes.gif differ diff --git a/images/smileys/icon_sad.gif b/images/smileys/icon_sad.gif new file mode 100644 index 00000000..d2ac78c0 Binary files /dev/null and b/images/smileys/icon_sad.gif differ diff --git a/images/smileys/icon_silenced.gif b/images/smileys/icon_silenced.gif new file mode 100644 index 00000000..448399b2 Binary files /dev/null and b/images/smileys/icon_silenced.gif differ diff --git a/images/smileys/icon_smile.gif b/images/smileys/icon_smile.gif new file mode 100644 index 00000000..7b1f6d30 Binary files /dev/null and b/images/smileys/icon_smile.gif differ diff --git a/images/smileys/icon_smile2.gif b/images/smileys/icon_smile2.gif new file mode 100644 index 00000000..769639d3 Binary files /dev/null and b/images/smileys/icon_smile2.gif differ diff --git a/images/smileys/icon_surprised.gif b/images/smileys/icon_surprised.gif new file mode 100644 index 00000000..cb214243 Binary files /dev/null and b/images/smileys/icon_surprised.gif differ diff --git a/images/smileys/icon_twisted.gif b/images/smileys/icon_twisted.gif new file mode 100644 index 00000000..502fe247 Binary files /dev/null and b/images/smileys/icon_twisted.gif differ diff --git a/images/smileys/icon_wink.gif b/images/smileys/icon_wink.gif new file mode 100644 index 00000000..d1482880 Binary files /dev/null and b/images/smileys/icon_wink.gif differ diff --git a/images/sorcerer.png b/images/sorcerer.png new file mode 100644 index 00000000..1d83dafa Binary files /dev/null and b/images/sorcerer.png differ diff --git a/images/success.png b/images/success.png new file mode 100644 index 00000000..a5ae9f11 Binary files /dev/null and b/images/success.png differ diff --git a/images/trash.png b/images/trash.png new file mode 100644 index 00000000..ebad933c Binary files /dev/null and b/images/trash.png differ diff --git a/images/true.png b/images/true.png new file mode 100644 index 00000000..67bbc40a Binary files /dev/null and b/images/true.png differ diff --git a/images/under_construction.jpg b/images/under_construction.jpg new file mode 100644 index 00000000..060e1c4f Binary files /dev/null and b/images/under_construction.jpg differ diff --git a/images/whiteskull.gif b/images/whiteskull.gif new file mode 100644 index 00000000..87c66131 Binary files /dev/null and b/images/whiteskull.gif differ diff --git a/images/yellow_skull.gif b/images/yellow_skull.gif new file mode 100644 index 00000000..2ea9ce7a Binary files /dev/null and b/images/yellow_skull.gif differ diff --git a/index.php b/index.php new file mode 100644 index 00000000..306a1e0e --- /dev/null +++ b/index.php @@ -0,0 +1 @@ + * @copyright 2017 MyAAC * @version 0.0.1 * @link http://my-aac.org */ require_once('common.php'); require_once(BASE . 'config.local.php'); if(file_exists(BASE . 'install') && (!isset($config['installed']) || !$config['installed'])) { header('Location: ' . BASE_DIR . '/install/'); die('Setup detected that install/ directory exists. Please visit this url to start MyAAC Installation.
Delete install/ directory if you already installed MyAAC.
Remember to REFRESH this page when you\'re done!'); } // define page visited, so it can be used within events system $page = isset($_REQUEST['subtopic']) ? $_REQUEST['subtopic'] : (isset($_GET['p']) ? $_GET['p'] : ''); if(empty($page) || preg_match('/[^A-z0-9_\-]/', $page)) $page = 'news'; $page = strtolower($page); define('PAGE', $page); $template_place_holders = array(); // event system require_once(SYSTEM . 'events.php'); $events = new Events(); $events->trigger('STARTUP'); require_once(SYSTEM . 'functions.php'); require_once(SYSTEM . 'init.php'); require_once(SYSTEM . 'login.php'); require_once(SYSTEM . 'status.php'); require_once(SYSTEM . 'template.php'); if($config['views_counter']) require_once(SYSTEM . 'counter.php'); if($config['visitors_counter']) { require_once(SYSTEM . 'libs/visitors.php'); $visitors = new Visitors($config['visitors_counter_ttl']); } // page content loading if(!isset($content[0])) $content = ''; $load_it = true; // check if site has been closed if($config['site_closed']) { if(!admin()) { $title = $config['site_closed_title']; $content .= $config['site_closed_message']; $load_it = false; } if(!$logged) { ob_start(); require(SYSTEM . 'pages/accountmanagement.php'); $content .= ob_get_contents(); ob_end_clean(); $load_it = false; } } if($load_it) { if($config['site_closed'] && admin()) $content .= '

Site is under maintenance (closed mode). Only privileged users can see it.

'; if($config['backward_support']) require(SYSTEM . 'compat_pages.php'); $ignore = false; $file = SYSTEM . 'pages/' . $page . '.php'; if(!@file_exists($file)) { $logged_access = 0; if($logged && $account_logged && $account_logged->isLoaded()) { $logged_access = $account_logged->getAccess(); } $query = $db->query( 'SELECT `title`, `body`, `php`' . ' FROM `' . TABLE_PREFIX . 'pages`' . ' WHERE `name` LIKE ' . $db->quote($page) . ' AND `hidden` != 1 AND `access` <= ' . $db->quote($logged_access)); if($query->rowCount() > 0) // found page { $ignore = true; $query = $query->fetch(); $title = $query['title']; if($query['php'] == '1') // execute it as php code { $tmp = substr($query['body'], 0, 10); if(($pos = strpos($tmp, ' $errno, 'errstr' => $errstr); } set_error_handler('error_handler'); ob_start(); eval($tmp); $content .= ob_get_contents(); ob_end_clean(); restore_error_handler(); if(isset($php_errors[0]) && superAdmin()) { var_dump($php_errors); } } else $content .= $query['body']; // plain html } else { $page = '404'; $file = SYSTEM . 'pages/404.php'; } } ob_start(); if($events->trigger('BEFORE_PAGE')) { if(!$ignore) require($file); } $content .= ob_get_contents(); ob_end_clean(); $events->trigger('AFTER_PAGE'); } $title_full = (isset($title) ? $title . $config['title_separator'] : '') . $config['lua']['serverName']; if(file_exists($template_path . '/index.php')) require($template_path . '/index.php'); else if(file_exists($template_path . '/template.php')) // deprecated require($template_path . '/template.php'); else if($config['backward_support'] && file_exists($template_path . '/layout.php')) { // backward support for gesior $SQL = $db; $layout_header = template_header(); $layout_name = $template_path; $main_content = $content; $config['access_admin_panel'] = 2; $group_id_of_acc_logged = 0; if($logged && $account_logged) $group_id_of_acc_logged = $account_logged->getCustomField('group_id'); $config['gifts_system'] = ($config['site']['shop_system'] == 1); //$config['site']['shop_system'] = $config['gifts_system'] ? '1' : '0'; $config['serverinfo_page'] = 1; $config['download_page'] = 1; if($config['forum'] != '') $config['forum_link'] = (strtolower($config['forum']) == 'site' ? internalLayoutLink('forum') : $config['forum']); $config['site'] = &$config; require($template_path . '/layout.php'); } else { // TODO: save more info to log file die('ERROR: Cannot load template.'); } echo '' . "\n"; if(($config['debug_level'] & 1) == 1) echo ''; if(($config['debug_level'] & 2) == 2) echo "\n" . ''; if(($config['debug_level'] & 4) == 4 && function_exists('memory_get_peak_usage')) echo "\n" . ''; $events->trigger('FINISH'); ?> \ No newline at end of file diff --git a/install/includes/.htaccess b/install/includes/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/install/includes/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/install/includes/database.php b/install/includes/database.php new file mode 100644 index 00000000..22563323 --- /dev/null +++ b/install/includes/database.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/install/includes/functions.php b/install/includes/functions.php new file mode 100644 index 00000000..edc40ff0 --- /dev/null +++ b/install/includes/functions.php @@ -0,0 +1,80 @@ +query($query); + } + catch(PDOException $error_) { + error($error_); + $error = true; + } + + return !$error; +} + +// define php version id if its not already +if(!defined('PHP_VERSION_ID')) { + $version = explode('.', PHP_VERSION); + + define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); +} + +function ini_get_bool($a) +{ + $b = ini_get($a); + + switch (strtolower($b)) + { + case 'on': + case 'yes': + case 'true': + return 'assert.active' !== $a; + + case 'stdout': + case 'stderr': + return 'display_errors' === $a; + + default: + return (bool) (int) $b; + } +} + +function next_buttons($previous = true, $next = true) +{ + global $locale, $step, $steps; + + $i = 1; + foreach($steps as $id => $value) + { + if($step == $value) + break; + + $i++; + } + + $ret = '
'; +/* if($previous) + $ret .= ''; + if($next) + $ret .= ''; +*/ + if($previous) + $ret .= ''; + if($next) + $ret .= ''; + + $ret .= '
'; + return $ret; +} + +function next_form($previous = true, $next = true) +{ + global $step; + + return '
+ ' . next_buttons($previous, $next) . ' +
'; +} +?> \ No newline at end of file diff --git a/install/includes/locale.php b/install/includes/locale.php new file mode 100644 index 00000000..8accaf41 --- /dev/null +++ b/install/includes/locale.php @@ -0,0 +1,51 @@ + 4 || !preg_match("/[a-z]/", $locale_)) // validate locale + $_COOKIE['locale'] = "en"; +} +else +{ + // detect locale + $locale_s = get_browser_languages(); + if(!sizeof($locale_s)) + $locale__ = 'en'; + else + { + foreach($locale_s as $id => $tmp) + { + $tmp_file = LOCALE . $tmp; + if(@file_exists($tmp_file)) + { + $locale_ = $tmp; + break; + } + } + } + + if(!isset($locale_)) + $locale_ = 'en'; +} + +require(LOCALE . 'en/main.php'); +require(LOCALE . 'en/install.php'); + +$file_main = LOCALE . $locale_ . '/main.php'; +if(!file_exists($file_main)) + $file_main = LOCALE . 'en/main.php'; + +$file_install = LOCALE . $locale_ . '/install.php'; +if(!file_exists($file_install)) + $file_install = LOCALE . 'en/install.php'; + +require($file_main); +require($file_install); +?> \ No newline at end of file diff --git a/install/includes/schema.sql b/install/includes/schema.sql new file mode 100644 index 00000000..68d03cbe --- /dev/null +++ b/install/includes/schema.sql @@ -0,0 +1,236 @@ +CREATE TABLE `myaac_account_actions` +( + `account_id` INT(11) NOT NULL, + `ip` INT(11) NOT NULL, + `date` INT(11) NOT NULL, + `action` VARCHAR(255) NOT NULL, + KEY (`account_id`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_bugtracker` +( + `account` VARCHAR(255) NOT NULL, + `type` INT(11) NOT NULL, + `status` INT(11) NOT NULL, + `text` text NOT NULL, + `id` INT(11) NOT NULL, + `subject` VARCHAR(255) NOT NULL, + `reply` INT(11) NOT NULL, + `who` INT(11) NOT NULL, + `uid` INT(11) NOT NULL AUTO_INCREMENT, + `tag` INT(11) NOT NULL, + PRIMARY KEY (`uid`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_changelog` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `body` VARCHAR(500) NOT NULL DEFAULT '', + `type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - added, 2 - removed, 3 - changed, 4 - fixed', + `where` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - server, 2 - site', + `date` INT(11) NOT NULL DEFAULT 0, + `player_id` INT(11) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hidden`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0); + +CREATE TABLE `myaac_commands` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `words` VARCHAR(30) NOT NULL DEFAULT 0, + `description` VARCHAR(300) NOT NULL, + `ordering` INT(11) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE (`words`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_config` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + `value` VARCHAR(1000) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE (`name`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_faq` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `question` VARCHAR(255) NOT NULL DEFAULT '', + `answer` VARCHAR(1020) NOT NULL, + `ordering` INT(11) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_forum_sections` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(32) NOT NULL, + `description` VARCHAR(255) NOT NULL DEFAULT '', + `ordering` INT(11) NOT NULL DEFAULT 0, + `closed` TINYINT(1) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; +INSERT INTO `myaac_forum_sections` (`id`, `name`, `description`, `closed`) VALUES (NULL, 'News', 'News commenting', 1); +INSERT INTO `myaac_forum_sections` (`id`, `name`, `description`) VALUES (NULL, 'Trade', 'Trade offers.'); +INSERT INTO `myaac_forum_sections` (`id`, `name`, `description`) VALUES (NULL, 'Quests', 'Quest making.'); +INSERT INTO `myaac_forum_sections` (`id`, `name`, `description`) VALUES (NULL, 'Pictures', 'Your pictures.'); +INSERT INTO `myaac_forum_sections` (`id`, `name`, `description`) VALUES (NULL, 'Bug Report', 'Report bugs there.'); + +CREATE TABLE `myaac_forum` +( + `id` int(11) NOT NULL AUTO_INCREMENT, + `first_post` int(11) NOT NULL default '0', + `last_post` int(11) NOT NULL default '0', + `section` int(3) NOT NULL default '0', + `replies` int(20) NOT NULL default '0', + `views` int(20) NOT NULL default '0', + `author_aid` int(20) NOT NULL default '0', + `author_guid` int(20) NOT NULL default '0', + `post_text` text NOT NULL, + `post_topic` varchar(255) NOT NULL, + `post_smile` tinyint(1) NOT NULL default '0', + `post_date` int(20) NOT NULL default '0', + `last_edit_aid` int(20) NOT NULL default '0', + `edit_date` int(20) NOT NULL default '0', + `post_ip` varchar(32) NOT NULL default '0.0.0.0', + `sticked` INT(11) NOT NULL DEFAULT '0', + `closed` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `section` (`section`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_monsters` ( + `hide_creature` tinyint(1) NOT NULL default '0', + `name` varchar(255) NOT NULL, + `mana` int(11) NOT NULL, + `exp` int(11) NOT NULL, + `health` int(11) NOT NULL, + `speed_lvl` int(11) NOT NULL default '1', + `use_haste` tinyint(1) NOT NULL, + `voices` text NOT NULL, + `immunities` varchar(255) NOT NULL, + `summonable` tinyint(1) NOT NULL, + `convinceable` tinyint(1) NOT NULL, + `race` varchar(255) NOT NULL, + `gfx_name` varchar(255) NOT NULL, + `file_path` varchar(255) NOT NULL +) ENGINE = MyISAM; + +CREATE TABLE `myaac_movies` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `title` VARCHAR(50) NOT NULL DEFAULT '', + `youtube_id` VARCHAR(20) NOT NULL, + `author` VARCHAR(50) NOT NULL DEFAULT '', + `ordering` INT(11) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_news` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `title` VARCHAR(50) NOT NULL, + `body` VARCHAR(10000) NOT NULL, + `type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - news, 2 - ticket, 3 - article', + `date` INT(11) NOT NULL DEFAULT 0, + `category` TINYINT(1) NOT NULL DEFAULT 0, + `player_id` INT(11) NOT NULL DEFAULT 0, + `last_modified_by` INT(11) NOT NULL DEFAULT 0, + `last_modified_date` INT(11) NOT NULL DEFAULT 0, + `comments` VARCHAR(50) NOT NULL, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_news_categories` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(50) NOT NULL DEFAULT "", + `description` VARCHAR(50) NOT NULL DEFAULT "", + `icon_id` INT(2) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0); +INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 1); +INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 2); +INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 3); +INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 4); +INSERT INTO `myaac_news` (`id`, `type`, `date`, `category`, `title`, `body`, `player_id`, `comments`, `hidden`) VALUES (NULL, '1', UNIX_TIMESTAMP(), '2', 'Hello!', 'MyAAC is just READY to use!', 'slawkens', 'http://my-aac.org', '0'); +INSERT INTO `myaac_news` (`id`, `type`, `date`, `category`, `title`, `body`, `player_id`, `comments`, `hidden`) VALUES (NULL, '2', UNIX_TIMESTAMP(), '4', 'Hello tickets!', 'http://my-aac.org', 'slawkens', '', '0'); + +CREATE TABLE `myaac_notepad` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `account_id` INT(11) NOT NULL, + /*`name` VARCHAR(30) NOT NULL,*/ + `content` TEXT NOT NULL DEFAULT '', + /*`public` TINYINT(1) NOT NULL DEFAULT 0*/ + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_pages` +( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + `title` VARCHAR(30) NOT NULL, + `body` TEXT NOT NULL, + `date` INT(11) NOT NULL DEFAULT 0, + `player_id` INT(11) NOT NULL DEFAULT 0, + `php` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0 - plain html, 1 - php', + `access` TINYINT(2) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_screenshots` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + `comment` VARCHAR(255) NOT NULL DEFAULT '', + `image` VARCHAR(255) NOT NULL, + `thumb` VARCHAR(255) NOT NULL, + `author` VARCHAR(50) NOT NULL DEFAULT '', + `ordering` INT(11) NOT NULL DEFAULT 0, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE = MyISAM; + +INSERT INTO `myaac_screenshots` (`id`, `ordering`, `name`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'Demon', 'images/screenshots/demon.jpg', 'images/screenshots/demon_thumb.gif', 'MyAAC'); + +CREATE TABLE `myaac_spells` +( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `spell` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `words` VARCHAR(255) NOT NULL, + `category` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - attack, 2 - healing, 3 - summon, 4 - supply, 5 - support', + `type` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 - instant, 2 - rune', + `level` INT(11) NOT NULL DEFAULT 0, + `maglevel` INT(11) NOT NULL DEFAULT 0, + `mana` INT(11) NOT NULL DEFAULT 0, + `soul` TINYINT(3) NOT NULL DEFAULT 0, + `conjure_count` TINYINT(3) NOT NULL DEFAULT 0, + `premium` TINYINT(1) NOT NULL DEFAULT 0, + `vocations` VARCHAR(32) NOT NULL, + `cities` VARCHAR(32) NOT NULL, + `hidden` TINYINT(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE (`spell`) +) ENGINE = MyISAM; + +CREATE TABLE `myaac_visitors` +( + `ip` VARCHAR(16) NOT NULL, + `lastvisit` INT(11) NOT NULL DEFAULT 0, + `page` VARCHAR(100) NOT NULL, + UNIQUE (`ip`) +) ENGINE = MyISAM; \ No newline at end of file diff --git a/install/index.php b/install/index.php new file mode 100644 index 00000000..9a0cc734 --- /dev/null +++ b/install/index.php @@ -0,0 +1,46 @@ + $value) + $_SESSION['var_' . $key] = $value; +} + +$steps = array(1 => 'welcome', 2 => 'license', 3 => 'requirements', 4 => 'config', 5 => 'database', 6 => 'finish'); +if(!in_array($step, $steps)) // check if step is valid + die('ERROR: Unknown step.'); + +if($step == 'database') +{ + foreach($_POST['vars'] as $key => $value) + { + if(empty($value)) + { + $step = 'config'; + $errors = '

' . $locale['please_fill_all'] . '

'; + break; + } + } +} + +// step include +ob_start(); +require('steps/' . $step . '.php'); +$content = ob_get_contents(); +ob_end_clean(); + +// render +require('template/template.php'); +//$_SESSION['laststep'] = $step; + +?> diff --git a/install/steps/.htaccess b/install/steps/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/install/steps/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/install/steps/config.php b/install/steps/config.php new file mode 100644 index 00000000..989f90f3 --- /dev/null +++ b/install/steps/config.php @@ -0,0 +1,113 @@ + +
+ + + + + + '; + +echo ' + + + + '; + ?> +
+ +
+ +
+ ' . $locale['step_config_' . $value . '_desc'] . ' +
+ +
+
+ ' . $locale['step_config_client_desc'] . ' +
+ +
\ No newline at end of file diff --git a/install/steps/database.php b/install/steps/database.php new file mode 100644 index 00000000..1bb411f3 --- /dev/null +++ b/install/steps/database.php @@ -0,0 +1,342 @@ + $value) + { + if(strpos($key, 'var_') !== false) + { + if($key == 'var_server_path') + { + $value = str_replace("\\", "/", $value); + if($value[strlen($value) - 1] != '/') + $value .= "/"; + } + + if($key != 'var_account' && $key != 'var_password') { + $content .= '$config[\'' . str_replace('var_', '', $key) . '\'] = \'' . $value . '\';'; + $content .= PHP_EOL; + } + } + } + + $config['server_path'] = $_SESSION['var_server_path']; + // take care of trailing slash at the end + if($config['server_path'][strlen($config['server_path']) - 1] != '/') + $config['server_path'] .= '/'; + + if(!file_exists($config['server_path'] . 'config.lua')) { + error($locale['step_database_error_config']); + $error = true; + } + + if(!$error) { + $config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); + if(isset($config['lua']['sqlType'])) // tfs 0.3 + $config['database_type'] = $config['lua']['sqlType']; + else if(isset($config['lua']['mysqlHost'])) // tfs 0.2/1.0 + $config['database_type'] = 'mysql'; + else if(isset($config['lua']['database_type'])) // otserv + $config['database_type'] = $config['lua']['database_type']; + else if(isset($config['lua']['sql_type'])) // otserv + $config['database_type'] = $config['lua']['sql_type']; + + $config['database_type'] = strtolower($config['database_type']); + if($config['database_type'] != 'mysql') { + $locale['step_database_error_only_mysql'] = str_replace('$DATABASE_TYPE$', '' . $config['database_type'] . '', $locale['step_database_error_only_mysql']); + error($locale['step_database_error_only_mysql']); + $error = true; + } + else { + success($locale['step_database_importing']); + require(BASE . 'install/includes/database.php'); + + if(!tableExist('accounts')) { + $locale['step_database_error_table'] = str_replace('$TABLE$', 'accounts', $locale['step_database_error_table']); + error($locale['step_database_error_table']); + $error = true; + } + + if(tableExist(TABLE_PREFIX . 'account_actions')) { + $locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']); + warning($locale['step_database_error_table_exist']); + } + else if(!$error) { + // import schema + try { + $db->query(file_get_contents(BASE . 'install/includes/schema.sql')); + } + catch(PDOException $error_) { + error($locale['step_database_error_schema'] . ' ' . $error_); + $error = true; + } + + if(!$error) { + $locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']); + success($locale['step_database_success_schema']); + } + } + + if(fieldExist('key', 'accounts')) { + if(query("ALTER TABLE `accounts` MODIFY `key` VARCHAR(64) NOT NULL DEFAULT '';")) + success($locale['step_database_modifying_field'] . ' accounts.key...'); + } + else { + if(query("ALTER TABLE `accounts` ADD `key` VARCHAR(64) NOT NULL DEFAULT '' AFTER `email`;")) + success($locale['step_database_adding_field'] . ' accounts.key...'); + } + + if(!fieldExist('blocked', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `blocked` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT 'internal usage' AFTER `key`;")) + success($locale['step_database_adding_field'] . ' accounts.created...'); + } + + if(!fieldExist('created', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `created` INT(11) NOT NULL DEFAULT 0 AFTER `" . (fieldExist('group_id', 'accounts') ? 'group_id' : 'blocked') . "`;")) + success($locale['step_database_adding_field'] . ' accounts.created...'); + } + + if(!fieldExist('rlname', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `rlname` VARCHAR(255) NOT NULL DEFAULT '' AFTER `created`;")) + success($locale['step_database_adding_field'] . ' accounts.rlname...'); + } + + if(!fieldExist('location', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `location` VARCHAR(255) NOT NULL DEFAULT '' AFTER `rlname`;")) + success($locale['step_database_adding_field'] . ' accounts.location...'); + } + + if(!fieldExist('country', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `country` VARCHAR(3) NOT NULL DEFAULT '' AFTER `location`;")) + success($locale['step_database_adding_field'] . ' accounts.country...'); + } + + if(fieldExist('page_lastday', 'accounts')) { + if(query("ALTER TABLE `accounts` CHANGE `page_lastday` `web_lastlogin` INT(11) NOT NULL DEFAULT 0;")) { + $tmp = str_replace('$FIELD$', 'accounts.page_lastday', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'accounts.web_lastlogin', $tmp); + success($tmp); + } + } + else if(!fieldExist('web_lastlogin', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `web_lastlogin` INT(11) NOT NULL DEFAULT 0 AFTER `country`;")) + success($locale['step_database_adding_field'] . ' accounts.created...'); + } + + if(!fieldExist('web_flags', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `web_flags` INT(11) NOT NULL DEFAULT 0 AFTER `web_lastlogin`;")) + success($locale['step_database_adding_field'] . ' accounts.country...'); + } + + if(!fieldExist('email_hash', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;")) + success($locale['step_database_adding_field'] . ' accounts.email_hash...'); + } + + if(!fieldExist('email_verified', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;")) + success($locale['step_database_adding_field'] . ' accounts.email_verified...'); + } + + if(!fieldExist('email_new', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;")) + success($locale['step_database_adding_field'] . ' accounts.email_new...'); + } + + if(!fieldExist('email_new_time', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `email_new_time` INT(11) NOT NULL DEFAULT 0 AFTER `email_new`;")) + success($locale['step_database_adding_field'] . ' accounts.email_new_time...'); + } + + if(!fieldExist('email_code', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `email_code` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_new_time`;")) + success($locale['step_database_adding_field'] . ' accounts.email_code...'); + } + + if(fieldExist('next_email', 'accounts')) { + if(query("ALTER TABLE `accounts` CHANGE `next_email` `email_next` INT(11) NOT NULL DEFAULT 0;")) { + $tmp = str_replace('$FIELD$', 'accounts.next_email', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'accounts.email_next', $tmp); + success($tmp); + } + } + else if(!fieldExist('email_next', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `email_next` INT(11) NOT NULL DEFAULT 0 AFTER `email_code`;")) + success($locale['step_database_adding_field'] . ' accounts.email_next...'); + } + + if(!fieldExist('premium_points', 'accounts')) { + if(query("ALTER TABLE `accounts` ADD `premium_points` INT(11) NOT NULL DEFAULT 0 AFTER `email_next`;")) + success($locale['step_database_adding_field'] . ' accounts.premium_points...'); + } + + if(!fieldExist('description', 'guilds')) { + if(query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL DEFAULT '';")) + success($locale['step_database_adding_field'] . ' guilds.description...'); + } + + if(fieldExist('logo_gfx_name', 'guilds')) { + if(query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) { + $tmp = str_replace('$FIELD$', 'guilds.logo_gfx_name', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'guilds.logo_name', $tmp); + success($tmp); + } + } + else if(!fieldExist('logo_name', 'guilds')) { + if(query("ALTER TABLE `guilds` ADD `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) + success($locale['step_database_adding_field'] . ' guilds.logo_name...'); + } + + if(!fieldExist('created', 'players')) { + if(query("ALTER TABLE `players` ADD `created` INT(11) NOT NULL DEFAULT 0;")) + success($locale['step_database_adding_field'] . ' players.created...'); + } + + if(fieldExist('hide_char', 'players')) { + if(query("ALTER TABLE `players` CHANGE `hide_char` `hidden` TINYINT(1) NOT NULL DEFAULT 0;")) { + $tmp = str_replace('$FIELD$', 'players.hide_char', $locale['step_database_changing_field']); + $tmp = str_replace('$FIELD_NEW$', 'players.hidden', $tmp); + success($tmp); + } + } + else if(!fieldExist('hidden', 'players')) { + if(query("ALTER TABLE `players` ADD `hidden` VARCHAR( 255 ) TINYINT(1) NOT NULL DEFAULT 0;")) + success($locale['step_database_adding_field'] . ' players.hidden...'); + } + + if(!fieldExist('comment', 'players')) { + if(query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL DEFAULT '';")) + success($locale['step_database_adding_field'] . ' players.comment...'); + } + + $account = $_SESSION['var_account']; + $password = $_SESSION['var_password']; + + $config_salt_enabled = fieldExist('salt', 'accounts'); + if($config_salt_enabled) + { + $salt = generateRandomString(10, false, true, true); + $password = $salt . $password; + } + + $account_db = new OTS_Account(); + $account_db->load(1); + if($account_db->isLoaded()) { + $account_db->setName('dummy_account'); + $account_db->setPassword('for sample characters. ' . generateRandomString(10)); + $account_db->save(); + } + else { + $new_account = $ots->createObject('Account'); + $new_account->create('dummy_account', 1); + $account_db->setPassword('for sample characters. ' . generateRandomString(10)); + } + + + $account_db = new OTS_Account(); + $account_db->find($account); + if($account_db->isLoaded()) { + if($config_salt_enabled) + $account_db->setSalt($salt); + + $account_db->setPassword(encrypt($password)); + $account_db->setEMail($_SESSION['var_mail_admin']); + $account_db->save(); + $account_db->setCustomField('web_flags', 3); + $account_db->setCustomField('country', 'us'); + + $_SESSION['account'] = $account_db->getId(); + } + else { + $new_account = $ots->createObject('Account'); + $new_account->create($account); + + if($config_salt_enabled) + $new_account->setSalt($salt); + + $new_account->setPassword(encrypt($password)); + $new_account->setEMail($_SESSION['var_mail_admin']); + $new_account->unblock(); + $new_account->save(); + $new_account->setCustomField('created', time()); + $new_account->setCustomField('web_flags', 3); + $new_account->setCustomField('country', 'us'); + $new_account->logAction('Account created.'); + + $_SESSION['account'] = $new_account->getId(); + } + + success($locale['step_database_created_account']); + $_SESSION['password'] = encrypt($password); + $_SESSION['remember_me'] = true; + + $deleted = 'deleted'; + if(fieldExist('deletion', 'players')) + $deleted = 'deletion'; + + $query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote('Rook Sample') . ' OR `name` = ' . $db->quote('Sorcerer Sample') . ' OR `name` = ' . $db->quote('Druid Sample') . ' OR `name` = ' . $db->quote('Paladin Sample') . ' OR `name` = ' . $db->quote('Knight Sample')); + if($query->rowCount() == 0) { + if(query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `skull`, `skulltime`, `lastlogout`, `blessings`, `balance`, `stamina`, `$deleted`, `created`, `hidden`, `comment`) VALUES + (null, 'Rook Sample', 1, 1, 8, 0, 185, 185, 4200, 118, 114, 38, 57, 130, 0, 0, 35, 35, 0, 100, 11, 2200, 1298, 7, '', 470, 1, 1255179613, 2453925456, 1, 0, 0, 1255179614, 0, 0, 151200000, 1, UNIX_TIMESTAMP(), 1, ''), + (null, 'Sorcerer Sample', 1, 1, 8, 1, 185, 185, 4200, 118, 114, 38, 57, 130, 0, 0, 35, 35, 0, 100, 11, 2200, 1298, 7, '', 470, 1, 1255179571, 2453925456, 1, 0, 0, 1255179612, 0, 0, 151200000, 1, UNIX_TIMESTAMP(), 1, ''), + (null, 'Druid Sample', 1, 1, 8, 2, 185, 185, 4200, 118, 114, 38, 57, 130, 0, 0, 35, 35, 0, 100, 11, 2200, 1298, 7, '', 470, 1, 1255179655, 2453925456, 1, 0, 0, 1255179658, 0, 0, 151200000, 1, UNIX_TIMESTAMP(), 1, ''), + (null, 'Paladin Sample', 1, 1, 8, 3, 185, 185, 4200, 118, 114, 38, 57, 129, 0, 0, 35, 35, 0, 100, 11, 2200, 1298, 7, '', 470, 1, 1255179854, 2453925456, 1, 0, 0, 1255179858, 0, 0, 151200000, 1, UNIX_TIMESTAMP(), 1, ''), + (null, 'Knight Sample', 1, 1, 8, 4, 185, 185, 4200, 118, 114, 38, 57, 131, 0, 0, 35, 35, 0, 100, 11, 2200, 1298, 7, '', 470, 1, 1255179620, 2453925456, 1, 0, 0, 1255179654, 0, 0, 151200000, 1, UNIX_TIMESTAMP(), 1, '');")) + success($locale['step_database_imported_players']); + } + + if(!$error && !isset($_SESSION['saved'])) { + $content .= '$config[\'installed\'] = true;'; + $content .= PHP_EOL; + if(strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false) { + $content .= '$config[\'friendly_urls\'] = true;'; + $content .= PHP_EOL; + } + + $content .= '$config[\'mail_enabled\'] = true;'; + $content .= PHP_EOL; + if(!check_mail($_SESSION['var_mail_admin'])) { + error($locale['step_config_mail_admin_error']); + $error = true; + } + if(!check_mail($_SESSION['var_mail_address'])) { + error($locale['step_config_mail_address_error']); + $error = true; + } + + $content .= '$config[\'client_download\'] = \'http://clients.halfaway.net/windows.php?tibia=\'. $config[\'client\'];'; + $content .= PHP_EOL; + $content .= '$config[\'client_download_linux\'] = \'http://clients.halfaway.net/linux.php?tibia=\'. $config[\'client\'];'; + $content .= PHP_EOL; + + $content .= "?>"; + $file = fopen(BASE . 'config.local.php', 'a+'); + if($file) { + if(!$error) { + fwrite($file, $content); + $_SESSION['saved'] = true; + } + } + else { + $locale['step_database_error_file'] = str_replace('$FILE$', '' . BASE . 'config.local.php', $locale['step_database_error_file']); + warning($locale['step_database_error_file'] . '
+ '); + } + } + } + } +} +?> + +
+ + +
\ No newline at end of file diff --git a/install/steps/finish.php b/install/steps/finish.php new file mode 100644 index 00000000..01b82686 --- /dev/null +++ b/install/steps/finish.php @@ -0,0 +1,20 @@ + +

+ + $value) { + if(strpos($key, 'var_') !== false) + unset($_SESSION[$key]); +} +unset($_SESSION['saved']); +?> \ No newline at end of file diff --git a/install/steps/license.php b/install/steps/license.php new file mode 100644 index 00000000..6a970fec --- /dev/null +++ b/install/steps/license.php @@ -0,0 +1,7 @@ +
+ + + + +
diff --git a/install/steps/requirements.php b/install/steps/requirements.php new file mode 100644 index 00000000..34b2862f --- /dev/null +++ b/install/steps/requirements.php @@ -0,0 +1,46 @@ +' . $name; + if(!empty($version)) + echo ': ' . $version . ''; + + echo '

'; + if(!$ok && !$warning) + $failed = true; +} + +$failed = false; + +// start validating +version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50000), PHP_VERSION); +foreach(array('config.local.php', 'images/guilds', 'images/houses', 'images/screenshots') as $value) +{ + $perms = (int) substr(decoct(fileperms(BASE . $value)), 2); + version_check($locale['step_requirements_write_perms'] . ': ' . $value, $perms >= 660); +} + +$ini_register_globals = ini_get_bool('register_globals'); +version_check('register_long_arrays', !$ini_register_globals, $ini_register_globals ? $locale['on'] : $locale['off']); + +$ini_safe_mode = ini_get_bool('safe_mode'); +version_check('safe_mode', !$ini_safe_mode, $ini_safe_mode ? $locale['on'] : $locale['off'], true); + +version_check('PDO extension loaded', extension_loaded('pdo'), '', false); +version_check('zip extension loaded', extension_loaded('zip'), '', false); + +if($failed) +{ + echo '
' . $locale['step_requirements_failed']; + echo next_form(true, false); +} +else + echo next_form(true, true); +?> \ No newline at end of file diff --git a/install/steps/welcome.php b/install/steps/welcome.php new file mode 100644 index 00000000..42b7e15b --- /dev/null +++ b/install/steps/welcome.php @@ -0,0 +1,31 @@ +' . $locale['already_installed'] . '

'; +else +{ +?> +
+ +

+ +
+ + +
+ \ No newline at end of file diff --git a/install/template/images/active.gif b/install/template/images/active.gif new file mode 100644 index 00000000..5678ff1a Binary files /dev/null and b/install/template/images/active.gif differ diff --git a/install/template/images/approve.gif b/install/template/images/approve.gif new file mode 100644 index 00000000..9bd09804 Binary files /dev/null and b/install/template/images/approve.gif differ diff --git a/install/template/images/background.jpg b/install/template/images/background.jpg new file mode 100644 index 00000000..c18e51c5 Binary files /dev/null and b/install/template/images/background.jpg differ diff --git a/install/template/images/bullet.gif b/install/template/images/bullet.gif new file mode 100644 index 00000000..354355e5 Binary files /dev/null and b/install/template/images/bullet.gif differ diff --git a/install/template/images/button.gif b/install/template/images/button.gif new file mode 100644 index 00000000..90674824 Binary files /dev/null and b/install/template/images/button.gif differ diff --git a/install/template/images/delete.gif b/install/template/images/delete.gif new file mode 100644 index 00000000..2b139379 Binary files /dev/null and b/install/template/images/delete.gif differ diff --git a/install/template/images/divider.gif b/install/template/images/divider.gif new file mode 100644 index 00000000..8004bdf4 Binary files /dev/null and b/install/template/images/divider.gif differ diff --git a/install/template/images/edit.gif b/install/template/images/edit.gif new file mode 100644 index 00000000..0675fc7b Binary files /dev/null and b/install/template/images/edit.gif differ diff --git a/install/template/images/error.gif b/install/template/images/error.gif new file mode 100644 index 00000000..352875dc Binary files /dev/null and b/install/template/images/error.gif differ diff --git a/install/template/images/footer.jpg b/install/template/images/footer.jpg new file mode 100644 index 00000000..afb61d95 Binary files /dev/null and b/install/template/images/footer.jpg differ diff --git a/install/template/images/negative.gif b/install/template/images/negative.gif new file mode 100644 index 00000000..2aeaf195 Binary files /dev/null and b/install/template/images/negative.gif differ diff --git a/install/template/images/note.gif b/install/template/images/note.gif new file mode 100644 index 00000000..9fa6bdd0 Binary files /dev/null and b/install/template/images/note.gif differ diff --git a/install/template/images/positive.gif b/install/template/images/positive.gif new file mode 100644 index 00000000..42426c42 Binary files /dev/null and b/install/template/images/positive.gif differ diff --git a/install/template/images/sidebody.gif b/install/template/images/sidebody.gif new file mode 100644 index 00000000..51681088 Binary files /dev/null and b/install/template/images/sidebody.gif differ diff --git a/install/template/images/sidehead.gif b/install/template/images/sidehead.gif new file mode 100644 index 00000000..59dec8e1 Binary files /dev/null and b/install/template/images/sidehead.gif differ diff --git a/install/template/images/success.gif b/install/template/images/success.gif new file mode 100644 index 00000000..c5206b56 Binary files /dev/null and b/install/template/images/success.gif differ diff --git a/install/template/images/userbox.gif b/install/template/images/userbox.gif new file mode 100644 index 00000000..ee9347b7 Binary files /dev/null and b/install/template/images/userbox.gif differ diff --git a/install/template/images/visitwebsite.gif b/install/template/images/visitwebsite.gif new file mode 100644 index 00000000..cdb7b475 Binary files /dev/null and b/install/template/images/visitwebsite.gif differ diff --git a/install/template/images/warning.gif b/install/template/images/warning.gif new file mode 100644 index 00000000..3a9a3fbc Binary files /dev/null and b/install/template/images/warning.gif differ diff --git a/install/template/images/wrapper.gif b/install/template/images/wrapper.gif new file mode 100644 index 00000000..d51dc8b0 Binary files /dev/null and b/install/template/images/wrapper.gif differ diff --git a/install/template/style.css b/install/template/style.css new file mode 100644 index 00000000..fb8743c3 --- /dev/null +++ b/install/template/style.css @@ -0,0 +1,297 @@ +* { + margin: 0; padding: 0; +} +body { + text-align: center; + font: 12px Verdana; + color: #000000; + background-color: #000000; +} +img { + border: 0; +} + +.break { + font-size: 0; + width: 0; height: 0; + clear: both; +} +.alignleft { + float: left; + margin: 4px 10px 5px 0; +} +.alignright { + float: right; + margin: 4px 0 5px 10px; +} +.aligncenter { + text-align: center; +} + +/** BEGIN wrapper **/ +#wrapper { + background: #ffffff url(images/background.jpg) repeat-x 0 0; + width: 980px; +} + +#header { + margin-bottom: 10px; + border-bottom: 1px solid #eee; + padding-bottom: 15px; +} + +#footer { + padding-top: 15px; + border-top: 1px solid #eee; + margin-top: 10px; + text-align: right; + color: #555; +} + +#header h1 { + font-weight: bold; + margin: 0; + padding: 0; +} + +#header span { + font-size: 25px; + color: #000; + font-weight: bold; + padding-left: 40px; + line-height: 80px; +} + +#version { + float: right; + color: #000; + font-size: 17px; + padding-top: 25px; + padding-right: 5px; +} + +/** BEGIN body **/ +#body { + background: url(images/wrapper.gif) repeat-y 0 0; +} +/** END body **/ + +/** BEGIN content **/ +#content { + width: 642px; + float: left; + padding: 20px 18px 20px 20px; + color: #434242; +} + + /** begin headers **/ + h1, h2, h3, h4, h5, h6 { + font-family: Tahoma; + margin-bottom: 10px; + } + h2, h3, h4, h5, h6 { + margin-top: 30px; + } + h1 { font-size: 2em; } + h2 { font-size: 1.6em; } + h3 { font-size: 1.3em; } + h4, h5, h6 { font-size: 1em; } + /** end headers **/ + + /** begin messages **/ + .error, .success, .note, .warning { + font-weight: bold; + font-size: 0.9em; + padding: 4px 10px 4px 24px; + background-repeat: no-repeat; + background-position: 5px 6px; + border-style: solid; + border-width: 1px; + } + .error { + background-color: #FDD9D9; + background-image: url(images/error.gif); + border-color: #FBA3A3; + color: #D80303; + } + .success { + background-color: #E4FCD9; + background-image: url(images/success.gif); + border-color: #BFFDA3; + color: #35A502; + } + .note { + background-color: #DDEAFA; + background-image: url(images/note.gif); + border-color: #A3D8FD; + color: #026DA5; + } + .warning { + background-color: #FBF0B3; + background-image: url(images/warning.gif); + border-color: #FBBB95; + color: #FD6002; + } + /** end messages **/ + + /** begin form **/ + form { + border: 1px solid #DDDDDD; + padding: 16px; + } + form .input { + padding-top: 12px; + clear: both; + } + form .first { + padding-top: 0; + } + form .input p { + margin-bottom: 7px !important; + } + form input { + margin-right: 5px; + } + form label { + margin-right: 10px; + color: #8B8B8B; + } + form input.text, form textarea { + border: 1px solid #BEBDBD; + font-size: 1em; + font-family: Verdana; + background-color: #F3F3F3; + color: #808080; + padding: 2px; + max-width: 100%; + } + .positive, .negative { + font-size: 0.9em; + font-weight: bold; + padding: 1px 0 0 20px; + background-repeat: no-repeat; + background-position: 0 0; + display: inline; + margin-top: 2px; + } + .positive { + background-image: url(images/positive.gif); + color: #35A502; + } + .negative { + background-image: url(images/negative.gif); + color: #D80303; + } + form textarea { + line-height: 1.6em; + } + form button, form input.button { + font-size: 0.9em; + font-family: Verdana; + font-weight: bold; + color: #ffffff; + background: #B6B4B4 url(images/button.gif) repeat-x 0 0; + border: 1px solid #B6B4B4; + padding: 5px 10px; + } + /** end form **/ + + /** begin table **/ + table { + + } + table th { + font-size: 0.9em; + color: #ffffff; + background-color: #679BC5; + padding: 2px 4px; + line-height: 1.6em; + } + table td { + line-height: 1.6em; + padding: 2px 4px; + } + table tr.odd td { background-color: #EEEEEE; } + table tr.even td { background-color: #E5E5E5; } + + /** end table **/ + + /** begin paragraphs, lists, etc. **/ + #content p { + line-height: 1.6em; + margin-bottom: 10px; + } + #content ul, #content ol { + list-style-position: inside; + } + #content li { + line-height: 1.6em; + padding: 2px 0 2px 0; + } + a { + color: #679BC5; + } + a:hover { + color: #ff0000; + text-decoration: none; + } + blockquote { + padding: 10px; + background-color: #eeeeee; + line-height: 1.6em; + border-width: 2px 0 1px; + border-style: solid; + border-color: #e0e0e0; + } + /** end paragraphs, lists, etc. **/ + +/** END content **/ + +/** BEGIN sidebar **/ +#sidebar { + width: 300px; + float: right; + padding: 10px 0; +} + #sidebar h2 { + background: green url(images/sidehead.gif) no-repeat 0 0; + margin: 0 10px; + font-size: 1em; + color: #ffffff; + padding: 7px 10px; + } + #sidebar ul { + list-style-type: none; + background: #E0E0E0 url(images/sidebody.gif) no-repeat 0 bottom; + padding: 10px; + margin: 0 10px 10px; + } + #sidebar ul li { + padding: 4px 0 4px 14px; + background: none; + line-height: 1.6em; + font-size: 0.9em; + font-weight: bold; + } + #sidebar ul li a { + color: #000000; + text-decoration: none; + } + #sidebar ul li a:hover { + text-decoration: none; + color: #ff0000; + } + + #sidebar ul li a:active { + text-decoration: none; + color: #ff0000; + } + + #sidebar ul li current { + text-decoration: none; + color: #ff0000; + } + .current { + text-decoration: none; + color: #ff0000; + } \ No newline at end of file diff --git a/install/template/template.php b/install/template/template.php new file mode 100644 index 00000000..dd6982e5 --- /dev/null +++ b/install/template/template.php @@ -0,0 +1,46 @@ + + + + MyAAC - <?php echo $locale['installation']; ?> + + + +
+ + + +
+ + + +
+ ' . $locale['step_' . $step . '_title'] . ''; + else + echo '

' . $locale['step_' . $step] . '

'; + echo $content; + ?> +
+ +
+
+ +
+ + + + \ No newline at end of file diff --git a/plugins/.htaccess b/plugins/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/plugins/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/.htaccess b/system/.htaccess new file mode 100644 index 00000000..dcd95120 --- /dev/null +++ b/system/.htaccess @@ -0,0 +1,2 @@ +Options -Indexes +Deny from all \ No newline at end of file diff --git a/system/cache/.htaccess b/system/cache/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/system/cache/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/compat_pages.php b/system/compat_pages.php new file mode 100644 index 00000000..4b3b3ad1 --- /dev/null +++ b/system/compat_pages.php @@ -0,0 +1,41 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +switch($page) +{ + case 'whoisonline': + $page = 'online'; + break; + + case 'latestnews': + $page = 'news'; + break; + + case 'tibiarules': + $page = 'rules'; + break; + + case 'killstatistics': + $page = 'lastkills'; + break; + + case 'buypoints': + $page = 'points'; + break; + + case 'shopsystem': + $page = 'gifts'; + break; + + default: + break; +} +?> diff --git a/system/counter.php b/system/counter.php new file mode 100644 index 00000000..00402cf4 --- /dev/null +++ b/system/counter.php @@ -0,0 +1,52 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +define('COUNTER_SYNC', 10); // how often counter is synchronized with database (each x site refreshes) + +$views_counter = 1; // default value, must be here! +if($cache->enabled()) +{ + $value = 0; + if(!$cache->fetch('views_counter', $value)) + { + $value = 0; + if(fetchDatabaseConfig('views_counter', $value)) + $views_counter = $value; + else + registerDatabaseConfig('views_counter', 1); // save in the database + } + else + $views_counter = $value; + + $cache->set('views_counter', ++$views_counter, 60 * 60); + if(($views_counter % COUNTER_SYNC) == 0) // sync with database + updateDatabaseConfig('views_counter', $views_counter); +/* + { + $cache->set('views_counter', 1); + + $value = 0; + if(fetchDatabaseConfig('views_counter', $value)) + $views_counter += $value; + }*/ +} +else +{ + $value = 0; + if(!fetchDatabaseConfig('views_counter', $value)) + registerDatabaseConfig('views_counter', 1); // save in the database + else + { + $views_counter = $value + 1; + updateDatabaseConfig('views_counter', $views_counter); // update counter + } +} +?> diff --git a/system/countries.conf.php b/system/countries.conf.php new file mode 100644 index 00000000..bac215c5 --- /dev/null +++ b/system/countries.conf.php @@ -0,0 +1 @@ + * @copyright 2017 MyAAC * @version 0.0.1 * @link http://my-aac.org */ defined('MYAAC') or die('Direct access not allowed!'); $config['countries'] = array ( 'af' => 'Afghanistan', 'al' => 'Albania', 'dz' => 'Algeria', 'as' => 'American Samoa', 'ad' => 'Andorra', 'ao' => 'Angola', 'ai' => 'Anguilla', 'aq' => 'Antarctica', 'ag' => 'Antigua and Barbuda', 'ar' => 'Argentina', 'am' => 'Armenia', 'aw' => 'Aruba', 'au' => 'Australia', 'at' => 'Austria', 'az' => 'Azerbaijan', 'bs' => 'Bahamas', 'bh' => 'Bahrain', 'bd' => 'Bangladesh', 'bb' => 'Barbados', 'by' => 'Belarus', 'be' => 'Belgium', 'bz' => 'Belize', 'bj' => 'Benin', 'bm' => 'Bermuda', 'bt' => 'Bhutan', 'bo' => 'Bolivia', 'ba' => 'Bosnia and Herzegovina', 'bw' => 'Botswana', 'bv' => 'Bouvet Island', 'br' => 'Brazil', 'io' => 'British Indian Ocean Territory', 'bn' => 'Brunei Darussalam', 'bg' => 'Bulgaria', 'bf' => 'Burkina Faso', 'bi' => 'Burundi', 'kh' => 'Cambodia', 'cm' => 'Cameroon', 'ca' => 'Canada', 'cv' => 'Cape Verde', 'ky' => 'Cayman Islands', 'cf' => 'Central African Republic', 'td' => 'Chad', 'cl' => 'Chile', 'cn' => 'China', 'cx' => 'Christmas Island', 'cc' => 'Cocos (Keeling) Islands', 'co' => 'Colombia', 'km' => 'Comoros', 'cg' => 'Congo', 'cd' => 'Congo, the Democratic Republic of the', 'ck' => 'Cook Islands', 'cr' => 'Costa Rica', 'ci' => 'Cote D\'Ivoire', 'hr' => 'Croatia', 'cu' => 'Cuba', 'cy' => 'Cyprus', 'cz' => 'Czech Republic', 'dk' => 'Denmark', 'dj' => 'Djibouti', 'dm' => 'Dominica', 'do' => 'Dominican Republic', 'ec' => 'Ecuador', 'eg' => 'Egypt', 'sv' => 'El Salvador', 'gq' => 'Equatorial Guinea', 'er' => 'Eritrea', 'ee' => 'Estonia', 'et' => 'Ethiopia', 'fk' => 'Falkland Islands (Malvinas)', 'fo' => 'Faroe Islands', 'fj' => 'Fiji', 'fi' => 'Finland', 'fr' => 'France', 'gf' => 'French Guiana', 'pf' => 'French Polynesia', 'tf' => 'French Southern Territories', 'ga' => 'Gabon', 'gm' => 'Gambia', 'ge' => 'Georgia', 'de' => 'Germany', 'gh' => 'Ghana', 'gi' => 'Gibraltar', 'gr' => 'Greece', 'gl' => 'Greenland', 'gd' => 'Grenada', 'gp' => 'Guadeloupe', 'gu' => 'Guam', 'gt' => 'Guatemala', 'gn' => 'Guinea', 'gw' => 'Guinea-Bissau', 'gy' => 'Guyana', 'ht' => 'Haiti', 'hm' => 'Heard Island and Mcdonald Islands', 'va' => 'Holy See (Vatican City State)', 'hn' => 'Honduras', 'hk' => 'Hong Kong', 'hu' => 'Hungary', 'is' => 'Iceland', 'in' => 'India', 'id' => 'Indonesia', 'ir' => 'Iran, Islamic Republic of', 'iq' => 'Iraq', 'ie' => 'Ireland', 'il' => 'Israel', 'it' => 'Italy', 'jm' => 'Jamaica', 'jp' => 'Japan', 'jo' => 'Jordan', 'kz' => 'Kazakhstan', 'ke' => 'Kenya', 'ki' => 'Kiribati', 'kp' => 'Korea, Democratic People\'s Republic of', 'kr' => 'Korea, Republic of', 'kw' => 'Kuwait', 'kg' => 'Kyrgyzstan', 'la' => 'Lao People\'s Democratic Republic', 'lv' => 'Latvia', 'lb' => 'Lebanon', 'ls' => 'Lesotho', 'lr' => 'Liberia', 'ly' => 'Libyan Arab Jamahiriya', 'li' => 'Liechtenstein', 'lt' => 'Lithuania', 'lu' => 'Luxembourg', 'mo' => 'Macao', 'mk' => 'Macedonia, the Former Yugoslav Republic of', 'mg' => 'Madagascar', 'mw' => 'Malawi', 'my' => 'Malaysia', 'mv' => 'Maldives', 'ml' => 'Mali', 'mt' => 'Malta', 'mh' => 'Marshall Islands', 'mq' => 'Martinique', 'mr' => 'Mauritania', 'mu' => 'Mauritius', 'yt' => 'Mayotte', 'mx' => 'Mexico', 'fm' => 'Micronesia, Federated States of', 'md' => 'Moldova, Republic of', 'mc' => 'Monaco', 'mn' => 'Mongolia', 'ms' => 'Montserrat', 'ma' => 'Morocco', 'mz' => 'Mozambique', 'mm' => 'Myanmar', 'na' => 'Namibia', 'nr' => 'Nauru', 'np' => 'Nepal', 'nl' => 'Netherlands', 'an' => 'Netherlands Antilles', 'nc' => 'New Caledonia', 'nz' => 'New Zealand', 'ni' => 'Nicaragua', 'ne' => 'Niger', 'ng' => 'Nigeria', 'nu' => 'Niue', 'nf' => 'Norfolk Island', 'mp' => 'Northern Mariana Islands', 'no' => 'Norway', 'om' => 'Oman', 'pk' => 'Pakistan', 'pw' => 'Palau', 'ps' => 'Palestinian Territory, Occupied', 'pa' => 'Panama', 'pg' => 'Papua New Guinea', 'py' => 'Paraguay', 'pe' => 'Peru', 'ph' => 'Philippines', 'pn' => 'Pitcairn', 'pl' => 'Poland', 'pt' => 'Portugal', 'pr' => 'Puerto Rico', 'qa' => 'Qatar', 're' => 'Reunion', 'ro' => 'Romania', 'ru' => 'Russian Federation', 'rw' => 'Rwanda', 'sh' => 'Saint Helena', 'kn' => 'Saint Kitts and Nevis', 'lc' => 'Saint Lucia', 'pm' => 'Saint Pierre and Miquelon', 'vc' => 'Saint Vincent and the Grenadines', 'ws' => 'Samoa', 'sm' => 'San Marino', 'st' => 'Sao Tome and Principe', 'sa' => 'Saudi Arabia', 'sn' => 'Senegal', 'cs' => 'Serbia and Montenegro', 'sc' => 'Seychelles', 'sl' => 'Sierra Leone', 'sg' => 'Singapore', 'sk' => 'Slovakia', 'si' => 'Slovenia', 'sb' => 'Solomon Islands', 'so' => 'Somalia', 'za' => 'South Africa', 'gs' => 'South Georgia and the South Sandwich Islands', 'es' => 'Spain', 'lk' => 'Sri Lanka', 'sd' => 'Sudan', 'sr' => 'Suriname', 'sj' => 'Svalbard and Jan Mayen', 'sz' => 'Swaziland', 'se' => 'Sweden', 'ch' => 'Switzerland', 'sy' => 'Syrian Arab Republic', 'tw' => 'Taiwan, Province of China', 'tj' => 'Tajikistan', 'tz' => 'Tanzania, United Republic of', 'th' => 'Thailand', 'tl' => 'Timor-Leste', 'tg' => 'Togo', 'tk' => 'Tokelau', 'to' => 'Tonga', 'tt' => 'Trinidad and Tobago', 'tn' => 'Tunisia', 'tr' => 'Turkey', 'tm' => 'Turkmenistan', 'tc' => 'Turks and Caicos Islands', 'tv' => 'Tuvalu', 'ug' => 'Uganda', 'ua' => 'Ukraine', 'ae' => 'United Arab Emirates', 'gb' => 'United Kingdom', 'us' => 'United States', 'um' => 'United States Minor Outlying Islands', 'uy' => 'Uruguay', 'uz' => 'Uzbekistan', 'vu' => 'Vanuatu', 've' => 'Venezuela', 'vn' => 'Viet Nam', 'vg' => 'Virgin Islands, British', 'vi' => 'Virgin Islands, U.s.', 'wf' => 'Wallis and Futuna', 'eh' => 'Western Sahara', 'ye' => 'Yemen', 'zm' => 'Zambia', 'zw' => 'Zimbabwe' ); ?> \ No newline at end of file diff --git a/system/data/.htaccess b/system/data/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/system/data/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/database.php b/system/database.php new file mode 100644 index 00000000..a2939e06 --- /dev/null +++ b/system/database.php @@ -0,0 +1,76 @@ +connect(POT::DB_MYSQL, + array( + 'host' => $config['database_host'], + 'user' => $config['database_user'], + 'password' => $config['database_password'], + 'database' => $config['database_name'] + ) + ); + } + catch(PDOException $error) { + die('ERROR: Cannot connect to MySQL database.
' . + 'Possible reasons:' . + '
    ' . + '
  • MySQL is not configured propertly in config.lua.
  • ' . + '
  • MySQL server is not running.
  • ' . + '
'); + } + $db = POT::getInstance()->getDBHandle(); +?> \ No newline at end of file diff --git a/system/events.php b/system/events.php new file mode 100644 index 00000000..ad53dee9 --- /dev/null +++ b/system/events.php @@ -0,0 +1,61 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +class Event +{ + private $_name, $_type, $_callback; + + public function __construct($name, $type, $callback) { + $this->_name = $name; + $this->_type = $type; + $this->_callback = $callback; + } + + public function execute($params) + { + $ret = false; + if(is_callable($this->_callback)) + { + $tmp = $this->_callback; + $ret = $tmp($params); + } + + return $ret; + } + + public function name() {return $this->_name;} + public function type() {return $this->_type;} +} + +class Events +{ + private static $_events = array(); + + public function register($event, $type = '', $callback = null) { + if(!($event instanceof Event)) + $event = new Event($event, $type, $callback); + + self::$_events[$event->type()][] = $event; + } + + public function trigger($type, $params = array()) + { + $ret = true; + if(isset(self::$_events[$type])) + { + foreach(self::$_events[$type] as $name => $event) + $ret = $event->execute($params); + } + + return $ret; + } +} +?> diff --git a/system/functions.php b/system/functions.php new file mode 100644 index 00000000..11753cce --- /dev/null +++ b/system/functions.php @@ -0,0 +1,1116 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +function success($message) { + echo '

' . $message . '

'; +} +function warning($message) { + echo '

' . $message . '

'; +} +function error($message) { + echo '

' . $message . '

'; +} + +function longToIp($ip) +{ + $exp = explode(".", long2ip($ip)); + return $exp[3].".".$exp[2].".".$exp[1].".".$exp[0]; +} + +function generateLink($url, $name, $blank = false) { + return '' . $name . ''; +} + +function getLink($page, $name, $blank = false) { + return generateLink(getPageLink($page), $name, $blank); +} + +function getPageLink($page, $action = null) +{ + global $config; + + // TODO: tibiacom template is not working correctly with this + if($config['friendly_urls']) + return BASE_URL . $page . ($action ? '/' . $action : ''); + + return BASE_URL . '?subtopic=' . $page . ($action ? '&action=' . $action : ''); +} +function internalLayoutLink($page, $action = null) {return getPageLink($page, $action);} + +function getPlayerLink($name, $generate = true) +{ + global $ots, $config; + + if(is_numeric($name)) + { + $player = $ots->createObject('Player'); + $player->load(intval($name)); + if($player->isLoaded()) + $name = $player->getName(); + } + + $url = ''; + if($config['friendly_urls']) + $url = BASE_URL . 'characters/' . urlencode($name); + else + $url = BASE_URL . '?subtopic=characters&name=' . urlencode($name); + + if(!$generate) return $url; + return generateLink($url, $name); +} + +function getHouseLink($name, $generate = true) +{ + global $db, $config; + + if(is_numeric($name)) + { + $house = $db->query( + 'SELECT ' . $db->fieldName('name') . + ' FROM ' . $db->tableName('houses') . + ' WHERE ' . $db->fieldName('id') . ' = ' . (int)$name); + if($house->rowCount() > 0) + $name = $house->fetchColumn(); + } + + $url = ''; + if($config['friendly_urls']) + $url = BASE_URL . 'houses/' . urlencode($name); + else + $url = BASE_URL . '?subtopic=houses&page=view&house=' . urlencode($name); + + if(!$generate) return $url; + return generateLink($url, $name); +} + +function getGuildLink($name, $generate = true) +{ + global $db, $config; + + if(is_numeric($name)) + { + $guild = $db->query( + 'SELECT ' . $db->fieldName('name') . + ' FROM ' . $db->tableName('guilds') . + ' WHERE ' . $db->fieldName('id') . ' = ' . (int)$name); + if($guild->rowCount() > 0) + $name = $guild->fetchColumn(); + } + + $url = ''; + if($config['friendly_urls']) + $url = BASE_URL . 'guilds/' . urlencode($name); + else + $url = BASE_URL . '?subtopic=guilds&action=show&guild=' . urlencode($name); + + if(!$generate) return $url; + return generateLink($url, $name); +} + +function getItemImage($id, $count = 1) +{ + $file_name = $id; + if($count > 1) + $file_name .= '-' . $count; + + global $config; + return ' ' .$id . ''; +} + +function getFlagImage($country) +{ + if(!isset($country[0])) + return ''; + + global $config; + if(!isset($config['countries'])) + require(SYSTEM . 'countries.conf.php'); + + return ''; +} + +/** + * Performs a boolean check on the value. + * + * @param mixed $v Variable to check. + * @return bool Value boolean status. + */ +function getBoolean($v) +{ + if(!$v || !isset($v[0])) return false; + + if(is_numeric($v)) + return intval($v) > 0; + + $v = strtolower($v); + return $v == 'yes' || $v == 'true'; +} + +/** + * Generates random string. + * + * @param int $length Length of the generated string. + * @param bool $numeric Should numbers by used too? + * @param bool $special Should special characters by used? + * @return string Generated string. + */ +function generateRandomString($length, $lowCase = true, $upCase = false, $numeric = false, $special = false) +{ + $characters = ''; + if($lowCase) + $characters .= 'abcdefghijklmnopqrstuxyvwz'; + + if($upCase) + $characters .= 'ABCDEFGHIJKLMNPQRSTUXYVWZ'; + + if($numeric) + $characters .= '123456789'; + + if($special) + $characters .= '+-*#&@!?'; + + $characters_length = strlen($characters) - 1; + if($characters_length <= 0) return ''; + + $ret = ''; + for($i = 0; $i < $length; $i++) + $ret .= $characters[mt_rand(0, $characters_length)]; + + return $ret; +} + +/** + * Get forum sections + * + * @return array Forum sections. + */ +function getForumSections() +{ + global $db; + $sections = $db->query('SELECT `id`, `name`, `description`, `closed` FROM ' . TABLE_PREFIX . 'forum_sections WHERE hidden != 1 ORDER BY `ordering`;'); + if($sections) + return $sections->fetchAll(); + + return array(); +} + +/** + * Retrieves data from myaac database config. + * + * @param string $name Key. + * @param string &$value Reference where requested data will be set to. + * @return bool False if value was not found in table, otherwise true. + */ +function fetchDatabaseConfig($name, &$value) +{ + global $db; + + $query = $db->query('SELECT ' . $db->fieldName('value') . ' FROM ' . $db->tableName(TABLE_PREFIX . 'config') . ' WHERE ' . $db->fieldName('name') . ' = ' . $db->quote($name)); + if($query->rowCount() <= 0) + return false; + + $value = $query->fetchColumn(); + return true; +} + +/** + * Retrieves data from database config. + * + * $param string $name Key. + * @return string Requested data. + */ +function getDatabaseConfig($name) +{ + $value = ''; + fetchDatabaseConfig($name, $value); + return $value; +} + +/** + * Register a new key pair in myaac database config. + * + * @param string $name Key name. + * @param string $value Data to be associated with key. + */ +function registerDatabaseConfig($name, $value) +{ + global $db; + $db->insert(TABLE_PREFIX . 'config', array('name' => $name, 'value' => $value)); +} + +/** + * Updates a value in myaac database config. + * + * @param string $name Key name. + * @param string $value New data. + */ +function updateDatabaseConfig($name, $value) +{ + global $db; + $db->update(TABLE_PREFIX . 'config', array('value' => $value), array('name' => $name)); +} + +/** + * Encrypt text using method specified in config.lua (encryptionType or passwordType) + */ +function encrypt($str) +{ + global $config; + if(isset($config['database_salt'])) // otserv + $str .= $config['database_salt']; + + $encryptionType = $config['database_encryption']; + if(isset($encryptionType) && strtolower($encryptionType) != 'plain') + { + if($encryptionType == 'vahash') + return base64_encode(hash('sha256', $str)); + + return hash($encryptionType, $str); + } + + return $str; +} + +function tableExist($table) +{ + global $db, $config; + $query = $db->query("SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = " . $db->quote($config['database_name']) . " AND `TABLE_NAME` = " . $db->quote($table) . ";"); + return $query->rowCount() > 0; +} + +function fieldExist($field, $table) +{ + global $db; + if(count($db->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $field . "'")->fetchAll())) + return true; + + return false; +} + +//delete player with name +function delete_player($name) +{ + global $db; + $player = new OTS_Player(); + $player->find($name); + if($player->isLoaded()) { + try { $db->query("DELETE FROM player_skills WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM guild_invites WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_items WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_depotitems WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_spells WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_storage WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_viplist WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_deaths WHERE player_id = '".$player->getId()."';"); } catch(PDOException $error) {} + try { $db->query("DELETE FROM player_deaths WHERE killed_by = '".$player->getId()."';"); } catch(PDOException $error) {} + $rank = $player->getRank(); + if($rank->isLoaded()) { + $guild = $rank->getGuild(); + if($guild->getOwner()->getId() == $player->getId()) { + $rank_list = $guild->getGuildRanksList(); + if(count($rank_list) > 0) { + $rank_list->orderBy('level'); + foreach($rank_list as $rank_in_guild) { + $players_with_rank = $rank_in_guild->getPlayersList(); + $players_with_rank->orderBy('name'); + $players_with_rank_number = count($players_with_rank); + if($players_with_rank_number > 0) { + foreach($players_with_rank as $player_in_guild) { + $player_in_guild->setRank(); + $player_in_guild->save(); + } + } + $rank_in_guild->delete(); + } + $guild->delete(); + } + } + } + $player->delete(); + return true; + } +} + +//delete guild with id +function delete_guild($id) +{ + $guild = new OTS_Guild(); + $guild->load($id); + if(!$guild->isLoaded()) + return false; + + $rank_list = $guild->getGuildRanksList(); + if(count($rank_list) > 0) { + $rank_list->orderBy('level'); + + global $db, $ots; + foreach($rank_list as $rank_in_guild) { + if(fieldExist('rank_id', 'players')) + $players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank->getId() . ' AND `deleted` = 0;'); + else + $players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_membership`.`rank_id` as `rank_id` FROM `players`, `guild_membership` WHERE `guild_membership`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_membership`.`player_id` ORDER BY `name`;'); + + $players_with_rank_number = $players_with_rank->rowCount(); + if($players_with_rank_number > 0) { + foreach($players_with_rank as $result) { + $player = $ots->createObject('Player'); + $player->load($result['id']); + if(!$player->isLoaded()) + continue; + + $player->setRank(); + $player->save(); + } + } + $rank_in_guild->delete(); + } + } + + $guild->delete(); + return true; +} + +/** + * Validate character name. + * Name lenght must be 3-25 chars + * + * @param string $name Name to check + * @param string $error Error description will be placed here + * @return bool Is name valid? + */ +function check_name($name, &$error = '') +{ + if(!isset($name[0])) + { + $error = 'Please enter character name.'; + return false; + } + + $length = strlen($name); + if($length < 3) + { + $error = 'Character name is too short. Min. lenght 3 characters.'; + return false; + } + + if($length > 25) + { + $error = 'Character name is too long. Max. lenght 25 characters.'; + return false; + } + + if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- [ ] '") != $length) + { + $error = 'Invalid name format. Use only A-Z.'; + return false; + } + + return preg_match("/[A-z ']{1,25}/", $name); +} + +/** + * Validate account name + * Name lenght must be 3-32 chars + * + * @param string $name Account name to check + * @param string $error Error description will be placed here + * @return bool Is account name valid? + */ +function check_account_name($name, &$error = '') +{ + if(!isset($name[0])) + { + $error = 'Please enter an account name.'; + return false; + } + + $length = strlen($name); + if($length < 3) + { + $error = 'Account name is too short (min. 3 chars).'; + return false; + } + + if($length > 32) + { + $error = 'Account name is too long (max. 32 chars).'; + return false; + } + + if(strspn($name, "QWERTYUIOPASDFGHJKLZXCVBNM0123456789") != $length) + { + $error = 'Invalid account name format. Use only A-Z and numbers 0-9.'; + return false; + } + + return preg_match("/[A-Z0-9]/", $name); +} + +//is it valid nick for new char? +function check_name_new_char($name) +{ + global $db, $config; + + $name_lower = strtolower($name); + + $first_words_blocked = array('admin ', 'administrator ', 'gm ', 'cm ', 'god ','tutor ', "'", '-'); + foreach($first_words_blocked as $word) + { + if($word == substr($name_lower, 0, strlen($word))) + return false; + } + + if(substr($name_lower, -1) == "'" || substr($name_lower, -1) == "-") + return false; + + if(substr($name_lower, 1, 1) == ' ') + return false; + + if(substr($name_lower, -2, 1) == " ") + return false; + + if(strtolower($config['lua']['serverName']) == $name_lower) + return false; + + $names_blocked = array('admin', 'administrator', 'gm', 'cm', 'god', 'tutor'); + foreach($names_blocked as $word) + { + if($word == $name_lower) + return false; + } + + $name_length = strlen($name_lower); + for($i = 0; $i < $name_length; $i++) + { + if(isset($name_lower[$i - 1]) && $name_lower[$i - 1] == ' ' && isset($name_lower[$i + 1]) && $name_lower[$i + 1] == ' ') + return false; + } + + $words_blocked = array('admin', 'administrator', 'gamemaster', 'game master', 'game-master', "game'master", '--', "''","' ", " '", '- ', ' -', "-'", "'-", 'fuck', 'sux', 'suck', 'noob', 'tutor'); + foreach($words_blocked as $word) + { + if(!(strpos($name_lower, $word) === false)) + return false; + } + + for($i = 0; $i < $name_length; $i++) + { + if(isset($name_lower[$i]) && isset($name_lower[$i + 1]) && $name_lower[$i] == $name_lower[$i + 1] && isset($name_lower[$i + 2]) && $name_lower[$i] == $name_lower[$i + 2]) + return false; + } + + for($i = 0; $i < $name_length; $i++) + { + if(isset($name_lower[$i - 1]) && $name_lower[$i - 1] == ' ' && isset($name_lower[$i + 1]) && $name_lower[$i + 1] == ' ') + return false; + } + + if(isset($config['monsters'])) + { + if(in_array($name_lower, $config['monsters'])) + return false; + } + + $monsters = $db->query( + 'SELECT ' . $db->fieldName('name') . + ' FROM ' . $db->tableName(TABLE_PREFIX . 'monsters') . + ' WHERE ' . $db->fieldName('name') . ' LIKE ' . $db->quote($name_lower)); + if($monsters->rowCount() > 0) + return false; + + $spells_name = $db->query( + 'SELECT ' . $db->fieldName('name') . + ' FROM ' . $db->tableName(TABLE_PREFIX . 'spells') . + ' WHERE ' . $db->fieldName('name') . ' LIKE ' . $db->quote($name_lower)); + if($spells_name->rowCount() > 0) + return false; + + $spells_words = $db->query( + 'SELECT ' . $db->fieldName('words') . + ' FROM ' . $db->tableName(TABLE_PREFIX . 'spells') . + ' WHERE ' . $db->fieldName('words') . ' = ' . $db->quote($name_lower)); + if($spells_words->rowCount() > 0) + return false; + + if(isset($config['npc'])) + { + if(in_array($name_lower, $config['npc'])) + return false; + } + + if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM- '") != $name_length) + return false; + + return preg_match("/[A-z ']{3,28}/", $name); +} + +function check_rank_name($name) +{ + if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789-[ ] ") != strlen($name)) + return false; + + return preg_match("/[A-z ]{1,32}/", $name); +} + +function check_guild_name($name) +{ + if(strspn($name, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789- ") != strlen($name)) + return false; + + return preg_match("/[A-z ]{3,32}/", $name); +} + +function check_password($pass) +{ + if(strspn($pass, "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890") != strlen($pass)) + return false; + + return preg_match("/[A-z0-9]{7,32}/", $pass); +} + +function check_mail($email) +{ + return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[A-z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $email); + //return preg_match("/[A-z0-9._-]+@[A-z0-9-]+\.[A-z]{2,4}/", $email); +} + +function check_number($number) +{ + return preg_match ("/^([0-9]+)$/", $number); +} + +//################### DISPLAY FUNCTIONS ##################### +//return shorter text (news ticker) +function short_text($text, $limit) +{ + if(strlen($text) > $limit) + return substr($text, 0, strrpos(substr($text, 0, $limit), " ")).'...'; + + return $text; +} + +function news_place() +{ + global $template_path, $news_content; + + $news = ''; + if(PAGE == 'news') + { + //add tickers to site - without it tickers will not be showed + if(isset($news_content)) + $news .= $news_content; + + //featured article +/* $news .= '
+
+
+
+
+ Contentbox headline +
+
+
+
+ Tutaj wpisz tytul
+ tutaj wpisz tresc newsa
+ zdjecie laduje sie w tibiacom/images/news/features.jpg
+ skad sie laduje mozesz zmienic linijke ponad komentarzem +
+
+
+
+
+
+
';*/ + } + + return $news; +} + +function output_errors($errors) +{ + global $template_path; +?> +
+
+
+
+
+
+
+
+
+
+
The Following Errors Have Occurred:
+ $message) + echo $message . '
'; + + echo '

'; +} + +/** + * Template place holder + * + * Types: head_start, head_end, body_start, body_end, center_top + * + */ +function template_place_holder($type) +{ + global $template_place_holders; + $ret = ''; + + if(array_key_exists($type, $template_place_holders) && is_array($template_place_holders[$type])) + $ret = implode($template_place_holders[$type]); + + if($type == 'head_start') + $ret .= template_header(); + elseif($type == 'body_end') + $ret .= template_ga_code(); + + return $ret; +} + +/** + * Returns content to be used by templates. + */ +function template_header($is_admin = false) +{ + global $title_full, $config; + $charset = isset($config['charset']) ? $config['charset'] : 'utf-8'; + + $ret = ' + + + '; + if(!$is_admin) + $ret .= ' + ' . $title_full . ' + '; + + $ret .= ' + + + + + + +'; + if(admin()) + $ret .= ' + +'; + if($config['recaptcha_enabled']) + $ret .= ""; + return $ret; +} + +/** + * Returns footer content to be used by templates. + */ +function template_footer() +{ + global $visitors, $config, $views_counter; + $ret = ''; + if(admin()) + $ret .= generateLink(ADMIN_URL, 'Admin Panel', true); + + if($config['visitors_counter']) + { + $amount = $visitors->getAmountVisitors(); + $ret .= '
Currently there ' . ($amount > 1 ? 'are' : 'is') . ' ' . $amount . ' visitor' . ($amount > 1 ? 's' : '') . '.'; + } + + if($config['views_counter']) + $ret .= '
Page has been viewed ' . $views_counter . ' times.'; + + if(admin()) + $ret .= '
Load time: ' . round(microtime(true) - START_TIME, 4) . ' seconds.'; + + if(isset($config['footer'][0])) + $ret .= '
' . $config['footer']; + + // please respect my work and help spreading the word, thanks! + return $ret . '
' . base64_decode('UG93ZXJlZCBieSA8YSBocmVmPSJodHRwOi8vbXktYWFjLm9yZyIgdGFyZ2V0PSJfYmxhbmsiPk15QUFDLjwvYT4='); +} + +function template_ga_code() +{ + global $config; + if(!isset($config['google_analytics_id'][0])) + return ''; + + return ' +'; +} + +function template_form() +{ + global $cache, $template_name; + if($cache->enabled()) + { + $tmp = ''; + if($cache->fetch('templates', $tmp)) { + $templates = unserialize($tmp); + } + else + { + $templates = get_templates(); + $cache->set('templates', serialize($templates), 120); + } + } + else + $templates = get_templates(); + + $options = ''; + foreach($templates as $key => $value) + $options .= ''; + + return '
+ + + '; +} + +function getStyle($i) +{ + global $config; + return is_int($i / 2) ? $config['darkborder'] : $config['lightborder']; +} + +$vowels = array("e", "y", "u", "i", "o", "a"); +function getCreatureName($killer, $showStatus = false, $extendedInfo = false) +{ + global $vowels, $ots, $config; + $str = ""; + if(is_numeric($killer)) + { + $player = $ots->createObject('Player'); + $player->load($killer); + if($player->isLoaded()) + { + $str .= ''; + if(!$showStatus) + return $str.''.$player->getName().''; + + $str .= ''.$player->getName().'
'; + if($extendedInfo) { + $str .= '
'.$player->getLevel().' '.$config['vocations'][$player->getVocation()].''; + } + return $str; + } + } + else + { + if($killer == "-1") + $players_rows .= "item or field"; + else + { + if(in_array(substr(strtolower($killer), 0, 1), $vowels)) + $players_rows .= "an "; + else + $players_rows .= "a "; + $players_rows .= $killer; + } + } + + return $players_rows; +} + +/** + * Find skill name using skill id. + * + * @param int $skillId Skill id. + * @param bool $suffix Should suffix also be added? + * @return string Skill name or 'unknown' if not found. + */ +function getSkillName($skillId, $suffix = true) +{ + switch($skillId) + { + case POT::SKILL_FIST: + { + $tmp = 'fist'; + if($suffix) + $tmp .= ' fighting'; + + return $tmp; + } + case POT::SKILL_CLUB: + { + $tmp = 'club'; + if($suffix) + $tmp .= ' fighting'; + + return $tmp; + } + case POT::SKILL_SWORD: + { + $tmp = 'sword'; + if($suffix) + $tmp .= ' fighting'; + + return $tmp; + } + case POT::SKILL_AXE: + { + $tmp = 'axe'; + if($suffix) + $tmp .= ' fighting'; + + return $tmp; + } + case POT::SKILL_DIST: + { + $tmp = 'distance'; + if($suffix) + $tmp .= ' fighting'; + + return $tmp; + } + case POT::SKILL_SHIELD: + return 'shielding'; + case POT::SKILL_FISH: + return 'fishing'; + case POT::SKILL__MAGLEVEL: + return 'magic level'; + case POT::SKILL__LEVEL: + return 'level'; + default: + break; + } + + return 'unknown'; +} + +/** + * Performs flag check on the current logged in user. + * Table in database: accounts, field: website_flags + * + * @param int @flag Flag to be verified. + * @return bool If user got flag. + */ +function hasFlag($flag) { + global $logged, $logged_flags; + return $logged && ($logged_flags & $flag) == $flag; +} +/** + * Check if current logged user have got admin flag set. + */ +function admin() { + return hasFlag(FLAG_ADMIN) || superAdmin(); +} +/** + * Check if current logged user have got super admin flag set. + */ +function superAdmin() { + return hasFlag(FLAG_SUPER_ADMIN); +} + +/** + * Format experience according to its amount (natural/negative number). + * + * @param int $exp Experience amount. + * @param bool $color Should result be colorized? + * @return string Resulted message attached in tag. + */ +function formatExperience($exp, $color = true) +{ + $ret = ''; + if($color) + { + $ret .= ' 0) + $ret .= ' color="green">'; + elseif($exp < 0) + $ret .= ' color="red">'; + else + $ret .= '>'; + } + + $ret .= '' . ($exp > 0 ? '+' : '') . number_format($exp) . ''; + if($color) + $ret .= ''; + + return $ret; +} + +function get_locales() +{ + $ret = array(); + + $path = LOCALE; + foreach(scandir($path) as $file) + { + if($file[0] != '.' && $file != '..' && is_dir($path . $file)) + $ret[] = $file; + } + + return $ret; +} + +function get_browser_languages() +{ + $ret = array(); + + $acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE']; + if(!isset($acceptLang[0])) + return $ret; + + $languages = strtolower($acceptLang); + // $languages = 'pl,en-us;q=0.7,en;q=0.3 '; + // need to remove spaces from strings to avoid error + $languages = str_replace(' ', '', $languages); + + foreach(explode(',', $languages) as $language_list) + $ret[] .= substr($language_list, 0, 2); + + return $ret; +} + +/** + * Generates list of templates, according to templates/ dir. + */ +function get_templates() +{ + $ret = array(); + + $path = TEMPLATES; + foreach(scandir($path) as $file) + { + if($file[0] != '.' && $file != '..' && is_dir($path . $file)) + $ret[] = $file; + } + + return $ret; +} + +function getWorldName($id) +{ + global $config; + foreach($config['worlds'] as $_id => $details) + { + if($id == $_id) + return $details['name']; + } + + return $config['lua']['serverName']; +} + +/** + * Mailing users. + * $config['mail_enabled'] have to be enabled. + * + * @param string $to Recipient email address. + * @param string $subject Subject of the message. + * @param string $body Message body in html format. + * @param string $altBody Alternative message body, plain text. + * @return bool PHPMailer status returned (success/failure). + */ +function _mail($to, $subject, $body, $altBody = '', $add_html_tags = true) +{ + global $mailer, $config; + if(!$mailer) + { + require(SYSTEM . 'libs/phpmailer/class.phpmailer.php'); + $mailer = new PHPMailer(); + } + + $signature_html = ''; + if(isset($config['mail_signature']['html'])) + $signature_html = $config['mail_signature']['html']; + + if($add_html_tags && isset($body[0])) + $body = '' . $body . '

' . $signature_html . ''; + else + $body .= '

' . $signature_html; + + if($config['smtp_enabled']) + { + $mailer->IsSMTP(); + $mailer->Host = $config['smtp_host']; + $mailer->Port = (int)$config['smtp_port']; + $mailer->SMTPAuth = $config['smtp_auth']; + $mailer->Username = $config['smtp_user']; + $mailer->Password = $config['smtp_pass']; + } + else + $mailer->IsMail(); + + $mailer->IsHTML(isset($body[0]) > 0); + $mailer->From = $config['mail_address']; + $mailer->Sender = $config['mail_address']; + $mailer->CharSet = 'utf-8'; + $mailer->FromName = $config['lua']['serverName']; + $mailer->Subject = $subject; + $mailer->AddAddress($to); + $mailer->Body = $body; + + $signature_plain = ''; + if(isset($config['mail_signature']['plain'])) + $signature_plain = $config['mail_signature']['plain']; + + if(isset($altBody[0])) + $mailer->AltBody = $altBody . $signature_plain; + + return $mailer->Send(); +} + +function convert_bytes($size) +{ + $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb'); + return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $unit[$i]; +} + +function log_append($file, $str) +{ + $f = fopen(LOGS . $file, 'a'); + fwrite($f, $str . PHP_EOL); + fclose($f); +} + +function load_config_lua($filename) +{ + global $config; + + $config_file = $filename; + if(!@file_exists($config_file)) + die('ERROR: Cannot find ' . $filename . ' file.'); + + $tempFile = tempnam('/tmp', 'lua'); + $file = fopen($tempFile, 'w'); + if(!$file) die('Cannot load server config!'); + + // TODO: new parser that will also load dofile() includes + + // strip lua comments to prevent parsing errors + fwrite($file, preg_replace('/(-)(-) (.*)/', '', file_get_contents($config_file))); + fclose($file); + + $result = array_merge(parse_ini_file($tempFile, true), isset($config['lua']) ? $config['lua'] : array()); + @unlink($tempFile); + return $result; +} +?> diff --git a/system/init.php b/system/init.php new file mode 100644 index 00000000..f2fa6ff5 --- /dev/null +++ b/system/init.php @@ -0,0 +1,154 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +// load configuration +require_once(BASE . 'config.php'); +if(file_exists(BASE . 'config.local.php')) // user customizations + require(BASE . 'config.local.php'); + +// take care of trailing slash at the end +if($config['server_path'][strlen($config['server_path']) - 1] != '/') + $config['server_path'] .= '/'; + +// enable gzip compression if supported by the browser +if($config['gzip_output'] && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) && function_exists('ob_gzhandler')) + ob_start('ob_gzhandler'); + +// cache +require_once(SYSTEM . 'libs/cache.php'); +$cache = Cache::getInstance($config['cache_engine'], $config['cache_prefix']); + +// trim values we receive +if(isset($_POST)) +{ + foreach($_POST as $var => $value) { + if(is_string($value)) { + $_POST[$var] = trim($value); + } + } +} +if(isset($_GET)) +{ + foreach($_GET as $var => $value) { + if(is_string($value)) + $_GET[$var] = trim($value); + } +} +if(isset($_REQUEST)) +{ + foreach($_REQUEST as $var => $value) { + if(is_string($value)) + $_REQUEST[$var] = trim($value); + } +} + +// load otserv config file +$tmp = ''; +if($cache->enabled() && $cache->fetch('config_lua', $tmp)) { + $config['lua'] = unserialize($tmp); + /*if(isset($config['lua']['myaac'][0])) { + foreach($config['lua']['myaac'] as $key => $value) + $config[$key] = $value; + }*/ +} +else +{ + $config['lua'] = load_config_lua($config['server_path'] . 'config.lua'); + + // cache config + if($cache->enabled()) + $cache->set('config_lua', serialize($config['lua']), 120); +} +unset($tmp); + +if(isset($config['lua']['servername'])) + $config['lua']['serverName'] = $config['lua']['servername']; + +// localize data/ directory +if(isset($config['lua']['dataDirectory'][0])) +{ + $tmp = $config['lua']['dataDirectory']; + if($tmp[0] != '/') + $tmp = $config['server_path'] . $tmp; + + if($tmp[strlen($tmp) - 1] != '/') // do not forget about trailing slash + $tmp .= '/'; +} +else if(isset($config['lua']['data_directory'][0])) +{ + $tmp = $config['lua']['data_directory']; + if($tmp[0] != '/') + $tmp = $config['server_path'] . $tmp; + + if($tmp[strlen($tmp) - 1] != '/') // do not forget about trailing slash + $tmp .= '/'; +} +else + $tmp = $config['server_path'] . 'data/'; + +$config['data_path'] = $tmp; +unset($tmp); + +// POT +require_once(SYSTEM . 'libs/pot/OTS.php'); +$ots = POT::getInstance(); +require_once(SYSTEM . 'database.php'); + +// load vocation names +$tmp = ''; +if($cache->enabled() && $cache->fetch('vocations', $tmp)) { + $config['vocations'] = unserialize($tmp); +} +else { + $vocations = new DOMDocument(); + $path_extra = 'XML/'; + if($config['otserv_version'] >= OTSERV_FIRST && $config['otserv_version'] <= OTSERV_LAST) + $path_extra = ''; + + $vocations->load($config['data_path'] . $path_extra . 'vocations.xml'); + + if(!$vocations) + die('ERROR: Cannot load vocations.xml file.'); + + $config['vocations'] = array(); + foreach($vocations->getElementsByTagName('vocation') as $vocation) { + $id = $vocation->getAttribute('id'); + if($id == $vocation->getAttribute('fromvoc')) + $config['vocations'][$id] = $vocation->getAttribute('name'); + else + $config['vocations'][$id + 4] = $vocation->getAttribute('name'); + } + + if($cache->enabled()) { + $cache->set('vocations', serialize($config['vocations']), 120); + } +} +unset($tmp, $id, $vocation); + +// load towns +/* TODO: doesnt work +ini_set('memory_limit', '-1'); +$tmp = ''; + +if($cache->enabled() && $cache->fetch('towns', $tmp)) { + $config['towns'] = unserialize($tmp); +} +else { + $towns = new OTS_OTBMFile(); + $towns->loadFile('D:/Projekty/opentibia/wodzislawski/data/world/wodzislawski.otbm'); + + $config['towns'] = $towns->getTownsList(); + if($cache->enabled()) { + $cache->set('towns', serialize($config['towns']), 120); + } +} +*/ +?> diff --git a/system/item.php b/system/item.php new file mode 100644 index 00000000..c756bded --- /dev/null +++ b/system/item.php @@ -0,0 +1,62 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +require_once(SYSTEM . 'libs/items.php'); + +Items::$files = array( + 'otb' => SYSTEM . 'data/items.otb', + 'spr' => SYSTEM . 'data/Tibia.spr', + 'dat' => SYSTEM . 'data/Tibia.dat' +); +Items::$outputDir = BASE . 'images/items/'; + +function generateItem($id = 100, $count = 1) { + Items::generate($id, $count); +} + +function itemImageExists($id, $count = 1) +{ + if(!isset($id)) + die('ERROR - itemImageExists: id has been not set!'); + + $file_name = $id; + if($count > 1) + $file_name .= '-' . $count; + + $file_name = Items::$outputDir . $file_name . '.gif'; + return file_exists($file_name); +} + +function outputItem($id = 100, $count = 1) +{ + if(!(int)$count) + $count = 1; + + if(!itemImageExists($id, $count)) + { + //echo 'plik istnieje'; + Items::generate($id, $count); + } + + $expires = 60 * 60 * 24 * 30; // 30 days + header('Content-type: image/gif'); + header('Cache-Control: public'); + header('Cache-Control: maxage=' . $expires); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT'); + + $file_name = $id; + if($count > 1) + $file_name .= '-' . $count; + + $file_name = Items::$outputDir . $file_name . '.gif'; + readfile($file_name); +} +?> diff --git a/system/libs/.htaccess b/system/libs/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/system/libs/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/libs/cache.php b/system/libs/cache.php new file mode 100644 index 00000000..01192bd9 --- /dev/null +++ b/system/libs/cache.php @@ -0,0 +1,69 @@ + + * @author Mark Samman (Talaturen) + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Cache +{ + static private $instance; + + static public function getInstance($engine = '', $prefix = '') + { + if(!self::$instance) { + switch(strtolower($engine)) { + case 'apc': + require('cache_apc.php'); + self::$instance = new Cache_APC($prefix); + break; + + case 'eaccelerator': + require('cache_eaccelerator.php'); + self::$instance = new Cache_eAccelerator($prefix); + break; + + case 'xcache': + require('cache_xcache.php'); + self::$instance = new Cache_XCache($prefix); + break; + + case 'file': + require('cache_file.php'); + self::$instance = new Cache_File($prefix, CACHE); + break; + + case 'auto': + self::$instance = self::getInstance(self::detect(), $prefix); + break; + + default: + self::$instance = new Cache(); + break; + } + } + + return self::$instance; + } + + static public function detect() + { + if(function_exists('apc_fetch')) + return 'apc'; + else if(function_exists('eaccelerator_get')) + return 'eaccelerator'; + else if(function_exists('xcache_get') && ini_get('xcache.var_size')) + return 'xcache'; + + return 'file'; + } + + public function enabled() {return false;} +} +?> diff --git a/system/libs/cache_apc.php b/system/libs/cache_apc.php new file mode 100644 index 00000000..09c27d40 --- /dev/null +++ b/system/libs/cache_apc.php @@ -0,0 +1,49 @@ + + * @author Mark Samman (Talaturen) + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Cache_APC +{ + private $prefix = ''; + private $enabled; + + public function __construct($prefix = '') + { + $this->prefix = $prefix; + $this->enabled = function_exists('apc_fetch'); + } + + public function set($key, $var, $ttl = 0) + { + $key = $this->prefix . $key; + apc_delete($key); + apc_store($key, $var, $ttl); + } + + public function get($key) + { + $tmp = ''; + if($this->fetch($key, $tmp)) + return $tmp; + + return ''; + } + + public function fetch($key, &$var) { + return ($var = apc_fetch($this->prefix . $key)) !== false; + } + + public function enabled() { + return $this->enabled; + } +} +?> diff --git a/system/libs/cache_eaccelerator.php b/system/libs/cache_eaccelerator.php new file mode 100644 index 00000000..e786d0cc --- /dev/null +++ b/system/libs/cache_eaccelerator.php @@ -0,0 +1,48 @@ + + * @author Mark Samman (Talaturen) + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Cache_eAccelerator +{ + private $prefix; + private $enabled; + + public function __construct($prefix = '') { + $this->prefix = $prefix; + $this->enabled = function_exists('eaccelerator_get'); + } + + public function set($key, $var, $ttl = 0) + { + $key = $this->prefix . $key; + eaccelerator_rm($key); + eaccelerator_put($key, $var, $ttl); + } + + public function get($key) + { + $tmp = ''; + if($this->fetch($key, $tmp)) + return $tmp; + + return ''; + } + + public function fetch($key, &$var) { + return ($var = eaccelerator_get($this->prefix . $key)) !== null; + } + + public function enabled() { + return $this->enabled; + } +} +?> diff --git a/system/libs/cache_file.php b/system/libs/cache_file.php new file mode 100644 index 00000000..5c6d35de --- /dev/null +++ b/system/libs/cache_file.php @@ -0,0 +1,62 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Cache_File +{ + private $prefix = ''; + private $dir = ''; + private $enabled; + + public function __construct($prefix = '', $dir = '') { + $this->prefix = $prefix; + $this->dir = $dir; + $this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir)); + } + + public function set($key, $var, $ttl = 0) + { + $file = $this->_name($key); + file_put_contents($file, $var); + if($ttl != 0) + touch($file, time() + $ttl); + else + touch($file, time() + 24 * 60 * 60); + } + + public function get($key) + { + $tmp = ''; + if($this->fetch($key, $tmp)) + return $tmp; + + return ''; + } + + public function fetch($key, &$var) + { + $file = $this->_name($key); + if(!file_exists($file) || filemtime($file) < time()) + return false; + + $var = file_get_contents($file); + return true; + } + + public function enabled() { + return $this->enabled; + } + + private function _name($key) { + return sprintf("%s/%s%s", $this->dir, $this->prefix, sha1($key)); + } +} +?> diff --git a/system/libs/cache_xcache.php b/system/libs/cache_xcache.php new file mode 100644 index 00000000..b6cce50a --- /dev/null +++ b/system/libs/cache_xcache.php @@ -0,0 +1,54 @@ + + * @author Mark Samman (Talaturen) + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Cache_XCache +{ + private $prefix = ''; + private $enabled; + + public function __construct($prefix = '') { + $this->prefix = $prefix; + $this->enabled = function_exists('xcache_get') && ini_get('xcache.var_size'); + } + + public function set($key, $var, $ttl = 0) + { + $key = $this->prefix . $key; + xcache_unset($key); + xcache_set($key, $var, $ttl); + } + + public function get($key) + { + $tmp = ''; + if($this->fetch($key, $tmp)) + return $tmp; + + return ''; + } + + public function fetch($key, &$var) + { + $key = $this->prefix . $key; + if(!xcache_isset($key)) + return false; + + $var = xcache_get($key); + return true; + } + + public function enabled() { + return $this->enabled; + } +} +?> diff --git a/system/libs/data.php b/system/libs/data.php new file mode 100644 index 00000000..88cbb4d3 --- /dev/null +++ b/system/libs/data.php @@ -0,0 +1,45 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); + +class Data +{ + private $table = ''; + + public function __construct($table) { + $this->table = $table; + } + + public function get($where) + { + global $db; + return $db->select($this->table, $where); + } + + public function add($data) + { + global $db; + return $db->insert($this->table, $data); + } + + public function delete($data, $where) + { + global $db; + return $db->delete($this->table, $data, $where); + } + + public function update($data, $where) + { + global $db; + return $db->update($this->table, $data, $where); + } +} +?> diff --git a/system/libs/dwoo/.htaccess b/system/libs/dwoo/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/system/libs/dwoo/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/libs/dwoo/CHANGELOG b/system/libs/dwoo/CHANGELOG new file mode 100644 index 00000000..b7f2ff88 --- /dev/null +++ b/system/libs/dwoo/CHANGELOG @@ -0,0 +1,508 @@ +[2010-02-07] 1.1.1 ++ Added {optional} plugin that just prints an optional var without any + notice if it doesn't exist ++ Added Dwoo::setTemplate() for testing purposes mostly +* Fixed an {extends} parsing bug that prevented the use of single-quotes + around the parent template's filename +* Fixed a security issue, if you didn't use a custom compiler factory but + passed the compiler directly to the get method with autoEscape enabled, + the autoEscape was disabled in included templates - Thanks to Fabien + Potencier for notifying me. +* Fixed a bug in {safe} when using variable-variables it would sometimes + corrupt the var name resulting in blank output +* Fixed a bug when accessing array indices that contain a minus sign, it + is now possible to access those using {$var[index-foo]}, + {$var['index-foo']} or {$index="index-foo"} {$var[$index]} +* Fixed a bug in {tif} that didn't work when 0 was given as the true or + false value +* Fixed a bug when using the autoEscape feature with sub-templates (the + compiled sub-template couldn't access the dwoo charset property, + resulting in a fatal error) +* Fixed a property reading bug on objects that implemented __get but not + __isset, implementing __isset is however very much recommended +* Fixed a Dwoo_Data bug in the append method when the index didn't exist + yet it threw a notice +* Fixed a bug when accessing global vars from a sub-template +* Fixed a couple bugs in the {dynamic} plugin with regard to using plugins + within a dynamic block +* Fixed a compilation bug when using a PluginProxy with highly nested calls +* Fixed a {load_templates} bug, plugins used in external templates were not + loaded correctly, same for custom user plugins +* Cached templates now check the source template for modification before + outputting the cached version +* Removed a couple of @-operator calls to file_get_contents + +[2009-07-18] 1.1.0 +! BC Break: Dwoo::initGlobals() is only called once during the Dwoo object + construction. If you had overriden it and need to update global data + before each template is executed you should instead override + Dwoo::initRuntimeVars() and push stuff in the globals array there. Also + be aware that this means captured data, foreach values and so-on will + persist from a parent template to an included one (but the include's + changes will not be reflected on the parent), and from a template + to the next if you render several in series. ++ Added {template} plugin that allows you to define sub-templates and then + call them (works recursively too, good for menus and lists) ++ Added {load_templates} to load external sub-templates into your file ++ Allowed string concatenation assignments with {$foo.="bar"} ++ Allowed access of static properties as {Foo::$bar} ++ Plugins/Helpers that use a dynamic number of arguments through + func_get_args are now working since the compiler lets any arguments in + excess pass through ++ Adapters: CodeIgniter: the adapter by Stefan Verstege has been added to + core and he will be its maintainer from now on ++ Adapters: CakePHP: this adapter is now added to core and is designed to + work with CakePHP 1.2 +* Adapters: Zend: Denis Arh is now appointed maintainer of that part and + fixed a few things since 1.0.1 +* The include_path isn't altered anymore, hopefully saving some stat calls +* User classes extending Dwoo_Template_File are now supported better with + regard to includes - Thanks to the Kayako.com team for the patch +* Objects now act like arrays when you access non-existing properties on + them (i.e. it outputs a notice only if it's output straight, and none + when passed to a function) +* For can now iterate backwards if you input numbers, it won't work with + variables though +* Slight performance improvement with big inheritance trees +* No more double-slashes in template paths since this seemed to cause + slight performance issues +* Fixed a bug with parsing AND/OR keywords in conditionals when they were + followed by round brackets +* Fixed assignments not handling multi-line values correctly +* Fixed parameter parsing issue when a plugin name was all uppercased +* Fixed assignments failing with autoEscape enabled +* Fixed parsing of vars with string keys that was too greedy +* Fixed an optimization causing foreach/for/loop variables not being + accessible when the foreach/.. name was set dynamically +* Fixed parsing of comments that were on top of the file when there are + spaces at the end of it +* Dwoo_Template::$chmod is now enforced for directories as well (#18) +* Many new unit tests to improve code coverage and a bunch of bug fixes + that resulted, but I didn't really keep track of them + +[2008-12-24] 1.0.1 +* Direct assignments like {$foo = 5} now allow spaces around the operator +* Fixed a {foreach} bug with the implode argument +* Fixed modulo operator in if statements +* Fixed date_format handling of negative and small unix timestamps +* Fixed a weird reference bug with ZF and includes.. whatever but thanks + to Denis Arh for the patch + +[2008-10-23] 1.0.0 +! BC Break: Small one that probably won't affect anyone, but it makes the + PluginProxy feature much stronger. Basically if you used a custom one you + will get a fatal error and need to update it to conform to the new + IPluginProxy interface, that's it ++ Compiler: the modifier syntax (|foo) can now be applied on functions and on + complex variables i.e. {$obj->getStuff()|upper} or {lower('foo')|upper} ++ SmartyCompat: Added a {section} plugin but I strongly discourage using it, + it was really made to support legacy templates, since {for} doesn't have to + handle {section}-BC anymore, it has been cleaned up a lot and the last + $skip parameter has been dropped +* The core Dwoo class doesn't need writable compile/cache dirs in the + constructor anymore so you can provide custom ones later through + ->setCompile(/Cache)Dir - thanks to Denis Arh for the patch +* Adapters: Zend: major overhaul thanks to Denis Arh, templates files should + probably be moved in the scripts subfolder after this update though, and + the settings array has changed a bit, you will get warnings if you don't + update the code anyway +* Plugins: improved the dump plugin, it now displays object's properties + and optionally public methods (if the new show_methods arg is set to true) + - thanks to Stephan Wentz for the patch +* Adapters: Zend: Added parameters to provide a custom engine (extends Dwoo) + or a custom data class (extends Dwoo_Data) - thanks to Maxime Merian for + the patch +* Compiler: added Dwoo_Compiler->setNestedCommentsHandling(true) to enable + parsing of nested comments (i.e. {* {* *} *} becomes a valid comment, useful + to comment out big chunks of code containing comments) +* Lines containing only comments and whitespace are now entirely removed +* Removed comments do not mess up the line count anymore (for error messages) +* Fixed parsing bug in {func()->propertyOfReturnedObject} +* Fixed file template class reading from the string compiler factory - thanks + to MrOxiMoron for the patch +* Fixed handling of variable variables that contained non standard characters +* Fixed a 1.0.0beta regression that messed with custom plugin directories + on Windows +* SmartyCompat: Fixed a few bugs in the adapter and processor - thanks to + Stefan Moonen for the patches + +[2008-09-08] 1.0.0beta +! Important note : Dwoo.php should not be included directly anymore, please + read the UPGRADE_NOTES file for more infos on the matter, if you don't + your Dwoo install will most likely break after the update anyway +! BC Break: {include} and {extends} now support the include path properly, + which means that if you include "foo/bar.html" from _any_ template and you + have an include path set on your template object, it will look in all those + paths for foo/bar.html. If you use relative paths, for example + if you include "../foo/bar.html" AND have an include path set, you will now + have a problem, because you can't mix both approaches, otherwise you should + be fine, so to fix this you should convert your relative includes/extends ++ Adapters: Added the Agavi interface for Dwoo + (see /Dwoo/Adapters/Agavi/README) ++ API: Added Dwoo_Compilation_Exception methods getCompiler() and + getTemplate() so you can catch the exception and use those to build a nicer + error view with all the details you want ++ Plugins: Added a mode parameter to {strip} to allow stripping of javascript + code blocks that use "// comments", because without this special mode the + comments result in syntax errors +* The Compiler now ensures that a template starting with get() is now stricter as to what it accepts as a "template", only + Dwoo_ITemplate objects or valid filenames are accepted +* Foreach and other similar plugins that support "else" now only count() + their input before processing when an else block follows +* Various optimizations +* Fixed compiler bug that created a parse error when you had comments in an + extended template +* Fixed extends bug when extending files in other directories using relative + paths +* Fixed parsing bug with "|modifier:param|modifier2} with:colon after it" +* Bug fixed with smarty functions called with no parameters (in compat mode) +* Fixed Dwoo::isArray() check, objects implementing ArrayAccess are now + valid (thanks to Daniel Cousineau for the patch) +* Fixed compiler warning when doing {func()->method()} or {func()->property} +* Fixed compiled/cached files being written in the wrong place when the path + to the template contains "../"s +* Fixed {if} failing with conditions using upper case operators (i.e. AND) + +[2008-08-03] 0.9.3 ++ Adapters: Added the ZendFramework interface for Dwoo + (see /Dwoo/Adapters/ZendFramework/README) ++ Plugins: Added the {a} block plugin to generate tags ++ Syntax: Added the ";" token that allows to group multiple instructions in one + single template tag, example: {if $foo; "> $foo";$bar;/} is equal to: + {if $foo}> {$foo}{$bar}{/} - This also allow block operations such as: + {a http://url.com; "Text" /} which equals to {a http://url.com}Text{/} ++ Syntax: Block plugins that you want to call without content can be + self-closed just like XML tags (e.g. {a "http://url.com" /} ). Be careful not + to close a non-block plugin like that however, since it will close it's + parent block ++ Syntax: Static methods can be called using {Class::method()} ++ Syntax: It is now possible to use a plugin's result as an object and call + a method or read a property from it, i.e. {fetchObject()->doStuff()} ++ API: Added Dwoo_Plugin::paramsToAttributes() utility function to help + with the creation of compilable xml/html-related plugins ++ API: Added Dwoo->setPluginProxy() and Dwoo_IPluginProxy that allow you to + hook into the compiler's plugin subsystem to provide your own plugin calls. + Thanks to Denis Arh for the patch + => http://forum.dwoo.org/viewtopic.php?id=70 ++ API: Dwoo->addPlugin() has a third parameter to mark a plugin as compilable ++ Compiler supports method calls into a method call's parameters +* Dwoo_Compiler::implode_r is now public/static so it can be used in other + places such as plugin proxies +* Syntax: Math expressions in strings are now only allowed when the entire + expression is delimited, e.g. {"/$foo/$bar"} evaluates as just that while + {"/`$foo/$bar`"} will result in "/".($foo/$bar), therefore processing the / + as a division, this is better since URLs using / are far more common than + math in strings + => http://forum.dwoo.org/viewtopic.php?id=50 +* Compiler now allows the use of the right delimiter inside strings (e.g. {"}"}) +* Fixed a bug preventing if blocks containing a {elseif} followed by {else} +* Fixed the Dwoo_ILoader interface and implemented it in Dwoo_Loader now + => http://forum.dwoo.org/viewtopic.php?id=70 +* Fixed a compileId auto-generation creating conflicts +* Include allows paths going in upper levels now such as : "../foo.html" +* Some compiler fixes regarding custom plugins + +[2008-06-28] 0.9.2 +! BC Break: Renamed the {strip} modifier/function to {whitespace}, this does + not affect the strip block, that has been moved off the compiler into a + plugin. Which is why the name conflict had to be resolved. Please report + any issue you might encounter when using the strip block +! BC Break: Changed the function signature of Dwoo_Block_Plugin::postProcessing + it only affects you if you had any custom block plugins, see UPGRADE_NOTES + for more details +! BC Break: Dwoo_ITemplate::cache() must now return the cached file name or + false if caching failed, only affects you if you had a custom template class + and implemented cache() yourself +! BC Break: Dwoo_Loader is not static anymore so anything you did on it directly + will break. Use $dwoo->getLoader()->addDirectory() instead of + Dwoo_Loader::addDirectory() for example +! BC Break: DWOO_COMPILE_DIRECTORY and DWOO_CACHE_DIRECTORY are gone, set those + paths in Dwoo's constructor (i.e. new Dwoo('compiledir', 'cachedir')) if you + need to override the default ones ++ Plugins: Added {dynamic} that allows cached templates to have dynamic + (non-cached) parts, when rendering a cached page, the dynamic parts can still + use the variables you provides ++ Plugins: Added {tif} that acts as a ternary if / allows you to use a ternary + operator inside it ++ API: Added a Dwoo_ILoader interface if you want to provide a custom plugin + loading solution (use $dwoo->setLoader($myLoader)) ++ Added line numbers in compilation errors and improved several error messages ++ Added magic object-access methods to Dwoo_Data, so you can assign values by + doing $data->var = $val; instead of $data->assign('var', $val); ++ Added get()/unassign()/isAssigned() methods to read, remove and check for the + presence of a var inside a Dwoo_Data object +* Plugins: added a fifth 'string $implode' parameter to {foreach}, it prints + whatever you provide it between each item of the foreach, just like implode() +* Plugins: added a fourth 'bool $case_sensitive' parameter to {replace} +* Plugins: added a fourth 'bool $trim' parameter to {capture} that trims + the captured text +* Made the dependency on the hash extension optional +* Fixed compiler bug that prevented method calls combined with named parameters +* Fixed compiler bug that prevented the % shortcut for constants to work within + function calls (basically it only worked as {%CONST}) +* Fixed compiler bug that prevented empty() to be called +* Fixed several modifier parsing bugs + => http://forum.dwoo.org/viewtopic.php?id=27 +* Fixed empty string parsing in modifier applied to variables +* Fixed compiler handling of {template_tag} where there was + no ';' at the end of the php tag +* Allowed method calls to work with named parameters +* Removed checks for methods/properties being present on objects before calling + them since these can be handled by __get() and __call() + => http://forum.dwoo.org/viewtopic.php?id=22 +* Calling {func (params)} (with the space between function and params) is now + allowed + => http://forum.dwoo.org/viewtopic.php?id=21 +* The compiler now allows \r, \n and \t to be parameter splitters as well as + "," and " ". You can therefore split complex function calls on multiple lines +* Converted most of the code to follow PEAR Coding Standards, hopefully this + didn't break anything that the tests missed +* A few other minor or internal changes + +[2008-05-30] 0.9.1 ++ API: Added Dwoo_Compiler->setAutoEscape() and getAutoEscape() to modify the + automatic html entity escaping setting. This is disabled by default, and when + enabled can be overriden with the {safe $var} plugin or the + {auto_escape disable} block plugin. The block plugin can also be used to + enable this mode from within a template ++ Syntax: Mixing named and unnamed parameters is now allowed, as long as the + unnamed ones appear first ++ Syntax: Added {/} shortcut that closes the last opened block +* Optimized scope-handling functions, {loop} and {with} are now slightly faster +* Fixed a bug in {date_format} that prevented anything but unix timestamps to + work +* {literal} and {strip} now follow the LooseOpeningsHandling setting +* Fixed complex variables (i.e. {$_root[$c[$x.0]].0}) parsing bugs +* Fixed $dwoo->addResource() breaking if the resource class was not loaded yet, + autoload should now be called (thanks mike) +* Fixed a block stack bug that messed up {textformat} and possibly usermade + block plugins + +[2008-05-10] 0.9.0 +! BC Break: changed all class names to be PEAR compliant (aka use underscores + to separate words/paths), sorry about that but I better do it now than in + six months +! BC Break: $dwoo->output() and get() have been swapped internally, but it + doesn't change anything for you unless you called output(*, *, *, true) + directly to emulate get(). This was done to reduce some overhead +! BC Break: $dwoo->getTemplate() changed to $dwoo->templateFactory() and + $dwoo->getCurrentTemplate() changed to $dwoo->getTemplate() for consistency + among all classes and factory functions ++ Added a compiled version of Dwoo that loads faster (especially with opcode + caches such as APC), include Dwoo.compiled.php instead of Dwoo.php on + production but if you want to file a bug use Dwoo.php please as it allows + you to get the proper file/line number where an error occurs. Do not remove + all other files however since they are not all included in the compiled + package ++ Plugins: Added {extends} and {block} to handle template inheritance, read + more about it at http://wiki.dwoo.org/index.php/TemplateInheritance ++ Plugins: Added {loop} that combines {foreach} and {with}, see + http://wiki.dwoo.org/index.php/Block:loop for details ++ Plugins: Added {do} that executes whatever you feed it whitout echoing the + result, used internally for extends but you can use it if required ++ Plugins: Added {eol} that prints an end of line character (OS-specific) ++ Syntax: Added shortcut for {$dwoo.const.*} using '%', for example you can use + {%FOO} instead of {$dwoo.const.FOO} ++ Syntax: When using named parameters, typing a parameter name without any + value is the same as typing param=true, for example {foo name="test" bar} and + {foo name="test" bar=true} are equals, can be useful for very complex plugins + with huge amounts of parameters. ++ Syntax: Added support for {$foo+=5}, {$foo="a"}, {$foo++} and {$foo--} ++ Syntax: Added shortcut for $dwoo.*, you can now use {$.foreach.foo} instead + of {$dwoo.foreach.foo} for example, applies to all $dwoo.* vars ++ Syntax: Added $ as a shortcut for current scope, $_ for $_parent and $__ for + $_root ++ API: Added getSource(), getUid() and getResourceIdentifier() to Dwoo_ITemplate ++ API: Added setSecurityPolicy() too Dwoo_ICompiler and modified the arguments + of its compile() method ++ API: Added a bunch of utility functions to Dwoo_Compiler, allowing compiled + plugins to access more of the compiler internals ++ Both cache and compile IDs can now have slashes in them to create subfolders + in the cache/compile dirs ++ Added a DWOO_CHMOD constant that, if set before you include Dwoo, allows you + to define the file mode of all the file/directories Dwoo will write, defaults + to 0777 ++ Added a 'data' argument to {include} to be able to feed data directly into it +* The compiler now throws Dwoo_Compilation_Exception exceptions upon failure + and security problems lead to a Dwoo_Security_Exception being thrown. Runtime + plugin errors and such trigger simple php errors to allow the template + execution to complete +* Fixed a potential concurrency issue (thanks to Rasmus Schultz for the patch) +* Moved all files to Dwoo/Class.php excepted for the core Dwoo.php file +* Various performance improvements, including the removal of a lot of isset() + calls. Doing {$foo} if foo is undefined will now display a PHP warning, but + doing {foreach $foo}..{/foreach} will not however, that way you don't have + to do {if isset($foo)} before the foreach, but automated isset() calls don't + impact performance as much as they did before. +* API: Dwoo_ITemplate->clearCache now requires a Dwoo instance as its first arg, + should not affect you unless you built a custom template class from scratch +* Reworked Dwoo template rendering to avoid variable conflicts with plugins +* {include} now uses the current resource if none is provided instead of using + file as it did before +* Dwoo uses include path instead of absolute includes +* Changed all line endings to Unix (line feed only) and all spaces left have + been converted to tabs (tabspace 4) +* TestFest happened early for Dwoo, lots of new tests and more code covered +* Fixed a regression in the handling of custom class plugins +* Fixed various bugs in the Adapter class and related smarty compatibility + features +* Fixed a classpath rebuilding bug that occured on some UNIX platforms due to + glob() returning false sometimes for empty folders +* Fixed a bug in Dwoo_Security_Policy->getAllowedDirectories(), no security + issue though +* Fixed a bug in Dwoo::setScope affecting {loop} and {with} +* Fixed a parsing bug when doing {"string"|modifier:$var} + +[2008-04-09] 0.3.4 +! BC Break: DWOO_PATH constant changed to DWOO_DIRECTORY +! BC Break: Smarty's @ operator for modifiers is now reversed, for example + $array|reverse will reverse the items of that array while $array|@reverse + will reverse each item of the given array (as if you used array_map) ++ Syntax: Added support for method calls on objects i.e. {$foo->bar()} ++ Added support for smarty security features, see the DwooSecurityPolicy class + and $dwoo->setSecurityPolicy() ++ API: Added a DwooCompiler->setLooseOpeningHandling() method that, if set to + true, allows tags to contain spaces between the opening bracket and the + content. Turned off by default as it allows to compile files containing + css and javascript without the need to escape it through {literal} or \{ ++ Added DWOO_CACHE_DIRECTORY and DWOO_COMPILE_DIRECTORY constants that you can + set before including Dwoo.php to override the defaults (although + Dwoo->setCacheDir/setCompileDir() still work to change that if required) ++ Added the DwooException class ++ Smarty: Added partial support for register_object(), unregister_object() and + get_registered_object(). All features can not be supported by the adapter + though so you might get compatibility warnings +* Fixed {elseif} bug that appeared when multiple elseif tags were used in a row +* Syntax: Improved simple math support to work within variable variables + (i.e. you can do {$array[$index+1]}) and within strings as well. To prevent + this enclose the variables in backticks (i.e. {"$foo/$bar"} will do the math + while {"`$foo`/$bar"} won't as $foo is properly delimited) +* Changed DwooLoader::addDirectory() so that it writes the class paths cache + into DWOO_COMPILE_DIRECTORY, that way you don't have to make your plugin + directory writable +* Made all the error triggering more consistent +* Changed automatic cacheId generation in DwooTemplateFile/String to be faster + +[2008-03-19] 0.3.3 ++ Syntax: Added support for $dwoo.const.CONSTANT and + $dwoo.const.Class::CONSTANT to read PHP constants from the template ++ Syntax: Added support for on/off/yes/no, that work as aliases for true/false ++ Syntax: Added the $dwoo.charset global variable ++ Plugins: Added {withelse} and made {with} compatible with {else} also ++ API: Added left/right delimiters customization, see DwooCompiler->setDelimiters() ++ API: Added DwooCompiler->triggerError() ++ API: Added Dwoo->clearCache() and DwooITemplate->clearCache() methods ++ Smarty: The smartyCompat prefilter converts {section} tags into {for} tags on the + fly, however it's not guaranteed to work with *all* section tags, let me know if + it breaks for you +* {with} now skips the entire block if it's variable doesn't exist, so by + itself it acts as if you would do {if $var}{with $var}{/with}{/if} +* Each resource has a compiler factory function assigned to it, allowing you to + easily provide a custom compiler without loading it on every page +* OutputFilters are now simply called Filters (they still use DwooFilter) +* Pre/PostFilters have become Pre/PostProcessors (they now use DwooProcessor) +* Compiler: Fixed parsing bug that prevented function names of 1character +* Compiler: Changed internal handling of variables to fix some errors being + thrown with specific cases +* Reorganized Dwoo/DwooCompiler and fully commented all the core classes + and interfaces + +[2008-03-09] 0.3.2 ++ Added access to superglobals through $dwoo.get.value, $dwoo.post.value, + etc. ++ Added outputFilters to Dwoo (use Dwoo->addOutputFilter and + Dwoo->removeOutputFilter) ++ Added preFilters and postFilters to DwooCompiler (use + DwooCompiler->addPreFilter, etc) ++ Added a html_format output filter that intends properly the html code, + use it only on full page templates ++ Plugins: Added {for} and {forelse} which allow to loop over an array or to + loop over a range of numbers ++ Plugins: Added {mailto}, {counter}, {eval}, {fetch} and {include} ++ Syntax : Enhanced support for implicit math operations, + {$var+$var2*var3+5} now works. Operations are executed from left to right + though, there is no operator priority. (i.e. 1+1*2 = (1+1)*2 = 4, not 3) ++ API: Added resources support through DwooITemplate implementations and + Dwoo->addResource() ++ API: Added Dwoo->getTemplate() to get the currently running template object ++ API: Added DwooCompiler::getInstance() to use only one compiler object when + rendering from the default compiler and to provide you with a singleton if + it's easier, however the class is not a singleton in the sense that it can + be instantiated separately ++ API: Added a factory method on DwooITemplate to support resources creation ++ Added a release tag so that all compiled templates are forced to recompile + after an update, however it is recommended to cleanup your "compiled" + directory now and then as each release uses new filenames ++ Added an abstract DwooFilter class that you can extend to build filters +* PHP function calls are now case insensitive +* Syntax: The compiler now parses expressions before modifiers, allowing for + {$var/2|number_format} for example +* DwooTemplateFile now extends DwooTemplateString instead of the other way + around as it was before +* {else} is now a general purpose plugin that can act as 'else' for foreach, + for and if/elseif, foreachelse is still available though + +[2008-03-05] 0.3.1 ++ Added {cycle} function ++ Syntax : Enabled support for associative arrays using + array(key="value", key2=5) for example, which you can assign or use in a + foreach directly ++ Syntax : Added support for {$var +-/*% X} (i.e. {$var + 4}), useful for + simple math operations without the math plugin ++ API : Added append/appendByRef to DwooData ++ Completely rebuilt DwooSmartyAdapter, it should "work" and fail silently if + you use a non supported function now, however you can set + $smarty->show_compat_errors=true; on it to receive notices about unsupported + features that you use +* Bug fixed in {literal} parsing +* Bug fixed in smarty functions handling +* API : Moved Plugin types constants to Dwoo so the compiler doesn't have to + be loaded unles really required +* API : Moved globals and var reinitialization in Dwoo into their own methods + so that child classes can easily add globals +* Some improvements in the compiler output +* Some changes in the cache handling of DwooTemplateFile +- Special thanks to Andrew Collins that found many of the bugs fixed in this + release + +[2008-03-02] 0.3.0 ++ Full template cache support ++ DwooTemplateString class to load templates from a string ++ Dwoo::VERSION constant ++ {dump} plugin to print out variables ++ Unit tests (with PHPUnit) covering 73% of the codebase right now, which + should help reducing regression bugs in the next versions. ++ Started commenting (with phpdocs) properly all the classes, should be + complete for 0.4.0 +* {capture} is now compilable and has a new boolean flag to append output into + the target variable instead of overwriting +* {foreach} supports direct input (instead of only variables), allowing + constructs like {foreach array(a,b,c) val}{$val}{/foreach} for example that + would output abc. +* pre/postProcessing functions in block plugins now receive an array of named + parameters instead of numbered +* Major refactoring of DwooTemplateFile and DwooCompiler +* Cleaned up members visibility in Dwoo/DwooCompiler +* Fixes in the compiler parsing and general variables handling +* Multiple bugfixes here and there thanks to the unit tests +* Optimized {foreach} a lot + +[2008-02-19] 0.2.1 +* Compiler fixes for argument parsing and handling of Smarty plugins + +[2008-02-14] 0.2.0 ++ Added support for plugins made for Smarty (that includes modifiers, + functions and blocks). Not thoroughly tested. ++ Major API changes in the way Dwoo must be run, it's now much more + flexible and should not change too much in the future. ++ Added support for custom plugins, filters should come in the next version + although the API to register them is already in. + +[2008-02-08] 0.1.0 +Initial release \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo.compiled.php b/system/libs/dwoo/Dwoo.compiled.php new file mode 100644 index 00000000..ed8b4696 --- /dev/null +++ b/system/libs/dwoo/Dwoo.compiled.php @@ -0,0 +1 @@ + array ( 'class' => 'Dwoo_Template_File', 'compiler' => null ), 'string' => array ( 'class' => 'Dwoo_Template_String', 'compiler' => null ) ); protected $loader = null; protected $template = null; protected $runtimePlugins; public $data; public $scope; protected $scopeTree; protected $stack; protected $curBlock; protected $buffer; protected $pluginProxy; public function __construct($compileDir = null, $cacheDir = null) { if ($compileDir !== null) { $this->setCompileDir($compileDir); } if ($cacheDir !== null) { $this->setCacheDir($cacheDir); } $this->initGlobals(); } public function __clone() { $this->template = null; unset($this->data); } public function output($tpl, $data = array(), Dwoo_ICompiler $compiler = null) { return $this->get($tpl, $data, $compiler, true); } public function get($_tpl, $data = array(), $_compiler = null, $_output = false) { if ($this->template instanceof Dwoo_ITemplate) { $proxy = clone $this; return $proxy->get($_tpl, $data, $_compiler, $_output); } if ($_tpl instanceof Dwoo_ITemplate) { } elseif (is_string($_tpl) && file_exists($_tpl)) { $_tpl = new Dwoo_Template_File($_tpl); } else { throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file', E_USER_NOTICE); } $this->template = $_tpl; if ($data instanceof Dwoo_IDataProvider) { $this->data = $data->getData(); } elseif (is_array($data)) { $this->data = $data; } else { throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s data argument must be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array', E_USER_NOTICE); } $this->globals['template'] = $_tpl->getName(); $this->initRuntimeVars($_tpl); $file = $_tpl->getCachedTemplate($this); $doCache = $file === true; $cacheLoaded = is_string($file); if ($cacheLoaded === true) { if ($_output === true) { include $file; $this->template = null; } else { ob_start(); include $file; $this->template = null; return ob_get_clean(); } } else { if ($doCache === true) { $dynamicId = uniqid(); } $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler); $out = include $compiledTemplate; if ($out === false) { $_tpl->forceCompilation(); $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler); $out = include $compiledTemplate; } if ($doCache === true) { $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '', $out); if (!class_exists('Dwoo_plugin_dynamic', false)) { $this->getLoader()->loadPlugin('dynamic'); } $out = Dwoo_Plugin_dynamic::unescape($out, $dynamicId, $compiledTemplate); } foreach ($this->filters as $filter) { if (is_array($filter) && $filter[0] instanceof Dwoo_Filter) { $out = call_user_func($filter, $out); } else { $out = call_user_func($filter, $this, $out); } } if ($doCache === true) { $file = $_tpl->cache($this, $out); if ($_output === true) { include $file; $this->template = null; } else { ob_start(); include $file; $this->template = null; return ob_get_clean(); } } else { $this->template = null; if ($_output === true) { echo $out; } return $out; } } } protected function initGlobals() { $this->globals = array ( 'version' => self::VERSION, 'ad' => 'Powered by Dwoo', 'now' => $_SERVER['REQUEST_TIME'], 'charset' => $this->charset, ); } protected function initRuntimeVars(Dwoo_ITemplate $tpl) { $this->runtimePlugins = array(); $this->scope =& $this->data; $this->scopeTree = array(); $this->stack = array(); $this->curBlock = null; $this->buffer = ''; } public function addPlugin($name, $callback, $compilable = false) { $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0; if (is_array($callback)) { if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) { $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0])); } else { $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]); } } elseif (class_exists($callback, false)) { if (is_subclass_of($callback, 'Dwoo_Block_Plugin')) { $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback); } else { $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback, 'function'=>'process'); } } elseif (function_exists($callback)) { $this->plugins[$name] = array('type'=>self::FUNC_PLUGIN | $compilable, 'callback'=>$callback); } else { throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists'); } } public function removePlugin($name) { if (isset($this->plugins[$name])) { unset($this->plugins[$name]); } } public function addFilter($callback, $autoload = false) { if ($autoload) { $class = 'Dwoo_Filter_'.$callback; if (!class_exists($class, false) && !function_exists($class)) { try { $this->getLoader()->loadPlugin($callback); } catch (Dwoo_Exception $e) { if (strstr($callback, 'Dwoo_Filter_')) { throw new Dwoo_Exception('Wrong filter name : '.$callback.', the "Dwoo_Filter_" prefix should not be used, please only use "'.str_replace('Dwoo_Filter_', '', $callback).'"'); } else { throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"'); } } } if (class_exists($class, false)) { $callback = array(new $class($this), 'process'); } elseif (function_exists($class)) { $callback = $class; } else { throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"'); } $this->filters[] = $callback; } else { $this->filters[] = $callback; } } public function removeFilter($callback) { if (($index = array_search('Dwoo_Filter_'.$callback, $this->filters, true)) !== false) { unset($this->filters[$index]); } elseif (($index = array_search($callback, $this->filters, true)) !== false) { unset($this->filters[$index]); } else { $class = 'Dwoo_Filter_' . $callback; foreach ($this->filters as $index=>$filter) { if (is_array($filter) && $filter[0] instanceof $class) { unset($this->filters[$index]); break; } } } } public function addResource($name, $class, $compilerFactory = null) { if (strlen($name) < 2) { throw new Dwoo_Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths'); } if (!class_exists($class)) { throw new Dwoo_Exception('Resource class does not exist'); } $interfaces = class_implements($class); if (in_array('Dwoo_ITemplate', $interfaces) === false) { throw new Dwoo_Exception('Resource class must implement Dwoo_ITemplate'); } $this->resources[$name] = array('class'=>$class, 'compiler'=>$compilerFactory); } public function removeResource($name) { unset($this->resources[$name]); if ($name==='file') { $this->resources['file'] = array('class'=>'Dwoo_Template_File', 'compiler'=>null); } } public function setLoader(Dwoo_ILoader $loader) { $this->loader = $loader; } public function getLoader() { if ($this->loader === null) { $this->loader = new Dwoo_Loader($this->getCompileDir()); } return $this->loader; } public function getCustomPlugins() { return $this->plugins; } public function getCacheDir() { if ($this->cacheDir === null) { $this->setCacheDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR); } return $this->cacheDir; } public function setCacheDir($dir) { $this->cacheDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR; if (is_writable($this->cacheDir) === false) { throw new Dwoo_Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable'); } } public function getCompileDir() { if ($this->compileDir === null) { $this->setCompileDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'compiled'.DIRECTORY_SEPARATOR); } return $this->compileDir; } public function setCompileDir($dir) { $this->compileDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR; if (is_writable($this->compileDir) === false) { throw new Dwoo_Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable'); } } public function getCacheTime() { return $this->cacheTime; } public function setCacheTime($seconds) { $this->cacheTime = (int) $seconds; } public function getCharset() { return $this->charset; } public function setCharset($charset) { $this->charset = strtolower((string) $charset); } public function getTemplate() { return $this->template; } public function setTemplate(Dwoo_ITemplate $tpl) { $this->template = $tpl; } public function setDefaultCompilerFactory($resourceName, $compilerFactory) { $this->resources[$resourceName]['compiler'] = $compilerFactory; } public function getDefaultCompilerFactory($resourceName) { return $this->resources[$resourceName]['compiler']; } public function setSecurityPolicy(Dwoo_Security_Policy $policy = null) { $this->securityPolicy = $policy; } public function getSecurityPolicy() { return $this->securityPolicy; } public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy) { $this->pluginProxy = $pluginProxy; } public function getPluginProxy() { return $this->pluginProxy; } public function isCached(Dwoo_ITemplate $tpl) { return is_string($tpl->getCachedTemplate($this)); } public function clearCache($olderThan=-1) { $cacheDirs = new RecursiveDirectoryIterator($this->getCacheDir()); $cache = new RecursiveIteratorIterator($cacheDirs); $expired = time() - $olderThan; $count = 0; foreach ($cache as $file) { if ($cache->isDot() || $cache->isDir() || substr($file, -5) !== '.html') { continue; } if ($cache->getCTime() < $expired) { $count += unlink((string) $file) ? 1 : 0; } } return $count; } public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) { if (isset($this->resources[$resourceName])) { return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate); } else { throw new Dwoo_Exception('Unknown resource type : '.$resourceName); } } public function isArray($value, $checkIsEmpty=false) { if (is_array($value) === true) { if ($checkIsEmpty === false) { return true; } else { return count($value) > 0; } } elseif ($value instanceof Iterator) { if ($checkIsEmpty === false) { return true; } elseif ($value instanceof Countable) { return count($value) > 0; } else { $value->rewind(); return $value->valid(); } } elseif ($value instanceof ArrayAccess) { if ($checkIsEmpty === false) { return true; } elseif ($value instanceof Countable) { return count($value) > 0; } else { return $value->offsetExists(0); } } return false; } public function triggerError($message, $level=E_USER_NOTICE) { if (!($tplIdentifier = $this->template->getResourceIdentifier())) { $tplIdentifier = $this->template->getResourceName(); } trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level); } public function addStack($blockName, array $args=array()) { if (isset($this->plugins[$blockName])) { $class = $this->plugins[$blockName]['class']; } else { $class = 'Dwoo_Plugin_'.$blockName; } if ($this->curBlock !== null) { $this->curBlock->buffer(ob_get_contents()); ob_clean(); } else { $this->buffer .= ob_get_contents(); ob_clean(); } $block = new $class($this); $cnt = count($args); if ($cnt===0) { $block->init(); } elseif ($cnt===1) { $block->init($args[0]); } elseif ($cnt===2) { $block->init($args[0], $args[1]); } elseif ($cnt===3) { $block->init($args[0], $args[1], $args[2]); } elseif ($cnt===4) { $block->init($args[0], $args[1], $args[2], $args[3]); } else { call_user_func_array(array($block,'init'), $args); } $this->stack[] = $this->curBlock = $block; return $block; } public function delStack() { $args = func_get_args(); $this->curBlock->buffer(ob_get_contents()); ob_clean(); $cnt = count($args); if ($cnt===0) { $this->curBlock->end(); } elseif ($cnt===1) { $this->curBlock->end($args[0]); } elseif ($cnt===2) { $this->curBlock->end($args[0], $args[1]); } elseif ($cnt===3) { $this->curBlock->end($args[0], $args[1], $args[2]); } elseif ($cnt===4) { $this->curBlock->end($args[0], $args[1], $args[2], $args[3]); } else { call_user_func_array(array($this->curBlock, 'end'), $args); } $tmp = array_pop($this->stack); if (count($this->stack) > 0) { $this->curBlock = end($this->stack); $this->curBlock->buffer($tmp->process()); } else { $this->curBlock = null; echo $tmp->process(); } unset($tmp); } public function getParentBlock(Dwoo_Block_Plugin $block) { $index = array_search($block, $this->stack, true); if ($index !== false && $index > 0) { return $this->stack[$index-1]; } return false; } public function findBlock($type) { if (isset($this->plugins[$type])) { $type = $this->plugins[$type]['class']; } else { $type = 'Dwoo_Plugin_'.str_replace('Dwoo_Plugin_', '', $type); } $keys = array_keys($this->stack); while (($key = array_pop($keys)) !== false) { if ($this->stack[$key] instanceof $type) { return $this->stack[$key]; } } return false; } public function getObjectPlugin($class) { if (isset($this->runtimePlugins[$class])) { return $this->runtimePlugins[$class]; } return $this->runtimePlugins[$class] = new $class($this); } public function classCall($plugName, array $params = array()) { $class = 'Dwoo_Plugin_'.$plugName; $plugin = $this->getObjectPlugin($class); $cnt = count($params); if ($cnt===0) { return $plugin->process(); } elseif ($cnt===1) { return $plugin->process($params[0]); } elseif ($cnt===2) { return $plugin->process($params[0], $params[1]); } elseif ($cnt===3) { return $plugin->process($params[0], $params[1], $params[2]); } elseif ($cnt===4) { return $plugin->process($params[0], $params[1], $params[2], $params[3]); } else { return call_user_func_array(array($plugin, 'process'), $params); } } public function arrayMap($callback, array $params) { if ($params[0] === $this) { $addThis = true; array_shift($params); } if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) { if (empty($params[0])) { return $params[0]; } $out = array(); $cnt = count($params); if (isset($addThis)) { array_unshift($params, $this); $items = $params[1]; $keys = array_keys($items); if (is_string($callback) === false) { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params); } } elseif ($cnt===1) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($this, $items[$i]); } } elseif ($cnt===2) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($this, $items[$i], $params[2]); } } elseif ($cnt===3) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($this, $items[$i], $params[2], $params[3]); } } else { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params); } } } else { $items = $params[0]; $keys = array_keys($items); if (is_string($callback) === false) { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array($items[$i]) + $params); } } elseif ($cnt===1) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i]); } } elseif ($cnt===2) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i], $params[1]); } } elseif ($cnt===3) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i], $params[1], $params[2]); } } elseif ($cnt===4) { while (($i = array_shift($keys)) !== null) { $out[] = $callback($items[$i], $params[1], $params[2], $params[3]); } } else { while (($i = array_shift($keys)) !== null) { $out[] = call_user_func_array($callback, array($items[$i]) + $params); } } } return $out; } else { return $params[0]; } } public function readVarInto($varstr, $data, $safeRead = false) { if ($data === null) { return null; } if (is_array($varstr) === false) { preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m); } else { $m = $varstr; } unset($varstr); while (list($k, $sep) = each($m[1])) { if ($sep === '.' || $sep === '[' || $sep === '') { if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) { $data = $data[$m[2][$k]]; } else { return null; } } else { if (is_object($data) && ($safeRead === false || isset($data->$m[2][$k]) || is_callable(array($data, '__get')))) { $data = $data->$m[2][$k]; } else { return null; } } } return $data; } public function readParentVar($parentLevels, $varstr = null) { $tree = $this->scopeTree; $cur = $this->data; while ($parentLevels--!==0) { array_pop($tree); } while (($i = array_shift($tree)) !== null) { if (is_object($cur)) { $cur = $cur->$i; } else { $cur = $cur[$i]; } } if ($varstr!==null) { return $this->readVarInto($varstr, $cur); } else { return $cur; } } public function readVar($varstr) { if (is_array($varstr)===true) { $m = $varstr; unset($varstr); } else { if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) { if ($varstr === 'dwoo') { return $this->globals; } elseif ($varstr === '__' || $varstr === '_root' ) { return $this->data; $varstr = substr($varstr, 6); } elseif ($varstr === '_' || $varstr === '_parent') { $varstr = '.'.$varstr; $tree = $this->scopeTree; $cur = $this->data; array_pop($tree); while (($i = array_shift($tree)) !== null) { if (is_object($cur)) { $cur = $cur->$i; } else { $cur = $cur[$i]; } } return $cur; } $cur = $this->scope; if (isset($cur[$varstr])) { return $cur[$varstr]; } else { return null; } } if (substr($varstr, 0, 1) === '.') { $varstr = 'dwoo'.$varstr; } preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m); } $i = $m[2][0]; if ($i === 'dwoo') { $cur = $this->globals; array_shift($m[2]); array_shift($m[1]); switch ($m[2][0]) { case 'get': $cur = $_GET; break; case 'post': $cur = $_POST; break; case 'session': $cur = $_SESSION; break; case 'cookies': case 'cookie': $cur = $_COOKIE; break; case 'server': $cur = $_SERVER; break; case 'env': $cur = $_ENV; break; case 'request': $cur = $_REQUEST; break; case 'const': array_shift($m[2]); if (defined($m[2][0])) { return constant($m[2][0]); } else { return null; } } if ($cur !== $this->globals) { array_shift($m[2]); array_shift($m[1]); } } elseif ($i === '__' || $i === '_root') { $cur = $this->data; array_shift($m[2]); array_shift($m[1]); } elseif ($i === '_' || $i === '_parent') { $tree = $this->scopeTree; $cur = $this->data; while (true) { array_pop($tree); array_shift($m[2]); array_shift($m[1]); if (current($m[2]) === '_' || current($m[2]) === '_parent') { continue; } while (($i = array_shift($tree)) !== null) { if (is_object($cur)) { $cur = $cur->$i; } else { $cur = $cur[$i]; } } break; } } else { $cur = $this->scope; } while (list($k, $sep) = each($m[1])) { if ($sep === '.' || $sep === '[' || $sep === '') { if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) { $cur = $cur[$m[2][$k]]; } else { return null; } } elseif ($sep === '->') { if (is_object($cur)) { $cur = $cur->$m[2][$k]; } else { return null; } } else { return null; } } return $cur; } public function assignInScope($value, $scope) { $tree =& $this->scopeTree; $data =& $this->data; if (!is_string($scope)) { return $this->triggerError('Assignments must be done into strings, ('.gettype($scope).') '.var_export($scope, true).' given', E_USER_ERROR); } if (strstr($scope, '.') === false && strstr($scope, '->') === false) { $this->scope[$scope] = $value; } else { preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m); $cur =& $this->scope; $last = array(array_pop($m[1]), array_pop($m[2])); while (list($k, $sep) = each($m[1])) { if ($sep === '.' || $sep === '[' || $sep === '') { if (is_array($cur) === false) { $cur = array(); } $cur =& $cur[$m[2][$k]]; } elseif ($sep === '->') { if (is_object($cur) === false) { $cur = new stdClass; } $cur =& $cur->$m[2][$k]; } else { return false; } } if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') { if (is_array($cur) === false) { $cur = array(); } $cur[$last[1]] = $value; } elseif ($last[0] === '->') { if (is_object($cur) === false) { $cur = new stdClass; } $cur->$last[1] = $value; } else { return false; } } } public function setScope($scope, $absolute = false) { $old = $this->scopeTree; if (is_string($scope)===true) { $scope = explode('.', $scope); } if ($absolute===true) { $this->scope =& $this->data; $this->scopeTree = array(); } while (($bit = array_shift($scope)) !== null) { if ($bit === '_' || $bit === '_parent') { array_pop($this->scopeTree); $this->scope =& $this->data; $cnt = count($this->scopeTree); for ($i=0;$i<$cnt;$i++) $this->scope =& $this->scope[$this->scopeTree[$i]]; } elseif ($bit === '__' || $bit === '_root') { $this->scope =& $this->data; $this->scopeTree = array(); } elseif (isset($this->scope[$bit])) { $this->scope =& $this->scope[$bit]; $this->scopeTree[] = $bit; } else { unset($this->scope); $this->scope = null; } } return $old; } public function getData() { return $this->data; } public function &getScope() { return $this->scope; } public function __call($method, $args) { $proxy = $this->getPluginProxy(); if (!$proxy) { throw new Dwoo_Exception('Call to undefined method '.__CLASS__.'::'.$method.'()'); } return call_user_func_array($proxy->getCallback($method), $args); } } interface Dwoo_IPluginProxy { public function handles($name); public function getCode($name, $params); public function getCallback($name); public function getLoader($name); } interface Dwoo_IElseable { } interface Dwoo_ILoader { public function loadPlugin($class, $forceRehash = true); } class Dwoo_Loader implements Dwoo_ILoader { protected $paths = array(); protected $classPath = array(); protected $cacheDir; protected $corePluginDir; public function __construct($cacheDir) { $this->corePluginDir = DWOO_DIRECTORY . 'plugins'; $this->cacheDir = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $cacheFile = $this->cacheDir.'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'; if (file_exists($cacheFile)) { $classpath = file_get_contents($cacheFile); $this->classPath = unserialize($classpath) + $this->classPath; } else { $this->rebuildClassPathCache($this->corePluginDir, $cacheFile); } } protected function rebuildClassPathCache($path, $cacheFile) { if ($cacheFile!==false) { $tmp = $this->classPath; $this->classPath = array(); } $list = glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*'); if (is_array($list)) { foreach ($list as $f) { if (is_dir($f)) { $this->rebuildClassPathCache($f, false); } else { $this->classPath[str_replace(array('function.','block.','modifier.','outputfilter.','filter.','prefilter.','postfilter.','pre.','post.','output.','shared.','helper.'), '', basename($f, '.php'))] = $f; } } } if ($cacheFile!==false) { if (!file_put_contents($cacheFile, serialize($this->classPath))) { throw new Dwoo_Exception('Could not write into '.$cacheFile.', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()'); } $this->classPath += $tmp; } } public function loadPlugin($class, $forceRehash = true) { if (!isset($this->classPath[$class]) || !(include $this->classPath[$class])) { if ($forceRehash) { $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'); foreach ($this->paths as $path=>$file) { $this->rebuildClassPathCache($path, $file); } if (isset($this->classPath[$class])) { include $this->classPath[$class]; } else { throw new Dwoo_Exception('Plugin '.$class.' can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE); } } else { throw new Dwoo_Exception('Plugin '.$class.' can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE); } } } public function addDirectory($pluginDirectory) { $pluginDir = realpath($pluginDirectory); if (!$pluginDir) { throw new Dwoo_Exception('Plugin directory does not exist or can not be read : '.$pluginDirectory); } $cacheFile = $this->cacheDir . 'classpath-'.substr(strtr($pluginDir, '/\\:'.PATH_SEPARATOR, '----'), strlen($pluginDir) > 80 ? -80 : 0).'.d'.Dwoo::RELEASE_TAG.'.php'; $this->paths[$pluginDir] = $cacheFile; if (file_exists($cacheFile)) { $classpath = file_get_contents($cacheFile); $this->classPath = unserialize($classpath) + $this->classPath; } else { $this->rebuildClassPathCache($pluginDir, $cacheFile); } } } class Dwoo_Exception extends Exception { } class Dwoo_Security_Policy { const PHP_ENCODE = 1; const PHP_REMOVE = 2; const PHP_ALLOW = 3; const CONST_DISALLOW = false; const CONST_ALLOW = true; protected $allowedPhpFunctions = array ( 'str_repeat', 'number_format', 'htmlentities', 'htmlspecialchars', 'long2ip', 'strlen', 'list', 'empty', 'count', 'sizeof', 'in_array', 'is_array', ); protected $allowedDirectories = array(); protected $phpHandling = self::PHP_REMOVE; protected $constHandling = self::CONST_DISALLOW; public function allowPhpFunction($func) { if (is_array($func)) foreach ($func as $fname) $this->allowedPhpFunctions[strtolower($fname)] = true; else $this->allowedPhpFunctions[strtolower($func)] = true; } public function disallowPhpFunction($func) { if (is_array($func)) foreach ($func as $fname) unset($this->allowedPhpFunctions[strtolower($fname)]); else unset($this->allowedPhpFunctions[strtolower($func)]); } public function getAllowedPhpFunctions() { return $this->allowedPhpFunctions; } public function allowDirectory($path) { if (is_array($path)) foreach ($path as $dir) $this->allowedDirectories[realpath($dir)] = true; else $this->allowedDirectories[realpath($path)] = true; } public function disallowDirectory($path) { if (is_array($path)) foreach ($path as $dir) unset($this->allowedDirectories[realpath($dir)]); else unset($this->allowedDirectories[realpath($path)]); } public function getAllowedDirectories() { return $this->allowedDirectories; } public function setPhpHandling($level = self::PHP_REMOVE) { $this->phpHandling = $level; } public function getPhpHandling() { return $this->phpHandling; } public function setConstantHandling($level = self::CONST_DISALLOW) { $this->constHandling = $level; } public function getConstantHandling() { return $this->constHandling; } } class Dwoo_Security_Exception extends Dwoo_Exception { } interface Dwoo_ICompilable { } interface Dwoo_ICompiler { public function compile(Dwoo $dwoo, Dwoo_ITemplate $template); public function setCustomPlugins(array $customPlugins); public function setSecurityPolicy(Dwoo_Security_Policy $policy = null); } interface Dwoo_IDataProvider { public function getData(); } interface Dwoo_ITemplate { public function getCacheTime(); public function setCacheTime($seconds = null); public function getCachedTemplate(Dwoo $dwoo); public function cache(Dwoo $dwoo, $output); public function clearCache(Dwoo $dwoo, $olderThan = -1); public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null); public function getName(); public function getResourceName(); public function getResourceIdentifier(); public function getSource(); public function getUid(); public function getCompiler(); public function getIsModifiedCode(); public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null); } interface Dwoo_ICompilable_Block { } abstract class Dwoo_Plugin { protected $dwoo; public function __construct(Dwoo $dwoo) { $this->dwoo = $dwoo; } public static function paramsToAttributes(array $params, $delim = '\'') { if (isset($params['*'])) { $params = array_merge($params, $params['*']); unset($params['*']); } $out = ''; foreach ($params as $attr=>$val) { $out .= ' '.$attr.'='; if (trim($val, '"\'')=='' || $val=='null') { $out .= str_replace($delim, '\\'.$delim, '""'); } elseif (substr($val, 0, 1) === $delim && substr($val, -1) === $delim) { $out .= str_replace($delim, '\\'.$delim, '"'.substr($val, 1, -1).'"'); } else { $out .= str_replace($delim, '\\'.$delim, '"') . $delim . '.'.$val.'.' . $delim . str_replace($delim, '\\'.$delim, '"'); } } return ltrim($out); } } abstract class Dwoo_Block_Plugin extends Dwoo_Plugin { protected $buffer = ''; public function buffer($input) { $this->buffer .= $input; } public function end() { } public function process() { return $this->buffer; } public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) { return Dwoo_Compiler::PHP_OPEN.$prepend.'$this->addStack("'.$type.'", array('.Dwoo_Compiler::implode_r($compiler->getCompiledParams($params)).'));'.$append.Dwoo_Compiler::PHP_CLOSE; } public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) { return $content . Dwoo_Compiler::PHP_OPEN.$prepend.'$this->delStack();'.$append.Dwoo_Compiler::PHP_CLOSE; } } abstract class Dwoo_Filter { protected $dwoo; public function __construct(Dwoo $dwoo) { $this->dwoo = $dwoo; } abstract public function process($input); } abstract class Dwoo_Processor { protected $compiler; public function __construct(Dwoo_Compiler $compiler) { $this->compiler = $compiler; } abstract public function process($input); } class Dwoo_Template_String implements Dwoo_ITemplate { protected $name; protected $compileId; protected $cacheId; protected $cacheTime; protected $compilationEnforced; protected static $cache = array('cached'=>array(), 'compiled'=>array()); protected $compiler; protected $chmod = 0777; public function __construct($templateString, $cacheTime = null, $cacheId = null, $compileId = null) { $this->template = $templateString; if (function_exists('hash')) { $this->name = hash('md4', $templateString); } else { $this->name = md5($templateString); } $this->cacheTime = $cacheTime; if ($compileId !== null) { $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } if ($cacheId !== null) { $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } } public function getCacheTime() { return $this->cacheTime; } public function setCacheTime($seconds = null) { $this->cacheTime = $seconds; } public function getChmod() { return $this->chmod; } public function setChmod($mask = null) { $this->chmod = $mask; } public function getName() { return $this->name; } public function getResourceName() { return 'string'; } public function getResourceIdentifier() { return false; } public function getSource() { return $this->template; } public function getUid() { return $this->name; } public function getCompiler() { return $this->compiler; } public function forceCompilation() { $this->compilationEnforced = true; } public function getCachedTemplate(Dwoo $dwoo) { if ($this->cacheTime !== null) { $cacheLength = $this->cacheTime; } else { $cacheLength = $dwoo->getCacheTime(); } if ($cacheLength === 0) { return false; } $cachedFile = $this->getCacheFilename($dwoo); if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) { return $cachedFile; } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === -1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($dwoo))) { self::$cache['cached'][$this->cacheId] = true; return $cachedFile; } else { return true; } } public function cache(Dwoo $dwoo, $output) { $cacheDir = $dwoo->getCacheDir(); $cachedFile = $this->getCacheFilename($dwoo); $temp = tempnam($cacheDir, 'temp'); if (!($file = @fopen($temp, 'wb'))) { $temp = $cacheDir . uniqid('temp'); if (!($file = @fopen($temp, 'wb'))) { trigger_error('Error writing temporary file \''.$temp.'\'', E_USER_WARNING); return false; } } fwrite($file, $output); fclose($file); $this->makeDirectory(dirname($cachedFile), $cacheDir); if (!@rename($temp, $cachedFile)) { @unlink($cachedFile); @rename($temp, $cachedFile); } if ($this->chmod !== null) { chmod($cachedFile, $this->chmod); } self::$cache['cached'][$this->cacheId] = true; return $cachedFile; } public function clearCache(Dwoo $dwoo, $olderThan = -1) { $cachedFile = $this->getCacheFilename($dwoo); return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile)); } public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null) { $compiledFile = $this->getCompiledFilename($dwoo); if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) { } elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) { self::$cache['compiled'][$this->compileId] = true; } else { $this->compilationEnforced = false; if ($compiler === null) { $compiler = $dwoo->getDefaultCompilerFactory($this->getResourceName()); if ($compiler === null || $compiler === array('Dwoo_Compiler', 'compilerFactory')) { if (class_exists('Dwoo_Compiler', false) === false) { include DWOO_DIRECTORY . 'Dwoo/Compiler.php'; } $compiler = Dwoo_Compiler::compilerFactory(); } else { $compiler = call_user_func($compiler); } } $this->compiler = $compiler; $compiler->setCustomPlugins($dwoo->getCustomPlugins()); $compiler->setSecurityPolicy($dwoo->getSecurityPolicy()); $this->makeDirectory(dirname($compiledFile), $dwoo->getCompileDir()); file_put_contents($compiledFile, $compiler->compile($dwoo, $this)); if ($this->chmod !== null) { chmod($compiledFile, $this->chmod); } self::$cache['compiled'][$this->compileId] = true; } return $compiledFile; } protected function isValidCompiledFile($file) { return file_exists($file); } public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) { return new self($resourceId, $cacheTime, $cacheId, $compileId); } protected function getCompiledFilename(Dwoo $dwoo) { if ($this->compileId===null) { $this->compileId = $this->name; } return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php'; } protected function getCacheFilename(Dwoo $dwoo) { if ($this->cacheId === null) { if (isset($_SERVER['REQUEST_URI']) === true) { $cacheId = $_SERVER['REQUEST_URI']; } elseif (isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['argv'])) { $cacheId = $_SERVER['SCRIPT_FILENAME'].'-'.implode('-', $_SERVER['argv']); } else { $cacheId = ''; } $this->getCompiledFilename($dwoo); $this->cacheId = str_replace('../', '__', $this->compileId . strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } return $dwoo->getCacheDir() . $this->cacheId.'.html'; } public function getIsModifiedCode() { return null; } protected function makeDirectory($path, $baseDir = null) { if (is_dir($path) === true) { return; } if ($this->chmod === null) { $chmod = 0777; } else { $chmod = $this->chmod; } mkdir($path, $chmod, true); if (strpos(PHP_OS, 'WIN') !== 0 && $baseDir !== null) { $path = strtr(str_replace($baseDir, '', $path), '\\', '/'); $folders = explode('/', trim($path, '/')); foreach ($folders as $folder) { $baseDir .= $folder . DIRECTORY_SEPARATOR; chmod($baseDir, $chmod); } } } } class Dwoo_Template_File extends Dwoo_Template_String { protected $file; protected $includePath = null; protected $resolvedPath = null; public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = null) { $this->file = $file; $this->name = basename($file); $this->cacheTime = $cacheTime; if ($compileId !== null) { $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } if ($cacheId !== null) { $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); } if (is_string($includePath)) { $this->includePath = array($includePath); } elseif (is_array($includePath)) { $this->includePath = $includePath; } } public function setIncludePath($paths) { if (is_array($paths) === false) { $paths = array($paths); } $this->includePath = $paths; $this->resolvedPath = null; } public function getIncludePath() { return $this->includePath; } protected function isValidCompiledFile($file) { return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file); } public function getSource() { return file_get_contents($this->getResourceIdentifier()); } public function getResourceName() { return 'file'; } public function getResourceIdentifier() { if ($this->resolvedPath !== null) { return $this->resolvedPath; } elseif ($this->includePath === null) { return $this->file; } else { foreach ($this->includePath as $path) { $path = rtrim($path, DIRECTORY_SEPARATOR); if (file_exists($path.DIRECTORY_SEPARATOR.$this->file) === true) { $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file; return $this->resolvedPath; } } throw new Dwoo_Exception('Template "'.$this->file.'" could not be found in any of your include path(s)'); } } public function getUid() { return (string) filemtime($this->getResourceIdentifier()); } public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) { if (DIRECTORY_SEPARATOR === '\\') { $resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array('\\t', '\\n', '\\r', '\\f', '\\v'), $resourceId); } $resourceId = strtr($resourceId, '\\', '/'); $includePath = null; if (file_exists($resourceId) === false) { if ($parentTemplate === null) { $parentTemplate = $dwoo->getTemplate(); } if ($parentTemplate instanceof Dwoo_Template_File) { if ($includePath = $parentTemplate->getIncludePath()) { if (strstr($resourceId, '../')) { throw new Dwoo_Exception('When using an include path you can not reference a template into a parent directory (using ../)'); } } else { $resourceId = dirname($parentTemplate->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId; if (file_exists($resourceId) === false) { return null; } } } else { return null; } } if ($policy = $dwoo->getSecurityPolicy()) { while (true) { if (preg_match('{^([a-z]+?)://}i', $resourceId)) { throw new Dwoo_Security_Exception('The security policy prevents you to read files from external sources : '.$resourceId.'.'); } if ($includePath) { break; } $resourceId = realpath($resourceId); $dirs = $policy->getAllowedDirectories(); foreach ($dirs as $dir=>$dummy) { if (strpos($resourceId, $dir) === 0) { break 2; } } throw new Dwoo_Security_Exception('The security policy prevents you to read '.$resourceId.''); } } $class = 'Dwoo_Template_File'; if ($parentTemplate) { $class = get_class($parentTemplate); } return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath); } protected function getCompiledFilename(Dwoo $dwoo) { if ($this->compileId===null) { $this->compileId = str_replace('../', '__', strtr($this->getResourceIdentifier(), '\\:', '/-')); } return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php'; } public function getIsModifiedCode() { return '"'.$this->getUid().'" == filemtime('.var_export($this->getResourceIdentifier(), true).')'; } } class Dwoo_Data implements Dwoo_IDataProvider { protected $data = array(); public function getData() { return $this->data; } public function clear($name = null) { if ($name === null) { $this->data = array(); } elseif (is_array($name)) { foreach ($name as $index) unset($this->data[$index]); } else { unset($this->data[$name]); } } public function setData(array $data) { $this->data = $data; } public function mergeData(array $data) { $args = func_get_args(); while (list(,$v) = each($args)) { if (is_array($v)) { $this->data = array_merge($this->data, $v); } } } public function assign($name, $val = null) { if (is_array($name)) { reset($name); while (list($k,$v) = each($name)) $this->data[$k] = $v; } else { $this->data[$name] = $val; } } public function __set($name, $value) { $this->assign($name, $value); } public function assignByRef($name, &$val) { $this->data[$name] =& $val; } public function append($name, $val = null, $merge = false) { if (is_array($name)) { foreach ($name as $key=>$val) { if (isset($this->data[$key]) && !is_array($this->data[$key])) { settype($this->data[$key], 'array'); } if ($merge === true && is_array($val)) { $this->data[$key] = $val + $this->data[$key]; } else { $this->data[$key][] = $val; } } } elseif ($val !== null) { if (isset($this->data[$name]) && !is_array($this->data[$name])) { settype($this->data[$name], 'array'); } elseif (!isset($this->data[$name])) { $this->data[$name] = array(); } if ($merge === true && is_array($val)) { $this->data[$name] = $val + $this->data[$name]; } else { $this->data[$name][] = $val; } } } public function appendByRef($name, &$val, $merge = false) { if (isset($this->data[$name]) && !is_array($this->data[$name])) { settype($this->data[$name], 'array'); } if ($merge === true && is_array($val)) { foreach ($val as $key => &$val) { $this->data[$name][$key] =& $val; } } else { $this->data[$name][] =& $val; } } public function isAssigned($name) { return isset($this->data[$name]); } public function __isset($name) { return isset($this->data[$name]); } public function unassign($name) { unset($this->data[$name]); } public function __unset($name) { unset($this->data[$name]); } public function get($name) { return $this->__get($name); } public function __get($name) { if (isset($this->data[$name])) { return $this->data[$name]; } else { throw new Dwoo_Exception('Tried to read a value that was not assigned yet : "'.$name.'"'); } } } \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo.php b/system/libs/dwoo/Dwoo.php new file mode 100644 index 00000000..52573651 --- /dev/null +++ b/system/libs/dwoo/Dwoo.php @@ -0,0 +1,1533 @@ + + * requirements : + * php 5.2.0 or above (might work below, it's a rough estimate) + * SPL and PCRE extensions (for php versions prior to 5.3.0) + * mbstring extension for some string manipulation plugins (especially if you intend to use UTF-8) + * recommended : + * hash extension (for Dwoo_Template_String - minor performance boost) + * + * project created : + * 2008-01-05 + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo +{ + /** + * current version number + * + * @var string + */ + const VERSION = '1.1.1'; + + /** + * unique number of this dwoo release + * + * this can be used by templates classes to check whether the compiled template + * has been compiled before this release or not, so that old templates are + * recompiled automatically when Dwoo is updated + */ + const RELEASE_TAG = 17; + + /**#@+ + * constants that represents all plugin types + * + * these are bitwise-operation-safe values to allow multiple types + * on a single plugin + * + * @var int + */ + const CLASS_PLUGIN = 1; + const FUNC_PLUGIN = 2; + const NATIVE_PLUGIN = 4; + const BLOCK_PLUGIN = 8; + const COMPILABLE_PLUGIN = 16; + const CUSTOM_PLUGIN = 32; + const SMARTY_MODIFIER = 64; + const SMARTY_BLOCK = 128; + const SMARTY_FUNCTION = 256; + const PROXY_PLUGIN = 512; + const TEMPLATE_PLUGIN = 1024; + /**#@-*/ + + /** + * character set of the template, used by string manipulation plugins + * + * it must be lowercase, but setCharset() will take care of that + * + * @see setCharset + * @see getCharset + * @var string + */ + protected $charset = 'utf-8'; + + /** + * global variables that are accessible through $dwoo.* in the templates + * + * default values include: + * + * $dwoo.version - current version number + * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org + * $dwoo.now - the current time + * $dwoo.template - the current template filename + * $dwoo.charset - the character set used by the template + * + * on top of that, foreach and other plugins can store special values in there, + * see their documentation for more details. + * + * @private + * @var array + */ + public $globals; + + /** + * directory where the compiled templates are stored + * + * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default) + * + * @var string + */ + protected $compileDir; + + /** + * directory where the cached templates are stored + * + * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default) + * + * @var string + */ + protected $cacheDir; + + /** + * defines how long (in seconds) the cached files must remain valid + * + * can be overriden on a per-template basis + * + * -1 = never delete + * 0 = disabled + * >0 = duration in seconds + * + * @var int + */ + protected $cacheTime = 0; + + /** + * security policy object + * + * @var Dwoo_Security_Policy + */ + protected $securityPolicy = null; + + /** + * stores the custom plugins callbacks + * + * @see addPlugin + * @see removePlugin + * @var array + */ + protected $plugins = array(); + + /** + * stores the filter callbacks + * + * @see addFilter + * @see removeFilter + * @var array + */ + protected $filters = array(); + + /** + * stores the resource types and associated + * classes / compiler classes + * + * @var array + */ + protected $resources = array + ( + 'file' => array + ( + 'class' => 'Dwoo_Template_File', + 'compiler' => null + ), + 'string' => array + ( + 'class' => 'Dwoo_Template_String', + 'compiler' => null + ) + ); + + /** + * the dwoo loader object used to load plugins by this dwoo instance + * + * @var Dwoo_ILoader + */ + protected $loader = null; + + /** + * currently rendered template, set to null when not-rendering + * + * @var Dwoo_ITemplate + */ + protected $template = null; + + /** + * stores the instances of the class plugins during template runtime + * + * @var array + */ + protected $runtimePlugins; + + /** + * stores the data during template runtime + * + * @var array + * @private + */ + public $data; + + /** + * stores the current scope during template runtime + * + * this should ideally not be accessed directly from outside template code + * + * @var mixed + * @private + */ + public $scope; + + /** + * stores the scope tree during template runtime + * + * @var array + */ + protected $scopeTree; + + /** + * stores the block plugins stack during template runtime + * + * @var array + */ + protected $stack; + + /** + * stores the current block plugin at the top of the stack during template runtime + * + * @var Dwoo_Block_Plugin + */ + protected $curBlock; + + /** + * stores the output buffer during template runtime + * + * @var string + */ + protected $buffer; + + /** + * stores plugin proxy + * + * @var Dwoo_IPluginProxy + */ + protected $pluginProxy; + + /** + * constructor, sets the cache and compile dir to the default values if not provided + * + * @param string $compileDir path to the compiled directory, defaults to lib/compiled + * @param string $cacheDir path to the cache directory, defaults to lib/cache + */ + public function __construct($compileDir = null, $cacheDir = null) + { + if ($compileDir !== null) { + $this->setCompileDir($compileDir); + } + if ($cacheDir !== null) { + $this->setCacheDir($cacheDir); + } + $this->initGlobals(); + } + + /** + * resets some runtime variables to allow a cloned object to be used to render sub-templates + */ + public function __clone() + { + $this->template = null; + unset($this->data); + } + + /** + * outputs the template instead of returning it, this is basically a shortcut for get(*, *, *, true) + * + * @see get + * @param mixed $tpl template, can either be a Dwoo_ITemplate object (i.e. Dwoo_Template_File), a valid path to a template, or + * a template as a string it is recommended to provide a Dwoo_ITemplate as it will probably make things faster, + * especially if you render a template multiple times + * @param mixed $data the data to use, can either be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array. if you're + * rendering the template from cache, it can be left null + * @param Dwoo_ICompiler $compiler the compiler that must be used to compile the template, if left empty a default + * Dwoo_Compiler will be used. + * @return string nothing or the template output if $output is true + */ + public function output($tpl, $data = array(), Dwoo_ICompiler $compiler = null) + { + return $this->get($tpl, $data, $compiler, true); + } + + /** + * returns the given template rendered using the provided data and optional compiler + * + * @param mixed $tpl template, can either be a Dwoo_ITemplate object (i.e. Dwoo_Template_File), a valid path to a template, or + * a template as a string it is recommended to provide a Dwoo_ITemplate as it will probably make things faster, + * especially if you render a template multiple times + * @param mixed $data the data to use, can either be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array. if you're + * rendering the template from cache, it can be left null + * @param Dwoo_ICompiler $compiler the compiler that must be used to compile the template, if left empty a default + * Dwoo_Compiler will be used. + * @param bool $output flag that defines whether the function returns the output of the template (false, default) or echoes it directly (true) + * @return string nothing or the template output if $output is true + */ + public function get($_tpl, $data = array(), $_compiler = null, $_output = false) + { + // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one + if ($this->template instanceof Dwoo_ITemplate) { + $proxy = clone $this; + return $proxy->get($_tpl, $data, $_compiler, $_output); + } + + // auto-create template if required + if ($_tpl instanceof Dwoo_ITemplate) { + // valid, skip + } elseif (is_string($_tpl) && file_exists($_tpl)) { + $_tpl = new Dwoo_Template_File($_tpl); + } else { + throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file', E_USER_NOTICE); + } + + // save the current template, enters render mode at the same time + // if another rendering is requested it will be proxied to a new Dwoo instance + $this->template = $_tpl; + + // load data + if ($data instanceof Dwoo_IDataProvider) { + $this->data = $data->getData(); + } elseif (is_array($data)) { + $this->data = $data; + } else { + throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s data argument must be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array', E_USER_NOTICE); + } + + $this->globals['template'] = $_tpl->getName(); + $this->initRuntimeVars($_tpl); + + // try to get cached template + $file = $_tpl->getCachedTemplate($this); + $doCache = $file === true; + $cacheLoaded = is_string($file); + + if ($cacheLoaded === true) { + // cache is present, run it + if ($_output === true) { + include $file; + $this->template = null; + } else { + ob_start(); + include $file; + $this->template = null; + return ob_get_clean(); + } + } else { + // no cache present + if ($doCache === true) { + $dynamicId = uniqid(); + } + + // render template + $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler); + $out = include $compiledTemplate; + + // template returned false so it needs to be recompiled + if ($out === false) { + $_tpl->forceCompilation(); + $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler); + $out = include $compiledTemplate; + } + + if ($doCache === true) { + $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '', $out); + if (!class_exists('Dwoo_plugin_dynamic', false)) { + $this->getLoader()->loadPlugin('dynamic'); + } + $out = Dwoo_Plugin_dynamic::unescape($out, $dynamicId, $compiledTemplate); + } + + // process filters + foreach ($this->filters as $filter) { + if (is_array($filter) && $filter[0] instanceof Dwoo_Filter) { + $out = call_user_func($filter, $out); + } else { + $out = call_user_func($filter, $this, $out); + } + } + + if ($doCache === true) { + // building cache + $file = $_tpl->cache($this, $out); + + // run it from the cache to be sure dynamics are rendered + if ($_output === true) { + include $file; + // exit render mode + $this->template = null; + } else { + ob_start(); + include $file; + // exit render mode + $this->template = null; + return ob_get_clean(); + } + } else { + // no need to build cache + // exit render mode + $this->template = null; + // output + if ($_output === true) { + echo $out; + } + return $out; + } + } + } + + /** + * re-initializes the globals array before each template run + * + * this method is only callede once when the Dwoo object is created + */ + protected function initGlobals() + { + $this->globals = array + ( + 'version' => self::VERSION, + 'ad' => 'Powered by Dwoo', + 'now' => $_SERVER['REQUEST_TIME'], + 'charset' => $this->charset, + ); + } + + /** + * re-initializes the runtime variables before each template run + * + * override this method to inject data in the globals array if needed, this + * method is called before each template execution + * + * @param Dwoo_ITemplate $tpl the template that is going to be rendered + */ + protected function initRuntimeVars(Dwoo_ITemplate $tpl) + { + $this->runtimePlugins = array(); + $this->scope =& $this->data; + $this->scopeTree = array(); + $this->stack = array(); + $this->curBlock = null; + $this->buffer = ''; + } + + /* + * --------- settings functions --------- + */ + + /** + * adds a custom plugin that is not in one of the plugin directories + * + * @param string $name the plugin name to be used in the templates + * @param callback $callback the plugin callback, either a function name, + * a class name or an array containing an object + * or class name and a method name + * @param bool $compilable if set to true, the plugin is assumed to be compilable + */ + public function addPlugin($name, $callback, $compilable = false) + { + $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0; + if (is_array($callback)) { + if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo_Block_Plugin')) { + $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0])); + } else { + $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>(is_object($callback[0]) ? get_class($callback[0]) : $callback[0]), 'function'=>$callback[1]); + } + } elseif (class_exists($callback, false)) { + if (is_subclass_of($callback, 'Dwoo_Block_Plugin')) { + $this->plugins[$name] = array('type'=>self::BLOCK_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback); + } else { + $this->plugins[$name] = array('type'=>self::CLASS_PLUGIN | $compilable, 'callback'=>$callback, 'class'=>$callback, 'function'=>'process'); + } + } elseif (function_exists($callback)) { + $this->plugins[$name] = array('type'=>self::FUNC_PLUGIN | $compilable, 'callback'=>$callback); + } else { + throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists'); + } + } + + /** + * removes a custom plugin + * + * @param string $name the plugin name + */ + public function removePlugin($name) + { + if (isset($this->plugins[$name])) { + unset($this->plugins[$name]); + } + } + + /** + * adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this instance + * + * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory + * @param bool $autoload if true, the first parameter must be a filter name from one of the plugin directories + */ + public function addFilter($callback, $autoload = false) + { + if ($autoload) { + $class = 'Dwoo_Filter_'.$callback; + + if (!class_exists($class, false) && !function_exists($class)) { + try { + $this->getLoader()->loadPlugin($callback); + } catch (Dwoo_Exception $e) { + if (strstr($callback, 'Dwoo_Filter_')) { + throw new Dwoo_Exception('Wrong filter name : '.$callback.', the "Dwoo_Filter_" prefix should not be used, please only use "'.str_replace('Dwoo_Filter_', '', $callback).'"'); + } else { + throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"'); + } + } + } + + if (class_exists($class, false)) { + $callback = array(new $class($this), 'process'); + } elseif (function_exists($class)) { + $callback = $class; + } else { + throw new Dwoo_Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"'); + } + + $this->filters[] = $callback; + } else { + $this->filters[] = $callback; + } + } + + /** + * removes a filter + * + * @param mixed $callback callback or filter name if it was autoloaded + */ + public function removeFilter($callback) + { + if (($index = array_search('Dwoo_Filter_'.$callback, $this->filters, true)) !== false) { + unset($this->filters[$index]); + } elseif (($index = array_search($callback, $this->filters, true)) !== false) { + unset($this->filters[$index]); + } else { + $class = 'Dwoo_Filter_' . $callback; + foreach ($this->filters as $index=>$filter) { + if (is_array($filter) && $filter[0] instanceof $class) { + unset($this->filters[$index]); + break; + } + } + } + } + + /** + * adds a resource or overrides a default one + * + * @param string $name the resource name + * @param string $class the resource class (which must implement Dwoo_ITemplate) + * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance used to compile this resource, if none is provided. by default it will produce a Dwoo_Compiler object + */ + public function addResource($name, $class, $compilerFactory = null) + { + if (strlen($name) < 2) { + throw new Dwoo_Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths'); + } + + if (!class_exists($class)) { + throw new Dwoo_Exception('Resource class does not exist'); + } + + $interfaces = class_implements($class); + if (in_array('Dwoo_ITemplate', $interfaces) === false) { + throw new Dwoo_Exception('Resource class must implement Dwoo_ITemplate'); + } + + $this->resources[$name] = array('class'=>$class, 'compiler'=>$compilerFactory); + } + + /** + * removes a custom resource + * + * @param string $name the resource name + */ + public function removeResource($name) + { + unset($this->resources[$name]); + if ($name==='file') { + $this->resources['file'] = array('class'=>'Dwoo_Template_File', 'compiler'=>null); + } + } + + /* + * --------- getters and setters --------- + */ + + /** + * sets the loader object to use to load plugins + * + * @param Dwoo_ILoader $loader loader object + */ + public function setLoader(Dwoo_ILoader $loader) + { + $this->loader = $loader; + } + + /** + * returns the current loader object or a default one if none is currently found + * + * @param Dwoo_ILoader + */ + public function getLoader() + { + if ($this->loader === null) { + $this->loader = new Dwoo_Loader($this->getCompileDir()); + } + + return $this->loader; + } + + /** + * returns the custom plugins loaded + * + * used by the Dwoo_ITemplate classes to pass the custom plugins to their Dwoo_ICompiler instance + * + * @return array + */ + public function getCustomPlugins() + { + return $this->plugins; + } + + /** + * returns the cache directory with a trailing DIRECTORY_SEPARATOR + * + * @return string + */ + public function getCacheDir() + { + if ($this->cacheDir === null) { + $this->setCacheDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR); + } + + return $this->cacheDir; + } + + /** + * sets the cache directory and automatically appends a DIRECTORY_SEPARATOR + * + * @param string $dir the cache directory + */ + public function setCacheDir($dir) + { + $this->cacheDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR; + if (is_writable($this->cacheDir) === false) { + throw new Dwoo_Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable'); + } + } + + /** + * returns the compile directory with a trailing DIRECTORY_SEPARATOR + * + * @return string + */ + public function getCompileDir() + { + if ($this->compileDir === null) { + $this->setCompileDir(dirname(__FILE__).DIRECTORY_SEPARATOR.'compiled'.DIRECTORY_SEPARATOR); + } + + return $this->compileDir; + } + + /** + * sets the compile directory and automatically appends a DIRECTORY_SEPARATOR + * + * @param string $dir the compile directory + */ + public function setCompileDir($dir) + { + $this->compileDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR; + if (is_writable($this->compileDir) === false) { + throw new Dwoo_Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable'); + } + } + + /** + * returns the default cache time that is used with templates that do not have a cache time set + * + * @return int the duration in seconds + */ + public function getCacheTime() + { + return $this->cacheTime; + } + + /** + * sets the default cache time to use with templates that do not have a cache time set + * + * @param int $seconds the duration in seconds + */ + public function setCacheTime($seconds) + { + $this->cacheTime = (int) $seconds; + } + + /** + * returns the character set used by the string manipulation plugins + * + * the charset is automatically lowercased + * + * @return string + */ + public function getCharset() + { + return $this->charset; + } + + /** + * sets the character set used by the string manipulation plugins + * + * the charset will be automatically lowercased + * + * @param string $charset the character set + */ + public function setCharset($charset) + { + $this->charset = strtolower((string) $charset); + } + + /** + * returns the current template being rendered, when applicable, or null + * + * @return Dwoo_ITemplate|null + */ + public function getTemplate() + { + return $this->template; + } + + /** + * sets the current template being rendered + * + * @param Dwoo_ITemplate $tpl template object + */ + public function setTemplate(Dwoo_ITemplate $tpl) + { + $this->template = $tpl; + } + + /** + * sets the default compiler factory function for the given resource name + * + * a compiler factory must return a Dwoo_ICompiler object pre-configured to fit your needs + * + * @param string $resourceName the resource name (i.e. file, string) + * @param callback $compilerFactory the compiler factory callback + */ + public function setDefaultCompilerFactory($resourceName, $compilerFactory) + { + $this->resources[$resourceName]['compiler'] = $compilerFactory; + } + + /** + * returns the default compiler factory function for the given resource name + * + * @param string $resourceName the resource name + * @return callback the compiler factory callback + */ + public function getDefaultCompilerFactory($resourceName) + { + return $this->resources[$resourceName]['compiler']; + } + + /** + * sets the security policy object to enforce some php security settings + * + * use this if untrusted persons can modify templates + * + * @param Dwoo_Security_Policy $policy the security policy object + */ + public function setSecurityPolicy(Dwoo_Security_Policy $policy = null) + { + $this->securityPolicy = $policy; + } + + /** + * returns the current security policy object or null by default + * + * @return Dwoo_Security_Policy|null the security policy object if any + */ + public function getSecurityPolicy() + { + return $this->securityPolicy; + } + + /** + * sets the object that must be used as a plugin proxy when plugin can't be found + * by dwoo's loader + * + * @param Dwoo_IPluginProxy $pluginProxy the proxy object + */ + public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy) { + $this->pluginProxy = $pluginProxy; + } + + /** + * returns the current plugin proxy object or null by default + * + * @param Dwoo_IPluginProxy|null the proxy object if any + */ + public function getPluginProxy() { + return $this->pluginProxy; + } + + /* + * --------- util functions --------- + */ + + /** + * [util function] checks whether the given template is cached or not + * + * @param Dwoo_ITemplate $tpl the template object + * @return bool + */ + public function isCached(Dwoo_ITemplate $tpl) + { + return is_string($tpl->getCachedTemplate($this)); + } + + /** + * [util function] clears the cached templates if they are older than the given time + * + * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared + * @return int the amount of templates cleared + */ + public function clearCache($olderThan=-1) + { + $cacheDirs = new RecursiveDirectoryIterator($this->getCacheDir()); + $cache = new RecursiveIteratorIterator($cacheDirs); + $expired = time() - $olderThan; + $count = 0; + foreach ($cache as $file) { + if ($cache->isDot() || $cache->isDir() || substr($file, -5) !== '.html') { + continue; + } + if ($cache->getCTime() < $expired) { + $count += unlink((string) $file) ? 1 : 0; + } + } + return $count; + } + + /** + * [util function] fetches a template object of the given resource + * + * @param string $resourceName the resource name (i.e. file, string) + * @param string $resourceId the resource identifier (i.e. file path) + * @param int $cacheTime the cache time setting for this resource + * @param string $cacheId the unique cache identifier + * @param string $compileId the unique compiler identifier + * @return Dwoo_ITemplate + */ + public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) + { + if (isset($this->resources[$resourceName])) { + // TODO could be changed to $this->resources[$resourceName]['class']::templateFactory(..) in 5.3 maybe + return call_user_func(array($this->resources[$resourceName]['class'], 'templateFactory'), $this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate); + } else { + throw new Dwoo_Exception('Unknown resource type : '.$resourceName); + } + } + + /** + * [util function] checks if the input is an array or an iterator object, optionally it can also check if it's empty + * + * @param mixed $value the variable to check + * @param bool $checkIsEmpty if true, the function will also check if the array is empty, + * and return true only if it's not empty + * @return bool true if it's an array (and not empty) or false if it's not an array (or if it's empty) + */ + public function isArray($value, $checkIsEmpty=false) + { + if (is_array($value) === true) { + if ($checkIsEmpty === false) { + return true; + } else { + return count($value) > 0; + } + } elseif ($value instanceof Iterator) { + if ($checkIsEmpty === false) { + return true; + } elseif ($value instanceof Countable) { + return count($value) > 0; + } else { + $value->rewind(); + return $value->valid(); + } + } elseif ($value instanceof ArrayAccess) { + if ($checkIsEmpty === false) { + return true; + } elseif ($value instanceof Countable) { + return count($value) > 0; + } else { + return $value->offsetExists(0); + } + } + return false; + } + + /** + * [util function] triggers a dwoo error + * + * @param string $message the error message + * @param int $level the error level, one of the PHP's E_* constants + */ + public function triggerError($message, $level=E_USER_NOTICE) + { + if (!($tplIdentifier = $this->template->getResourceIdentifier())) { + $tplIdentifier = $this->template->getResourceName(); + } + trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level); + } + + /* + * --------- runtime functions --------- + */ + + /** + * [runtime function] adds a block to the block stack + * + * @param string $blockName the block name (without Dwoo_Plugin_ prefix) + * @param array $args the arguments to be passed to the block's init() function + * @return Dwoo_Block_Plugin the newly created block + */ + public function addStack($blockName, array $args=array()) + { + if (isset($this->plugins[$blockName])) { + $class = $this->plugins[$blockName]['class']; + } else { + $class = 'Dwoo_Plugin_'.$blockName; + } + + if ($this->curBlock !== null) { + $this->curBlock->buffer(ob_get_contents()); + ob_clean(); + } else { + $this->buffer .= ob_get_contents(); + ob_clean(); + } + + $block = new $class($this); + + $cnt = count($args); + if ($cnt===0) { + $block->init(); + } elseif ($cnt===1) { + $block->init($args[0]); + } elseif ($cnt===2) { + $block->init($args[0], $args[1]); + } elseif ($cnt===3) { + $block->init($args[0], $args[1], $args[2]); + } elseif ($cnt===4) { + $block->init($args[0], $args[1], $args[2], $args[3]); + } else { + call_user_func_array(array($block,'init'), $args); + } + + $this->stack[] = $this->curBlock = $block; + return $block; + } + + /** + * [runtime function] removes the plugin at the top of the block stack + * + * calls the block buffer() function, followed by a call to end() + * and finally a call to process() + */ + public function delStack() + { + $args = func_get_args(); + + $this->curBlock->buffer(ob_get_contents()); + ob_clean(); + + $cnt = count($args); + if ($cnt===0) { + $this->curBlock->end(); + } elseif ($cnt===1) { + $this->curBlock->end($args[0]); + } elseif ($cnt===2) { + $this->curBlock->end($args[0], $args[1]); + } elseif ($cnt===3) { + $this->curBlock->end($args[0], $args[1], $args[2]); + } elseif ($cnt===4) { + $this->curBlock->end($args[0], $args[1], $args[2], $args[3]); + } else { + call_user_func_array(array($this->curBlock, 'end'), $args); + } + + $tmp = array_pop($this->stack); + + if (count($this->stack) > 0) { + $this->curBlock = end($this->stack); + $this->curBlock->buffer($tmp->process()); + } else { + $this->curBlock = null; + echo $tmp->process(); + } + + unset($tmp); + } + + /** + * [runtime function] returns the parent block of the given block + * + * @param Dwoo_Block_Plugin $block + * @return Dwoo_Block_Plugin or false if the given block isn't in the stack + */ + public function getParentBlock(Dwoo_Block_Plugin $block) + { + $index = array_search($block, $this->stack, true); + if ($index !== false && $index > 0) { + return $this->stack[$index-1]; + } + return false; + } + + /** + * [runtime function] finds the closest block of the given type, starting at the top of the stack + * + * @param string $type the type of plugin you want to find + * @return Dwoo_Block_Plugin or false if no plugin of such type is in the stack + */ + public function findBlock($type) + { + if (isset($this->plugins[$type])) { + $type = $this->plugins[$type]['class']; + } else { + $type = 'Dwoo_Plugin_'.str_replace('Dwoo_Plugin_', '', $type); + } + + $keys = array_keys($this->stack); + while (($key = array_pop($keys)) !== false) { + if ($this->stack[$key] instanceof $type) { + return $this->stack[$key]; + } + } + return false; + } + + /** + * [runtime function] returns a Dwoo_Plugin of the given class + * + * this is so a single instance of every class plugin is created at each template run, + * allowing class plugins to have "per-template-run" static variables + * + * @private + * @param string $class the class name + * @return mixed an object of the given class + */ + public function getObjectPlugin($class) + { + if (isset($this->runtimePlugins[$class])) { + return $this->runtimePlugins[$class]; + } + return $this->runtimePlugins[$class] = new $class($this); + } + + /** + * [runtime function] calls the process() method of the given class-plugin name + * + * @param string $plugName the class plugin name (without Dwoo_Plugin_ prefix) + * @param array $params an array of parameters to send to the process() method + * @return string the process() return value + */ + public function classCall($plugName, array $params = array()) + { + $class = 'Dwoo_Plugin_'.$plugName; + + $plugin = $this->getObjectPlugin($class); + + $cnt = count($params); + if ($cnt===0) { + return $plugin->process(); + } elseif ($cnt===1) { + return $plugin->process($params[0]); + } elseif ($cnt===2) { + return $plugin->process($params[0], $params[1]); + } elseif ($cnt===3) { + return $plugin->process($params[0], $params[1], $params[2]); + } elseif ($cnt===4) { + return $plugin->process($params[0], $params[1], $params[2], $params[3]); + } else { + return call_user_func_array(array($plugin, 'process'), $params); + } + } + + /** + * [runtime function] calls a php function + * + * @param string $callback the function to call + * @param array $params an array of parameters to send to the function + * @return mixed the return value of the called function + */ + public function arrayMap($callback, array $params) + { + if ($params[0] === $this) { + $addThis = true; + array_shift($params); + } + if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) { + if (empty($params[0])) { + return $params[0]; + } + + // array map + $out = array(); + $cnt = count($params); + + if (isset($addThis)) { + array_unshift($params, $this); + $items = $params[1]; + $keys = array_keys($items); + + if (is_string($callback) === false) { + while (($i = array_shift($keys)) !== null) { + $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params); + } + } elseif ($cnt===1) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($this, $items[$i]); + } + } elseif ($cnt===2) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($this, $items[$i], $params[2]); + } + } elseif ($cnt===3) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($this, $items[$i], $params[2], $params[3]); + } + } else { + while (($i = array_shift($keys)) !== null) { + $out[] = call_user_func_array($callback, array(1=>$items[$i]) + $params); + } + } + } else { + $items = $params[0]; + $keys = array_keys($items); + + if (is_string($callback) === false) { + while (($i = array_shift($keys)) !== null) { + $out[] = call_user_func_array($callback, array($items[$i]) + $params); + } + } elseif ($cnt===1) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($items[$i]); + } + } elseif ($cnt===2) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($items[$i], $params[1]); + } + } elseif ($cnt===3) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($items[$i], $params[1], $params[2]); + } + } elseif ($cnt===4) { + while (($i = array_shift($keys)) !== null) { + $out[] = $callback($items[$i], $params[1], $params[2], $params[3]); + } + } else { + while (($i = array_shift($keys)) !== null) { + $out[] = call_user_func_array($callback, array($items[$i]) + $params); + } + } + } + return $out; + } else { + return $params[0]; + } + } + + /** + * [runtime function] reads a variable into the given data array + * + * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property") + * @param mixed $data the data array or object to read from + * @param bool $safeRead if true, the function will check whether the index exists to prevent any notices from being output + * @return mixed + */ + public function readVarInto($varstr, $data, $safeRead = false) + { + if ($data === null) { + return null; + } + + if (is_array($varstr) === false) { + preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m); + } else { + $m = $varstr; + } + unset($varstr); + + while (list($k, $sep) = each($m[1])) { + if ($sep === '.' || $sep === '[' || $sep === '') { + if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) { + $data = $data[$m[2][$k]]; + } else { + return null; + } + } else { + if (is_object($data) && ($safeRead === false || isset($data->$m[2][$k]) || is_callable(array($data, '__get')))) { + $data = $data->$m[2][$k]; + } else { + return null; + } + } + } + + return $data; + } + + /** + * [runtime function] reads a variable into the parent scope + * + * @param int $parentLevels the amount of parent levels to go from the current scope + * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property") + * @return mixed + */ + public function readParentVar($parentLevels, $varstr = null) + { + $tree = $this->scopeTree; + $cur = $this->data; + + while ($parentLevels--!==0) { + array_pop($tree); + } + + while (($i = array_shift($tree)) !== null) { + if (is_object($cur)) { + $cur = $cur->$i; + } else { + $cur = $cur[$i]; + } + } + + if ($varstr!==null) { + return $this->readVarInto($varstr, $cur); + } else { + return $cur; + } + } + + /** + * [runtime function] reads a variable into the current scope + * + * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property") + * @return mixed + */ + public function readVar($varstr) + { + if (is_array($varstr)===true) { + $m = $varstr; + unset($varstr); + } else { + if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) { + if ($varstr === 'dwoo') { + return $this->globals; + } elseif ($varstr === '__' || $varstr === '_root' ) { + return $this->data; + $varstr = substr($varstr, 6); + } elseif ($varstr === '_' || $varstr === '_parent') { + $varstr = '.'.$varstr; + $tree = $this->scopeTree; + $cur = $this->data; + array_pop($tree); + + while (($i = array_shift($tree)) !== null) { + if (is_object($cur)) { + $cur = $cur->$i; + } else { + $cur = $cur[$i]; + } + } + + return $cur; + } + + $cur = $this->scope; + + if (isset($cur[$varstr])) { + return $cur[$varstr]; + } else { + return null; + } + } + + if (substr($varstr, 0, 1) === '.') { + $varstr = 'dwoo'.$varstr; + } + + preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m); + } + + $i = $m[2][0]; + if ($i === 'dwoo') { + $cur = $this->globals; + array_shift($m[2]); + array_shift($m[1]); + switch ($m[2][0]) { + + case 'get': + $cur = $_GET; + break; + case 'post': + $cur = $_POST; + break; + case 'session': + $cur = $_SESSION; + break; + case 'cookies': + case 'cookie': + $cur = $_COOKIE; + break; + case 'server': + $cur = $_SERVER; + break; + case 'env': + $cur = $_ENV; + break; + case 'request': + $cur = $_REQUEST; + break; + case 'const': + array_shift($m[2]); + if (defined($m[2][0])) { + return constant($m[2][0]); + } else { + return null; + } + + } + if ($cur !== $this->globals) { + array_shift($m[2]); + array_shift($m[1]); + } + } elseif ($i === '__' || $i === '_root') { + $cur = $this->data; + array_shift($m[2]); + array_shift($m[1]); + } elseif ($i === '_' || $i === '_parent') { + $tree = $this->scopeTree; + $cur = $this->data; + + while (true) { + array_pop($tree); + array_shift($m[2]); + array_shift($m[1]); + if (current($m[2]) === '_' || current($m[2]) === '_parent') { + continue; + } + + while (($i = array_shift($tree)) !== null) { + if (is_object($cur)) { + $cur = $cur->$i; + } else { + $cur = $cur[$i]; + } + } + break; + } + } else { + $cur = $this->scope; + } + + while (list($k, $sep) = each($m[1])) { + if ($sep === '.' || $sep === '[' || $sep === '') { + if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) { + $cur = $cur[$m[2][$k]]; + } else { + return null; + } + } elseif ($sep === '->') { + if (is_object($cur)) { + $cur = $cur->$m[2][$k]; + } else { + return null; + } + } else { + return null; + } + } + + return $cur; + } + + /** + * [runtime function] assign the value to the given variable + * + * @param mixed $value the value to assign + * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property") + * @return bool true if assigned correctly or false if a problem occured while parsing the var string + */ + public function assignInScope($value, $scope) + { + $tree =& $this->scopeTree; + $data =& $this->data; + + if (!is_string($scope)) { + return $this->triggerError('Assignments must be done into strings, ('.gettype($scope).') '.var_export($scope, true).' given', E_USER_ERROR); + } + if (strstr($scope, '.') === false && strstr($scope, '->') === false) { + $this->scope[$scope] = $value; + } else { + // TODO handle _root/_parent scopes ? + preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m); + + $cur =& $this->scope; + $last = array(array_pop($m[1]), array_pop($m[2])); + + while (list($k, $sep) = each($m[1])) { + if ($sep === '.' || $sep === '[' || $sep === '') { + if (is_array($cur) === false) { + $cur = array(); + } + $cur =& $cur[$m[2][$k]]; + } elseif ($sep === '->') { + if (is_object($cur) === false) { + $cur = new stdClass; + } + $cur =& $cur->$m[2][$k]; + } else { + return false; + } + } + + if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') { + if (is_array($cur) === false) { + $cur = array(); + } + $cur[$last[1]] = $value; + } elseif ($last[0] === '->') { + if (is_object($cur) === false) { + $cur = new stdClass; + } + $cur->$last[1] = $value; + } else { + return false; + } + } + } + + /** + * [runtime function] sets the scope to the given scope string or array + * + * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2") + * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope + * @return array the current scope tree + */ + public function setScope($scope, $absolute = false) + { + $old = $this->scopeTree; + + if (is_string($scope)===true) { + $scope = explode('.', $scope); + } + + if ($absolute===true) { + $this->scope =& $this->data; + $this->scopeTree = array(); + } + + while (($bit = array_shift($scope)) !== null) { + if ($bit === '_' || $bit === '_parent') { + array_pop($this->scopeTree); + $this->scope =& $this->data; + $cnt = count($this->scopeTree); + for ($i=0;$i<$cnt;$i++) + $this->scope =& $this->scope[$this->scopeTree[$i]]; + } elseif ($bit === '__' || $bit === '_root') { + $this->scope =& $this->data; + $this->scopeTree = array(); + } elseif (isset($this->scope[$bit])) { + $this->scope =& $this->scope[$bit]; + $this->scopeTree[] = $bit; + } else { + unset($this->scope); + $this->scope = null; + } + } + + return $old; + } + + /** + * [runtime function] returns the entire data array + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * [runtime function] returns a reference to the current scope + * + * @return &mixed + */ + public function &getScope() + { + return $this->scope; + } + + /** + * Redirects all calls to unexisting to plugin proxy. + * + * @param string Method name + * @param array List of arguments + * @return mixed + */ + public function __call($method, $args) { + $proxy = $this->getPluginProxy(); + if (!$proxy) { + throw new Dwoo_Exception('Call to undefined method '.__CLASS__.'::'.$method.'()'); + } + return call_user_func_array($proxy->getCallback($method), $args); + } +} diff --git a/system/libs/dwoo/Dwoo/Adapters/Agavi/DwooRenderer.php b/system/libs/dwoo/Dwoo/Adapters/Agavi/DwooRenderer.php new file mode 100644 index 00000000..d532ad7f --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/Agavi/DwooRenderer.php @@ -0,0 +1,196 @@ + + * + * ro + * rq + * ct + * us + * tm + * rd + * + * true + * %core.lib_dir%/dwoo_plugins + * + * + * - add dwoo's directory to your include path or include dwooAutoload.php yourself + * either through agavi's autoload.xml (with name="Dwoo") or through your index.php + * + * Notes: + * - you can copy the /Dwoo/Adapters/Agavi/dwoo_plugins directory to your agavi app's + * lib directory, or change the plugin_dir parameter in the output_types.xml file. + * these plugins are agavi-specific helpers that shortens the syntax to call common + * agavi helpers (i18n, routing, ..) + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the + * use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class DwooRenderer extends AgaviRenderer implements AgaviIReusableRenderer +{ + /** + * @constant string The directory inside the cache dir where templates will + * be stored in compiled form. + */ + const COMPILE_DIR = 'templates'; + + /** + * @constant string The subdirectory inside the compile dir where templates + * will be stored in compiled form. + */ + const COMPILE_SUBDIR = 'dwoo'; + + /** + * @constant string The directory inside the cache dir where cached content + * will be stored. + */ + const CACHE_DIR = 'dwoo'; + + /** + * @var Dwoo Dwoo template engine. + */ + protected $dwoo = null; + + /** + * @var string A string with the default template file extension, + * including the dot. + */ + protected $defaultExtension = '.html'; + + /** + * stores the (optional) plugin directory to add to the Dwoo_Loader + */ + protected $plugin_dir = null; + + /** + * Pre-serialization callback. + * + * Excludes the Dwoo instance to prevent excessive serialization load. + */ + public function __sleep() + { + $keys = parent::__sleep(); + unset($keys[array_search('dwoo', $keys)]); + return $keys; + } + + /** + * Initialize this Renderer. + * + * @param AgaviContext The current application context. + * @param array An associative array of initialization parameters. + */ + public function initialize(AgaviContext $context, array $parameters = array()) + { + parent::initialize($context, $parameters); + + $this->plugin_dir = $this->getParameter('plugin_dir', $this->plugin_dir); + } + + /** + * provides a custom compiler to the dwoo renderer with optional settings + * you can set in the agavi output_types.xml config file + * + * @return Dwoo_Compiler + */ + public function compilerFactory() + { + if (class_exists('Dwoo_Compiler', false) === false) { + include DWOO_DIRECTORY . 'Dwoo/Compiler.php'; + } + $compiler = Dwoo_Compiler::compilerFactory(); + $compiler->setAutoEscape((bool) $this->getParameter('auto_escape', false)); + return $compiler; + } + + /** + * Grab a cleaned up dwoo instance. + * + * @return Dwoo A Dwoo instance. + */ + protected function getEngine() + { + if($this->dwoo) { + return $this->dwoo; + } + + if(!class_exists('Dwoo')) { + if (file_exists(dirname(__FILE__).'/../../../dwooAutoload.php')) { + // file was dropped with the entire dwoo package + require dirname(__FILE__).'/../../../dwooAutoload.php'; + } else { + // assume the dwoo package is in the include path + require 'dwooAutoload.php'; + } + } + + $parentMode = fileperms(AgaviConfig::get('core.cache_dir')); + + $compileDir = AgaviConfig::get('core.cache_dir') . DIRECTORY_SEPARATOR . self::COMPILE_DIR . DIRECTORY_SEPARATOR . self::COMPILE_SUBDIR; + AgaviToolkit::mkdir($compileDir, $parentMode, true); + + $cacheDir = AgaviConfig::get('core.cache_dir') . DIRECTORY_SEPARATOR . self::CACHE_DIR; + AgaviToolkit::mkdir($cacheDir, $parentMode, true); + + $this->dwoo = new Dwoo($compileDir, $cacheDir); + + if (!empty($this->plugin_dir)) { + $this->dwoo->getLoader()->addDirectory($this->plugin_dir); + } + + $this->dwoo->setDefaultCompilerFactory('file', array($this, 'compilerFactory')); + + return $this->dwoo; + } + + /** + * Render the presentation and return the result. + * + * @param AgaviTemplateLayer The template layer to render. + * @param array The template variables. + * @param array The slots. + * @param array Associative array of additional assigns. + * + * @return string A rendered result. + */ + public function render(AgaviTemplateLayer $layer, array &$attributes = array(), array &$slots = array(), array &$moreAssigns = array()) + { + $engine = $this->getEngine(); + + $data = array(); + if($this->extractVars) { + $data = $attributes; + } else { + $data[$this->varName] = &$attributes; + } + + $data[$this->slotsVarName] =& $slots; + + foreach($this->assigns as $key => $getter) { + $data[$key] = $this->context->$getter(); + } + + foreach($moreAssigns as $key => &$value) { + if(isset($this->moreAssignNames[$key])) { + $key = $this->moreAssignNames[$key]; + } + $data[$key] =& $value; + } + + return $engine->get($layer->getResourceStreamIdentifier(), $data); + } +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/Agavi/README b/system/libs/dwoo/Dwoo/Adapters/Agavi/README new file mode 100644 index 00000000..825ce603 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/Agavi/README @@ -0,0 +1,27 @@ +// ------------------------ +// Install notes : +// ------------------------ + + - drop dwoo's directory in app/lib/renderer (create if needed) + + - add a renderer to app/config/output_types.xml as such : + + + ro + rq + ct + us + tm + rd + + true + %core.lib_dir%/dwoo_plugins + + + - add the renderer to app/config/autoload.xml as such : + %core.lib_dir%/renderer/dwoo/Dwoo/Adapter/Agavi/DwooRenderer.php + + - you can copy the /Dwoo/Adapters/Agavi/dwoo_plugins directory to your agavi app's + lib directory, or change the plugin_dir parameter in the output_types.xml file. + these plugins are agavi-specific helpers that shortens the syntax to call common + agavi helpers (i18n, routing, ..) diff --git a/system/libs/dwoo/Dwoo/Adapters/Agavi/dwoo_plugins/t.php b/system/libs/dwoo/Dwoo/Adapters/Agavi/dwoo_plugins/t.php new file mode 100644 index 00000000..d501fb0a --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/Agavi/dwoo_plugins/t.php @@ -0,0 +1,32 @@ +Agavi specific plugin + * + * uses AgaviTranslationManager to localize a string + * + *
+ *  * string : the string to localize
+ * 
+ * + * Examples: + * + * {t "Hello"} + * {t $header} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +function Dwoo_Plugin_t_compile(Dwoo_Compiler $compiler, $string) +{ + return '$this->data[\'tm\']->_('.$string.')'; +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/Agavi/dwoo_plugins/url.php b/system/libs/dwoo/Dwoo/Adapters/Agavi/dwoo_plugins/url.php new file mode 100644 index 00000000..bb8b222d --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/Agavi/dwoo_plugins/url.php @@ -0,0 +1,54 @@ +Agavi specific plugin + * + * uses AgaviRouting to create an url + * + *
+ *  * route : the route name, optional (by default the current url is returned)
+ *  * params : an array with variables to build the route, optional
+ *  * options : an array of options to pass to the routing object, optional
+ *  * rest : for convenience, you can just pass named parameters that will be used as
+ *           the params array, but you must not provide the params array in this case
+ * 
+ * + * Examples: + * + * {a url("route.name" array(param="Value", param2=$otherVal))}Here is a link{/a} + *
{* without any parameter it just returns the current url *} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +function Dwoo_Plugin_url_compile(Dwoo_Compiler $compiler, $route = null, $params = null, $options = null, array $rest = array()) +{ + if ($params == 'null') { + if (count($rest)) { + $params = array(); + foreach ($rest as $k=>$v) { + if (is_numeric($k)) { + $params[] = $k.'=>'.$v; + } else { + $params[] = '"'.$k.'"=>'.$v; + } + } + $params = 'array('.implode(', ', $params).')'; + } else { + $params = 'array()'; + } + } + if ($options == 'null') { + $options = 'array()'; + } + return '$this->data[\'ro\']->gen('.$route.', '.$params.', '.$options.')'; +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/CakePHP/README b/system/libs/dwoo/Dwoo/Adapters/CakePHP/README new file mode 100644 index 00000000..46a73fc2 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CakePHP/README @@ -0,0 +1,33 @@ +// CakePHP Dwoo bridge - v0.2 +// ------------------------ +// Installation : +// ------------------------ +// 1. Download and install the dwoo library, preferably on the +// 'vendors' directory of CakePHP. However you can place it +// anywhere you want; if you do, make sure to change the App::import +// line in dwoo.php to include the dwoo library properly. +// +// 2. Place this file in the app/views directory, or on cake/libs/view. +// +// 3. Create the app/tmp/dwoo/cache and app/tmp/dwoo/compile directories +// and make sure they are writable. +// ------------------------ +// Usage example : +// ------------------------ + +// In your controller class you need to change the view property to +// use Dwoo at some point in the execution using : + +$this->view = 'Dwoo'; + +// Or you can also override the view property in your AppController class as such : + +class AppController extends Controller { + public $view = 'Dwoo'; +} + +// If you want another template extension (default is .tpl) you must +// edit the dwoo.php file at line 44 and change it to : +$this->ext = ".html"; + +//{include $templatedir."index.tpl"} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/CakePHP/dwoo.php b/system/libs/dwoo/Dwoo/Adapters/CakePHP/dwoo.php new file mode 100644 index 00000000..4a247e3f --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CakePHP/dwoo.php @@ -0,0 +1,143 @@ + 'dwoo/dwooAutoload.php')); + +/** + * Dwoo adapter for CakePHP + * + * Based on SmartyView by Mark John S. Buenconsejo + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * This file is released under the LGPL + * "GNU Lesser General Public License" + * More information can be found here: + * {@link http://www.gnu.org/copyleft/lesser.html} + * + * @author Mark John S. Buenconsejo + * @author Giangi + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class DwooView extends View +{ + protected $_sv_template_dir; + protected $_sv_layout_dir; + protected $_sv_compile_dir; + protected $_sv_cache_dir; + protected $_sv_compile_id; + + protected $_dwoo; + + public $sv_processedTpl; + + public function __construct(&$controller) + { + parent::__construct($controller); + + $this->ext = '.tpl'; + + $this->_sv_template_dir = array + ( + VIEWS . $this->viewPath . DS . $this->subDir, + VIEWS . $this->viewPath, + VIEWS + ); + + $this->_sv_layout_dir = array + ( + LAYOUTS . $this->subDir, + VIEWS + ); + + $this->_sv_compile_dir = TMP . 'dwoo' . DS . 'compile'; + $this->_sv_cache_dir = TMP . 'dwoo' . DS . 'cache'; + + $this->_dwoo = new Dwoo($this->_sv_compile_dir, $this->_sv_cache_dir); + + $this->_sv_compile_id = $controller->name; + + $this->_dwoo->sv_this = $this; + $this->_dwoo->setSecurityPolicy(); + + return; + } + + /** + * changes the template directory + */ + public function setTemplateDir($path = VIEW) { + $old = $this->_sv_template_dir; + $this->_sv_template_dir = $path; + + return $old; + } + + public function getTemplateDir() { + return $this->_sv_template_dir ; + } + + public function _render($___viewFn, $___data_for_view, $___play_safe = true, $loadHelpers = true) + { + // let's determine if this is a layout call or a template call + // and change the template dir accordingly + $layout = false; + if(isset($___data_for_view['content_for_layout'])) { + $this->_sv_template_dir = $this->_sv_layout_dir; + $layout = true; + } + + $tpl = new Dwoo_Template_File($___viewFn); + $data = $___data_for_view; + + $data['view'] = $this; + + if ($this->helpers != false && $loadHelpers === true) { + $loadedHelpers = array(); + $loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers); + + foreach (array_keys($loadedHelpers) as $helper) { + $camelBackedHelper = strtolower(substr($helper, 0, 1)) . substr($helper, 1); + + ${$camelBackedHelper} = $loadedHelpers[$helper]; + + if (is_array(${$camelBackedHelper}->helpers) && !empty(${$camelBackedHelper}->helpers)) { + $subHelpers = ${$camelBackedHelper}->helpers; + foreach ($subHelpers as $subHelper) { + ${$camelBackedHelper}->{$subHelper} = $loadedHelpers[$subHelper]; + } + } + + if(isset($this->passedArgs)) { + ${$camelBackedHelper}->passedArgs = $this->passedArgs; + } + + $this->loaded[$camelBackedHelper] = ${$camelBackedHelper}; + + $data[$camelBackedHelper] = ${$camelBackedHelper}; + } + } + + if ($this->helpers != false && $loadHelpers === true) { + foreach ($loadedHelpers as $helper) { + if (is_object($helper)) { + if (is_subclass_of($helper, 'Helper') || is_subclass_of($helper, 'helper')) { + $helper->beforeRender(); + } + } + } + } + + return $this->_dwoo->get($tpl, $data); + } + + public function get(){ + return $this->_dwoo; + } +} diff --git a/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/README b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/README new file mode 100644 index 00000000..1cf086f4 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/README @@ -0,0 +1,36 @@ +CodeIgniter/Dwoo adapater +------------------------- +Integration of Dwoo into Codeigniter (1.7.0 >) + +Links: +Dwoo - http://dwoo.org +CodeIgniter - http://codeigniter.com + +Installation: +1) Extract package into your application directory (i.e. $webroot/application or + $webroot/system/application) +2) Change the parameters in config/dwootemplate.php +3) Create the compile and cache directory you set in your config file in step 2 + and give it the correct rights (chmod 777 when on *nix) +4) Extract/copy the Dwoo package into application/libraries/dwoo +5) Browse to : http://[yoururl]/dwoowelcome + + +Version info +1.0.2 [11-03-2009] Fixed a problem with $data attribute (which Dwoo also used) +1.0.1 [12-11-2008] Removed some & in the dwootemplate + Changed licencse + Changed 'output' in 'get' in the dwootemplate (line 122) +1.0.0 [11-11-2008] Initial release + + +Questions/Remarks? +mail to: stefan.verstege@newmedia.nl +IM me on GTALK: verstege@gmail.com +Contact me on the Dwoo forums: stefanv + +---------[ copyright notice ]----------------------------------------------------------------------- +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. + +License http://dwoo.org/LICENSE Modified BSD License \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/config/dwootemplate.php b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/config/dwootemplate.php new file mode 100644 index 00000000..0fb0f415 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/config/dwootemplate.php @@ -0,0 +1,12 @@ +load->library('Dwootemplate'); + $this->dwootemplate->assign('itshowlate', date('H:i:s')); + $this->dwootemplate->display('dwoowelcome.tpl'); + } +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/libraries/Dwootemplate.php b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/libraries/Dwootemplate.php new file mode 100644 index 00000000..68d58efd --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/libraries/Dwootemplate.php @@ -0,0 +1,172 @@ + + * @copyright Copyright (c) 2008, Stefan Verstege + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://www.newmedia.nl/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + * + * @uses the dwoo package from http://dwoo.org + */ +class Dwootemplate extends Dwoo { + protected $dwoo_data = array(); + + /** + * Constructor for the DwooTemplate engine + * + */ + public function __construct() { + // Call parents constructor + parent::__construct(); + + // Set the config settings + $this->initialize(); + + // Assign some defaults to dwoo + $CI = get_instance(); + $this->dwoo_data = new Dwoo_Data(); + $this->dwoo_data->js_files = array(); + $this->dwoo_data->css_files = array(); + $this->dwoo_data->CI = $CI; + $this->dwoo_data->site_url = $CI->config->site_url(); // so we can get the full path to CI easily + $this->dwoo_data->uniqid = uniqid(); + $this->dwoo_data->timestamp = mktime(); + + log_message('debug', "Dwoo Template Class Initialized"); + } + + + /** + * Assign data to dwoo data object + * + * @param string $key + * @param mixed $value + */ + public function assign($key, $value) { + $this->dwoo_data->$key = $value; + } + + + /** + * Add Javascript files to template + * + * @param string $js + */ + public function add_js($js) { + $current = $this->dwoo_data->js_files; + $current[] = $js; + $this->dwoo_data->js_files = $current; + } + + + /** + * Add Css stylesheets to template + * + * @param string $css + */ + public function add_css($css) { + $current = $this->dwoo_data->css_files; + $current[] = $css; + $this->dwoo_data->css_files = $current; + } + + + /** + * Display or return the compiled template + * Since we assign the results to the standard CI output module + * you can also use the helper from CI in your templates!! + * + * @param string $sTemplate + * @param boolean $return + * @return mixed + */ + public function display($sTemplate, $return = FALSE) { + // Start benchmark + $CI = get_instance(); + $CI->benchmark->mark('dwoo_parse_start'); + + // Check if file exists + if ( !file_exists($this->template_dir . $sTemplate ) ) { + $message = sprintf('Template file \'%s\' not found.', $sTemplate); + show_error($message); + log_message('error', $message); + } + + // Create new template + $tpl = new Dwoo_Template_File($this->template_dir . $sTemplate); + + // render the template + $template = $this->get($tpl, $this->dwoo_data); + + // Finish benchmark + $CI->benchmark->mark('dwoo_parse_end'); + + // Return results or not ? + if ($return == FALSE) { + $CI->output->final_output = $template; + } else { + return $template; + } + } + + + /** + * Toggle Codeigniter profiler on/off + * + */ + public function enable_profiler($toggle = TRUE) { + $CI = get_instance(); + $CI->output->enable_profiler($toggle); + } + + + /** + * Set http header + * + * @example $this->output->set_header("HTTP/1.1 200 OK"); + * @example $this->output->set_header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_update).' GMT'); + * @param string $header + */ + public function set_header($header) { + $CI = get_instance(); + $CI->output->set_header($header); + } + + + /** + * Set status header + * + * @example $this->output->set_status_header('401'); + * @example // Sets the header as: Unauthorized + * @param string $header + */ + public function set_status_header($header) { + $CI = get_instance(); + $CI->output->set_status_header($header); + } + + + /** + * Assign the dwootemplate config items to the instance + * + */ + private function initialize() { + $CI = get_instance(); + $CI->config->load('dwootemplate', TRUE); + $config = $CI->config->item('dwootemplate'); + foreach ($config as $key => $val) { + $this->$key = $val; + } + } +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/views/dwoowelcome.tpl b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/views/dwoowelcome.tpl new file mode 100644 index 00000000..95cf53ad --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/views/dwoowelcome.tpl @@ -0,0 +1,31 @@ +{extends "page.tpl"} + +{block "title"} +Welcome to Dwoo-ed CodeIgniter +{/block} + +{block "content"} +

Welcome to Dwoo-ed CodeIgniter!

+ +

The page you are looking at is being generated dynamically by CodeIgniter in combination with the 'Smarty-killer' Dwoo template engine. +The page is rendered at {$itshowlate} by the Dwoo_compiler.

+ +

If you would like to edit this page you'll find it located at:

+application/views/dwoowelcome.tpl + +

The corresponding controller for this page is found at:

+application/controllers/dwoowelcome.php + +

The library for Dwoo integration can be found at:

+application/libraries/Dwootemplate.php + +

If you are exploring Dwoo for the very first time, you should start by reading the {anchor uri='http://dwoo.org/' title='Dwoo website'}.

+

If you are exploring CodeIgniter for the very first time, you should start by reading the {anchor uri='http://codeigniter.com/user_guide/' title='User Guide'}.

+ +
+Usage:
+$this->load->library('Dwootemplate');
+$this->dwootemplate->assign('test', 'test');
+$this->dwootemplate->display('dwoowelcome.tpl');
+
+{/block} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/views/page.tpl b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/views/page.tpl new file mode 100644 index 00000000..42a6bfcd --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/CodeIgniter/views/page.tpl @@ -0,0 +1,57 @@ + + +{block "title"}Here come the title{/block} + + + + +{block "content"}Here comes the content{/block} + + \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/ZendFramework/PluginProxy.php b/system/libs/dwoo/Dwoo/Adapters/ZendFramework/PluginProxy.php new file mode 100644 index 00000000..d6beeb4c --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/ZendFramework/PluginProxy.php @@ -0,0 +1,96 @@ + + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Denis Arh, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Adapters_ZendFramework_PluginProxy implements Dwoo_IPluginProxy +{ + /** + * reference to the zend view owning this proxy + * + * @var Zend_View_Interface + */ + public $view; + + /** + * Dwoo_Adapters_ZendFramework_PluginProxy's constructor. + * + * @param Zend_View_Interface $view + */ + public function __construct(Zend_View_Interface $view) { + $this->view = $view; + } + + /** + * Called from Dwoo_Compiler to check if the requested plugin is available + * + * @param string $name + * @return bool + */ + public function handles($name) { + try { + $this->view->getHelper($name); + } catch (Zend_Loader_PluginLoader_Exception $e) { + return false; + } + + return true; + } + + /** + * returns the code (as a string) to call the plugin + * (this will be executed at runtime inside the Dwoo class) + * + * @param string $name the plugin name + * @param array $params a parameter array, array key "*" is the rest array + * @return string + */ + public function getCode($name, $params) { + return '$this->getPluginProxy()->view->'. $name .'('.Dwoo_Compiler::implode_r($params).')'; + } + + /** + * returns a callback to the plugin, this is used with the reflection API to + * find out about the plugin's parameter names etc. + * + * should you need a rest array (i.e. for ZendFramework helpers) without the + * possibility to edit the plugin's code, you can provide a callback to some + * other function with the correct parameter signature, i.e. : + * + * return array($this, "callbackHelper"); + * // and callbackHelper would be as such: + * public function callbackHelper(array $rest=array()){} + * + * + * @param string $name the plugin name + * @return callback + */ + public function getCallback($name) { + return array($this->view->getHelper($name), $name); + } + + /** + * returns some code that will check if the plugin is loaded and if not load it + * this is optional, if your plugins are autoloaded or whatever, just return an + * empty string + * + * @param string $name the plugin name + * @return string + */ + public function getLoader($name) { + return ''; + } +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/ZendFramework/README b/system/libs/dwoo/Dwoo/Adapters/ZendFramework/README new file mode 100644 index 00000000..51d70943 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/ZendFramework/README @@ -0,0 +1,32 @@ +// ------------------------ +// Usage example : +// ------------------------ +// Note that you might need to manually include 'lib/Dwoo.php', +// 'lib/Dwoo/Adapters/ZendFramework/View.php' and +// 'lib/Dwoo/Adapters/ZendFramework/PluginProxy.php' for this to +// work as expected, depending on your ZF setup +// +// If anyone writes a more advanced how-to please let me know +// ------------------------ + +$view = new Dwoo_Adapters_ZendFramework_View(array( + 'compileDir' => 'path/to/compile_dir' // set to null or remove this line to use defaults + 'cacheDir' => 'path/to/cache_dir' // set to null or remove this line to use defaults +)); + +// This allows you to use ZF's helpers as if they were Dwoo plugins (i.e. {doctype} will call the doctype helper) + +$view->setPluginProxy(new Dwoo_Adapters_ZendFramework_PluginProxy(new Zend_View())); + + +// 1. example - used with the Zend Controller + +$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view); + +Zend_Controller_Action_HelperBroker::addHelper($viewRenderer); + + +// 2. example - used manually + +$view->assign('foo', 'bar'); +$view->display('foobar.phtml'); \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Adapters/ZendFramework/View.php b/system/libs/dwoo/Dwoo/Adapters/ZendFramework/View.php new file mode 100644 index 00000000..faa840cf --- /dev/null +++ b/system/libs/dwoo/Dwoo/Adapters/ZendFramework/View.php @@ -0,0 +1,512 @@ + + * @author Stephan Wentz + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Adapters_ZendFramework_View extends Zend_View_Abstract +{ + /** + * @var Dwoo + */ + protected $_engine = null; + + /** + * @var Dwoo_Data + */ + protected $_dataProvider = null; + + /** + * @var Dwoo_Compiler + */ + protected $_compiler = null; + + /** + * Changing Filter's scope to play nicely + * + * @var array + */ + protected $_filter = array(); + + + /** + * @var string + */ + protected $_templateFileClass = 'Dwoo_Template_File'; + + /** + * @var array + */ + protected $_templateFileSettings = array(); + + /** + * @var Dwoo_IPluginProxy + */ + protected $_pluginProxy = null; + + /** + * Constructor method. + * See setOptions for $opt details + * + * @see setOptions + * @param array|Zend_Config List of options or Zend_Config instance + */ + public function __construct($opt = array()) + { + + if (is_array($opt)) { + $this->setOptions($opt); + } elseif ($opt instanceof Zend_Config) { + $this->setConfig($opt); + } + + $this->init(); + } + + /** + * Set object state from options array + * - engine = engine class name|engine object|array of options for engine + * - dataProvider = data provider class name|data provider object|array of options for data provider + * - compiler = compiler class name|compiler object|array of options for compiler + * - templateFile = + * + * Array of options: + * - type class name or object for engine, dataProvider or compiler + * - any set* method (compileDir for setCompileDir ...) + * + * @param array $options + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setOptions(array $opt = array()) + { + // BC checks + // TODO remove in 1.1 + if (isset($opt['compileDir']) || isset($opt['compile_dir'])) { + trigger_error('Dwoo ZF Adapter: the compile dir should be set in the $options[\'engine\'][\'compileDir\'] value the adapter settings', E_USER_WARNING); + } + + if (isset($opt['cacheDir']) || isset($opt['cache_dir'])) { + trigger_error('Dwoo ZF Adapter: the cache dir should be set in the $options[\'engine\'][\'cacheDir\'] value the adapter settings', E_USER_WARNING); + } + // end BC + + // Making sure that everything is loaded. + $classes = array('engine', 'dataProvider', 'compiler'); + + // Setting options to Dwoo objects... + foreach ($opt as $type => $settings) { + if (!method_exists($this, 'set' . $type)) { + throw new Dwoo_Exception("Unknown type $type"); + } + + if (is_string($settings) || is_object($settings)) { + call_user_func(array($this, 'set' . $type), $settings); + } elseif (is_array($settings)) { + // Set requested class + if (array_key_exists('type', $settings)) { + call_user_func(array($this, 'set' . $type), $settings['type']); + } + + if (in_array($type, $classes)) { + // Call get so that the class is initialized + $rel = call_user_func(array($this, 'get' . $type)); + + // Call set*() methods so that all the settings are set. + foreach ($settings as $method => $value) { + if (method_exists($rel, 'set' . $method)) { + call_user_func(array($rel, 'set' . $method), $value); + } + } + } elseif ('templateFile' == $type) { + // Remember the settings for the templateFile + $this->_templateFileSettings = $settings; + } + } + } + } + + /** + * Set object state from Zend_Config object + * + * @param Zend_Config $config + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config->toArray()); + } + + /** + * Called before template rendering + * + * Binds plugin proxy to the Dwoo. + * + * @see Dwoo_Adapters_ZendFramework_View::getPluginProxy(); + * @see Dwoo::setPluginProxy(); + */ + protected function preRender() + { + $this->getEngine()->setPluginProxy($this->getPluginProxy()); + } + + /** + * Wraper for Dwoo_Data::__set() + * allows to assign variables using the object syntax + * + * @see Dwoo_Data::__set() + * @param string $name the variable name + * @param string $value the value to assign to it + */ + public function __set($name, $value) + { + $this->getDataProvider()->__set($name, $value); + } + + /** + * Sraper for Dwoo_Data::__get() allows to read variables using the object + * syntax + * + * @see Dwoo_Data::__get() + * @param string $name the variable name + * @return mixed + */ + public function __get($name) + { + return $this->getDataProvider()->__get($name); + } + + /** + * Wraper for Dwoo_Data::__isset() + * supports calls to isset($dwooData->var) + * + * @see Dwoo_Data::__isset() + * @param string $name the variable name + */ + public function __isset($name) + { + return $this->getDataProvider()->__isset($name); + } + + /** + * Wraper for Dwoo_Data::_unset() + * supports unsetting variables using the object syntax + * + * @see Dwoo_Data::__unset() + * @param string $name the variable name + */ + public function __unset($name) + { + $this->getDataProvider()->__unset($name); + } + + /** + * Catches clone request and clones data provider + */ + public function __clone() { + $this->setDataProvider(clone $this->getDataProvider()); + } + + /** + * Returns plugin proxy interface + * + * @return Dwoo_IPluginProxy + */ + public function getPluginProxy() + { + if (!$this->_pluginProxy) { + $this->_pluginProxy = new Dwoo_Adapters_ZendFramework_PluginProxy($this); + } + + return $this->_pluginProxy; + } + + /** + * Sets plugin proxy + * + * @param Dwoo_IPluginProxy + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy) + { + $this->_pluginProxy = $pluginProxy; + return $this; + } + + /** + * Sets template engine + * + * @param string|Dwoo Object or name of the class + */ + public function setEngine($engine) + { + // if param given as an object + if ($engine instanceof Dwoo) { + $this->_engine = $engine; + } + // + elseif (is_subclass_of($engine, 'Dwoo') || 'Dwoo' === $engine) { + $this->_engine = new $engine(); + } + else { + throw new Dwoo_Exception("Custom engine must be a subclass of Dwoo"); + } + } + + /** + * Return the Dwoo template engine object + * + * @return Dwoo + */ + public function getEngine() + { + if (null === $this->_engine) { + $this->_engine = new Dwoo(); + } + + return $this->_engine; + } + + /** + * Sets Dwoo data object + * + * @param string|Dwoo_Data Object or name of the class + */ + public function setDataProvider($data) + { + if ($data instanceof Dwoo_IDataProvider) { + $this->_dataProvider = $data; + } + elseif (is_subclass_of($data, 'Dwoo_Data') || 'Dwoo_Data' == $data) { + $this->_dataProvider = new $data(); + } + else { + throw new Dwoo_Exception("Custom data provider must be a subclass of Dwoo_Data or instance of Dwoo_IDataProvider"); + } + } + + /** + * Return the Dwoo data object + * + * @return Dwoo_Data + */ + public function getDataProvider() + { + if (null === $this->_dataProvider) { + $this->_dataProvider = new Dwoo_Data; + } + + return $this->_dataProvider; + } + + + /** + * Sets Dwoo compiler + * + * @param string|Dwoo_Compiler Object or name of the class + */ + public function setCompiler($compiler) + { + + // if param given as an object + if ($compiler instanceof Dwoo_ICompiler) { + $this->_compiler = $compiler; + } + // if param given as a string + elseif (is_subclass_of($compiler, 'Dwoo_Compiler') || 'Dwoo_Compiler' == $compiler) { + $this->_compiler = new $compiler; + } + else { + throw new Dwoo_Exception("Custom compiler must be a subclass of Dwoo_Compiler or instance of Dwoo_ICompiler"); + } + } + + /** + * Return the Dwoo compiler object + * + * @return Dwoo_Data + */ + public function getCompiler() + { + if (null === $this->_compiler) { + $this->_compiler = Dwoo_Compiler::compilerFactory(); + } + + return $this->_compiler; + } + + /** + * Initializes Dwoo_ITemplate type of class and sets properties from _templateFileSettings + * + * @param string Template location + * @return Dwoo_ITemplate + */ + public function getTemplateFile($template) { + $templateFileClass = $this->_templateFileClass; + + $dwooTemplateFile = new $templateFileClass($template); + + if (!($dwooTemplateFile instanceof Dwoo_ITemplate)) { + throw new Dwoo_Exception("Custom templateFile class must be a subclass of Dwoo_ITemplate"); + } + + foreach ($this->_templateFileSettings as $method => $value) { + if (method_exists($dwooTemplateFile, 'set' . $method)) { + call_user_func(array($dwooTemplateFile, 'set' . $method), $value); + } + } + + return $dwooTemplateFile; + } + + /** + * Dwoo_ITemplate type of class + * + * @param string Name of the class + * @return void + */ + public function setTemplateFile($tempateFileClass) { + $this->_templateFileClass = $tempateFileClass; + } + + /** + * Passes data to Dwoo_Data object + * + * @see Dwoo_Data::assign() + * @param array|string $name + * @param mixed $val + * @return Dwoo_Adapters_ZendFramework_View + */ + public function assign($name, $val = null) + { + $this->getDataProvider()->assign($name, $val); + return $this; + } + + /** + * Return list of all assigned variables + * + * @return array + */ + public function getVars() + { + return $this->_dataProvider->getData(); + } + + /** + * Clear all assigned variables + * + * Clears all variables assigned to Zend_View either via {@link assign()} or + * property overloading ({@link __get()}/{@link __set()}). + * + * @return void + * @return Dwoo_Adapters_ZendFramework_View + */ + public function clearVars() + { + $this->getDataProvider()->clear(); + return $this; + } + + /** + * Wraper for parent's render method so preRender method + * can be called (that will bind the plugin proxy to the + * engine. + * + * @see Zend_View_Abstract::render + * @return string The script output. + */ + public function render($name) + { + $this->preRender(); + return parent::render($name); + } + + /** + * Processes a view script and outputs it. Output is then + * passed through filters. + * + * @param string $name The script script name to process. + * @return string The script output. + */ + public function _run() + { + echo $this->_engine->get( + $this->getTemplateFile(func_get_arg(0)), + $this->getDataProvider(), + $this->getCompiler() + ); + } + + /** + * Add plugin path + * + * @param string $dir Directory + * @return Dwoo_Adapters_ZendFramework_View + */ + public function addPluginDir($dir) + { + $this->getEngine()->getLoader()->addDirectory($dir); + return $this; + } + + /** + * Set compile path + * + * @param string $dir Directory + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setCompileDir($dir) + { + $this->getEngine()->setCompileDir($dir); + return $this; + } + + /** + * Set cache path + * + * @param string $dir Directory + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setCacheDir($dir) + { + $this->getEngine()->setCacheDir($dir); + return $this; + } + + /** + * Set cache lifetime + * + * @param string $seconds Lifetime in seconds + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setCacheLifetime($seconds) + { + $this->getEngine()->setCacheTime($seconds); + return $this; + } + + /** + * Set charset + * + * @param string $charset + * @return Dwoo_Adapters_ZendFramework_View + */ + public function setCharset($charset) + { + $this->_engine->setCharset($charset); + return $this; + } +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/Block/Plugin.php b/system/libs/dwoo/Dwoo/Block/Plugin.php new file mode 100644 index 00000000..5f937360 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Block/Plugin.php @@ -0,0 +1,103 @@ +init() method, it will receive the parameters that + * are in the template code and is called when the block starts + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +abstract class Dwoo_Block_Plugin extends Dwoo_Plugin +{ + /** + * stores the contents of the block while it runs + * + * @var string + */ + protected $buffer = ''; + + /** + * buffers input, override only if necessary + * + * @var string $input the content that must be buffered + */ + public function buffer($input) + { + $this->buffer .= $input; + } + + // initialization code, receives the parameters from {block param1 param2} + // public function init($arg, $arg, ...); + + /** + * called when the block ends, this is most of the time followed right away by a call + * of process() but not always, so this should be used to do any shutdown operations on the + * block object, if required. + */ + public function end() + { + } + + /** + * called when the block output is required by a parent block + * + * this must read $this->buffer and return it processed + * + * @return string + */ + public function process() + { + return $this->buffer; + } + + /** + * called at compile time to define what the block should output in the compiled template code, happens when the block is declared + * + * basically this will replace the {block arg arg arg} tag in the template + * + * @param Dwoo_Compiler $compiler the compiler instance that calls this function + * @param array $params an array containing original and compiled parameters + * @param string $prepend that is just meant to allow a child class to call + * parent::postProcessing($compiler, $params, "foo();") to add a command before the + * default commands are executed + * @param string $append that is just meant to allow a child class to call + * parent::postProcessing($compiler, $params, null, "foo();") to add a command after the + * default commands are executed + * @param string $type the type is the plugin class name used + */ + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return Dwoo_Compiler::PHP_OPEN.$prepend.'$this->addStack("'.$type.'", array('.Dwoo_Compiler::implode_r($compiler->getCompiledParams($params)).'));'.$append.Dwoo_Compiler::PHP_CLOSE; + } + + /** + * called at compile time to define what the block should output in the compiled template code, happens when the block is ended + * + * basically this will replace the {/block} tag in the template + * + * @see preProcessing + * @param Dwoo_Compiler $compiler the compiler instance that calls this function + * @param array $params an array containing original and compiled parameters, see preProcessing() for more details + * @param string $prepend that is just meant to allow a child class to call + * parent::postProcessing($compiler, $params, "foo();") to add a command before the + * default commands are executed + * @param string $append that is just meant to allow a child class to call + * parent::postProcessing($compiler, $params, null, "foo();") to add a command after the + * default commands are executed + * @param string $content the entire content of the block being closed + */ + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content . Dwoo_Compiler::PHP_OPEN.$prepend.'$this->delStack();'.$append.Dwoo_Compiler::PHP_CLOSE; + } +} diff --git a/system/libs/dwoo/Dwoo/Compilation/Exception.php b/system/libs/dwoo/Dwoo/Compilation/Exception.php new file mode 100644 index 00000000..863c7979 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Compilation/Exception.php @@ -0,0 +1,38 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Compilation_Exception extends Dwoo_Exception +{ + protected $compiler; + protected $template; + + public function __construct(Dwoo_Compiler $compiler, $message) + { + $this->compiler = $compiler; + $this->template = $compiler->getDwoo()->getTemplate(); + parent::__construct('Compilation error at line '.$compiler->getLine().' in "'.$this->template->getResourceName().':'.$this->template->getResourceIdentifier().'" : '.$message); + } + + public function getCompiler() + { + return $this->compiler; + } + + public function getTemplate() + { + return $this->template; + } +} diff --git a/system/libs/dwoo/Dwoo/Compiler.php b/system/libs/dwoo/Dwoo/Compiler.php new file mode 100644 index 00000000..caf0f798 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Compiler.php @@ -0,0 +1,3086 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Compiler implements Dwoo_ICompiler +{ + /** + * constant that represents a php opening tag + * + * use it in case it needs to be adjusted + * + * @var string + */ + const PHP_OPEN = ""; + + /** + * boolean flag to enable or disable debugging output + * + * @var bool + */ + public $debug = false; + + /** + * left script delimiter + * + * @var string + */ + protected $ld = '{'; + + /** + * left script delimiter with escaped regex meta characters + * + * @var string + */ + protected $ldr = '\\{'; + + /** + * right script delimiter + * + * @var string + */ + protected $rd = '}'; + + /** + * right script delimiter with escaped regex meta characters + * + * @var string + */ + protected $rdr = '\\}'; + + /** + * defines whether the nested comments should be parsed as nested or not + * + * defaults to false (classic block comment parsing as in all languages) + * + * @var bool + */ + protected $allowNestedComments = false; + + /** + * defines whether opening and closing tags can contain spaces before valid data or not + * + * turn to true if you want to be sloppy with the syntax, but when set to false it allows + * to skip javascript and css tags as long as they are in the form "{ something", which is + * nice. default is false. + * + * @var bool + */ + protected $allowLooseOpenings = false; + + /** + * defines whether the compiler will automatically html-escape variables or not + * + * default is false + * + * @var bool + */ + protected $autoEscape = false; + + /** + * security policy object + * + * @var Dwoo_Security_Policy + */ + protected $securityPolicy; + + /** + * stores the custom plugins registered with this compiler + * + * @var array + */ + protected $customPlugins = array(); + + /** + * stores the template plugins registered with this compiler + * + * @var array + */ + protected $templatePlugins = array(); + + /** + * stores the pre- and post-processors callbacks + * + * @var array + */ + protected $processors = array('pre'=>array(), 'post'=>array()); + + /** + * stores a list of plugins that are used in the currently compiled + * template, and that are not compilable. these plugins will be loaded + * during the template's runtime if required. + * + * it is a 1D array formatted as key:pluginName value:pluginType + * + * @var array + */ + protected $usedPlugins; + + /** + * stores the template undergoing compilation + * + * @var string + */ + protected $template; + + /** + * stores the current pointer position inside the template + * + * @var int + */ + protected $pointer; + + /** + * stores the current line count inside the template for debugging purposes + * + * @var int + */ + protected $line; + + /** + * stores the current template source while compiling it + * + * @var string + */ + protected $templateSource; + + /** + * stores the data within which the scope moves + * + * @var array + */ + protected $data; + + /** + * variable scope of the compiler, set to null if + * it can not be resolved to a static string (i.e. if some + * plugin defines a new scope based on a variable array key) + * + * @var mixed + */ + protected $scope; + + /** + * variable scope tree, that allows to rebuild the current + * scope if required, i.e. when going to a parent level + * + * @var array + */ + protected $scopeTree; + + /** + * block plugins stack, accessible through some methods + * + * @see findBlock + * @see getCurrentBlock + * @see addBlock + * @see addCustomBlock + * @see injectBlock + * @see removeBlock + * @see removeTopBlock + * + * @var array + */ + protected $stack = array(); + + /** + * current block at the top of the block plugins stack, + * accessible through getCurrentBlock + * + * @see getCurrentBlock + * + * @var Dwoo_Block_Plugin + */ + protected $curBlock; + + /** + * current dwoo object that uses this compiler, or null + * + * @var Dwoo + */ + protected $dwoo; + + /** + * holds an instance of this class, used by getInstance when you don't + * provide a custom compiler in order to save resources + * + * @var Dwoo_Compiler + */ + protected static $instance; + + /** + * constructor + * + * saves the created instance so that child templates get the same one + */ + public function __construct() + { + self::$instance = $this; + } + + /** + * sets the delimiters to use in the templates + * + * delimiters can be multi-character strings but should not be one of those as they will + * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and finally "#" only if you intend to use config-vars with the #var# syntax. + * + * @param string $left left delimiter + * @param string $right right delimiter + */ + public function setDelimiters($left, $right) + { + $this->ld = $left; + $this->rd = $right; + $this->ldr = preg_quote($left, '/'); + $this->rdr = preg_quote($right, '/'); + } + + /** + * returns the left and right template delimiters + * + * @return array containing the left and the right delimiters + */ + public function getDelimiters() + { + return array($this->ld, $this->rd); + } + + /** + * sets the way to handle nested comments, if set to true + * {* foo {* some other *} comment *} will be stripped correctly. + * + * if false it will remove {* foo {* some other *} and leave "comment *}" alone, + * this is the default behavior + * + * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false) + */ + public function setNestedCommentsHandling($allow = true) { + $this->allowNestedComments = (bool) $allow; + } + + /** + * returns the nested comments handling setting + * + * @see setNestedCommentsHandling + * @return bool true if nested comments are allowed + */ + public function getNestedCommentsHandling() { + return $this->allowNestedComments; + } + + /** + * sets the tag openings handling strictness, if set to true, template tags can + * contain spaces before the first function/string/variable such as { $foo} is valid. + * + * if set to false (default setting), { $foo} is invalid but that is however a good thing + * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering + * an error, same goes for javascript. + * + * @param bool $allow true to allow loose handling, false to restore default setting + */ + public function setLooseOpeningHandling($allow = false) + { + $this->allowLooseOpenings = (bool) $allow; + } + + /** + * returns the tag openings handling strictness setting + * + * @see setLooseOpeningHandling + * @return bool true if loose tags are allowed + */ + public function getLooseOpeningHandling() + { + return $this->allowLooseOpenings; + } + + /** + * changes the auto escape setting + * + * if enabled, the compiler will automatically html-escape variables, + * unless they are passed through the safe function such as {$var|safe} + * or {safe $var} + * + * default setting is disabled/false + * + * @param bool $enabled set to true to enable, false to disable + */ + public function setAutoEscape($enabled) + { + $this->autoEscape = (bool) $enabled; + } + + /** + * returns the auto escape setting + * + * default setting is disabled/false + * + * @return bool + */ + public function getAutoEscape() + { + return $this->autoEscape; + } + + /** + * adds a preprocessor to the compiler, it will be called + * before the template is compiled + * + * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to true + * @param bool $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else you must provide a valid callback + */ + public function addPreProcessor($callback, $autoload = false) + { + if ($autoload) { + $name = str_replace('Dwoo_Processor_', '', $callback); + $class = 'Dwoo_Processor_'.$name; + + if (class_exists($class, false)) { + $callback = array(new $class($this), 'process'); + } elseif (function_exists($class)) { + $callback = $class; + } else { + $callback = array('autoload'=>true, 'class'=>$class, 'name'=>$name); + } + + $this->processors['pre'][] = $callback; + } else { + $this->processors['pre'][] = $callback; + } + } + + /** + * removes a preprocessor from the compiler + * + * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded + */ + public function removePreProcessor($callback) + { + if (($index = array_search($callback, $this->processors['pre'], true)) !== false) { + unset($this->processors['pre'][$index]); + } elseif (($index = array_search('Dwoo_Processor_'.str_replace('Dwoo_Processor_', '', $callback), $this->processors['pre'], true)) !== false) { + unset($this->processors['pre'][$index]); + } else { + $class = 'Dwoo_Processor_' . str_replace('Dwoo_Processor_', '', $callback); + foreach ($this->processors['pre'] as $index=>$proc) { + if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) { + unset($this->processors['pre'][$index]); + break; + } + } + } + } + + /** + * adds a postprocessor to the compiler, it will be called + * before the template is compiled + * + * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to true + * @param bool $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else you must provide a valid callback + */ + public function addPostProcessor($callback, $autoload = false) + { + if ($autoload) { + $name = str_replace('Dwoo_Processor_', '', $callback); + $class = 'Dwoo_Processor_'.$name; + + if (class_exists($class, false)) { + $callback = array(new $class($this), 'process'); + } elseif (function_exists($class)) { + $callback = $class; + } else { + $callback = array('autoload'=>true, 'class'=>$class, 'name'=>$name); + } + + $this->processors['post'][] = $callback; + } else { + $this->processors['post'][] = $callback; + } + } + + /** + * removes a postprocessor from the compiler + * + * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded + */ + public function removePostProcessor($callback) + { + if (($index = array_search($callback, $this->processors['post'], true)) !== false) { + unset($this->processors['post'][$index]); + } elseif (($index = array_search('Dwoo_Processor_'.str_replace('Dwoo_Processor_', '', $callback), $this->processors['post'], true)) !== false) { + unset($this->processors['post'][$index]); + } else { + $class = 'Dwoo_Processor_' . str_replace('Dwoo_Processor_', '', $callback); + foreach ($this->processors['post'] as $index=>$proc) { + if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) { + unset($this->processors['post'][$index]); + break; + } + } + } + } + + /** + * internal function to autoload processors at runtime if required + * + * @param string $class the class/function name + * @param string $name the plugin name (without Dwoo_Plugin_ prefix) + */ + protected function loadProcessor($class, $name) + { + if (!class_exists($class, false) && !function_exists($class)) { + try { + $this->dwoo->getLoader()->loadPlugin($name); + } catch (Dwoo_Exception $e) { + throw new Dwoo_Exception('Processor '.$name.' could not be found in your plugin directories, please ensure it is in a file named '.$name.'.php in the plugin directory'); + } + } + + if (class_exists($class, false)) { + return array(new $class($this), 'process'); + } + + if (function_exists($class)) { + return $class; + } + + throw new Dwoo_Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"'); + } + + /** + * adds an used plugin, this is reserved for use by the {template} plugin + * + * this is required so that plugin loading bubbles up from loaded + * template files to the current one + * + * @private + * @param string $name function name + * @param int $type plugin type (Dwoo::*_PLUGIN) + */ + public function addUsedPlugin($name, $type) + { + $this->usedPlugins[$name] = $type; + } + + /** + * returns all the plugins this template uses + * + * @private + * @return array the list of used plugins in the parsed template + */ + public function getUsedPlugins() + { + return $this->usedPlugins; + } + + /** + * adds a template plugin, this is reserved for use by the {template} plugin + * + * this is required because the template functions are not declared yet + * during compilation, so we must have a way of validating their argument + * signature without using the reflection api + * + * @private + * @param string $name function name + * @param array $params parameter array to help validate the function call + * @param string $uuid unique id of the function + * @param string $body function php code + */ + public function addTemplatePlugin($name, array $params, $uuid, $body = null) + { + $this->templatePlugins[$name] = array('params'=> $params, 'body' => $body, 'uuid' => $uuid); + } + + /** + * returns all the parsed sub-templates + * + * @private + * @return array the parsed sub-templates + */ + public function getTemplatePlugins() + { + return $this->templatePlugins; + } + + /** + * marks a template plugin as being called, which means its source must be included in the compiled template + * + * @param string $name function name + */ + public function useTemplatePlugin($name) + { + $this->templatePlugins[$name]['called'] = true; + } + + /** + * adds the custom plugins loaded into Dwoo to the compiler so it can load them + * + * @see Dwoo::addPlugin + * @param array $customPlugins an array of custom plugins + */ + public function setCustomPlugins(array $customPlugins) + { + $this->customPlugins = $customPlugins; + } + + /** + * sets the security policy object to enforce some php security settings + * + * use this if untrusted persons can modify templates, + * set it on the Dwoo object as it will be passed onto the compiler automatically + * + * @param Dwoo_Security_Policy $policy the security policy object + */ + public function setSecurityPolicy(Dwoo_Security_Policy $policy = null) + { + $this->securityPolicy = $policy; + } + + /** + * returns the current security policy object or null by default + * + * @return Dwoo_Security_Policy|null the security policy object if any + */ + public function getSecurityPolicy() + { + return $this->securityPolicy; + } + + /** + * sets the pointer position + * + * @param int $position the new pointer position + * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position + */ + public function setPointer($position, $isOffset = false) + { + if ($isOffset) { + $this->pointer += $position; + } else { + $this->pointer = $position; + } + } + + /** + * returns the current pointer position, only available during compilation of a template + * + * @return int + */ + public function getPointer() + { + return $this->pointer; + } + + /** + * sets the line number + * + * @param int $number the new line number + * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position + */ + public function setLine($number, $isOffset = false) + { + if ($isOffset) { + $this->line += $number; + } else { + $this->line = $number; + } + } + + /** + * returns the current line number, only available during compilation of a template + * + * @return int + */ + public function getLine() + { + return $this->line; + } + + /** + * returns the dwoo object that initiated this template compilation, only available during compilation of a template + * + * @return Dwoo + */ + public function getDwoo() + { + return $this->dwoo; + } + + /** + * overwrites the template that is being compiled + * + * @param string $newSource the template source that must replace the current one + * @param bool $fromPointer if set to true, only the source from the current pointer position is replaced + * @return string the template or partial template + */ + public function setTemplateSource($newSource, $fromPointer = false) + { + if ($fromPointer === true) { + $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource; + } else { + $this->templateSource = $newSource; + } + } + + /** + * returns the template that is being compiled + * + * @param mixed $fromPointer if set to true, only the source from the current pointer + * position is returned, if a number is given it overrides the current pointer + * @return string the template or partial template + */ + public function getTemplateSource($fromPointer = false) + { + if ($fromPointer === true) { + return substr($this->templateSource, $this->pointer); + } elseif (is_numeric($fromPointer)) { + return substr($this->templateSource, $fromPointer); + } else { + return $this->templateSource; + } + } + + /** + * resets the compilation pointer, effectively restarting the compilation process + * + * this is useful if a plugin modifies the template source since it might need to be recompiled + */ + public function recompile() + { + $this->setPointer(0); + } + + /** + * compiles the provided string down to php code + * + * @param string $tpl the template to compile + * @return string a compiled php string + */ + public function compile(Dwoo $dwoo, Dwoo_ITemplate $template) + { + // init vars + $tpl = $template->getSource(); + $ptr = 0; + $this->dwoo = $dwoo; + $this->template = $template; + $this->templateSource =& $tpl; + $this->pointer =& $ptr; + + while (true) { + // if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed + if ($ptr===0) { + // resets variables + $this->usedPlugins = array(); + $this->data = array(); + $this->scope =& $this->data; + $this->scopeTree = array(); + $this->stack = array(); + $this->line = 1; + $this->templatePlugins = array(); + // add top level block + $compiled = $this->addBlock('topLevelBlock', array(), 0); + $this->stack[0]['buffer'] = ''; + + if ($this->debug) echo 'COMPILER INIT
'; + + if ($this->debug) echo 'PROCESSING PREPROCESSORS ('.count($this->processors['pre']).')
'; + + // runs preprocessors + foreach ($this->processors['pre'] as $preProc) { + if (is_array($preProc) && isset($preProc['autoload'])) { + $preProc = $this->loadProcessor($preProc['class'], $preProc['name']); + } + if (is_array($preProc) && $preProc[0] instanceof Dwoo_Processor) { + $tpl = call_user_func($preProc, $tpl); + } else { + $tpl = call_user_func($preProc, $this, $tpl); + } + } + unset($preProc); + + // show template source if debug + if ($this->debug) echo '
'.print_r(htmlentities($tpl), true).'

'; + + // strips php tags if required by the security policy + if ($this->securityPolicy !== null) { + $search = array('{<\?php.*?\?>}'); + if (ini_get('short_open_tags')) { + $search = array('{<\?.*?\?>}', '{<%.*?%>}'); + } + switch($this->securityPolicy->getPhpHandling()) { + + case Dwoo_Security_Policy::PHP_ALLOW: + break; + case Dwoo_Security_Policy::PHP_ENCODE: + $tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl); + break; + case Dwoo_Security_Policy::PHP_REMOVE: + $tpl = preg_replace($search, '', $tpl); + + } + } + } + + $pos = strpos($tpl, $this->ld, $ptr); + + if ($pos === false) { + $this->push(substr($tpl, $ptr), 0); + break; + } elseif (substr($tpl, $pos-1, 1) === '\\' && substr($tpl, $pos-2, 1) !== '\\') { + $this->push(substr($tpl, $ptr, $pos-$ptr-1) . $this->ld); + $ptr = $pos+strlen($this->ld); + } elseif (preg_match('/^'.$this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr.'/s', substr($tpl, $pos), $litOpen)) { + if (!preg_match('/'.$this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr.'/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) { + throw new Dwoo_Compilation_Exception($this, 'The {literal} blocks must be closed explicitly with {/literal}'); + } + $endpos = $litClose[0][1]; + $this->push(substr($tpl, $ptr, $pos-$ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos-$pos-strlen($litOpen[0]))); + $ptr = $endpos+strlen($litClose[0][0]); + } else { + if (substr($tpl, $pos-2, 1) === '\\' && substr($tpl, $pos-1, 1) === '\\') { + $this->push(substr($tpl, $ptr, $pos-$ptr-1)); + $ptr = $pos; + } + + $this->push(substr($tpl, $ptr, $pos-$ptr)); + $ptr = $pos; + + $pos += strlen($this->ld); + if ($this->allowLooseOpenings) { + while (substr($tpl, $pos, 1) === ' ') { + $pos+=1; + } + } else { + if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") { + $ptr = $pos; + $this->push($this->ld); + continue; + } + } + + // check that there is an end tag present + if (strpos($tpl, $this->rd, $pos) === false) { + throw new Dwoo_Compilation_Exception($this, 'A template tag was not closed, started with "'.substr($tpl, $ptr, 30).'"'); + } + + + $ptr += strlen($this->ld); + $subptr = $ptr; + + while (true) { + $parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr); + + // reload loop if the compiler was reset + if ($ptr === 0) { + continue 2; + } + + $len = $subptr - $ptr; + $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n")); + $ptr += $len; + + if ($parsed === false) { + break; + } + } + + // adds additional line breaks between php closing and opening tags because the php parser removes those if there is just a single line break + if (substr($this->curBlock['buffer'], -2) === '?>' && preg_match('{^(([\r\n])([\r\n]?))}', substr($tpl, $ptr, 3), $m)) { + if ($m[3] === '') { + $ptr+=1; + $this->push($m[1].$m[1], 1); + } else { + $ptr+=2; + $this->push($m[1]."\n", 2); + } + } + } + } + + $compiled .= $this->removeBlock('topLevelBlock'); + + if ($this->debug) echo 'PROCESSING POSTPROCESSORS
'; + + foreach ($this->processors['post'] as $postProc) { + if (is_array($postProc) && isset($postProc['autoload'])) { + $postProc = $this->loadProcessor($postProc['class'], $postProc['name']); + } + if (is_array($postProc) && $postProc[0] instanceof Dwoo_Processor) { + $compiled = call_user_func($postProc, $compiled); + } else { + $compiled = call_user_func($postProc, $this, $compiled); + } + } + unset($postProc); + + if ($this->debug) echo 'COMPILATION COMPLETE : MEM USAGE : '.memory_get_usage().'
'; + + $output = "usedPlugins as $plugin=>$type) { + if ($type & Dwoo::CUSTOM_PLUGIN) { + continue; + } + + switch($type) { + + case Dwoo::BLOCK_PLUGIN: + case Dwoo::CLASS_PLUGIN: + $output .= "if (class_exists('Dwoo_Plugin_$plugin', false)===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::FUNC_PLUGIN: + $output .= "if (function_exists('Dwoo_Plugin_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::SMARTY_MODIFIER: + $output .= "if (function_exists('smarty_modifier_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::SMARTY_FUNCTION: + $output .= "if (function_exists('smarty_function_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::SMARTY_BLOCK: + $output .= "if (function_exists('smarty_block_$plugin')===false)\n\t\$this->getLoader()->loadPlugin('$plugin');\n"; + break; + case Dwoo::PROXY_PLUGIN: + $output .= $this->getDwoo()->getPluginProxy()->getPreloader($plugin); + break; + default: + throw new Dwoo_Compilation_Exception($this, 'Type error for '.$plugin.' with type'.$type); + + } + } + + foreach ($this->templatePlugins as $function => $attr) { + if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) { + $this->resolveSubTemplateDependencies($function); + } + } + foreach ($this->templatePlugins as $function) { + if (isset($function['called']) && $function['called'] === true) { + $output .= $function['body'].PHP_EOL; + } + } + + $output .= $compiled."\n?>"; + + $output = preg_replace('/(?\s*)<\?xml#is', '$1', $output); + + if ($this->debug) { + echo '
';
+			$lines = preg_split('{\r\n|\n|
}', highlight_string(($output), true)); + array_shift($lines); + foreach ($lines as $i=>$line) { + echo ($i+1).'. '.$line."\r\n"; + } + } + if ($this->debug) echo '
'; + + $this->template = $this->dwoo = null; + $tpl = null; + + return $output; + } + + /** + * checks what sub-templates are used in every sub-template so that we're sure they are all compiled + * + * @param string $function the sub-template name + */ + protected function resolveSubTemplateDependencies($function) + { + $body = $this->templatePlugins[$function]['body']; + foreach ($this->templatePlugins as $func => $attr) { + if ($func !== $function && !isset($attr['called']) && strpos($body, 'Dwoo_Plugin_'.$func) !== false) { + $this->templatePlugins[$func]['called'] = true; + $this->resolveSubTemplateDependencies($func); + } + } + $this->templatePlugins[$function]['checked'] = true; + } + + /** + * adds compiled content to the current block + * + * @param string $content the content to push + * @param int $lineCount newlines count in content, optional + */ + public function push($content, $lineCount = null) + { + if ($lineCount === null) { + $lineCount = substr_count($content, "\n"); + } + + if ($this->curBlock['buffer'] === null && count($this->stack) > 1) { + // buffer is not initialized yet (the block has just been created) + $this->stack[count($this->stack)-2]['buffer'] .= (string) $content; + $this->curBlock['buffer'] = ''; + } else { + if (!isset($this->curBlock['buffer'])) { + throw new Dwoo_Compilation_Exception($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere'); + } + // append current content to current block's buffer + $this->curBlock['buffer'] .= (string) $content; + } + $this->line += $lineCount; + } + + /** + * sets the scope + * + * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that + * variables are compiled in a more evaluative way than just $this->scope['key'] + * + * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2") + * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope + * @return array the current scope tree + */ + public function setScope($scope, $absolute = false) + { + $old = $this->scopeTree; + + if ($scope===null) { + unset($this->scope); + $this->scope = null; + } + + if (is_array($scope)===false) { + $scope = explode('.', $scope); + } + + if ($absolute===true) { + $this->scope =& $this->data; + $this->scopeTree = array(); + } + + while (($bit = array_shift($scope)) !== null) { + if ($bit === '_parent' || $bit === '_') { + array_pop($this->scopeTree); + reset($this->scopeTree); + $this->scope =& $this->data; + $cnt = count($this->scopeTree); + for ($i=0;$i<$cnt;$i++) + $this->scope =& $this->scope[$this->scopeTree[$i]]; + } elseif ($bit === '_root' || $bit === '__') { + $this->scope =& $this->data; + $this->scopeTree = array(); + } elseif (isset($this->scope[$bit])) { + $this->scope =& $this->scope[$bit]; + $this->scopeTree[] = $bit; + } else { + $this->scope[$bit] = array(); + $this->scope =& $this->scope[$bit]; + $this->scopeTree[] = $bit; + } + } + + return $old; + } + + /** + * adds a block to the top of the block stack + * + * @param string $type block type (name) + * @param array $params the parameters array + * @param int $paramtype the parameters type (see mapParams), 0, 1 or 2 + * @return string the preProcessing() method's output + */ + public function addBlock($type, array $params, $paramtype) + { + $class = 'Dwoo_Plugin_'.$type; + if (class_exists($class, false) === false) { + $this->dwoo->getLoader()->loadPlugin($type); + } + + $params = $this->mapParams($params, array($class, 'init'), $paramtype); + + $this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'class' => $class, 'buffer' => null); + $this->curBlock =& $this->stack[count($this->stack)-1]; + return call_user_func(array($class,'preProcessing'), $this, $params, '', '', $type); + } + + /** + * adds a custom block to the top of the block stack + * + * @param string $type block type (name) + * @param array $params the parameters array + * @param int $paramtype the parameters type (see mapParams), 0, 1 or 2 + * @return string the preProcessing() method's output + */ + public function addCustomBlock($type, array $params, $paramtype) + { + $callback = $this->customPlugins[$type]['callback']; + if (is_array($callback)) { + $class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0]; + } else { + $class = $callback; + } + + $params = $this->mapParams($params, array($class, 'init'), $paramtype); + + $this->stack[] = array('type' => $type, 'params' => $params, 'custom' => true, 'class' => $class, 'buffer' => null); + $this->curBlock =& $this->stack[count($this->stack)-1]; + return call_user_func(array($class,'preProcessing'), $this, $params, '', '', $type); + } + + /** + * injects a block at the top of the plugin stack without calling its preProcessing method + * + * used by {else} blocks to re-add themselves after having closed everything up to their parent + * + * @param string $type block type (name) + * @param array $params parameters array + */ + public function injectBlock($type, array $params) + { + $class = 'Dwoo_Plugin_'.$type; + if (class_exists($class, false) === false) { + $this->dwoo->getLoader()->loadPlugin($type); + } + $this->stack[] = array('type' => $type, 'params' => $params, 'custom' => false, 'class' => $class, 'buffer' => null); + $this->curBlock =& $this->stack[count($this->stack)-1]; + } + + /** + * removes the closest-to-top block of the given type and all other + * blocks encountered while going down the block stack + * + * @param string $type block type (name) + * @return string the output of all postProcessing() method's return values of the closed blocks + */ + public function removeBlock($type) + { + $output = ''; + + $pluginType = $this->getPluginType($type); + if ($pluginType & Dwoo::SMARTY_BLOCK) { + $type = 'smartyinterface'; + } + while (true) { + while ($top = array_pop($this->stack)) { + if ($top['custom']) { + $class = $top['class']; + } else { + $class = 'Dwoo_Plugin_'.$top['type']; + } + if (count($this->stack)) { + $this->curBlock =& $this->stack[count($this->stack)-1]; + $this->push(call_user_func(array($class, 'postProcessing'), $this, $top['params'], '', '', $top['buffer']), 0); + } else { + $null = null; + $this->curBlock =& $null; + $output = call_user_func(array($class, 'postProcessing'), $this, $top['params'], '', '', $top['buffer']); + } + + if ($top['type'] === $type) { + break 2; + } + } + + throw new Dwoo_Compilation_Exception($this, 'Syntax malformation, a block of type "'.$type.'" was closed but was not opened'); + break; + } + + return $output; + } + + /** + * returns a reference to the first block of the given type encountered and + * optionally closes all blocks until it finds it + * + * this is mainly used by {else} plugins to close everything that was opened + * between their parent and themselves + * + * @param string $type the block type (name) + * @param bool $closeAlong whether to close all blocks encountered while going down the block stack or not + * @return &array the array is as such: array('type'=>pluginName, 'params'=>parameter array, + * 'custom'=>bool defining whether it's a custom plugin or not, for internal use) + */ + public function &findBlock($type, $closeAlong = false) + { + if ($closeAlong===true) { + while ($b = end($this->stack)) { + if ($b['type']===$type) { + return $this->stack[key($this->stack)]; + } + $this->push($this->removeTopBlock(), 0); + } + } else { + end($this->stack); + while ($b = current($this->stack)) { + if ($b['type']===$type) { + return $this->stack[key($this->stack)]; + } + prev($this->stack); + } + } + + throw new Dwoo_Compilation_Exception($this, 'A parent block of type "'.$type.'" is required and can not be found'); + } + + /** + * returns a reference to the current block array + * + * @return &array the array is as such: array('type'=>pluginName, 'params'=>parameter array, + * 'custom'=>bool defining whether it's a custom plugin or not, for internal use) + */ + public function &getCurrentBlock() + { + return $this->curBlock; + } + + /** + * removes the block at the top of the stack and calls its postProcessing() method + * + * @return string the postProcessing() method's output + */ + public function removeTopBlock() + { + $o = array_pop($this->stack); + if ($o === null) { + throw new Dwoo_Compilation_Exception($this, 'Syntax malformation, a block of unknown type was closed but was not opened.'); + } + if ($o['custom']) { + $class = $o['class']; + } else { + $class = 'Dwoo_Plugin_'.$o['type']; + } + + $this->curBlock =& $this->stack[count($this->stack)-1]; + + return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']); + } + + /** + * returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out of the given parameter array + * + * @param array $params parameter array + * @return array filtered parameters + */ + public function getCompiledParams(array $params) + { + foreach ($params as $k=>$p) { + if (is_array($p)) { + $params[$k] = $p[0]; + } + } + return $params; + } + + /** + * returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given parameter array + * + * @param array $params parameter array + * @return array filtered parameters + */ + public function getRealParams(array $params) + { + foreach ($params as $k=>$p) { + if (is_array($p)) { + $params[$k] = $p[1]; + } + } + return $params; + } + + /** + * entry point of the parser, it redirects calls to other parse* functions + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parse($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + if ($to === null) { + $to = strlen($in); + } + $first = substr($in, $from, 1); + + if ($first === false) { + throw new Dwoo_Compilation_Exception($this, 'Unexpected EOF, a template tag was not closed'); + } + + while ($first===" " || $first==="\n" || $first==="\t" || $first==="\r") { + if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) { + // end template tag + $pointer += strlen($this->rd); + if ($this->debug) echo 'TEMPLATE PARSING ENDED
'; + return false; + } + $from++; + if ($pointer !== null) { + $pointer++; + } + if ($from >= $to) { + if (is_array($parsingParams)) { + return $parsingParams; + } else { + return ''; + } + } + $first = $in[$from]; + } + + $substr = substr($in, $from, $to-$from); + + if ($this->debug) echo '
PARSE CALL : PARSING "'.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...':'').'" @ '.$from.':'.$to.' in '.$curBlock.' : pointer='.$pointer.'
'; + $parsed = ""; + + if ($curBlock === 'root' && $first === '*') { + $src = $this->getTemplateSource(); + $startpos = $this->getPointer() - strlen($this->ld); + if (substr($src, $startpos, strlen($this->ld)) === $this->ld) { + if ($startpos > 0) { + do { + $char = substr($src, --$startpos, 1); + if ($char == "\n") { + $startpos++; + $whitespaceStart = true; + break; + } + } while ($startpos > 0 && ($char == ' ' || $char == "\t")); + } + + if (!isset($whitespaceStart)) { + $startpos = $this->getPointer(); + } else { + $pointer -= $this->getPointer() - $startpos; + } + + if ($this->allowNestedComments && strpos($src, $this->ld.'*', $this->getPointer()) !== false) { + $comOpen = $this->ld.'*'; + $comClose = '*'.$this->rd; + $level = 1; + $start = $startpos; + $ptr = $this->getPointer() + '*'; + + while ($level > 0 && $ptr < strlen($src)) { + $open = strpos($src, $comOpen, $ptr); + $close = strpos($src, $comClose, $ptr); + + if ($open !== false && $close !== false) { + if ($open < $close) { + $ptr = $open + strlen($comOpen); + $level++; + } else { + $ptr = $close + strlen($comClose); + $level--; + } + } elseif ($open !== false) { + $ptr = $open + strlen($comOpen); + $level++; + } elseif ($close !== false) { + $ptr = $close + strlen($comClose); + $level--; + } else { + $ptr = strlen($src); + } + } + $endpos = $ptr - strlen('*'.$this->rd); + } else { + $endpos = strpos($src, '*'.$this->rd, $startpos); + if ($endpos == false) { + throw new Dwoo_Compilation_Exception($this, 'Un-ended comment'); + } + } + $pointer += $endpos - $startpos + strlen('*'.$this->rd); + if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos+strlen('*'.$this->rd)), $m)) { + $pointer += strlen($m[0]); + $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld))); + } + return false; + } + } + + if ($first==='$') { + // var + $out = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer); + $parsed = 'var'; + } elseif ($first==='%' && preg_match('#^%[a-z]#i', $substr)) { + // const + $out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer); + } elseif ($first==='"' || $first==="'") { + // string + $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer); + } elseif (preg_match('/^[a-z][a-z0-9_]*(?:::[a-z][a-z0-9_]*)?('.(is_array($parsingParams)||$curBlock!='root'?'':'\s+[^(]|').'\s*\(|\s*'.$this->rdr.'|\s*;)/i', $substr)) { + // func + $out = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer); + $parsed = 'func'; + } elseif ($first === ';') { + // instruction end + if ($this->debug) echo 'END OF INSTRUCTION
'; + if ($pointer !== null) { + $pointer++; + } + return $this->parse($in, $from+1, $to, false, 'root', $pointer); + } elseif ($curBlock === 'root' && preg_match('#^/([a-z][a-z0-9_]*)?#i', $substr, $match)) { + // close block + if (!empty($match[1]) && $match[1] == 'else') { + throw new Dwoo_Compilation_Exception($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed'); + } + if (!empty($match[1]) && $match[1] == 'elseif') { + throw new Dwoo_Compilation_Exception($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them'); + } + if ($pointer !== null) { + $pointer += strlen($match[0]); + } + if (empty($match[1])) { + if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') { + $pointer -= strlen($match[0]); + } + if ($this->debug) echo 'TOP BLOCK CLOSED
'; + return $this->removeTopBlock(); + } else { + if ($this->debug) echo 'BLOCK OF TYPE '.$match[1].' CLOSED
'; + return $this->removeBlock($match[1]); + } + } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) { + // end template tag + if ($this->debug) echo 'TAG PARSING ENDED
'; + $pointer += strlen($this->rd); + return false; + } elseif (is_array($parsingParams) && preg_match('#^([a-z0-9_]+\s*=)(?:\s+|[^=]).*#i', $substr, $match)) { + // named parameter + if ($this->debug) echo 'NAMED PARAM FOUND
'; + $len = strlen($match[1]); + while (substr($in, $from+$len, 1)===' ') { + $len++; + } + if ($pointer !== null) { + $pointer += $len; + } + + $output = array(trim(substr(trim($match[1]), 0, -1)), $this->parse($in, $from+$len, $to, false, 'namedparam', $pointer)); + + $parsingParams[] = $output; + return $parsingParams; + } elseif (preg_match('#^([a-z0-9_]+::\$[a-z0-9_]+)#i', $substr, $match)) { + // static member access + $parsed = 'var'; + if (is_array($parsingParams)) { + $parsingParams[] = array($match[1], $match[1]); + $out = $parsingParams; + } else { + $out = $match[1]; + } + $pointer += strlen($match[1]); + } elseif ($substr!=='' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) { + // unquoted string, bool or number + $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer); + } else { + // parse error + throw new Dwoo_Compilation_Exception($this, 'Parse error in "'.substr($in, $from, $to-$from).'"'); + } + + if (empty($out)) { + return ''; + } + + $substr = substr($in, $pointer, $to-$pointer); + + // var parsed, check if any var-extension applies + if ($parsed==='var') { + if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) { + if($this->debug) echo 'PARSING POST-VAR EXPRESSION '.$substr.'
'; + // parse expressions + $pointer += strlen($match[0]) - 1; + if (is_array($parsingParams)) { + if ($match[2] == '$') { + $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer); + } else { + $expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer); + } + $out[count($out)-1][0] .= $match[1] . $expr[0][0]; + $out[count($out)-1][1] .= $match[1] . $expr[0][1]; + } else { + if ($match[2] == '$') { + $expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer); + } else { + $expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer); + } + if (is_array($out) && is_array($expr)) { + $out[0] .= $match[1] . $expr[0]; + $out[1] .= $match[1] . $expr[1]; + } elseif (is_array($out)) { + $out[0] .= $match[1] . $expr; + $out[1] .= $match[1] . $expr; + } elseif (is_array($expr)) { + $out .= $match[1] . $expr[0]; + } else { + $out .= $match[1] . $expr; + } + } + } else if ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) { + if($this->debug) echo 'PARSING POST-VAR ASSIGNMENT '.$substr.'
'; + // parse assignment + $value = $match[2]; + $operator = trim($match[1]); + if (substr($value, 0, 1) == '=') { + throw new Dwoo_Compilation_Exception($this, 'Unexpected "=" in '.$substr.''); + } + + if ($pointer !== null) { + $pointer += strlen($match[1]); + } + + if ($operator !== '++' && $operator !== '--') { + $parts = array(); + $ptr = 0; + $parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr); + $pointer += $ptr; + + // load if plugin + try { + $this->getPluginType('if'); + } catch (Dwoo_Exception $e) { + throw new Dwoo_Compilation_Exception($this, 'Assignments require the "if" plugin to be accessible'); + } + + $parts = $this->mapParams($parts, array('Dwoo_Plugin_if', 'init'), 1); + $parts = $this->getCompiledParams($parts); + + $value = Dwoo_Plugin_if::replaceKeywords($parts['*'], $this); + $echo = ''; + } else { + $value = array(); + $echo = 'echo '; + } + + if ($this->autoEscape) { + $out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out); + } + $out = Dwoo_Compiler::PHP_OPEN. $echo . $out . $operator . implode(' ', $value) . Dwoo_Compiler::PHP_CLOSE; + } + } + + if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^\|@?[a-z0-9_]+(:.*)?#i', $substr, $match)) { + // parse modifier on funcs or vars + $srcPointer = $pointer; + if (is_array($parsingParams)) { + $tmp = $this->replaceModifiers(array(null, null, $out[count($out)-1][0], $match[0]), 'var', $pointer); + $out[count($out)-1][0] = $tmp; + $out[count($out)-1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer); + } else { + $out = $this->replaceModifiers(array(null, null, $out, $match[0]), 'var', $pointer); + } + } + + // func parsed, check if any func-extension applies + if ($parsed==='func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z].*)?#is', $substr, $match)) { + // parse method call or property read + $ptr = 0; + + if (is_array($parsingParams)) { + $output = $this->parseMethodCall($out[count($out)-1][1], $match[0], $curBlock, $ptr); + + $out[count($out)-1][0] = $output; + $out[count($out)-1][1] .= substr($match[0], 0, $ptr); + } else { + $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr); + } + + $pointer += $ptr; + } + + if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) { + return self::PHP_OPEN .'echo '.$out.';'. self::PHP_CLOSE; + } else { + return $out; + } + } + + /** + * parses a function call + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $cmdstr = substr($in, $from, $to-$from); + preg_match('/^([a-z][a-z0-9_]*(?:::[a-z][a-z0-9_]*)?)(\s*'.$this->rdr.'|\s*;)?/i', $cmdstr, $match); + + if (empty($match[1])) { + throw new Dwoo_Compilation_Exception($this, 'Parse error, invalid function name : '.substr($cmdstr, 0, 15)); + } + + $func = $match[1]; + + if (!empty($match[2])) { + $cmdstr = $match[1]; + } + + if ($this->debug) echo 'FUNC FOUND ('.$func.')
'; + + $paramsep = ''; + + if (is_array($parsingParams) || $curBlock != 'root') { + $paramspos = strpos($cmdstr, '('); + $paramsep = ')'; + } elseif(preg_match_all('#[a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) { + $paramspos = $match[1][0][1]; + $paramsep = substr($match[1][0][0], -1) === '(' ? ')':''; + if($paramsep === ')') { + $paramspos += strlen($match[1][0][0]) - 1; + if(substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') { + $paramsep = ''; + if(strlen($match[1][0][0]) > 1) { + $paramspos--; + } + } + } + } else { + $paramspos = false; + } + + $state = 0; + + if ($paramspos === false) { + $params = array(); + + if ($curBlock !== 'root') { + return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer); + } + } else { + if ($curBlock === 'condition') { + // load if plugin + $this->getPluginType('if'); + if (Dwoo_Plugin_if::replaceKeywords(array($func), $this) !== array($func)) { + return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer); + } + } + $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos-strlen($func))); + $paramstr = substr($cmdstr, $paramspos+1); + if (substr($paramstr, -1, 1) === $paramsep) { + $paramstr = substr($paramstr, 0, -1); + } + + if (strlen($paramstr)===0) { + $params = array(); + $paramstr = ''; + } else { + $ptr = 0; + $params = array(); + if ($func === 'empty') { + $params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr); + } else { + while ($ptr < strlen($paramstr)) { + while (true) { + if ($ptr >= strlen($paramstr)) { + break 2; + } + + if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') { + if ($this->debug) echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT '.$ptr.'
'; + break 2; + } elseif ($paramstr[$ptr] === ';') { + $ptr++; + if ($this->debug) echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT '.$ptr.'
'; + break 2; + } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') { + if ($this->debug) echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT '.$ptr.'
'; + break 2; + } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) { + if ($this->debug) echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT '.$ptr.'
'; + break 2; + } + + if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") { + $ptr++; + } else { + break; + } + } + + if ($this->debug) echo 'FUNC START PARAM PARSING WITH POINTER AT '.$ptr.'
'; + + if ($func === 'if' || $func === 'elseif' || $func === 'tif') { + $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr); + } else { + $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr); + } + + if ($this->debug) echo 'PARAM PARSED, POINTER AT '.$ptr.' ('.substr($paramstr, $ptr-1, 3).')
'; + } + } + $paramstr = substr($paramstr, 0, $ptr); + $state = 0; + foreach ($params as $k=>$p) { + if (is_array($p) && is_array($p[1])) { + $state |= 2; + } else { + if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) { + $params[$k] = array($m[2], array('true', 'true')); + } else { + if ($state & 2) { + throw new Dwoo_Compilation_Exception($this, 'You can not use an unnamed parameter after a named one'); + } + $state |= 1; + } + } + } + } + } + + if ($pointer !== null) { + $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0); + if ($this->debug) echo 'FUNC ADDS '.((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)).' TO POINTER
'; + } + + if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) { + $pluginType = Dwoo::NATIVE_PLUGIN; + } else { + $pluginType = $this->getPluginType($func); + } + + // blocks + if ($pluginType & Dwoo::BLOCK_PLUGIN) { + if ($curBlock !== 'root' || is_array($parsingParams)) { + throw new Dwoo_Compilation_Exception($this, 'Block plugins can not be used as other plugin\'s arguments'); + } + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + return $this->addCustomBlock($func, $params, $state); + } else { + return $this->addBlock($func, $params, $state); + } + } elseif ($pluginType & Dwoo::SMARTY_BLOCK) { + if ($curBlock !== 'root' || is_array($parsingParams)) { + throw new Dwoo_Compilation_Exception($this, 'Block plugins can not be used as other plugin\'s arguments'); + } + + if ($state & 2) { + array_unshift($params, array('__functype', array($pluginType, $pluginType))); + array_unshift($params, array('__funcname', array($func, $func))); + } else { + array_unshift($params, array($pluginType, $pluginType)); + array_unshift($params, array($func, $func)); + } + + return $this->addBlock('smartyinterface', $params, $state); + } + + // funcs + if ($pluginType & Dwoo::NATIVE_PLUGIN || $pluginType & Dwoo::SMARTY_FUNCTION || $pluginType & Dwoo::SMARTY_BLOCK) { + $params = $this->mapParams($params, null, $state); + } elseif ($pluginType & Dwoo::CLASS_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $params = $this->mapParams($params, array($this->customPlugins[$func]['class'], $this->customPlugins[$func]['function']), $state); + } else { + $params = $this->mapParams($params, array('Dwoo_Plugin_'.$func, ($pluginType & Dwoo::COMPILABLE_PLUGIN) ? 'compile' : 'process'), $state); + } + } elseif ($pluginType & Dwoo::FUNC_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state); + } else { + $params = $this->mapParams($params, 'Dwoo_Plugin_'.$func.(($pluginType & Dwoo::COMPILABLE_PLUGIN) ? '_compile' : ''), $state); + } + } elseif ($pluginType & Dwoo::SMARTY_MODIFIER) { + $output = 'smarty_modifier_'.$func.'('.implode(', ', $params).')'; + } elseif ($pluginType & Dwoo::PROXY_PLUGIN) { + $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state); + } elseif ($pluginType & Dwoo::TEMPLATE_PLUGIN) { + // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values)) + $map = array(); + foreach ($this->templatePlugins[$func]['params'] as $param=>$defValue) { + if ($param == 'rest') { + $param = '*'; + } + $hasDefault = $defValue !== null; + if ($defValue === 'null') { + $defValue = null; + } elseif ($defValue === 'false') { + $defValue = false; + } elseif ($defValue === 'true') { + $defValue = true; + } elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) { + $defValue = substr($defValue, 1, -1); + } + $map[] = array($param, $hasDefault, $defValue); + } + + $params = $this->mapParams($params, null, $state, $map); + } + + // only keep php-syntax-safe values for non-block plugins + foreach ($params as &$p) { + $p = $p[0]; + } + if ($pluginType & Dwoo::NATIVE_PLUGIN) { + if ($func === 'do') { + if (isset($params['*'])) { + $output = implode(';', $params['*']).';'; + } else { + $output = ''; + } + + if (is_array($parsingParams) || $curBlock !== 'root') { + throw new Dwoo_Compilation_Exception($this, 'Do can not be used inside another function or block'); + } else { + return self::PHP_OPEN.$output.self::PHP_CLOSE; + } + } else { + if (isset($params['*'])) { + $output = $func.'('.implode(', ', $params['*']).')'; + } else { + $output = $func.'()'; + } + } + } elseif ($pluginType & Dwoo::FUNC_PLUGIN) { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $funcCompiler = $this->customPlugins[$func]['callback']; + } else { + $funcCompiler = 'Dwoo_Plugin_'.$func.'_compile'; + } + array_unshift($params, $this); + $output = call_user_func_array($funcCompiler, $params); + } else { + array_unshift($params, '$this'); + $params = self::implode_r($params); + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + $output = 'call_user_func(\''.$callback.'\', '.$params.')'; + } else { + $output = 'Dwoo_Plugin_'.$func.'('.$params.')'; + } + } + } elseif ($pluginType & Dwoo::CLASS_PLUGIN) { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (!is_array($callback)) { + if (!method_exists($callback, 'compile')) { + throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use'); + } + if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) { + $funcCompiler = array($callback, 'compile'); + } else { + $funcCompiler = array(new $callback, 'compile'); + } + } else { + $funcCompiler = $callback; + } + } else { + $funcCompiler = array('Dwoo_Plugin_'.$func, 'compile'); + array_unshift($params, $this); + } + $output = call_user_func_array($funcCompiler, $params); + } else { + $params = self::implode_r($params); + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (!is_array($callback)) { + if (!method_exists($callback, 'process')) { + throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "process" method to be usable, or you should provide a full callback to the method to use'); + } + if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) { + $output = 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')'; + } else { + $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback.'\'), \'process\'), '.$params.')'; + } + } elseif (is_object($callback[0])) { + $output = 'call_user_func(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), '.$params.')'; + } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) { + $output = 'call_user_func(array(\''.$callback[0].'\', \''.$callback[1].'\'), '.$params.')'; + } else { + $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback[0].'\'), \''.$callback[1].'\'), '.$params.')'; + } + if (empty($params)) { + $output = substr($output, 0, -3).')'; + } + } else { + $output = '$this->classCall(\''.$func.'\', array('.$params.'))'; + } + } + } elseif ($pluginType & Dwoo::PROXY_PLUGIN) { + $output = call_user_func(array($this->dwoo->getPluginProxy(), 'getCode'), $func, $params); + } elseif ($pluginType & Dwoo::SMARTY_FUNCTION) { + if (isset($params['*'])) { + $params = self::implode_r($params['*'], true); + } else { + $params = ''; + } + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (is_array($callback)) { + if (is_object($callback[0])) { + $output = 'call_user_func_array(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array(array('.$params.'), $this))'; + } else { + $output = 'call_user_func_array(array(\''.$callback[0].'\', \''.$callback[1].'\'), array(array('.$params.'), $this))'; + } + } else { + $output = $callback.'(array('.$params.'), $this)'; + } + } else { + $output = 'smarty_function_'.$func.'(array('.$params.'), $this)'; + } + } elseif ($pluginType & Dwoo::TEMPLATE_PLUGIN) { + array_unshift($params, '$this'); + $params = self::implode_r($params); + $output = 'Dwoo_Plugin_'.$func.'_'.$this->templatePlugins[$func]['uuid'].'('.$params.')'; + $this->templatePlugins[$func]['called'] = true; + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, $output); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, $output); + } else { + return $output; + } + } + + /** + * parses a string + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseString($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $substr = substr($in, $from, $to-$from); + $first = $substr[0]; + + if ($this->debug) echo 'STRING FOUND (in '.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...':'').')
'; + $strend = false; + $o = $from+1; + while ($strend === false) { + $strend = strpos($in, $first, $o); + if ($strend === false) { + throw new Dwoo_Compilation_Exception($this, 'Unfinished string, started with '.substr($in, $from, $to-$from)); + } + if (substr($in, $strend-1, 1) === '\\') { + $o = $strend+1; + $strend = false; + } + } + if ($this->debug) echo 'STRING DELIMITED: '.substr($in, $from, $strend+1-$from).'
'; + + $srcOutput = substr($in, $from, $strend+1-$from); + + if ($pointer !== null) { + $pointer += strlen($srcOutput); + } + + $output = $this->replaceStringVars($srcOutput, $first); + + // handle modifiers + if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend+1-$from), $match)) { + $modstr = $match[1]; + + if ($curBlock === 'root' && substr($modstr, -1) === '}') { + $modstr = substr($modstr, 0, -1); + } + $modstr = str_replace('\\'.$first, $first, $modstr); + $ptr = 0; + $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr); + + $strend += $ptr; + if ($pointer !== null) { + $pointer += $ptr; + } + $srcOutput .= substr($substr, $strend+1-$from, $ptr); + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, substr($srcOutput, 1, -1)); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, substr($srcOutput, 1, -1)); + } else { + return $output; + } + } + + /** + * parses a constant + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $substr = substr($in, $from, $to-$from); + + if ($this->debug) { + echo 'CONST FOUND : '.$substr.'
'; + } + + if (!preg_match('#^%([a-z0-9_:]+)#i', $substr, $m)) { + throw new Dwoo_Compilation_Exception($this, 'Invalid constant'); + } + + if ($pointer !== null) { + $pointer += strlen($m[0]); + } + + $output = $this->parseConstKey($m[1], $curBlock); + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, $m[1]); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, $m[1]); + } else { + return $output; + } + } + + /** + * parses a constant + * + * @param string $key the constant to parse + * @param string $curBlock the current parser-block being processed + * @return string parsed constant + */ + protected function parseConstKey($key, $curBlock) + { + if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === Dwoo_Security_Policy::CONST_DISALLOW) { + return 'null'; + } + + if ($curBlock !== 'root') { + $output = '(defined("'.$key.'") ? '.$key.' : null)'; + } else { + $output = $key; + } + + return $output; + } + + /** + * parses a variable + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $substr = substr($in, $from, $to-$from); + + if (preg_match('#(\$?\.?[a-z0-9_:]*(?:(?:(?:\.|->)(?:[a-z0-9_:]+|(?R))|\[(?:[a-z0-9_:]+|(?R)|(["\'])[^\2]*?\2)\]))*)' . // var key + ($curBlock==='root' || $curBlock==='function' || $curBlock==='namedparam' || $curBlock==='condition' || $curBlock==='variable' || $curBlock==='expression' ? '(\(.*)?' : '()') . // method call + ($curBlock==='root' || $curBlock==='function' || $curBlock==='namedparam' || $curBlock==='condition' || $curBlock==='variable' || $curBlock==='delimited_string' ? '((?:(?:[+/*%=-])(?:(?_:-]+(?:\([^)]*\))?|(?'))); + $key = substr($match[1], 1, strrpos($match[1], '->')-1); + $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3]; + } + + if ($hasModifiers) { + $matchedLength -= strlen($match[5]); + } + + if ($pointer !== null) { + $pointer += $matchedLength; + } + + // replace useless brackets by dot accessed vars + $key = preg_replace('#\[([^$%\[.>-]+)\]#', '.$1', $key); + + // prevent $foo->$bar calls because it doesn't seem worth the trouble + if (strpos($key, '->$') !== false) { + throw new Dwoo_Compilation_Exception($this, 'You can not access an object\'s property using a variable name.'); + } + + if ($this->debug) { + if ($hasMethodCall) { + echo 'METHOD CALL FOUND : $'.$key.substr($methodCall, 0, 30).'
'; + } else { + echo 'VAR FOUND : $'.$key.'
'; + } + } + + $key = str_replace('"', '\\"', $key); + + $cnt=substr_count($key, '$'); + if ($cnt > 0) { + $uid = 0; + $parsed = array($uid => ''); + $current =& $parsed; + $curTxt =& $parsed[$uid++]; + $tree = array(); + $chars = str_split($key, 1); + $inSplittedVar = false; + $bracketCount = 0; + + while (($char = array_shift($chars)) !== null) { + if ($char === '[') { + if (count($tree) > 0) { + $bracketCount++; + } else { + $tree[] =& $current; + $current[$uid] = array($uid+1 => ''); + $current =& $current[$uid++]; + $curTxt =& $current[$uid++]; + continue; + } + } elseif ($char === ']') { + if ($bracketCount > 0) { + $bracketCount--; + } else { + $current =& $tree[count($tree)-1]; + array_pop($tree); + if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') { + $current[$uid] = ''; + $curTxt =& $current[$uid++]; + } + continue; + } + } elseif ($char === '$') { + if (count($tree) == 0) { + $curTxt =& $current[$uid++]; + $inSplittedVar = true; + } + } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) { + $curTxt =& $current[$uid++]; + $inSplittedVar = false; + } + + $curTxt .= $char; + } + unset($uid, $current, $curTxt, $tree, $chars); + + if ($this->debug) echo 'RECURSIVE VAR REPLACEMENT : '.$key.'
'; + + $key = $this->flattenVarTree($parsed); + + if ($this->debug) echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key.'
'; + + $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("'.$key.'")'); + } else { + $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock); + } + + // methods + if ($hasMethodCall) { + $ptr = 0; + + $output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr); + + if ($pointer !== null) { + $pointer += $ptr; + } + $matchedLength += $ptr; + } + + if ($hasExpression) { + // expressions + preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch); + + foreach ($expMatch[1] as $k=>$operator) { + if (substr($expMatch[2][$k], 0, 1)==='=') { + $assign = true; + if ($operator === '=') { + throw new Dwoo_Compilation_Exception($this, 'Invalid expression '.$substr.', can not use "==" in expressions'); + } + if ($curBlock !== 'root') { + throw new Dwoo_Compilation_Exception($this, 'Invalid expression '.$substr.', assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}'); + } + $operator .= '='; + $expMatch[2][$k] = substr($expMatch[2][$k], 1); + } + + if (substr($expMatch[2][$k], 0, 1)==='-' && strlen($expMatch[2][$k]) > 1) { + $operator .= '-'; + $expMatch[2][$k] = substr($expMatch[2][$k], 1); + } + if (($operator==='+'||$operator==='-') && $expMatch[2][$k]===$operator) { + $output = '('.$output.$operator.$operator.')'; + break; + } elseif (substr($expMatch[2][$k], 0, 1) === '$') { + $output = '('.$output.' '.$operator.' '.$this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')'; + } elseif (substr($expMatch[2][$k], 0, 1) === '%') { + $output = '('.$output.' '.$operator.' '.$this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')'; + } elseif (!empty($expMatch[2][$k])) { + $output = '('.$output.' '.$operator.' '.str_replace(',', '.', $expMatch[2][$k]).')'; + } else { + throw new Dwoo_Compilation_Exception($this, 'Unfinished expression '.$substr.', missing var or number after math operator'); + } + } + } + + if ($this->autoEscape === true) { + $output = '(is_string($tmp='.$output.') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)'; + } + + // handle modifiers + if ($curBlock !== 'modifier' && $hasModifiers) { + $ptr = 0; + $output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr); + if ($pointer !== null) { + $pointer += $ptr; + } + $matchedLength += $ptr; + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($output, $key); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($output, $key); + } elseif ($curBlock === 'string' || $curBlock === 'delimited_string') { + return array($matchedLength, $output); + } elseif ($curBlock === 'expression' || $curBlock === 'variable') { + return $output; + } elseif (isset($assign)) { + return self::PHP_OPEN.$output.';'.self::PHP_CLOSE; + } else { + return $output; + } + } else { + if ($curBlock === 'string' || $curBlock === 'delimited_string') { + return array(0, ''); + } else { + throw new Dwoo_Compilation_Exception($this, 'Invalid variable name '.$substr.''); + } + } + } + + /** + * parses any number of chained method calls/property reads + * + * @param string $output the variable or whatever upon which the method are called + * @param string $methodCall method call source, starting at "->" + * @param string $curBlock the current parser-block being processed + * @param int $pointer a reference to a pointer that will be increased by the amount of characters parsed + * @return string parsed call(s)/read(s) + */ + protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer) + { + $ptr = 0; + $len = strlen($methodCall); + + while ($ptr < $len) { + if (strpos($methodCall, '->', $ptr) === $ptr) { + $ptr += 2; + } + + if (in_array($methodCall[$ptr], array(';', '/', ' ', "\t", "\r", "\n", ')', '+', '*', '%', '=', '-', '|')) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd) { + // break char found + break; + } + + if(!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) { + throw new Dwoo_Compilation_Exception($this, 'Invalid method name : '.substr($methodCall, $ptr, 20)); + } + + if (empty($methMatch[2])) { + // property + if ($curBlock === 'root') { + $output .= '->'.$methMatch[1]; + } else { + $output = '(($tmp = '.$output.') ? $tmp->'.$methMatch[1].' : null)'; + } + $ptr += strlen($methMatch[1]); + } else { + // method + if (substr($methMatch[2], 0, 2) === '()') { + $parsedCall = '->'.$methMatch[1].'()'; + $ptr += strlen($methMatch[1]) + 2; + } else { + $parsedCall = '->'.$this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr); + } + if ($curBlock === 'root') { + $output .= $parsedCall; + } else { + $output = '(($tmp = '.$output.') ? $tmp'.$parsedCall.' : null)'; + } + } + } + + $pointer += $ptr; + return $output; + } + + /** + * parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save runtime processing time + * + * @param string $key the variable to parse + * @param string $curBlock the current parser-block being processed + * @return string parsed variable + */ + protected function parseVarKey($key, $curBlock) + { + if ($key === '') { + return '$this->scope'; + } + if (substr($key, 0, 1) === '.') { + $key = 'dwoo'.$key; + } + if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) { + $global = strtoupper($m[1]); + if ($global === 'COOKIES') { + $global = 'COOKIE'; + } + $key = '$_'.$global; + foreach (explode('.', ltrim($m[2], '.')) as $part) + $key .= '['.var_export($part, true).']'; + if ($curBlock === 'root') { + $output = $key; + } else { + $output = '(isset('.$key.')?'.$key.':null)'; + } + } elseif (preg_match('#dwoo\.const\.([a-z0-9_:]+)#i', $key, $m)) { + return $this->parseConstKey($m[1], $curBlock); + } elseif ($this->scope !== null) { + if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) { + if ($key === 'dwoo') { + $output = '$this->globals'; + } elseif ($key === '_root' || $key === '__') { + $output = '$this->data'; + } elseif ($key === '_parent' || $key === '_') { + $output = '$this->readParentVar(1)'; + } elseif ($key === '_key') { + $output = '$tmp_key'; + } else { + if ($curBlock === 'root') { + $output = '$this->scope["'.$key.'"]'; + } else { + $output = '(isset($this->scope["'.$key.'"]) ? $this->scope["'.$key.'"] : null)'; + } + } + } else { + preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m); + + $i = $m[2][0]; + if ($i === '_parent' || $i === '_') { + $parentCnt = 0; + + while (true) { + $parentCnt++; + array_shift($m[2]); + array_shift($m[1]); + if (current($m[2]) === '_parent') { + continue; + } + break; + } + + $output = '$this->readParentVar('.$parentCnt.')'; + } else { + if ($i === 'dwoo') { + $output = '$this->globals'; + array_shift($m[2]); + array_shift($m[1]); + } elseif ($i === '_root' || $i === '__') { + $output = '$this->data'; + array_shift($m[2]); + array_shift($m[1]); + } elseif ($i === '_key') { + $output = '$tmp_key'; + } else { + $output = '$this->scope'; + } + + while (count($m[1]) && $m[1][0] !== '->') { + $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]); + if(substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") { + $output .= '['.$m[2][0].']'; + } else { + $output .= '["'.$m[2][0].'"]'; + } + array_shift($m[2]); + array_shift($m[1]); + } + + if ($curBlock !== 'root') { + $output = '(isset('.$output.') ? '.$output.':null)'; + } + } + + if (count($m[2])) { + unset($m[0]); + $output = '$this->readVarInto('.str_replace("\n", '', var_export($m, true)).', '.$output.', '.($curBlock == 'root' ? 'false': 'true').')'; + } + } + } else { + preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m); + unset($m[0]); + $output = '$this->readVar('.str_replace("\n", '', var_export($m, true)).')'; + } + + return $output; + } + + /** + * flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz, + * it computes the contents of the brackets first and works out from there + * + * @param array $tree the variable tree parsed by he parseVar() method that must be flattened + * @param bool $recursed leave that to false by default, it is only for internal use + * @return string flattened tree + */ + protected function flattenVarTree(array $tree, $recursed=false) + { + $out = $recursed ? '".$this->readVarInto(' : ''; + foreach ($tree as $bit) { + if (is_array($bit)) { + $out.='.'.$this->flattenVarTree($bit, false); + } else { + $key = str_replace('"', '\\"', $bit); + + if (substr($key, 0, 1)==='$') { + $out .= '".'.$this->parseVar($key, 0, strlen($key), false, 'variable').'."'; + } else { + $cnt = substr_count($key, '$'); + + if ($this->debug) echo 'PARSING SUBVARS IN : '.$key.'
'; + if ($cnt > 0) { + while (--$cnt >= 0) { + if (isset($last)) { + $last = strrpos($key, '$', - (strlen($key) - $last + 1)); + } else { + $last = strrpos($key, '$'); + } + preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*'. + '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch); + + $len = strlen($submatch[0]); + $key = substr_replace( + $key, + preg_replace_callback( + '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)'. + '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', + array($this, 'replaceVarKeyHelper'), substr($key, $last, $len) + ), + $last, + $len + ); + if ($this->debug) echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key.'
'; + } + unset($last); + + $out .= $key; + } else { + $out .= $key; + } + } + } + } + $out .= $recursed ? ', true)."' : ''; + return $out; + } + + /** + * helper function that parses a variable + * + * @param array $match the matched variable, array(1=>"string match") + * @return string parsed variable + */ + protected function replaceVarKeyHelper($match) + { + return '".'.$this->parseVar($match[0], 0, strlen($match[0]), false, 'variable').'."'; + } + + /** + * parses various constants, operators or non-quoted strings + * + * @param string $in the string within which we must parse something + * @param int $from the starting offset of the parsed area + * @param int $to the ending offset of the parsed area + * @param mixed $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by default + * @param string $curBlock the current parser-block being processed + * @param mixed $pointer a reference to a pointer that will be increased by the amount of characters parsed, or null by default + * @return string parsed values + */ + protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock='', &$pointer = null) + { + $first = $in[$from]; + $substr = substr($in, $from, $to-$from); + + $end = strlen($substr); + + if ($curBlock === 'condition') { + $breakChars = array('(', ')', ' ', '||', '&&', '|', '&', '>=', '<=', '===', '==', '=', '!==', '!=', '<<', '<', '>>', '>', '^', '~', ',', '+', '-', '*', '/', '%', '!', '?', ':', $this->rd, ';'); + } elseif ($curBlock === 'modifier') { + $breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ";", $this->rd); + } elseif ($curBlock === 'expression') { + $breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ";", $this->rd); + } else { + $breakChars = array(' ', ',', ')', "\r", "\n", "\t", ";", $this->rd); + } + + $breaker = false; + while (list($k,$char) = each($breakChars)) { + $test = strpos($substr, $char); + if ($test !== false && $test < $end) { + $end = $test; + $breaker = $k; + } + } + + if ($curBlock === 'condition') { + if ($end === 0 && $breaker !== false) { + $end = strlen($breakChars[$breaker]); + } + } + + if ($end !== false) { + $substr = substr($substr, 0, $end); + } + + if ($pointer !== null) { + $pointer += strlen($substr); + } + + $src = $substr; + $substr = trim($substr); + + if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') { + if ($this->debug) echo 'BOOLEAN(FALSE) PARSED
'; + $substr = 'false'; + } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') { + if ($this->debug) echo 'BOOLEAN(TRUE) PARSED
'; + $substr = 'true'; + } elseif ($substr === 'null' || $substr === 'NULL') { + if ($this->debug) echo 'NULL PARSED
'; + $substr = 'null'; + } elseif (is_numeric($substr)) { + $substr = (float) $substr; + if ((int) $substr == $substr) { + $substr = (int) $substr; + } + if ($this->debug) echo 'NUMBER ('.$substr.') PARSED
'; + } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) { + if ($this->debug) echo 'SIMPLE MATH PARSED
'; + $substr = '('.$substr.')'; + } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) { + if ($this->debug) echo 'BREAKCHAR ('.$substr.') PARSED
'; + //$substr = '"'.$substr.'"'; + } else { + $substr = $this->replaceStringVars('\''.str_replace('\'', '\\\'', $substr).'\'', '\'', $curBlock); + + if ($this->debug) echo 'BLABBER ('.$substr.') CASTED AS STRING
'; + } + + if (is_array($parsingParams)) { + $parsingParams[] = array($substr, $src); + return $parsingParams; + } elseif ($curBlock === 'namedparam') { + return array($substr, $src); + } elseif ($curBlock === 'expression') { + return $substr; + } else { + throw new Exception('Something went wrong'); + } + } + + /** + * replaces variables within a parsed string + * + * @param string $string the parsed string + * @param string $first the first character parsed in the string, which is the string delimiter (' or ") + * @param string $curBlock the current parser-block being processed + * @return string the original string with variables replaced + */ + protected function replaceStringVars($string, $first, $curBlock='') + { + $pos = 0; + if ($this->debug) echo 'STRING VAR REPLACEMENT : '.$string.'
'; + // replace vars + while (($pos = strpos($string, '$', $pos)) !== false) { + $prev = substr($string, $pos-1, 1); + if ($prev === '\\') { + $pos++; + continue; + } + + $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string':'string'))); + $len = $var[0]; + $var = $this->parse(str_replace('\\'.$first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string':'string'))); + + if ($prev === '`' && substr($string, $pos+$len, 1) === '`') { + $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos-1, $len+2); + } else { + $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos, $len); + } + $pos += strlen($var[1]) + 2; + if ($this->debug) echo 'STRING VAR REPLACEMENT DONE : '.$string.'
'; + } + + // handle modifiers + // TODO Obsolete? + $string = preg_replace_callback('#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array($this, 'replaceModifiers'), $string); + + // replace escaped dollar operators by unescaped ones if required + if ($first==="'") { + $string = str_replace('\\$', '$', $string); + } + + return $string; + } + + /** + * replaces the modifiers applied to a string or a variable + * + * @param array $m the regex matches that must be array(1=>"double or single quotes enclosing a string, when applicable", 2=>"the string or var", 3=>"the modifiers matched") + * @param string $curBlock the current parser-block being processed + * @return string the input enclosed with various function calls according to the modifiers found + */ + protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null) + { + if ($this->debug) echo 'PARSING MODIFIERS : '.$m[3].'
'; + + if ($pointer !== null) { + $pointer += strlen($m[3]); + } + // remove first pipe + $cmdstrsrc = substr($m[3], 1); + // remove last quote if present + if (substr($cmdstrsrc, -1, 1) === $m[1]) { + $cmdstrsrc = substr($cmdstrsrc, 0, -1); + $add = $m[1]; + } + + $output = $m[2]; + + $continue = true; + while (strlen($cmdstrsrc) > 0 && $continue) { + if ($cmdstrsrc[0] === '|') { + $cmdstrsrc = substr($cmdstrsrc, 1); + continue; + } + if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) { + if ($this->debug) echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND
'; + $continue = false; + if ($pointer !== null) { + $pointer -= strlen($cmdstrsrc); + } + break; + } + $cmdstr = $cmdstrsrc; + $paramsep = ':'; + if (!preg_match('/^(@{0,2}[a-z][a-z0-9_]*)(:)?/i', $cmdstr, $match)) { + throw new Dwoo_Compilation_Exception($this, 'Invalid modifier name, started with : '.substr($cmdstr, 0, 10)); + } + $paramspos = !empty($match[2]) ? strlen($match[1]) : false; + $func = $match[1]; + + $state = 0; + if ($paramspos === false) { + $cmdstrsrc = substr($cmdstrsrc, strlen($func)); + $params = array(); + if ($this->debug) echo 'MODIFIER ('.$func.') CALLED WITH NO PARAMS
'; + } else { + $paramstr = substr($cmdstr, $paramspos+1); + if (substr($paramstr, -1, 1) === $paramsep) { + $paramstr = substr($paramstr, 0, -1); + } + + $ptr = 0; + $params = array(); + while ($ptr < strlen($paramstr)) { + if ($this->debug) echo 'MODIFIER ('.$func.') START PARAM PARSING WITH POINTER AT '.$ptr.'
'; + if ($this->debug) echo $paramstr.'--'.$ptr.'--'.strlen($paramstr).'--modifier
'; + $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr); + if ($this->debug) echo 'PARAM PARSED, POINTER AT '.$ptr.'
'; + + if ($ptr >= strlen($paramstr)) { + if ($this->debug) echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED
'; + break; + } + + if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) { + if ($this->debug) echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT '.$ptr.'
'; + if ($paramstr[$ptr] !== '|') { + $continue = false; + if ($pointer !== null) { + $pointer -= strlen($paramstr) - $ptr; + } + } + $ptr++; + break; + } + if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') { + $ptr++; + } + } + $cmdstrsrc = substr($cmdstrsrc, strlen($func)+1+$ptr); + $paramstr = substr($paramstr, 0, $ptr); + foreach ($params as $k=>$p) { + if (is_array($p) && is_array($p[1])) { + $state |= 2; + } else { + if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) { + $params[$k] = array($m[2], array('true', 'true')); + } else { + if ($state & 2) { + throw new Dwoo_Compilation_Exception($this, 'You can not use an unnamed parameter after a named one'); + } + $state |= 1; + } + } + } + } + + // check if we must use array_map with this plugin or not + $mapped = false; + if (substr($func, 0, 1) === '@') { + $func = substr($func, 1); + $mapped = true; + } + + $pluginType = $this->getPluginType($func); + + if ($state & 2) { + array_unshift($params, array('value', array($output, $output))); + } else { + array_unshift($params, array($output, $output)); + } + + if ($pluginType & Dwoo::NATIVE_PLUGIN) { + $params = $this->mapParams($params, null, $state); + + $params = $params['*'][0]; + + $params = self::implode_r($params); + + if ($mapped) { + $output = '$this->arrayMap(\''.$func.'\', array('.$params.'))'; + } else { + $output = $func.'('.$params.')'; + } + } elseif ($pluginType & Dwoo::PROXY_PLUGIN) { + $params = $this->mapParams($params, $this->getDwoo()->getPluginProxy()->getCallback($func), $state); + foreach ($params as &$p) + $p = $p[0]; + $output = call_user_func(array($this->dwoo->getPluginProxy(), 'getCode'), $func, $params); + } elseif ($pluginType & Dwoo::SMARTY_MODIFIER) { + $params = $this->mapParams($params, null, $state); + $params = $params['*'][0]; + + $params = self::implode_r($params); + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (is_array($callback)) { + if (is_object($callback[0])) { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))'; + } else { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))'; + } + } elseif ($mapped) { + $output = '$this->arrayMap(\''.$callback.'\', array('.$params.'))'; + } else { + $output = $callback.'('.$params.')'; + } + } elseif ($mapped) { + $output = '$this->arrayMap(\'smarty_modifier_'.$func.'\', array('.$params.'))'; + } else { + $output = 'smarty_modifier_'.$func.'('.$params.')'; + } + } else { + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + $pluginName = $callback; + } else { + $pluginName = 'Dwoo_Plugin_'.$func; + + if ($pluginType & Dwoo::CLASS_PLUGIN) { + $callback = array($pluginName, ($pluginType & Dwoo::COMPILABLE_PLUGIN) ? 'compile' : 'process'); + } else { + $callback = $pluginName . (($pluginType & Dwoo::COMPILABLE_PLUGIN) ? '_compile' : ''); + } + } + + $params = $this->mapParams($params, $callback, $state); + + foreach ($params as &$p) + $p = $p[0]; + + if ($pluginType & Dwoo::FUNC_PLUGIN) { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($mapped) { + throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.'); + } + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $funcCompiler = $this->customPlugins[$func]['callback']; + } else { + $funcCompiler = 'Dwoo_Plugin_'.$func.'_compile'; + } + array_unshift($params, $this); + $output = call_user_func_array($funcCompiler, $params); + } else { + array_unshift($params, '$this'); + + $params = self::implode_r($params); + if ($mapped) { + $output = '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))'; + } else { + $output = $pluginName.'('.$params.')'; + } + } + } else { + if ($pluginType & Dwoo::COMPILABLE_PLUGIN) { + if ($mapped) { + throw new Dwoo_Compilation_Exception($this, 'The @ operator can not be used on compiled plugins.'); + } + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $callback = $this->customPlugins[$func]['callback']; + if (!is_array($callback)) { + if (!method_exists($callback, 'compile')) { + throw new Dwoo_Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use'); + } + if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) { + $funcCompiler = array($callback, 'compile'); + } else { + $funcCompiler = array(new $callback, 'compile'); + } + } else { + $funcCompiler = $callback; + } + } else { + $funcCompiler = array('Dwoo_Plugin_'.$func, 'compile'); + array_unshift($params, $this); + } + $output = call_user_func_array($funcCompiler, $params); + } else { + $params = self::implode_r($params); + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + if (is_object($callback[0])) { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))'; + } else { + $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))'; + } + } elseif ($mapped) { + $output = '$this->arrayMap(array($this->getObjectPlugin(\'Dwoo_Plugin_'.$func.'\'), \'process\'), array('.$params.'))'; + } else { + $output = '$this->classCall(\''.$func.'\', array('.$params.'))'; + } + } + } + } + } + + if ($curBlock === 'var' || $m[1] === null) { + return $output; + } elseif ($curBlock === 'string' || $curBlock === 'root') { + return $m[1].'.'.$output.'.'.$m[1].(isset($add)?$add:null); + } + } + + /** + * recursively implodes an array in a similar manner as var_export() does but with some tweaks + * to handle pre-compiled values and the fact that we do not need to enclose everything with + * "array" and do not require top-level keys to be displayed + * + * @param array $params the array to implode + * @param bool $recursiveCall if set to true, the function outputs key names for the top level + * @return string the imploded array + */ + public static function implode_r(array $params, $recursiveCall = false) + { + $out = ''; + foreach ($params as $k=>$p) { + if (is_array($p)) { + $out2 = 'array('; + foreach ($p as $k2=>$v) + $out2 .= var_export($k2, true).' => '.(is_array($v) ? 'array('.self::implode_r($v, true).')' : $v).', '; + $p = rtrim($out2, ', ').')'; + } + if ($recursiveCall) { + $out .= var_export($k, true).' => '.$p.', '; + } else { + $out .= $p.', '; + } + } + return rtrim($out, ', '); + } + + /** + * returns the plugin type of a plugin and adds it to the used plugins array if required + * + * @param string $name plugin name, as found in the template + * @return int type as a multi bit flag composed of the Dwoo plugin types constants + */ + protected function getPluginType($name) + { + $pluginType = -1; + + if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || + ($this->securityPolicy !== null && in_array(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) { + $phpFunc = true; + } + + while ($pluginType <= 0) { + if (isset($this->templatePlugins[$name])) { + $pluginType = Dwoo::TEMPLATE_PLUGIN | Dwoo::COMPILABLE_PLUGIN; + } elseif (isset($this->customPlugins[$name])) { + $pluginType = $this->customPlugins[$name]['type'] | Dwoo::CUSTOM_PLUGIN; + } elseif (class_exists('Dwoo_Plugin_'.$name, false) !== false) { + if (is_subclass_of('Dwoo_Plugin_'.$name, 'Dwoo_Block_Plugin')) { + $pluginType = Dwoo::BLOCK_PLUGIN; + } else { + $pluginType = Dwoo::CLASS_PLUGIN; + } + $interfaces = class_implements('Dwoo_Plugin_'.$name, false); + if (in_array('Dwoo_ICompilable', $interfaces) !== false || in_array('Dwoo_ICompilable_Block', $interfaces) !== false) { + $pluginType |= Dwoo::COMPILABLE_PLUGIN; + } + } elseif (function_exists('Dwoo_Plugin_'.$name) !== false) { + $pluginType = Dwoo::FUNC_PLUGIN; + } elseif (function_exists('Dwoo_Plugin_'.$name.'_compile')) { + $pluginType = Dwoo::FUNC_PLUGIN | Dwoo::COMPILABLE_PLUGIN; + } elseif (function_exists('smarty_modifier_'.$name) !== false) { + $pluginType = Dwoo::SMARTY_MODIFIER; + } elseif (function_exists('smarty_function_'.$name) !== false) { + $pluginType = Dwoo::SMARTY_FUNCTION; + } elseif (function_exists('smarty_block_'.$name) !== false) { + $pluginType = Dwoo::SMARTY_BLOCK; + } else { + if ($pluginType===-1) { + try { + $this->dwoo->getLoader()->loadPlugin($name, isset($phpFunc)===false); + } catch (Exception $e) { + if (isset($phpFunc)) { + $pluginType = Dwoo::NATIVE_PLUGIN; + } elseif (is_object($this->dwoo->getPluginProxy()) && $this->dwoo->getPluginProxy()->handles($name)) { + $pluginType = Dwoo::PROXY_PLUGIN; + break; + } else { + throw $e; + } + } + } else { + throw new Dwoo_Exception('Plugin "'.$name.'" could not be found'); + } + $pluginType++; + } + } + + if (($pluginType & Dwoo::COMPILABLE_PLUGIN) === 0 && ($pluginType & Dwoo::NATIVE_PLUGIN) === 0 && ($pluginType & Dwoo::PROXY_PLUGIN) === 0) { + $this->addUsedPlugin($name, $pluginType); + } + + return $pluginType; + } + + /** + * allows a plugin to load another one at compile time, this will also mark + * it as used by this template so it will be loaded at runtime (which can be + * useful for compiled plugins that rely on another plugin when their compiled + * code runs) + * + * @param string $name the plugin name + */ + public function loadPlugin($name) { + $this->getPluginType($name); + } + + /** + * runs htmlentities over the matched blocks when the security policy enforces that + * + * @param array $match matched php block + * @return string the htmlentities-converted string + */ + protected function phpTagEncodingHelper($match) + { + return htmlspecialchars($match[0]); + } + + /** + * maps the parameters received from the template onto the parameters required by the given callback + * + * @param array $params the array of parameters + * @param callback $callback the function or method to reflect on to find out the required parameters + * @param int $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named parameters call + * @param array $map the parameter map to use, if not provided it will be built from the callback + * @return array parameters sorted in the correct order with missing optional parameters filled + */ + protected function mapParams(array $params, $callback, $callType=2, $map = null) + { + if (!$map) { + $map = $this->getParamMap($callback); + } + + $paramlist = array(); + + // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values)) + $ps = array(); + foreach ($params as $p) { + if (is_array($p[1])) { + $ps[$p[0]] = $p[1]; + } else { + $ps[] = $p; + } + } + + // loops over the param map and assigns values from the template or default value for unset optional params + while (list($k,$v) = each($map)) { + if ($v[0] === '*') { + // "rest" array parameter, fill every remaining params in it and then break + if (count($ps) === 0) { + if ($v[1]===false) { + throw new Dwoo_Compilation_Exception($this, 'Rest argument missing for '.str_replace(array('Dwoo_Plugin_', '_compile'), '', (is_array($callback) ? $callback[0] : $callback))); + } else { + break; + } + } + $tmp = array(); + $tmp2 = array(); + foreach ($ps as $i=>$p) { + $tmp[$i] = $p[0]; + $tmp2[$i] = $p[1]; + unset($ps[$i]); + } + $paramlist[$v[0]] = array($tmp, $tmp2); + unset($tmp, $tmp2, $i, $p); + break; + } elseif (isset($ps[$v[0]])) { + // parameter is defined as named param + $paramlist[$v[0]] = $ps[$v[0]]; + unset($ps[$v[0]]); + } elseif (isset($ps[$k])) { + // parameter is defined as ordered param + $paramlist[$v[0]] = $ps[$k]; + unset($ps[$k]); + } elseif ($v[1]===false) { + // parameter is not defined and not optional, throw error + if (is_array($callback)) { + if (is_object($callback[0])) { + $name = get_class($callback[0]) . '::' . $callback[1]; + } else { + $name = $callback[0]; + } + } else { + $name = $callback; + } + + throw new Dwoo_Compilation_Exception($this, 'Argument '.$k.'/'.$v[0].' missing for '.str_replace(array('Dwoo_Plugin_', '_compile'), '', $name)); + } elseif ($v[2]===null) { + // enforce lowercased null if default value is null (php outputs NULL with var export) + $paramlist[$v[0]] = array('null', null); + } else { + // outputs default value with var_export + $paramlist[$v[0]] = array(var_export($v[2], true), $v[2]); + } + } + + if (count($ps)) { + foreach ($ps as $i=>$p) { + array_push($paramlist, $p); + } + } + + return $paramlist; + } + + /** + * returns the parameter map of the given callback, it filters out entries typed as Dwoo and Dwoo_Compiler and turns the rest parameter into a "*" + * + * @param callback $callback the function/method to reflect on + * @return array processed parameter map + */ + protected function getParamMap($callback) + { + if (is_null($callback)) { + return array(array('*', true)); + } + if (is_array($callback)) { + $ref = new ReflectionMethod($callback[0], $callback[1]); + } else { + $ref = new ReflectionFunction($callback); + } + + $out = array(); + foreach ($ref->getParameters() as $param) { + if (($class = $param->getClass()) !== null && $class->name === 'Dwoo') { + continue; + } + if (($class = $param->getClass()) !== null && $class->name === 'Dwoo_Compiler') { + continue; + } + if ($param->getName() === 'rest' && $param->isArray() === true) { + $out[] = array('*', $param->isOptional(), null); + } + $out[] = array($param->getName(), $param->isOptional(), $param->isOptional() ? $param->getDefaultValue() : null); + } + + return $out; + } + + /** + * returns a default instance of this compiler, used by default by all Dwoo templates that do not have a + * specific compiler assigned and when you do not override the default compiler factory function + * + * @see Dwoo::setDefaultCompilerFactory() + * @return Dwoo_Compiler + */ + public static function compilerFactory() + { + if (self::$instance === null) { + new self; + } + return self::$instance; + } +} diff --git a/system/libs/dwoo/Dwoo/Data.php b/system/libs/dwoo/Dwoo/Data.php new file mode 100644 index 00000000..c5f292ec --- /dev/null +++ b/system/libs/dwoo/Dwoo/Data.php @@ -0,0 +1,250 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Data implements Dwoo_IDataProvider +{ + /** + * data array + * + * @var array + */ + protected $data = array(); + + /** + * returns the data array + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * clears a the entire data or only the given key + * + * @param array|string $name clears only one value if you give a name, multiple values if + * you give an array of names, or the entire data if left null + */ + public function clear($name = null) + { + if ($name === null) { + $this->data = array(); + } elseif (is_array($name)) { + foreach ($name as $index) + unset($this->data[$index]); + } else { + unset($this->data[$name]); + } + } + + /** + * overwrites the entire data with the given array + * + * @param array $data the new data array to use + */ + public function setData(array $data) + { + $this->data = $data; + } + + /** + * merges the given array(s) with the current data with array_merge + * + * @param array $data the array to merge + * @param array $data2 $data3 ... other arrays to merge, optional, etc. + */ + public function mergeData(array $data) + { + $args = func_get_args(); + while (list(,$v) = each($args)) { + if (is_array($v)) { + $this->data = array_merge($this->data, $v); + } + } + } + + /** + * assigns a value or an array of values to the data object + * + * @param array|string $name an associative array of multiple (index=>value) or a string + * that is the index to use, i.e. a value assigned to "foo" will be + * accessible in the template through {$foo} + * @param mixed $val the value to assign, or null if $name was an array + */ + public function assign($name, $val = null) + { + if (is_array($name)) { + reset($name); + while (list($k,$v) = each($name)) + $this->data[$k] = $v; + } else { + $this->data[$name] = $val; + } + } + + /** + * allows to assign variables using the object syntax + * + * @param string $name the variable name + * @param string $value the value to assign to it + */ + public function __set($name, $value) + { + $this->assign($name, $value); + } + + /** + * assigns a value by reference to the data object + * + * @param string $name the index to use, i.e. a value assigned to "foo" will be + * accessible in the template through {$foo} + * @param mixed $val the value to assign by reference + */ + public function assignByRef($name, &$val) + { + $this->data[$name] =& $val; + } + + /** + * appends values or an array of values to the data object + * + * @param array|string $name an associative array of multiple (index=>value) or a string + * that is the index to use, i.e. a value assigned to "foo" will be + * accessible in the template through {$foo} + * @param mixed $val the value to assign, or null if $name was an array + * @param bool $merge true to merge data or false to append, defaults to false + */ + public function append($name, $val = null, $merge = false) + { + if (is_array($name)) { + foreach ($name as $key=>$val) { + if (isset($this->data[$key]) && !is_array($this->data[$key])) { + settype($this->data[$key], 'array'); + } + + if ($merge === true && is_array($val)) { + $this->data[$key] = $val + $this->data[$key]; + } else { + $this->data[$key][] = $val; + } + } + } elseif ($val !== null) { + if (isset($this->data[$name]) && !is_array($this->data[$name])) { + settype($this->data[$name], 'array'); + } elseif (!isset($this->data[$name])) { + $this->data[$name] = array(); + } + + if ($merge === true && is_array($val)) { + $this->data[$name] = $val + $this->data[$name]; + } else { + $this->data[$name][] = $val; + } + } + } + + /** + * appends a value by reference to the data object + * + * @param string $name the index to use, i.e. a value assigned to "foo" will be + * accessible in the template through {$foo} + * @param mixed $val the value to append by reference + * @param bool $merge true to merge data or false to append, defaults to false + */ + public function appendByRef($name, &$val, $merge = false) + { + if (isset($this->data[$name]) && !is_array($this->data[$name])) { + settype($this->data[$name], 'array'); + } + + if ($merge === true && is_array($val)) { + foreach ($val as $key => &$val) { + $this->data[$name][$key] =& $val; + } + } else { + $this->data[$name][] =& $val; + } + } + + /** + * returns true if the variable has been assigned already, false otherwise + * + * @param string $name the variable name + * @return bool + */ + public function isAssigned($name) + { + return isset($this->data[$name]); + } + + /** + * supports calls to isset($dwooData->var) + * + * @param string $name the variable name + */ + public function __isset($name) + { + return isset($this->data[$name]); + } + + /** + * unassigns/removes a variable + * + * @param string $name the variable name + */ + public function unassign($name) + { + unset($this->data[$name]); + } + + /** + * supports unsetting variables using the object syntax + * + * @param string $name the variable name + */ + public function __unset($name) + { + unset($this->data[$name]); + } + + /** + * returns a variable if it was assigned + * + * @param string $name the variable name + * @return mixed + */ + public function get($name) + { + return $this->__get($name); + } + + /** + * allows to read variables using the object syntax + * + * @param string $name the variable name + * @return mixed + */ + public function __get($name) + { + if (isset($this->data[$name])) { + return $this->data[$name]; + } else { + throw new Dwoo_Exception('Tried to read a value that was not assigned yet : "'.$name.'"'); + } + } +} diff --git a/system/libs/dwoo/Dwoo/Exception.php b/system/libs/dwoo/Dwoo/Exception.php new file mode 100644 index 00000000..83549bde --- /dev/null +++ b/system/libs/dwoo/Dwoo/Exception.php @@ -0,0 +1,19 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Exception extends Exception +{ +} diff --git a/system/libs/dwoo/Dwoo/Filter.php b/system/libs/dwoo/Dwoo/Filter.php new file mode 100644 index 00000000..60845723 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Filter.php @@ -0,0 +1,44 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +abstract class Dwoo_Filter +{ + /** + * the dwoo instance that runs this filter + * + * @var Dwoo + */ + protected $dwoo; + + /** + * constructor, if you override it, call parent::__construct($dwoo); or assign + * the dwoo instance yourself if you need it + * + * @param Dwoo $dwoo the dwoo instance that runs this plugin + */ + public function __construct(Dwoo $dwoo) + { + $this->dwoo = $dwoo; + } + + /** + * processes the input and returns it filtered + * + * @param string $input the template to process + * @return string + */ + abstract public function process($input); +} diff --git a/system/libs/dwoo/Dwoo/ICompilable.php b/system/libs/dwoo/Dwoo/ICompilable.php new file mode 100644 index 00000000..02ad54bf --- /dev/null +++ b/system/libs/dwoo/Dwoo/ICompilable.php @@ -0,0 +1,26 @@ +public static function compile(Dwoo_Compiler $compiler, $arg, $arg, ...), + * which replaces the process() method (that means compile() should have all arguments it requires). + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_ICompilable +{ + // this replaces the process function + //public static function compile(Dwoo_Compiler $compiler, $arg, $arg, ...); +} diff --git a/system/libs/dwoo/Dwoo/ICompilable/Block.php b/system/libs/dwoo/Dwoo/ICompilable/Block.php new file mode 100644 index 00000000..b7f3b542 --- /dev/null +++ b/system/libs/dwoo/Dwoo/ICompilable/Block.php @@ -0,0 +1,21 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_ICompilable_Block +{ +} diff --git a/system/libs/dwoo/Dwoo/ICompiler.php b/system/libs/dwoo/Dwoo/ICompiler.php new file mode 100644 index 00000000..68f7d782 --- /dev/null +++ b/system/libs/dwoo/Dwoo/ICompiler.php @@ -0,0 +1,49 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_ICompiler +{ + /** + * compiles the provided string down to php code + * + * @param string $templateStr the template to compile + * @return string a compiled php code string + */ + public function compile(Dwoo $dwoo, Dwoo_ITemplate $template); + + /** + * adds the custom plugins loaded into Dwoo to the compiler so it can load them + * + * @see Dwoo::addPlugin + * @param array $customPlugins an array of custom plugins + */ + public function setCustomPlugins(array $customPlugins); + + /** + * sets the security policy object to enforce some php security settings + * + * use this if untrusted persons can modify templates, + * set it on the Dwoo object as it will be passed onto the compiler automatically + * + * @param Dwoo_Security_Policy $policy the security policy object + */ + public function setSecurityPolicy(Dwoo_Security_Policy $policy = null); +} diff --git a/system/libs/dwoo/Dwoo/IDataProvider.php b/system/libs/dwoo/Dwoo/IDataProvider.php new file mode 100644 index 00000000..35d66317 --- /dev/null +++ b/system/libs/dwoo/Dwoo/IDataProvider.php @@ -0,0 +1,25 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_IDataProvider +{ + /** + * returns the data as an associative array that will be used in the template + * + * @return array + */ + public function getData(); +} diff --git a/system/libs/dwoo/Dwoo/IElseable.php b/system/libs/dwoo/Dwoo/IElseable.php new file mode 100644 index 00000000..03002585 --- /dev/null +++ b/system/libs/dwoo/Dwoo/IElseable.php @@ -0,0 +1,24 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_IElseable +{ +} diff --git a/system/libs/dwoo/Dwoo/ILoader.php b/system/libs/dwoo/Dwoo/ILoader.php new file mode 100644 index 00000000..dc0fe44a --- /dev/null +++ b/system/libs/dwoo/Dwoo/ILoader.php @@ -0,0 +1,30 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_ILoader +{ + /** + * loads a plugin file + * + * the second parameter is used to avoid permanent rehashing when using php functions, + * however this means that if you have add a plugin that overrides a php function you have + * to delete the classpath.cache file(s) by hand to force a rehash of the plugins + * + * @param string $class the plugin name, without the Dwoo_Plugin_ prefix + * @param bool $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it has just been added, defaults to true + */ + public function loadPlugin($class, $forceRehash = true); +} diff --git a/system/libs/dwoo/Dwoo/IPluginProxy.php b/system/libs/dwoo/Dwoo/IPluginProxy.php new file mode 100644 index 00000000..3d02fb40 --- /dev/null +++ b/system/libs/dwoo/Dwoo/IPluginProxy.php @@ -0,0 +1,65 @@ + + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Denis Arh, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +interface Dwoo_IPluginProxy +{ + /** + * returns true or false to say whether the given plugin is handled by this proxy or not + * + * @param string $name the plugin name + * @return bool true if the plugin is known and usable, otherwise false + */ + public function handles($name); + + /** + * returns the code (as a string) to call the plugin + * (this will be executed at runtime inside the Dwoo class) + * + * @param string $name the plugin name + * @param array $params a parameter array, array key "*" is the rest array + * @return string + */ + public function getCode($name, $params); + + /** + * returns a callback to the plugin, this is used with the reflection API to + * find out about the plugin's parameter names etc. + * + * should you need a rest array without the possibility to edit the + * plugin's code, you can provide a callback to some + * other function with the correct parameter signature, i.e. : + * + * return array($this, "callbackHelper"); + * // and callbackHelper would be as such: + * public function callbackHelper(array $rest=array()){} + * + * + * @param string $name the plugin name + * @return callback + */ + public function getCallback($name); + + /** + * returns some code that will check if the plugin is loaded and if not load it + * this is optional, if your plugins are autoloaded or whatever, just return an + * empty string + * + * @param string $name the plugin name + * @return string + */ + public function getLoader($name); +} \ No newline at end of file diff --git a/system/libs/dwoo/Dwoo/ITemplate.php b/system/libs/dwoo/Dwoo/ITemplate.php new file mode 100644 index 00000000..5c83dcb0 --- /dev/null +++ b/system/libs/dwoo/Dwoo/ITemplate.php @@ -0,0 +1,150 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +interface Dwoo_ITemplate +{ + /** + * returns the cache duration for this template + * + * defaults to null if it was not provided + * + * @return int|null + */ + public function getCacheTime(); + + /** + * sets the cache duration for this template + * + * can be used to set it after the object is created if you did not provide + * it in the constructor + * + * @param int $seconds duration of the cache validity for this template, if + * null it defaults to the Dwoo instance's cache time. 0 = disable and + * -1 = infinite cache + */ + public function setCacheTime($seconds = null); + + /** + * returns the cached template output file name, true if it's cache-able but not cached + * or false if it's not cached + * + * @param Dwoo $dwoo the dwoo instance that requests it + * @return string|bool + */ + public function getCachedTemplate(Dwoo $dwoo); + + /** + * caches the provided output into the cache file + * + * @param Dwoo $dwoo the dwoo instance that requests it + * @param string $output the template output + * @return mixed full path of the cached file or false upon failure + */ + public function cache(Dwoo $dwoo, $output); + + /** + * clears the cached template if it's older than the given time + * + * @param Dwoo $dwoo the dwoo instance that was used to cache that template + * @param int $olderThan minimum time (in seconds) required for the cache to be cleared + * @return bool true if the cache was not present or if it was deleted, false if it remains there + */ + public function clearCache(Dwoo $dwoo, $olderThan = -1); + + /** + * returns the compiled template file name + * + * @param Dwoo $dwoo the dwoo instance that requests it + * @param Dwoo_ICompiler $compiler the compiler that must be used + * @return string + */ + public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null); + + /** + * returns the template name + * + * @return string + */ + public function getName(); + + /** + * returns the resource name for this template class + * + * @return string + */ + public function getResourceName(); + + /** + * returns the resource identifier for this template or false if it has no identifier + * + * @return string|false + */ + public function getResourceIdentifier(); + + /** + * returns the template source of this template + * + * @return string + */ + public function getSource(); + + /** + * returns an unique string identifying the current version of this template, + * for example a timestamp of the last modified date or a hash of the template source + * + * @return string + */ + public function getUid(); + + /** + * returns the compiler used by this template, if it was just compiled, or null + * + * @return Dwoo_ICompiler + */ + public function getCompiler(); + + /** + * returns some php code that will check if this template has been modified or not + * + * if the function returns null, the template will be instanciated and then the Uid checked + * + * @return string + */ + public function getIsModifiedCode(); + + /** + * returns a new template object from the given resource identifier, null if no include is + * possible (resource not found), or false if include is not permitted by this resource type + * + * this method should also check if $dwoo->getSecurityPolicy() is null or not and do the + * necessary permission checks if required, if the security policy prevents the template + * generation it should throw a new Dwoo_Security_Exception with a relevant message + * + * @param mixed $resourceId the resource identifier + * @param int $cacheTime duration of the cache validity for this template, + * if null it defaults to the Dwoo instance that will + * render this template + * @param string $cacheId the unique cache identifier of this page or anything else that + * makes this template's content unique, if null it defaults + * to the current url + * @param string $compileId the unique compiled identifier, which is used to distinguish this + * template from others, if null it defaults to the filename+bits of the path + * @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through + * an include, extends or any other plugin) + * @return Dwoo_ITemplate|null|false + */ + public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null); +} diff --git a/system/libs/dwoo/Dwoo/Loader.php b/system/libs/dwoo/Dwoo/Loader.php new file mode 100644 index 00000000..437a1285 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Loader.php @@ -0,0 +1,147 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Loader implements Dwoo_ILoader +{ + /** + * stores the plugin directories + * + * @see addDirectory + * @var array + */ + protected $paths = array(); + + /** + * stores the plugins names/paths relationships + * don't edit this on your own, use addDirectory + * + * @see addDirectory + * @var array + */ + protected $classPath = array(); + + /** + * path where class paths cache files are written + * + * @var string + */ + protected $cacheDir; + + protected $corePluginDir; + + public function __construct($cacheDir) + { + $this->corePluginDir = DWOO_DIRECTORY . 'plugins'; + $this->cacheDir = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + + // include class paths or rebuild paths if the cache file isn't there + $cacheFile = $this->cacheDir.'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'; + if (file_exists($cacheFile)) { + $classpath = file_get_contents($cacheFile); + $this->classPath = unserialize($classpath) + $this->classPath; + } else { + $this->rebuildClassPathCache($this->corePluginDir, $cacheFile); + } + } + + /** + * rebuilds class paths, scans the given directory recursively and saves all paths in the given file + * + * @param string $path the plugin path to scan + * @param string $cacheFile the file where to store the plugin paths cache, it will be overwritten + */ + protected function rebuildClassPathCache($path, $cacheFile) + { + if ($cacheFile!==false) { + $tmp = $this->classPath; + $this->classPath = array(); + } + + // iterates over all files/folders + $list = glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*'); + if (is_array($list)) { + foreach ($list as $f) { + if (is_dir($f)) { + $this->rebuildClassPathCache($f, false); + } else { + $this->classPath[str_replace(array('function.','block.','modifier.','outputfilter.','filter.','prefilter.','postfilter.','pre.','post.','output.','shared.','helper.'), '', basename($f, '.php'))] = $f; + } + } + } + + // save in file if it's the first call (not recursed) + if ($cacheFile!==false) { + if (!file_put_contents($cacheFile, serialize($this->classPath))) { + throw new Dwoo_Exception('Could not write into '.$cacheFile.', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()'); + } + $this->classPath += $tmp; + } + } + + /** + * loads a plugin file + * + * @param string $class the plugin name, without the Dwoo_Plugin_ prefix + * @param bool $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it has just been added, defaults to true + */ + public function loadPlugin($class, $forceRehash = true) + { + // a new class was added or the include failed so we rebuild the cache + if (!isset($this->classPath[$class]) || !(include $this->classPath[$class])) { + if ($forceRehash) { + $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d'.Dwoo::RELEASE_TAG.'.php'); + foreach ($this->paths as $path=>$file) { + $this->rebuildClassPathCache($path, $file); + } + if (isset($this->classPath[$class])) { + include $this->classPath[$class]; + } else { + throw new Dwoo_Exception('Plugin '.$class.' can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE); + } + } else { + throw new Dwoo_Exception('Plugin '.$class.' can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE); + } + } + } + + /** + * adds a plugin directory, the plugins found in the new plugin directory + * will take precedence over the other directories (including the default + * dwoo plugin directory), you can use this for example to override plugins + * in a specific directory for a specific application while keeping all your + * usual plugins in the same place for all applications. + * + * TOCOM don't forget that php functions overrides are not rehashed so you + * need to clear the classpath caches by hand when adding those + * + * @param string $pluginDirectory the plugin path to scan + */ + public function addDirectory($pluginDirectory) + { + $pluginDir = realpath($pluginDirectory); + if (!$pluginDir) { + throw new Dwoo_Exception('Plugin directory does not exist or can not be read : '.$pluginDirectory); + } + $cacheFile = $this->cacheDir . 'classpath-'.substr(strtr($pluginDir, '/\\:'.PATH_SEPARATOR, '----'), strlen($pluginDir) > 80 ? -80 : 0).'.d'.Dwoo::RELEASE_TAG.'.php'; + $this->paths[$pluginDir] = $cacheFile; + if (file_exists($cacheFile)) { + $classpath = file_get_contents($cacheFile); + $this->classPath = unserialize($classpath) + $this->classPath; + } else { + $this->rebuildClassPathCache($pluginDir, $cacheFile); + } + } +} diff --git a/system/libs/dwoo/Dwoo/Plugin.php b/system/libs/dwoo/Dwoo/Plugin.php new file mode 100644 index 00000000..053448c9 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Plugin.php @@ -0,0 +1,85 @@ +process() method, it will receive the parameters that + * are in the template code + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +abstract class Dwoo_Plugin +{ + /** + * the dwoo instance that runs this plugin + * + * @var Dwoo + */ + protected $dwoo; + + /** + * constructor, if you override it, call parent::__construct($dwoo); or assign + * the dwoo instance yourself if you need it + * + * @param Dwoo $dwoo the dwoo instance that runs this plugin + */ + public function __construct(Dwoo $dwoo) + { + $this->dwoo = $dwoo; + } + + // plugins should always implement : + // public function process($arg, $arg, ...) + // or for block plugins : + // public function init($arg, $arg, ...) + + // this could be enforced with : + // abstract public function process(...); + // if my feature request gets enough interest one day + // see => http://bugs.php.net/bug.php?id=44043 + + /** + * utility function that converts an array of compiled parameters (or rest array) to a string of xml/html tag attributes + * + * this is to be used in preProcessing or postProcessing functions, example : + * $p = $compiler->getCompiledParams($params); + * // get only the rest array as attributes + * $attributes = Dwoo_Plugin::paramsToAttributes($p['*']); + * // get all the parameters as attributes (if there is a rest array, it will be included) + * $attributes = Dwoo_Plugin::paramsToAttributes($p); + * + * @param array $params an array of attributeName=>value items that will be compiled to be ready for inclusion in a php string + * @param string $delim the string delimiter you want to use (defaults to ') + * @return string + */ + public static function paramsToAttributes(array $params, $delim = '\'') + { + if (isset($params['*'])) { + $params = array_merge($params, $params['*']); + unset($params['*']); + } + + $out = ''; + foreach ($params as $attr=>$val) { + $out .= ' '.$attr.'='; + if (trim($val, '"\'')=='' || $val=='null') { + $out .= str_replace($delim, '\\'.$delim, '""'); + } elseif (substr($val, 0, 1) === $delim && substr($val, -1) === $delim) { + $out .= str_replace($delim, '\\'.$delim, '"'.substr($val, 1, -1).'"'); + } else { + $out .= str_replace($delim, '\\'.$delim, '"') . $delim . '.'.$val.'.' . $delim . str_replace($delim, '\\'.$delim, '"'); + } + } + + return ltrim($out); + } +} diff --git a/system/libs/dwoo/Dwoo/Processor.php b/system/libs/dwoo/Dwoo/Processor.php new file mode 100644 index 00000000..e3287f17 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Processor.php @@ -0,0 +1,44 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +abstract class Dwoo_Processor +{ + /** + * the compiler instance that runs this processor + * + * @var Dwoo + */ + protected $compiler; + + /** + * constructor, if you override it, call parent::__construct($dwoo); or assign + * the dwoo instance yourself if you need it + * + * @param Dwoo $dwoo the dwoo instance that runs this plugin + */ + public function __construct(Dwoo_Compiler $compiler) + { + $this->compiler = $compiler; + } + + /** + * processes the input and returns it filtered + * + * @param string $input the template to process + * @return string + */ + abstract public function process($input); +} diff --git a/system/libs/dwoo/Dwoo/Security/Exception.php b/system/libs/dwoo/Dwoo/Security/Exception.php new file mode 100644 index 00000000..fbae9447 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Security/Exception.php @@ -0,0 +1,19 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Security_Exception extends Dwoo_Exception +{ +} diff --git a/system/libs/dwoo/Dwoo/Security/Policy.php b/system/libs/dwoo/Dwoo/Security/Policy.php new file mode 100644 index 00000000..8875f6d0 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Security/Policy.php @@ -0,0 +1,199 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Security_Policy +{ + /**#@+ + * php handling constants, defaults to PHP_REMOVE + * + * PHP_REMOVE : remove all (+ short tags if your short tags option is on) from the input template + * PHP_ALLOW : leave them as they are + * PHP_ENCODE : run htmlentities over them + * + * @var int + */ + const PHP_ENCODE = 1; + const PHP_REMOVE = 2; + const PHP_ALLOW = 3; + /**#@-*/ + + /**#@+ + * constant handling constants, defaults to CONST_DISALLOW + * + * CONST_DISALLOW : throw an error if {$dwoo.const.*} is used in the template + * CONST_ALLOW : allow {$dwoo.const.*} calls + */ + const CONST_DISALLOW = false; + const CONST_ALLOW = true; + /**#@-*/ + + /** + * php functions that are allowed to be used within the template + * + * @var array + */ + protected $allowedPhpFunctions = array + ( + 'str_repeat', 'number_format', 'htmlentities', 'htmlspecialchars', + 'long2ip', 'strlen', 'list', 'empty', 'count', 'sizeof', 'in_array', 'is_array', + ); + + /** + * paths that are safe to use with include or other file-access plugins + * + * @var array + */ + protected $allowedDirectories = array(); + + /** + * stores the php handling level + * + * defaults to Dwoo_Security_Policy::PHP_REMOVE + * + * @var int + */ + protected $phpHandling = self::PHP_REMOVE; + + /** + * stores the constant handling level + * + * defaults to Dwoo_Security_Policy::CONST_DISALLOW + * + * @var bool + */ + protected $constHandling = self::CONST_DISALLOW; + + /** + * adds a php function to the allowed list + * + * @param mixed $func function name or array of function names + */ + public function allowPhpFunction($func) + { + if (is_array($func)) + foreach ($func as $fname) + $this->allowedPhpFunctions[strtolower($fname)] = true; + else + $this->allowedPhpFunctions[strtolower($func)] = true; + } + + /** + * removes a php function from the allowed list + * + * @param mixed $func function name or array of function names + */ + public function disallowPhpFunction($func) + { + if (is_array($func)) + foreach ($func as $fname) + unset($this->allowedPhpFunctions[strtolower($fname)]); + else + unset($this->allowedPhpFunctions[strtolower($func)]); + } + + /** + * returns the list of php functions allowed to run, note that the function names + * are stored in the array keys and not values + * + * @return array + */ + public function getAllowedPhpFunctions() + { + return $this->allowedPhpFunctions; + } + + /** + * adds a directory to the safelist for includes and other file-access plugins + * + * note that all the includePath directories you provide to the Dwoo_Template_File class + * are automatically marked as safe + * + * @param mixed $path a path name or an array of paths + */ + public function allowDirectory($path) + { + if (is_array($path)) + foreach ($path as $dir) + $this->allowedDirectories[realpath($dir)] = true; + else + $this->allowedDirectories[realpath($path)] = true; + } + + /** + * removes a directory from the safelist + * + * @param mixed $path a path name or an array of paths + */ + public function disallowDirectory($path) + { + if (is_array($path)) + foreach ($path as $dir) + unset($this->allowedDirectories[realpath($dir)]); + else + unset($this->allowedDirectories[realpath($path)]); + } + + /** + * returns the list of safe paths, note that the paths are stored in the array + * keys and not values + * + * @return array + */ + public function getAllowedDirectories() + { + return $this->allowedDirectories; + } + + /** + * sets the php handling level, defaults to REMOVE + * + * @param int $level one of the Dwoo_Security_Policy::PHP_* constants + */ + public function setPhpHandling($level = self::PHP_REMOVE) + { + $this->phpHandling = $level; + } + + /** + * returns the php handling level + * + * @return int the current level, one of the Dwoo_Security_Policy::PHP_* constants + */ + public function getPhpHandling() + { + return $this->phpHandling; + } + + /** + * sets the constant handling level, defaults to CONST_DISALLOW + * + * @param bool $level one of the Dwoo_Security_Policy::CONST_* constants + */ + public function setConstantHandling($level = self::CONST_DISALLOW) + { + $this->constHandling = $level; + } + + /** + * returns the constant handling level + * + * @return bool the current level, one of the Dwoo_Security_Policy::CONST_* constants + */ + public function getConstantHandling() + { + return $this->constHandling; + } +} diff --git a/system/libs/dwoo/Dwoo/Smarty/Adapter.php b/system/libs/dwoo/Dwoo/Smarty/Adapter.php new file mode 100644 index 00000000..b4a620cd --- /dev/null +++ b/system/libs/dwoo/Dwoo/Smarty/Adapter.php @@ -0,0 +1,518 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Smarty__Adapter extends Dwoo +{ + // magic get/set/call functions that handle unsupported features + public function __set($p, $v) + { + if ($p==='scope') { + $this->scope = $v; + return; + } + if ($p==='data') { + $this->data = $v; + return; + } + if (array_key_exists($p, $this->compat['properties']) !== false) { + if ($this->show_compat_errors) { + $this->triggerError('Property '.$p.' is not available in the Dwoo_Smarty_Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE); + } + $this->compat['properties'][$p] = $v; + } else { + if ($this->show_compat_errors) { + $this->triggerError('Property '.$p.' is not available in the Dwoo_Smarty_Adapter, but it is not listed as such, so you might want to tell me about it at j.boggiano@seld.be', E_USER_NOTICE); + } + } + } + + public function __get($p) + { + if (array_key_exists($p, $this->compat['properties']) !== false) { + if ($this->show_compat_errors) { + $this->triggerError('Property '.$p.' is not available in the Dwoo_Smarty_Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE); + } + return $this->compat['properties'][$p]; + } else { + if ($this->show_compat_errors) { + $this->triggerError('Property '.$p.' is not available in the Dwoo_Smarty_Adapter, but it is not listed as such, so you might want to tell me about it at j.boggiano@seld.be', E_USER_NOTICE); + } + } + } + + public function __call($m, $a) + { + if (method_exists($this->dataProvider, $m)) { + call_user_func_array(array($this->dataProvider, $m), $a); + } elseif ($this->show_compat_errors) { + if (array_search($m, $this->compat['methods']) !== false) { + $this->triggerError('Method '.$m.' is not available in the Dwoo_Smarty_Adapter, however it might be implemented in the future, check out http://wiki.dwoo.org/index.php/SmartySupport for more details.', E_USER_NOTICE); + } else { + $this->triggerError('Method '.$m.' is not available in the Dwoo_Smarty_Adapter, but it is not listed as such, so you might want to tell me about it at j.boggiano@seld.be', E_USER_NOTICE); + } + } + } + + // list of unsupported properties and methods + protected $compat = array + ( + 'methods' => array + ( + 'register_resource', 'unregister_resource', 'load_filter', 'clear_compiled_tpl', + 'clear_config', 'get_config_vars', 'config_load' + ), + 'properties' => array + ( + 'cache_handler_func' => null, + 'debugging' => false, + 'error_reporting' => null, + 'debugging_ctrl' => 'NONE', + 'request_vars_order' => 'EGPCS', + 'request_use_auto_globals' => true, + 'use_sub_dirs' => false, + 'autoload_filters' => array(), + 'default_template_handler_func' => '', + 'debug_tpl' => '', + 'cache_modified_check' => false, + 'default_modifiers' => array(), + 'default_resource_type' => 'file', + 'config_overwrite' => true, + 'config_booleanize' => true, + 'config_read_hidden' => false, + 'config_fix_newlines' => true, + 'config_class' => 'Config_File', + ), + ); + + // security vars + public $security = false; + public $trusted_dir = array(); + public $secure_dir = array(); + public $php_handling = SMARTY_PHP_PASSTHRU; + public $security_settings = array + ( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array + ( + 'list', 'empty', 'count', 'sizeof', + 'in_array', 'is_array', + ), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array(), + 'ALLOW_CONSTANTS' => false + ); + + // paths + public $template_dir = 'templates'; + public $compile_dir = 'templates_c'; + public $config_dir = 'configs'; + public $cache_dir = 'cache'; + public $plugins_dir = array(); + + // misc options + public $left_delimiter = '{'; + public $right_delimiter = '}'; + public $compile_check = true; + public $force_compile = false; + public $caching = 0; + public $cache_lifetime = 3600; + public $compile_id = null; + public $compiler_file = null; + public $compiler_class = null; + + // dwoo/smarty compat layer + public $show_compat_errors = false; + protected $dataProvider; + protected $_filters = array('pre'=>array(), 'post'=>array(), 'output'=>array()); + protected static $tplCache = array(); + protected $compiler = null; + + public function __construct() + { + parent::__construct(); + $this->charset = 'iso-8859-1'; + $this->dataProvider = new Dwoo_Data(); + $this->compiler = new Dwoo_Compiler(); + } + + public function display($filename, $cacheId=null, $compileId=null) + { + $this->fetch($filename, $cacheId, $compileId, true); + } + + public function fetch($filename, $cacheId=null, $compileId=null, $display=false) + { + $this->setCacheDir($this->cache_dir); + $this->setCompileDir($this->compile_dir); + + if ($this->security) { + $policy = new Dwoo_Security_Policy(); + $policy->addPhpFunction(array_merge($this->security_settings['IF_FUNCS'], $this->security_settings['MODIFIER_FUNCS'])); + + $phpTags = $this->security_settings['PHP_HANDLING'] ? SMARTY_PHP_ALLOW : $this->php_handling; + if ($this->security_settings['PHP_TAGS']) { + $phpTags = SMARTY_PHP_ALLOW; + } + switch($phpTags) { + case SMARTY_PHP_ALLOW: + case SMARTY_PHP_PASSTHRU: + $phpTags = Dwoo_Security_Policy::PHP_ALLOW; + break; + case SMARTY_PHP_QUOTE: + $phpTags = Dwoo_Security_Policy::PHP_ENCODE; + break; + case SMARTY_PHP_REMOVE: + default: + $phpTags = Dwoo_Security_Policy::PHP_REMOVE; + break; + } + $policy->setPhpHandling($phpTags); + + $policy->setConstantHandling($this->security_settings['ALLOW_CONSTANTS']); + + if ($this->security_settings['INCLUDE_ANY']) { + $policy->allowDirectory(preg_replace('{^((?:[a-z]:)?[\\\\/]).*}i', '$1', __FILE__)); + } else { + $policy->allowDirectory($this->secure_dir); + } + + $this->setSecurityPolicy($policy); + } + + if (!empty($this->plugins_dir)) { + foreach ($this->plugins_dir as $dir) { + $this->getLoader()->addDirectory(rtrim($dir, '\\/')); + } + } + + $tpl = $this->makeTemplate($filename, $cacheId, $compileId); + if ($this->force_compile) { + $tpl->forceCompilation(); + } + + if ($this->caching > 0) { + $this->cacheTime = $this->cache_lifetime; + } else { + $this->cacheTime = 0; + } + + if ($this->compiler_class !== null) { + if ($this->compiler_file !== null && !class_exists($this->compiler_class, false)) { + include $this->compiler_file; + } + $this->compiler = new $this->compiler_class; + } else { + $this->compiler->addPreProcessor('smarty_compat', true); + $this->compiler->setLooseOpeningHandling(true); + } + + $this->compiler->setDelimiters($this->left_delimiter, $this->right_delimiter); + + return $this->get($tpl, $this->dataProvider, $this->compiler, $display===true); + } + + public function get($_tpl, $data = array(), $_compiler = null, $_output = false) + { + if ($_compiler === null) { + $_compiler = $this->compiler; + } + return parent::get($_tpl, $data, $_compiler, $_output); + } + + public function register_function($name, $callback, $cacheable=true, $cache_attrs=null) + { + if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_FUNCTION) { + throw new Dwoo_Exception('Multiple plugins of different types can not share the same name'); + } + $this->plugins[$name] = array('type'=>self::SMARTY_FUNCTION, 'callback'=>$callback); + } + + public function unregister_function($name) + { + unset($this->plugins[$name]); + } + + public function register_block($name, $callback, $cacheable=true, $cache_attrs=null) + { + if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_BLOCK) { + throw new Dwoo_Exception('Multiple plugins of different types can not share the same name'); + } + $this->plugins[$name] = array('type'=>self::SMARTY_BLOCK, 'callback'=>$callback); + } + + public function unregister_block($name) + { + unset($this->plugins[$name]); + } + + public function register_modifier($name, $callback) + { + if (isset($this->plugins[$name]) && $this->plugins[$name][0] !== self::SMARTY_MODIFIER) { + throw new Dwoo_Exception('Multiple plugins of different types can not share the same name'); + } + $this->plugins[$name] = array('type'=>self::SMARTY_MODIFIER, 'callback'=>$callback); + } + + public function unregister_modifier($name) + { + unset($this->plugins[$name]); + } + + public function register_prefilter($callback) + { + $processor = new Dwoo_SmartyProcessorAdapter($this->compiler); + $processor->registerCallback($callback); + $this->_filters['pre'][] = $processor; + $this->compiler->addPreProcessor($processor); + } + + public function unregister_prefilter($callback) + { + foreach ($this->_filters['pre'] as $index => $processor) + if ($processor->callback === $callback) { + $this->compiler->removePostProcessor($processor); + unset($this->_filters['pre'][$index]); + } + } + + public function register_postfilter($callback) + { + $processor = new Dwoo_SmartyProcessorAdapter($this->compiler); + $processor->registerCallback($callback); + $this->_filters['post'][] = $processor; + $this->compiler->addPostProcessor($processor); + } + + public function unregister_postfilter($callback) + { + foreach ($this->_filters['post'] as $index => $processor) + if ($processor->callback === $callback) { + $this->compiler->removePostProcessor($processor); + unset($this->_filters['post'][$index]); + } + } + + public function register_outputfilter($callback) + { + $filter = new Dwoo_SmartyFilterAdapter($this); + $filter->registerCallback($callback); + $this->_filters['output'][] = $filter; + $this->addFilter($filter); + } + + public function unregister_outputfilter($callback) + { + foreach ($this->_filters['output'] as $index => $filter) + if ($filter->callback === $callback) { + $this->removeOutputFilter($filter); + unset($this->_filters['output'][$index]); + } + } + + function register_object($object, $object_impl, $allowed = array(), $smarty_args = false, $block_methods = array()) + { + settype($allowed, 'array'); + settype($block_methods, 'array'); + settype($smarty_args, 'boolean'); + + if (!empty($allowed) && $this->show_compat_errors) { + $this->triggerError('You can register objects but can not restrict the method/properties used, this is PHP5, you have proper OOP access restrictions so use them.', E_USER_NOTICE); + } + + if ($smarty_args) { + $this->triggerError('You can register objects but methods will be called using method($arg1, $arg2, $arg3), not as an argument array like smarty did.', E_USER_NOTICE); + } + + if (!empty($block_methods)) { + $this->triggerError('You can register objects but can not use methods as being block methods, you have to build a plugin for that.', E_USER_NOTICE); + } + + $this->dataProvider->assign($object, $object_impl); + } + + function unregister_object($object) + { + $this->dataProvider->clear($object); + } + + function get_registered_object($name) { + $data = $this->dataProvider->getData(); + if (isset($data[$name]) && is_object($data[$name])) { + return $data[$name]; + } else { + trigger_error('Dwoo_Compiler: object "'.$name.'" was not registered or is not an object', E_USER_ERROR); + } + } + + public function template_exists($filename) + { + if (!is_array($this->template_dir)) { + return file_exists($this->template_dir.DIRECTORY_SEPARATOR.$filename); + } else { + foreach ($this->template_dir as $tpl_dir) { + if (file_exists($tpl_dir.DIRECTORY_SEPARATOR.$filename)) { + return true; + } + } + return false; + } + } + + public function is_cached($tpl, $cacheId = null, $compileId = null) + { + return $this->isCached($this->makeTemplate($tpl, $cacheId, $compileId)); + } + + public function append_by_ref($var, &$value, $merge=false) + { + $this->dataProvider->appendByRef($var, $value, $merge); + } + + public function assign_by_ref($name, &$val) + { + $this->dataProvider->assignByRef($name, $val); + } + + public function clear_assign($var) + { + $this->dataProvider->clear($var); + } + + public function clear_all_assign() + { + $this->dataProvider->clear(); + } + + public function get_template_vars($name=null) + { + if ($this->show_compat_errors) { + trigger_error('get_template_vars does not return values by reference, if you try to modify the data that way you should modify your code.', E_USER_NOTICE); + } + + $data = $this->dataProvider->getData(); + if ($name === null) + return $data; + elseif (isset($data[$name])) + return $data[$name]; + return null; + } + + public function clear_all_cache($olderThan = 0) + { + $this->clearCache($olderThan); + } + + public function clear_cache($template, $cacheId = null, $compileId = null, $olderThan = 0) + { + $this->makeTemplate($template, $cacheId, $compileId)->clearCache($olderThan); + } + + public function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + $this->triggerError($error_msg, $error_type); + } + + protected function initGlobals() + { + parent::initGlobals(); + $this->globals['ldelim'] = '{'; + $this->globals['rdelim'] = '}'; + } + + protected function makeTemplate($file, $cacheId, $compileId) + { + if ($compileId === null) + $compileId = $this->compile_id; + + $hash = bin2hex(md5($file.$cacheId.$compileId, true)); + if (!isset(self::$tplCache[$hash])) { + // abs path + if (substr($file, 0, 1) === '/' || substr($file, 1, 1) === ':') { + self::$tplCache[$hash] = new Dwoo_Template_File($file, null, $cacheId, $compileId); + } elseif (is_string($this->template_dir) || is_array($this->template_dir)) { + self::$tplCache[$hash] = new Dwoo_Template_File($file, null, $cacheId, $compileId, $this->template_dir); + } else { + throw new Exception('Unable to load "'.$file.'", check the template_dir'); + } + } + return self::$tplCache[$hash]; + } + + public function triggerError($message, $level=E_USER_NOTICE) + { + if (is_object($this->template)) { + return parent::triggerError($message, $level); + } + trigger_error('Dwoo error : '.$message, $level); + } +} + +class Dwoo_Smarty_Filter_Adapter extends Dwoo_Filter +{ + public $callback; + + public function process($input) + { + return call_user_func($this->callback, $input); + } + + public function registerCallback($callback) + { + $this->callback = $callback; + } +} + +class Dwoo_Smarty_Processor_Adapter extends Dwoo_Processor +{ + public $callback; + + public function process($input) + { + return call_user_func($this->callback, $input); + } + + public function registerCallback($callback) + { + $this->callback = $callback; + } +} + +// cloaks the adapter if possible with the smarty name to fool type-hinted plugins +if (class_exists('Smarty', false) === false) +{ + interface Smarty {} + class Dwoo_Smarty_Adapter extends Dwoo_Smarty__Adapter implements Smarty {} +} +else +{ + class Dwoo_Smarty_Adapter extends Dwoo_Smarty__Adapter {} +} diff --git a/system/libs/dwoo/Dwoo/Template/File.php b/system/libs/dwoo/Dwoo/Template/File.php new file mode 100644 index 00000000..4dda0f33 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Template/File.php @@ -0,0 +1,270 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Template_File extends Dwoo_Template_String +{ + /** + * template filename + * + * @var string + */ + protected $file; + + /** + * include path(s) to look into to find this template + * + * @var array + */ + protected $includePath = null; + + /** + * resolved path cache when looking for a file in multiple include paths + * + * this is reset when the include path is changed + * + * @var string + */ + protected $resolvedPath = null; + + /** + * creates a template from a file + * + * @param string $file the path to the template file, make sure it exists + * @param int $cacheTime duration of the cache validity for this template, + * if null it defaults to the Dwoo instance that will + * render this template + * @param string $cacheId the unique cache identifier of this page or anything else that + * makes this template's content unique, if null it defaults + * to the current url + * @param string $compileId the unique compiled identifier, which is used to distinguish this + * template from others, if null it defaults to the filename+bits of the path + * @param mixed $includePath a string for a single path to look into for the given file, or an array of paths + */ + public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = null) + { + $this->file = $file; + $this->name = basename($file); + $this->cacheTime = $cacheTime; + + if ($compileId !== null) { + $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); + } + + if ($cacheId !== null) { + $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); + } + + if (is_string($includePath)) { + $this->includePath = array($includePath); + } elseif (is_array($includePath)) { + $this->includePath = $includePath; + } + } + + /** + * sets the include path(s) to where the given template filename must be looked up + * + * @param mixed $paths the path to look into, can be string for a single path or an array of paths + */ + public function setIncludePath($paths) + { + if (is_array($paths) === false) { + $paths = array($paths); + } + + $this->includePath = $paths; + $this->resolvedPath = null; + } + + /** + * return the current include path(s) + * + * @return array + */ + public function getIncludePath() + { + return $this->includePath; + } + + /** + * Checks if compiled file is valid (exists and it's the modification is greater or + * equal to the modification time of the template file) + * + * @param string file + * @return boolean True cache file existance and it's modification time + */ + protected function isValidCompiledFile($file) { + return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file); + } + + /** + * returns the template source of this template + * + * @return string + */ + public function getSource() + { + return file_get_contents($this->getResourceIdentifier()); + } + + /** + * returns the resource name for this template class + * + * @return string + */ + public function getResourceName() + { + return 'file'; + } + + /** + * returns this template's source filename + * + * @return string + */ + public function getResourceIdentifier() + { + if ($this->resolvedPath !== null) { + return $this->resolvedPath; + } elseif ($this->includePath === null) { + return $this->file; + } else { + foreach ($this->includePath as $path) { + $path = rtrim($path, DIRECTORY_SEPARATOR); + if (file_exists($path.DIRECTORY_SEPARATOR.$this->file) === true) { + $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file; + return $this->resolvedPath; + } + } + + throw new Dwoo_Exception('Template "'.$this->file.'" could not be found in any of your include path(s)'); + } + } + + /** + * returns an unique value identifying the current version of this template, + * in this case it's the unix timestamp of the last modification + * + * @return string + */ + public function getUid() + { + return (string) filemtime($this->getResourceIdentifier()); + } + + /** + * returns a new template object from the given include name, null if no include is + * possible (resource not found), or false if include is not permitted by this resource type + * + * @param Dwoo $dwoo the dwoo instance requiring it + * @param mixed $resourceId the filename (relative to this template's dir) of the template to include + * @param int $cacheTime duration of the cache validity for this template, + * if null it defaults to the Dwoo instance that will + * render this template + * @param string $cacheId the unique cache identifier of this page or anything else that + * makes this template's content unique, if null it defaults + * to the current url + * @param string $compileId the unique compiled identifier, which is used to distinguish this + * template from others, if null it defaults to the filename+bits of the path + * @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through + * an include, extends or any other plugin) + * @return Dwoo_Template_File|null + */ + public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) + { + if (DIRECTORY_SEPARATOR === '\\') { + $resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array('\\t', '\\n', '\\r', '\\f', '\\v'), $resourceId); + } + $resourceId = strtr($resourceId, '\\', '/'); + + $includePath = null; + + if (file_exists($resourceId) === false) { + if ($parentTemplate === null) { + $parentTemplate = $dwoo->getTemplate(); + } + if ($parentTemplate instanceof Dwoo_Template_File) { + if ($includePath = $parentTemplate->getIncludePath()) { + if (strstr($resourceId, '../')) { + throw new Dwoo_Exception('When using an include path you can not reference a template into a parent directory (using ../)'); + } + } else { + $resourceId = dirname($parentTemplate->getResourceIdentifier()).DIRECTORY_SEPARATOR.$resourceId; + if (file_exists($resourceId) === false) { + return null; + } + } + } else { + return null; + } + } + + if ($policy = $dwoo->getSecurityPolicy()) { + while (true) { + if (preg_match('{^([a-z]+?)://}i', $resourceId)) { + throw new Dwoo_Security_Exception('The security policy prevents you to read files from external sources : '.$resourceId.'.'); + } + + if ($includePath) { + break; + } + + $resourceId = realpath($resourceId); + $dirs = $policy->getAllowedDirectories(); + foreach ($dirs as $dir=>$dummy) { + if (strpos($resourceId, $dir) === 0) { + break 2; + } + } + throw new Dwoo_Security_Exception('The security policy prevents you to read '.$resourceId.''); + } + } + + $class = 'Dwoo_Template_File'; + if ($parentTemplate) { + $class = get_class($parentTemplate); + } + return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath); + } + + /** + * returns the full compiled file name and assigns a default value to it if + * required + * + * @param Dwoo $dwoo the dwoo instance that requests the file name + * @return string the full path to the compiled file + */ + protected function getCompiledFilename(Dwoo $dwoo) + { + // no compile id was provided, set default + if ($this->compileId===null) { + $this->compileId = str_replace('../', '__', strtr($this->getResourceIdentifier(), '\\:', '/-')); + } + return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php'; + } + + /** + * returns some php code that will check if this template has been modified or not + * + * if the function returns null, the template will be instanciated and then the Uid checked + * + * @return string + */ + public function getIsModifiedCode() + { + return '"'.$this->getUid().'" == filemtime('.var_export($this->getResourceIdentifier(), true).')'; + } +} diff --git a/system/libs/dwoo/Dwoo/Template/String.php b/system/libs/dwoo/Dwoo/Template/String.php new file mode 100644 index 00000000..6fbcaa42 --- /dev/null +++ b/system/libs/dwoo/Dwoo/Template/String.php @@ -0,0 +1,497 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Template_String implements Dwoo_ITemplate +{ + /** + * template name + * + * @var string + */ + protected $name; + + /** + * template compilation id + * + * @var string + */ + protected $compileId; + + /** + * template cache id, if not provided in the constructor, it is set to + * the md4 hash of the request_uri. it is however highly recommended to + * provide one that will fit your needs. + * + * in all cases, the compilation id is prepended to the cache id to separate + * templates with similar cache ids from one another + * + * @var string + */ + protected $cacheId; + + /** + * validity duration of the generated cache file (in seconds) + * + * set to -1 for infinite cache, 0 to disable and null to inherit the Dwoo instance's cache time + * + * @var int + */ + protected $cacheTime; + + /** + * boolean flag that defines whether the compilation should be enforced (once) or + * not use this if you have issues with the compiled templates not being updated + * but if you do need this it's most likely that you should file a bug report + * + * @var bool + */ + protected $compilationEnforced; + + /** + * caches the results of the file checks to save some time when the same + * templates is rendered several times + * + * @var array + */ + protected static $cache = array('cached'=>array(), 'compiled'=>array()); + + /** + * holds the compiler that built this template + * + * @var Dwoo_ICompiler + */ + protected $compiler; + + /** + * chmod value for all files written (cached or compiled ones) + * + * set to null if you don't want any chmod operation to happen + * + * @var int + */ + protected $chmod = 0777; + + /** + * creates a template from a string + * + * @param string $templateString the template to use + * @param int $cacheTime duration of the cache validity for this template, + * if null it defaults to the Dwoo instance that will + * render this template, set to -1 for infinite cache or 0 to disable + * @param string $cacheId the unique cache identifier of this page or anything else that + * makes this template's content unique, if null it defaults + * to the current url + * @param string $compileId the unique compiled identifier, which is used to distinguish this + * template from others, if null it defaults to the md4 hash of the template + */ + public function __construct($templateString, $cacheTime = null, $cacheId = null, $compileId = null) + { + $this->template = $templateString; + if (function_exists('hash')) { + $this->name = hash('md4', $templateString); + } else { + $this->name = md5($templateString); + } + $this->cacheTime = $cacheTime; + + if ($compileId !== null) { + $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); + } + + if ($cacheId !== null) { + $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); + } + } + + /** + * returns the cache duration for this template + * + * defaults to null if it was not provided + * + * @return int|null + */ + public function getCacheTime() + { + return $this->cacheTime; + } + + /** + * sets the cache duration for this template + * + * can be used to set it after the object is created if you did not provide + * it in the constructor + * + * @param int $seconds duration of the cache validity for this template, if + * null it defaults to the Dwoo instance's cache time. 0 = disable and + * -1 = infinite cache + */ + public function setCacheTime($seconds = null) + { + $this->cacheTime = $seconds; + } + + /** + * returns the chmod value for all files written (cached or compiled ones) + * + * defaults to 0777 + * + * @return int|null + */ + public function getChmod() + { + return $this->chmod; + } + + /** + * set the chmod value for all files written (cached or compiled ones) + * + * set to null if you don't want to do any chmod() operation + * + * @param int $mask new bitmask to use for all files + */ + public function setChmod($mask = null) + { + $this->chmod = $mask; + } + + /** + * returns the template name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * returns the resource name for this template class + * + * @return string + */ + public function getResourceName() + { + return 'string'; + } + + /** + * returns the resource identifier for this template, false here as strings don't have identifiers + * + * @return false + */ + public function getResourceIdentifier() + { + return false; + } + + /** + * returns the template source of this template + * + * @return string + */ + public function getSource() + { + return $this->template; + } + + /** + * returns an unique value identifying the current version of this template, + * in this case it's the md4 hash of the content + * + * @return string + */ + public function getUid() + { + return $this->name; + } + + /** + * returns the compiler used by this template, if it was just compiled, or null + * + * @return Dwoo_ICompiler + */ + public function getCompiler() + { + return $this->compiler; + } + + /** + * marks this template as compile-forced, which means it will be recompiled even if it + * was already saved and wasn't modified since the last compilation. do not use this in production, + * it's only meant to be used in development (and the development of dwoo particularly) + */ + public function forceCompilation() + { + $this->compilationEnforced = true; + } + + /** + * returns the cached template output file name, true if it's cache-able but not cached + * or false if it's not cached + * + * @param Dwoo $dwoo the dwoo instance that requests it + * @return string|bool + */ + public function getCachedTemplate(Dwoo $dwoo) + { + if ($this->cacheTime !== null) { + $cacheLength = $this->cacheTime; + } else { + $cacheLength = $dwoo->getCacheTime(); + } + + // file is not cacheable + if ($cacheLength === 0) { + return false; + } + + $cachedFile = $this->getCacheFilename($dwoo); + + if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) { + // already checked, return cache file + return $cachedFile; + } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === -1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($dwoo))) { + // cache is still valid and can be loaded + self::$cache['cached'][$this->cacheId] = true; + return $cachedFile; + } else { + // file is cacheable + return true; + } + } + + /** + * caches the provided output into the cache file + * + * @param Dwoo $dwoo the dwoo instance that requests it + * @param string $output the template output + * @return mixed full path of the cached file or false upon failure + */ + public function cache(Dwoo $dwoo, $output) + { + $cacheDir = $dwoo->getCacheDir(); + $cachedFile = $this->getCacheFilename($dwoo); + + // the code below is courtesy of Rasmus Schultz, + // thanks for his help on avoiding concurency issues + $temp = tempnam($cacheDir, 'temp'); + if (!($file = @fopen($temp, 'wb'))) { + $temp = $cacheDir . uniqid('temp'); + if (!($file = @fopen($temp, 'wb'))) { + trigger_error('Error writing temporary file \''.$temp.'\'', E_USER_WARNING); + return false; + } + } + + fwrite($file, $output); + fclose($file); + + $this->makeDirectory(dirname($cachedFile), $cacheDir); + if (!@rename($temp, $cachedFile)) { + @unlink($cachedFile); + @rename($temp, $cachedFile); + } + + if ($this->chmod !== null) { + chmod($cachedFile, $this->chmod); + } + + self::$cache['cached'][$this->cacheId] = true; + + return $cachedFile; + } + + /** + * clears the cached template if it's older than the given time + * + * @param Dwoo $dwoo the dwoo instance that was used to cache that template + * @param int $olderThan minimum time (in seconds) required for the cache to be cleared + * @return bool true if the cache was not present or if it was deleted, false if it remains there + */ + public function clearCache(Dwoo $dwoo, $olderThan = -1) + { + $cachedFile = $this->getCacheFilename($dwoo); + + return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile)); + } + + /** + * returns the compiled template file name + * + * @param Dwoo $dwoo the dwoo instance that requests it + * @param Dwoo_ICompiler $compiler the compiler that must be used + * @return string + */ + public function getCompiledTemplate(Dwoo $dwoo, Dwoo_ICompiler $compiler = null) + { + $compiledFile = $this->getCompiledFilename($dwoo); + + if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) { + // already checked, return compiled file + } elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) { + // template is compiled + self::$cache['compiled'][$this->compileId] = true; + } else { + // compiles the template + $this->compilationEnforced = false; + + if ($compiler === null) { + $compiler = $dwoo->getDefaultCompilerFactory($this->getResourceName()); + + if ($compiler === null || $compiler === array('Dwoo_Compiler', 'compilerFactory')) { + if (class_exists('Dwoo_Compiler', false) === false) { + include DWOO_DIRECTORY . 'Dwoo/Compiler.php'; + } + $compiler = Dwoo_Compiler::compilerFactory(); + } else { + $compiler = call_user_func($compiler); + } + } + + $this->compiler = $compiler; + + $compiler->setCustomPlugins($dwoo->getCustomPlugins()); + $compiler->setSecurityPolicy($dwoo->getSecurityPolicy()); + $this->makeDirectory(dirname($compiledFile), $dwoo->getCompileDir()); + file_put_contents($compiledFile, $compiler->compile($dwoo, $this)); + if ($this->chmod !== null) { + chmod($compiledFile, $this->chmod); + } + + self::$cache['compiled'][$this->compileId] = true; + } + + return $compiledFile; + } + + /** + * Checks if compiled file is valid (it exists) + * + * @param string file + * @return boolean True cache file existance + */ + protected function isValidCompiledFile($file) { + return file_exists($file); + } + + /** + * returns a new template string object with the resource id being the template source code + * + * @param Dwoo $dwoo the dwoo instance requiring it + * @param mixed $resourceId the filename (relative to this template's dir) of the template to include + * @param int $cacheTime duration of the cache validity for this template, + * if null it defaults to the Dwoo instance that will + * render this template + * @param string $cacheId the unique cache identifier of this page or anything else that + * makes this template's content unique, if null it defaults + * to the current url + * @param string $compileId the unique compiled identifier, which is used to distinguish this + * template from others, if null it defaults to the filename+bits of the path + * @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through + * an include, extends or any other plugin) + * @return Dwoo_Template_String + */ + public static function templateFactory(Dwoo $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null) + { + return new self($resourceId, $cacheTime, $cacheId, $compileId); + } + + /** + * returns the full compiled file name and assigns a default value to it if + * required + * + * @param Dwoo $dwoo the dwoo instance that requests the file name + * @return string the full path to the compiled file + */ + protected function getCompiledFilename(Dwoo $dwoo) + { + // no compile id was provided, set default + if ($this->compileId===null) { + $this->compileId = $this->name; + } + return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo::RELEASE_TAG.'.php'; + } + + /** + * returns the full cached file name and assigns a default value to it if + * required + * + * @param Dwoo $dwoo the dwoo instance that requests the file name + * @return string the full path to the cached file + */ + protected function getCacheFilename(Dwoo $dwoo) + { + // no cache id provided, use request_uri as default + if ($this->cacheId === null) { + if (isset($_SERVER['REQUEST_URI']) === true) { + $cacheId = $_SERVER['REQUEST_URI']; + } elseif (isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['argv'])) { + $cacheId = $_SERVER['SCRIPT_FILENAME'].'-'.implode('-', $_SERVER['argv']); + } else { + $cacheId = ''; + } + // force compiled id generation + $this->getCompiledFilename($dwoo); + + $this->cacheId = str_replace('../', '__', $this->compileId . strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------')); + } + return $dwoo->getCacheDir() . $this->cacheId.'.html'; + } + + /** + * returns some php code that will check if this template has been modified or not + * + * if the function returns null, the template will be instanciated and then the Uid checked + * + * @return string + */ + public function getIsModifiedCode() + { + return null; + } + + /** + * ensures the given path exists + * + * @param string $path any path + * @param string $baseDir the base directory where the directory is created + * ($path must still contain the full path, $baseDir + * is only used for unix permissions) + */ + protected function makeDirectory($path, $baseDir = null) + { + if (is_dir($path) === true) { + return; + } + + if ($this->chmod === null) { + $chmod = 0777; + } else { + $chmod = $this->chmod; + } + mkdir($path, $chmod, true); + + // enforce the correct mode for all directories created + if (strpos(PHP_OS, 'WIN') !== 0 && $baseDir !== null) { + $path = strtr(str_replace($baseDir, '', $path), '\\', '/'); + $folders = explode('/', trim($path, '/')); + foreach ($folders as $folder) { + $baseDir .= $folder . DIRECTORY_SEPARATOR; + chmod($baseDir, $chmod); + } + } + } +} diff --git a/system/libs/dwoo/LICENSE b/system/libs/dwoo/LICENSE new file mode 100644 index 00000000..55dd4a4c --- /dev/null +++ b/system/libs/dwoo/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2008, Dwoo / Jordi Boggiano +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 Dwoo nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY JORDI BOGGIANO ''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 JORDI BOGGIANO 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/system/libs/dwoo/README b/system/libs/dwoo/README new file mode 100644 index 00000000..317179a1 --- /dev/null +++ b/system/libs/dwoo/README @@ -0,0 +1,79 @@ +----------------------------------------------------------------------------- +-- WHAT IS DWOO? readme - version 1.0.0 +----------------------------------------------------------------------------- +Dwoo is a PHP5 Template Engine that was started in early 2008. The idea came +from the fact that Smarty, a well known template engine, is getting older and +older. It carries the weight of it's age, having old features that are +inconsistent compared to newer ones, being written for PHP4 its Object +Oriented aspect doesn't take advantage of PHP5's more advanced features in +the area, etc. Hence Dwoo was born, hoping to provide a more up to date and +stronger engine. + +So far it has proven to be faster than Smarty in many areas, and it provides +a compatibility layer to allow developers that have been using Smarty for +years to switch their application over to Dwoo progressively. + +----------------------------------------------------------------------------- +-- DOCUMENTATION +----------------------------------------------------------------------------- +Dwoo's website to get the latest version is at http://dwoo.org/ + +The wiki/documentation pages are available at http://wiki.dwoo.org/ + +----------------------------------------------------------------------------- +-- LICENSE +----------------------------------------------------------------------------- +Dwoo is released under the Modified BSD license. +See the LICENSE file included in the archive or go to the URL below to obtain +a copy. + +http://dwoo.org/LICENSE + +----------------------------------------------------------------------------- +-- QUICK START - RUNNING DWOO +----------------------------------------------------------------------------- +/***************************** Basic Example *******************************/ +// Include the main class (it should handle the rest on its own) +include 'path/to/dwooAutoload.php'; + +// Create the controller, this is reusable +$dwoo = new Dwoo(); + +// Load a template file (name it as you please), this is reusable +// if you want to render multiple times the same template with different data +$tpl = new Dwoo_Template_File('path/to/index.tpl'); + +// Create a data set, if you don't like this you can directly input an +// associative array in $dwoo->output() +$data = new Dwoo_Data(); +// Fill it with some data +$data->assign('foo', 'BAR'); +$data->assign('bar', 'BAZ'); + +// Outputs the result ... +$dwoo->output($tpl, $data); +// ... or get it to use it somewhere else +$dwoo->get($tpl, $data); + +/***************************** Loop Example *******************************/ +// To loop over multiple articles of a blog for instance, if you have a +// template file representing an article, you could do the following : + +include 'path/to/dwooAutoload.php'; + +$dwoo = new Dwoo(); +$tpl = new Dwoo_Template_File('path/to/article.tpl'); + +$pageContent = ''; + +// Loop over articles that have been retrieved from the DB +foreach($articles as $article) { + // Either associate variables one by one + $data = new Dwoo_Data(); + $data->assign('title', $article['title']; + $data->assign('content', $article['content']); + $pageContent .= $dwoo->get($tpl, $data); + + // Or use the article directly (which is a lot easier in this case) + $pageContent .= $dwoo->get($tpl, $article); +} \ No newline at end of file diff --git a/system/libs/dwoo/UPGRADE_NOTES b/system/libs/dwoo/UPGRADE_NOTES new file mode 100644 index 00000000..5f01896f --- /dev/null +++ b/system/libs/dwoo/UPGRADE_NOTES @@ -0,0 +1,65 @@ +----------------------------------------------------------------------------- +-- Upgrading to Dwoo v1.0.0beta +----------------------------------------------------------------------------- + +1. Dwoo classes loading +----------------------- + +While everything was previously included by Dwoo.php, this version introduces +an autoload function (dwooAutoload) that handles this automatically. This +means your choices are now : + +a) change your : include 'path/to/Dwoo.php'; + into : include 'path/to/dwooAutoload.php'; + this is the recommended setting, especially during development, so that if you + are seeing a Dwoo error and want to report a bug, you get proper line numbers + with the error and not just "error in Dwoo.compiled.php at line 2" + +b) use the compiled version of Dwoo, this is "experimental" and seems to provide better + performances mostly under windows, with a linux server it might imrpove performances + slightly if you have an opcode cache (APC, xcache, ..) : + include 'path/to/Dwoo.compiled.php'; + +c) load Dwoo classes yourself somehow, as part of your autoload function or + whatever suits you best + +----------------------------------------------------------------------------- +-- Upgrading to Dwoo v0.9.2 +----------------------------------------------------------------------------- + +1. Block plugins +---------------- + +This version introduced a backward compatibility break with block plugins, this +was needed to allow compile-time access to the block's (parsed) content, be +very careful if you manipulate this content since it is php code and should remain +so if you don't want syntax errors (which are fatal) during template run. + +Error message : + + Strict Standards: Declaration of Dwoo_Plugin_*::postProcessing() should be compatible with that of Dwoo_Block_Plugin::postProcessing() + +Solution : + + * Change your block plugins postProcessing method declaration to the following : + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + + * Then add "$content" to the beginning of your return value, or modify it if required + +2. Strip modifier +----------------- + +The strip modifier had the same name as the strip block, this worked when the block +was hard coded within the compiler, but with the API change (see above) I was able +to move it to a plugin. Since both plugins don't have the same purpose, there was +a real problem and I had to rename it. The renaming will be handled by the smarty compatibility +layer, but if you used it without smarty compatibility, you should edit your templates. + +3. DWOO_COMPILE_DIRECTORY and DWOO_CACHE_DIRECTORY constants +------------------------------------------------------------ + +If you used those before, you will now get an exception when loading Dwoo. This is done +on purpose to help people to make the transition to the new method of doing it : + + $dwoo = new Dwoo('myCompileDir', 'myCacheDir'); \ No newline at end of file diff --git a/system/libs/dwoo/cache/.gitignore b/system/libs/dwoo/cache/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/system/libs/dwoo/compiled/.gitignore b/system/libs/dwoo/compiled/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/system/libs/dwoo/dwooAutoload.php b/system/libs/dwoo/dwooAutoload.php new file mode 100644 index 00000000..1352db19 --- /dev/null +++ b/system/libs/dwoo/dwooAutoload.php @@ -0,0 +1,12 @@ + + * * href : the target URI where the link must point + * * rest : any other attributes you want to add to the tag can be added as named parameters + * + * + * Example : + * + * + * {* Create a simple link out of an url variable and add a special class attribute: *} + * + * {a $url class="external" /} + * + * {* Mark a link as active depending on some other variable : *} + * + * {a $link.url class=tif($link.active "active"); $link.title /} + * + * {* This is similar to: {$link.title} *} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_a extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($href, array $rest=array()) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $p = $compiler->getCompiledParams($params); + + $out = Dwoo_Compiler::PHP_OPEN . 'echo \'\';' . Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $p = $compiler->getCompiledParams($params); + + // no content was provided so use the url as display text + if ($content == "") { + // merge into the href if href is a string + if (substr($p['href'], -1) === '"' || substr($p['href'], -1) === '\'') { + return Dwoo_Compiler::PHP_OPEN . 'echo '.substr($p['href'], 0, -1).''.substr($p['href'], -1).';'.Dwoo_Compiler::PHP_CLOSE; + } + // otherwise append + return Dwoo_Compiler::PHP_OPEN . 'echo '.$p['href'].'.\'\';'.Dwoo_Compiler::PHP_CLOSE; + } + + // return content + return $content . ''; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/auto_escape.php b/system/libs/dwoo/plugins/builtin/blocks/auto_escape.php new file mode 100644 index 00000000..e85f4450 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/auto_escape.php @@ -0,0 +1,61 @@ + + * * enabled : if set to "on", "enable", true or 1 then the compiler autoescaping is enabled inside this block. set to "off", "disable", false or 0 to disable it + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_auto_escape extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + protected static $stack = array(); + + public function init($enabled) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $params = $compiler->getCompiledParams($params); + switch(strtolower(trim((string) $params['enabled'], '"\''))) { + + case 'on': + case 'true': + case 'enabled': + case 'enable': + case '1': + $enable = true; + break; + case 'off': + case 'false': + case 'disabled': + case 'disable': + case '0': + $enable = false; + break; + default: + throw new Dwoo_Compilation_Exception($compiler, 'Auto_Escape : Invalid parameter ('.$params['enabled'].'), valid parameters are "enable"/true or "disable"/false'); + + } + + self::$stack[] = $compiler->getAutoEscape(); + $compiler->setAutoEscape($enable); + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $compiler->setAutoEscape(array_pop(self::$stack)); + return $content; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/block.php b/system/libs/dwoo/plugins/builtin/blocks/block.php new file mode 100644 index 00000000..b396d9e6 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/block.php @@ -0,0 +1,34 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_block extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($name='') + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/capture.php b/system/libs/dwoo/plugins/builtin/blocks/capture.php new file mode 100644 index 00000000..43ef3de1 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/capture.php @@ -0,0 +1,61 @@ + + * * name : capture name, used to read the value afterwards + * * assign : if set, the value is also saved in the given variable + * * cat : if true, the value is appended to the previous one (if any) instead of overwriting it + * + * If the cat parameter is true, the content + * will be appended to the existing content + * + * Example : + * + * + * {capture "foo"} + * Anything in here won't show, it will be saved for later use.. + * {/capture} + * Output was : {$.capture.foo} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_capture extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($name = 'default', $assign = null, $cat = false, $trim = false) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return Dwoo_Compiler::PHP_OPEN.$prepend.'ob_start();'.$append.Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + + $out = $content . Dwoo_Compiler::PHP_OPEN.$prepend."\n".'$tmp = ob_get_clean();'; + if ($params['trim'] !== 'false' && $params['trim'] !== 0) { + $out .= "\n".'$tmp = trim($tmp);'; + } + if ($params['cat'] === 'true' || $params['cat'] === 1) { + $out .= "\n".'$tmp = $this->readVar(\'dwoo.capture.\'.'.$params['name'].') . $tmp;'; + } + if ($params['assign'] !== 'null') { + $out .= "\n".'$this->scope['.$params['assign'].'] = $tmp;'; + } + return $out . "\n".'$this->globals[\'capture\']['.$params['name'].'] = $tmp;'.$append.Dwoo_Compiler::PHP_CLOSE; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/dynamic.php b/system/libs/dwoo/plugins/builtin/blocks/dynamic.php new file mode 100644 index 00000000..783eae8d --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/dynamic.php @@ -0,0 +1,65 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_dynamic extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $output = Dwoo_Compiler::PHP_OPEN . + 'if($doCache) {'."\n\t". + 'echo \''. + str_replace('\'', '\\\'', $content) . + '\';'. + "\n} else {\n\t"; + if(substr($content, 0, strlen(Dwoo_Compiler::PHP_OPEN)) == Dwoo_Compiler::PHP_OPEN) { + $output .= substr($content, strlen(Dwoo_Compiler::PHP_OPEN)); + } else { + $output .= Dwoo_Compiler::PHP_CLOSE . $content; + } + if(substr($output, -strlen(Dwoo_Compiler::PHP_CLOSE)) == Dwoo_Compiler::PHP_CLOSE) { + $output = substr($output, 0, -strlen(Dwoo_Compiler::PHP_CLOSE)); + } else { + $output .= Dwoo_Compiler::PHP_OPEN; + } + $output .= "\n}". Dwoo_Compiler::PHP_CLOSE; + + return $output; + } + + public static function unescape($output, $dynamicId, $compiledFile) + { + $output = preg_replace_callback('/(.+?)<\/dwoo:dynamic_'.$dynamicId.'>/s', array('self', 'unescapePhp'), $output, -1, $count); + // re-add the includes on top of the file + if ($count && preg_match('#/\* template head \*/(.+?)/\* end template head \*/#s', file_get_contents($compiledFile), $m)) { + $output = ''.$output; + } + return $output; + } + + public static function unescapePhp($match) + { + return preg_replace('{<\?php /\*'.$match[1].'\*/ echo \'(.+?)\'; \?>}s', '$1', $match[2]); + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/else.php b/system/libs/dwoo/plugins/builtin/blocks/else.php new file mode 100644 index 00000000..32f1563f --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/else.php @@ -0,0 +1,63 @@ + + * {foreach $array val} + * $array is not empty so we display it's values : {$val} + * {else} + * if this shows, it means that $array is empty or doesn't exist. + * {/foreach} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_else extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $preContent = ''; + while (true) { + $preContent .= $compiler->removeTopBlock(); + $block =& $compiler->getCurrentBlock(); + $interfaces = class_implements($block['class'], false); + if (in_array('Dwoo_IElseable', $interfaces) !== false) { + break; + } + } + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + return $preContent; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/elseif.php b/system/libs/dwoo/plugins/builtin/blocks/elseif.php new file mode 100644 index 00000000..14949ace --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/elseif.php @@ -0,0 +1,60 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_elseif extends Dwoo_Plugin_if implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public function init(array $rest) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $preContent = ''; + while (true) { + $preContent .= $compiler->removeTopBlock(); + $block =& $compiler->getCurrentBlock(); + $interfaces = class_implements($block['class'], false); + if (in_array('Dwoo_IElseable', $interfaces) !== false) { + break; + } + } + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + return $preContent; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $params = $compiler->getCompiledParams($params); + + $pre = Dwoo_Compiler::PHP_OPEN."elseif (".implode(' ', self::replaceKeywords($params['*'], $compiler)).") {\n" . Dwoo_Compiler::PHP_CLOSE; + $post = Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = $pre . $content . $post; + return ''; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/for.php b/system/libs/dwoo/plugins/builtin/blocks/for.php new file mode 100644 index 00000000..aeabb2a0 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/for.php @@ -0,0 +1,147 @@ + + * * name : for name to access it's iterator variables through {$.for.name.var} see {@link http://wiki.dwoo.org/index.php/IteratorVariables} for details + * * from : array to iterate from (which equals 0) or a number as a start value + * * to : value to stop iterating at (equals count($array) by default if you set an array in from) + * * step : defines the incrementation of the pointer at each iteration + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Plugin_for extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($name, $from, $to=null, $step=1, $skip=0) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + // get block params and save the current template pointer to use it in the postProcessing method + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params']['tplPointer'] = $compiler->getPointer(); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + $tpl = $compiler->getTemplateSource($params['tplPointer']); + + // assigns params + $from = $params['from']; + $name = $params['name']; + $step = $params['step']; + $to = $params['to']; + + // evaluates which global variables have to be computed + $varName = '$dwoo.for.'.trim($name, '"\'').'.'; + $shortVarName = '$.for.'.trim($name, '"\'').'.'; + $usesAny = strpos($tpl, $varName) !== false || strpos($tpl, $shortVarName) !== false; + $usesFirst = strpos($tpl, $varName.'first') !== false || strpos($tpl, $shortVarName.'first') !== false; + $usesLast = strpos($tpl, $varName.'last') !== false || strpos($tpl, $shortVarName.'last') !== false; + $usesIndex = strpos($tpl, $varName.'index') !== false || strpos($tpl, $shortVarName.'index') !== false; + $usesIteration = $usesFirst || $usesLast || strpos($tpl, $varName.'iteration') !== false || strpos($tpl, $shortVarName.'iteration') !== false; + $usesShow = strpos($tpl, $varName.'show') !== false || strpos($tpl, $shortVarName.'show') !== false; + $usesTotal = $usesLast || strpos($tpl, $varName.'total') !== false || strpos($tpl, $shortVarName.'total') !== false; + + if (strpos($name, '$this->scope[') !== false) { + $usesAny = $usesFirst = $usesLast = $usesIndex = $usesIteration = $usesShow = $usesTotal = true; + } + + // gets foreach id + $cnt = self::$cnt++; + + // builds pre processing output for + $out = Dwoo_Compiler::PHP_OPEN . "\n".'$_for'.$cnt.'_from = '.$from.';'. + "\n".'$_for'.$cnt.'_to = '.$to.';'. + "\n".'$_for'.$cnt.'_step = abs('.$step.');'. + "\n".'if (is_numeric($_for'.$cnt.'_from) && !is_numeric($_for'.$cnt.'_to)) { $this->triggerError(\'For requires the to parameter when using a numerical from\'); }'. + "\n".'$tmp_shows = $this->isArray($_for'.$cnt.'_from, true) || (is_numeric($_for'.$cnt.'_from) && (abs(($_for'.$cnt.'_from - $_for'.$cnt.'_to)/$_for'.$cnt.'_step) !== 0 || $_for'.$cnt.'_from == $_for'.$cnt.'_to));'; + // adds foreach properties + if ($usesAny) { + $out .= "\n".'$this->globals["for"]['.$name.'] = array'."\n("; + if ($usesIndex) $out .="\n\t".'"index" => 0,'; + if ($usesIteration) $out .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $out .="\n\t".'"first" => null,'; + if ($usesLast) $out .="\n\t".'"last" => null,'; + if ($usesShow) $out .="\n\t".'"show" => $tmp_shows,'; + if ($usesTotal) $out .="\n\t".'"total" => $this->isArray($_for'.$cnt.'_from) ? floor(count($_for'.$cnt.'_from) / $_for'.$cnt.'_step) : (is_numeric($_for'.$cnt.'_from) ? abs(($_for'.$cnt.'_to + 1 - $_for'.$cnt.'_from)/$_for'.$cnt.'_step) : 0),'; + $out.="\n);\n".'$_for'.$cnt.'_glob =& $this->globals["for"]['.$name.'];'; + } + // checks if for must be looped + $out .= "\n".'if ($tmp_shows)'."\n{"; + // set from/to to correct values if an array was given + $out .= "\n\t".'if ($this->isArray($_for'.$cnt.'_from, true)) { + $_for'.$cnt.'_to = is_numeric($_for'.$cnt.'_to) ? $_for'.$cnt.'_to - $_for'.$cnt.'_step : count($_for'.$cnt.'_from) - 1; + $_for'.$cnt.'_from = 0; + }'; + + // if input are pure numbers it shouldn't reorder them, if it's variables it gets too messy though so in that case a counter should be used + $reverse = false; + $condition = '<='; + $incrementer = '+'; + + if (preg_match('{^(["\']?)([0-9]+)\1$}', $from, $mN1) && preg_match('{^(["\']?)([0-9]+)\1$}', $to, $mN2)) { + $from = (int) $mN1[2]; + $to = (int) $mN2[2]; + if ($from > $to) { + $reverse = true; + $condition = '>='; + $incrementer = '-'; + } + } + + // reverse from and to if needed + if (!$reverse) { + $out .= "\n\t".'if ($_for'.$cnt.'_from > $_for'.$cnt.'_to) { + $tmp = $_for'.$cnt.'_from; + $_for'.$cnt.'_from = $_for'.$cnt.'_to; + $_for'.$cnt.'_to = $tmp; + }'; + } + + $out .= ' + for ($this->scope['.$name.'] = $_for'.$cnt.'_from; $this->scope['.$name.'] '.$condition.' $_for'.$cnt.'_to; $this->scope['.$name.'] '.$incrementer.'= $_for'.$cnt.'_step)'."\n\t{"; + // updates properties + if ($usesIndex) { + $out .="\n\t\t".'$_for'.$cnt.'_glob["index"] = $this->scope['.$name.'];'; + } + if ($usesFirst) { + $out .= "\n\t\t".'$_for'.$cnt.'_glob["first"] = (string) ($_for'.$cnt.'_glob["iteration"] === 1);'; + } + if ($usesLast) { + $out .= "\n\t\t".'$_for'.$cnt.'_glob["last"] = (string) ($_for'.$cnt.'_glob["iteration"] === $_for'.$cnt.'_glob["total"]);'; + } + $out .= "\n/* -- for start output */\n".Dwoo_Compiler::PHP_CLOSE; + + + // build post processing output and cache it + $postOut = Dwoo_Compiler::PHP_OPEN . '/* -- for end output */'; + // update properties + if ($usesIteration) { + $postOut .= "\n\t\t".'$_for'.$cnt.'_glob["iteration"]+=1;'; + } + // end loop + $postOut .= "\n\t}\n}\n".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $postOut .= $params['hasElse']; + } + + return $out . $content . $postOut; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/foreach.php b/system/libs/dwoo/plugins/builtin/blocks/foreach.php new file mode 100644 index 00000000..2c2f9728 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/foreach.php @@ -0,0 +1,152 @@ + + * * from : the array that you want to iterate over + * * key : variable name for the key (or for the item if item is not defined) + * * item : variable name for each item + * * name : foreach name to access it's iterator variables through {$.foreach.name.var} see {@link http://wiki.dwoo.org/index.php/IteratorVariables} for details + * + * Example : + * + * + * {foreach $array val} + * {$val.something} + * {/foreach} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Plugin_foreach extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($from, $key=null, $item=null, $name='default', $implode=null) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + // get block params and save the current template pointer to use it in the postProcessing method + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params']['tplPointer'] = $compiler->getPointer(); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + $tpl = $compiler->getTemplateSource($params['tplPointer']); + + // assigns params + $src = $params['from']; + + if ($params['item'] !== 'null') { + if ($params['key'] !== 'null') { + $key = $params['key']; + } + $val = $params['item']; + } elseif ($params['key'] !== 'null') { + $val = $params['key']; + } else { + throw new Dwoo_Compilation_Exception($compiler, 'Foreach item parameter missing'); + } + $name = $params['name']; + + if (substr($val, 0, 1) !== '"' && substr($val, 0, 1) !== '\'') { + throw new Dwoo_Compilation_Exception($compiler, 'Foreach item parameter must be of type string'); + } + if (isset($key) && substr($val, 0, 1) !== '"' && substr($val, 0, 1) !== '\'') { + throw new Dwoo_Compilation_Exception($compiler, 'Foreach key parameter must be of type string'); + } + + // evaluates which global variables have to be computed + $varName = '$dwoo.foreach.'.trim($name, '"\'').'.'; + $shortVarName = '$.foreach.'.trim($name, '"\'').'.'; + $usesAny = strpos($tpl, $varName) !== false || strpos($tpl, $shortVarName) !== false; + $usesFirst = strpos($tpl, $varName.'first') !== false || strpos($tpl, $shortVarName.'first') !== false; + $usesLast = strpos($tpl, $varName.'last') !== false || strpos($tpl, $shortVarName.'last') !== false; + $usesIndex = $usesFirst || strpos($tpl, $varName.'index') !== false || strpos($tpl, $shortVarName.'index') !== false; + $usesIteration = $usesLast || strpos($tpl, $varName.'iteration') !== false || strpos($tpl, $shortVarName.'iteration') !== false; + $usesShow = strpos($tpl, $varName.'show') !== false || strpos($tpl, $shortVarName.'show') !== false; + $usesTotal = $usesLast || strpos($tpl, $varName.'total') !== false || strpos($tpl, $shortVarName.'total') !== false; + + if (strpos($name, '$this->scope[') !== false) { + $usesAny = $usesFirst = $usesLast = $usesIndex = $usesIteration = $usesShow = $usesTotal = true; + } + + // override globals vars if implode is used + if ($params['implode'] !== 'null') { + $implode = $params['implode']; + $usesAny = true; + $usesLast = true; + $usesIteration = true; + $usesTotal = true; + } + + // gets foreach id + $cnt = self::$cnt++; + + // build pre content output + $pre = Dwoo_Compiler::PHP_OPEN . "\n".'$_fh'.$cnt.'_data = '.$src.';'; + // adds foreach properties + if ($usesAny) { + $pre .= "\n".'$this->globals["foreach"]['.$name.'] = array'."\n("; + if ($usesIndex) $pre .="\n\t".'"index" => 0,'; + if ($usesIteration) $pre .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $pre .="\n\t".'"first" => null,'; + if ($usesLast) $pre .="\n\t".'"last" => null,'; + if ($usesShow) $pre .="\n\t".'"show" => $this->isArray($_fh'.$cnt.'_data, true),'; + if ($usesTotal) $pre .="\n\t".'"total" => $this->isArray($_fh'.$cnt.'_data) ? count($_fh'.$cnt.'_data) : 0,'; + $pre.="\n);\n".'$_fh'.$cnt.'_glob =& $this->globals["foreach"]['.$name.'];'; + } + // checks if foreach must be looped + $pre .= "\n".'if ($this->isArray($_fh'.$cnt.'_data'.(isset($params['hasElse']) ? ', true' : '').') === true)'."\n{"; + // iterates over keys + $pre .= "\n\t".'foreach ($_fh'.$cnt.'_data as '.(isset($key)?'$this->scope['.$key.']=>':'').'$this->scope['.$val.'])'."\n\t{"; + // updates properties + if ($usesFirst) { + $pre .= "\n\t\t".'$_fh'.$cnt.'_glob["first"] = (string) ($_fh'.$cnt.'_glob["index"] === 0);'; + } + if ($usesLast) { + $pre .= "\n\t\t".'$_fh'.$cnt.'_glob["last"] = (string) ($_fh'.$cnt.'_glob["iteration"] === $_fh'.$cnt.'_glob["total"]);'; + } + $pre .= "\n/* -- foreach start output */\n".Dwoo_Compiler::PHP_CLOSE; + + // build post content output + $post = Dwoo_Compiler::PHP_OPEN . "\n"; + + if (isset($implode)) { + $post .= '/* -- implode */'."\n".'if (!$_fh'.$cnt.'_glob["last"]) {'. + "\n\t".'echo '.$implode.";\n}\n"; + } + $post .= '/* -- foreach end output */'; + // update properties + if ($usesIndex) { + $post.="\n\t\t".'$_fh'.$cnt.'_glob["index"]+=1;'; + } + if ($usesIteration) { + $post.="\n\t\t".'$_fh'.$cnt.'_glob["iteration"]+=1;'; + } + // end loop + $post .= "\n\t}\n}".Dwoo_Compiler::PHP_CLOSE; + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/foreachelse.php b/system/libs/dwoo/plugins/builtin/blocks/foreachelse.php new file mode 100644 index 00000000..fbae0ea1 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/foreachelse.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_foreachelse extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $with =& $compiler->findBlock('foreach', true); + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/forelse.php b/system/libs/dwoo/plugins/builtin/blocks/forelse.php new file mode 100644 index 00000000..74bde5ba --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/forelse.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_forelse extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $with =& $compiler->findBlock('for', true); + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/if.php b/system/libs/dwoo/plugins/builtin/blocks/if.php new file mode 100644 index 00000000..51cf5365 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/if.php @@ -0,0 +1,180 @@ + == + * neq or ne -> != + * gte or ge -> >= + * lte or le -> <= + * gt -> > + * lt -> < + * mod -> % + * not -> ! + * X is [not] div by Y -> (X % Y) == 0 + * X is [not] even [by Y] -> (X % 2) == 0 or ((X/Y) % 2) == 0 + * X is [not] odd [by Y] -> (X % 2) != 0 or ((X/Y) % 2) != 0 + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_if extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public function init(array $rest) + { + } + + public static function replaceKeywords(array $params, Dwoo_Compiler $compiler) + { + $p = array(); + + reset($params); + while (list($k,$v) = each($params)) { + $v = (string) $v; + if(substr($v, 0, 1) === '"' || substr($v, 0, 1) === '\'') { + $vmod = strtolower(substr($v, 1, -1)); + } else { + $vmod = strtolower($v); + } + switch($vmod) { + + case 'and': + $p[] = '&&'; + break; + case 'or': + $p[] = '||'; + break; + case '==': + case 'eq': + $p[] = '=='; + break; + case '<>': + case '!=': + case 'ne': + case 'neq': + $p[] = '!='; + break; + case '>=': + case 'gte': + case 'ge': + $p[] = '>='; + break; + case '<=': + case 'lte': + case 'le': + $p[] = '<='; + break; + case '>': + case 'gt': + $p[] = '>'; + break; + case '<': + case 'lt': + $p[] = '<'; + break; + case '===': + $p[] = '==='; + break; + case '!==': + $p[] = '!=='; + break; + case 'is': + if (isset($params[$k+1]) && strtolower(trim($params[$k+1], '"\'')) === 'not') { + $negate = true; + next($params); + } else { + $negate = false; + } + $ptr = 1+(int)$negate; + if (!isset($params[$k+$ptr])) { + $params[$k+$ptr] = ''; + } else { + $params[$k+$ptr] = trim($params[$k+$ptr], '"\''); + } + switch($params[$k+$ptr]) { + + case 'div': + if (isset($params[$k+$ptr+1]) && strtolower(trim($params[$k+$ptr+1], '"\'')) === 'by') { + $p[] = ' % '.$params[$k+$ptr+2].' '.($negate?'!':'=').'== 0'; + next($params); + next($params); + next($params); + } else { + throw new Dwoo_Compilation_Exception($compiler, 'If : Syntax error : syntax should be "if $a is [not] div by $b", found '.$params[$k-1].' is '.($negate?'not ':'').'div '.$params[$k+$ptr+1].' '.$params[$k+$ptr+2]); + } + break; + case 'even': + $a = array_pop($p); + if (isset($params[$k+$ptr+1]) && strtolower(trim($params[$k+$ptr+1], '"\'')) === 'by') { + $b = $params[$k+$ptr+2]; + $p[] = '('.$a .' / '.$b.') % 2 '.($negate?'!':'=').'== 0'; + next($params); + next($params); + } else { + $p[] = $a.' % 2 '.($negate?'!':'=').'== 0'; + } + next($params); + break; + case 'odd': + $a = array_pop($p); + if (isset($params[$k+$ptr+1]) && strtolower(trim($params[$k+$ptr+1], '"\'')) === 'by') { + $b = $params[$k+$ptr+2]; + $p[] = '('.$a .' / '.$b.') % 2 '.($negate?'=':'!').'== 0'; + next($params); + next($params); + } else { + $p[] = $a.' % 2 '.($negate?'=':'!').'== 0'; + } + next($params); + break; + default: + throw new Dwoo_Compilation_Exception($compiler, 'If : Syntax error : syntax should be "if $a is [not] (div|even|odd) [by $b]", found '.$params[$k-1].' is '.$params[$k+$ptr+1]); + + } + break; + case '%': + case 'mod': + $p[] = '%'; + break; + case '!': + case 'not': + $p[] = '!'; + break; + default: + $p[] = $v; + + } + } + + return $p; + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + + $pre = Dwoo_Compiler::PHP_OPEN.'if ('.implode(' ', self::replaceKeywords($params['*'], $compiler)).") {\n".Dwoo_Compiler::PHP_CLOSE; + + $post = Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/loop.php b/system/libs/dwoo/plugins/builtin/blocks/loop.php new file mode 100644 index 00000000..026795c6 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/loop.php @@ -0,0 +1,128 @@ + + * * from : the array that you want to iterate over + * * name : loop name to access it's iterator variables through {$.loop.name.var} see {@link http://wiki.dwoo.org/index.php/IteratorVariables} for details + * + * Example : + * + * instead of a foreach block such as : + * + * + * {foreach $variable value} + * {$value.foo} {$value.bar} + * {/foreach} + * + * + * you can do : + * + * + * {loop $variable} + * {$foo} {$bar} + * {/loop} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Plugin_loop extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($from, $name='default') + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + // get block params and save the current template pointer to use it in the postProcessing method + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params']['tplPointer'] = $compiler->getPointer(); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + $tpl = $compiler->getTemplateSource($params['tplPointer']); + + // assigns params + $src = $params['from']; + $name = $params['name']; + + // evaluates which global variables have to be computed + $varName = '$dwoo.loop.'.trim($name, '"\'').'.'; + $shortVarName = '$.loop.'.trim($name, '"\'').'.'; + $usesAny = strpos($tpl, $varName) !== false || strpos($tpl, $shortVarName) !== false; + $usesFirst = strpos($tpl, $varName.'first') !== false || strpos($tpl, $shortVarName.'first') !== false; + $usesLast = strpos($tpl, $varName.'last') !== false || strpos($tpl, $shortVarName.'last') !== false; + $usesIndex = $usesFirst || strpos($tpl, $varName.'index') !== false || strpos($tpl, $shortVarName.'index') !== false; + $usesIteration = $usesLast || strpos($tpl, $varName.'iteration') !== false || strpos($tpl, $shortVarName.'iteration') !== false; + $usesShow = strpos($tpl, $varName.'show') !== false || strpos($tpl, $shortVarName.'show') !== false; + $usesTotal = $usesLast || strpos($tpl, $varName.'total') !== false || strpos($tpl, $shortVarName.'total') !== false; + + if (strpos($name, '$this->scope[') !== false) { + $usesAny = $usesFirst = $usesLast = $usesIndex = $usesIteration = $usesShow = $usesTotal = true; + } + + // gets foreach id + $cnt = self::$cnt++; + + // builds pre processing output + $pre = Dwoo_Compiler::PHP_OPEN . "\n".'$_loop'.$cnt.'_data = '.$src.';'; + // adds foreach properties + if ($usesAny) { + $pre .= "\n".'$this->globals["loop"]['.$name.'] = array'."\n("; + if ($usesIndex) $pre .="\n\t".'"index" => 0,'; + if ($usesIteration) $pre .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $pre .="\n\t".'"first" => null,'; + if ($usesLast) $pre .="\n\t".'"last" => null,'; + if ($usesShow) $pre .="\n\t".'"show" => $this->isArray($_loop'.$cnt.'_data, true),'; + if ($usesTotal) $pre .="\n\t".'"total" => $this->isArray($_loop'.$cnt.'_data) ? count($_loop'.$cnt.'_data) : 0,'; + $pre.="\n);\n".'$_loop'.$cnt.'_glob =& $this->globals["loop"]['.$name.'];'; + } + // checks if the loop must be looped + $pre .= "\n".'if ($this->isArray($_loop'.$cnt.'_data'.(isset($params['hasElse']) ? ', true' : '').') === true)'."\n{"; + // iterates over keys + $pre .= "\n\t".'foreach ($_loop'.$cnt.'_data as $tmp_key => $this->scope["-loop-"])'."\n\t{"; + // updates properties + if ($usesFirst) { + $pre .= "\n\t\t".'$_loop'.$cnt.'_glob["first"] = (string) ($_loop'.$cnt.'_glob["index"] === 0);'; + } + if ($usesLast) { + $pre .= "\n\t\t".'$_loop'.$cnt.'_glob["last"] = (string) ($_loop'.$cnt.'_glob["iteration"] === $_loop'.$cnt.'_glob["total"]);'; + } + $pre .= "\n\t\t".'$_loop'.$cnt.'_scope = $this->setScope(array("-loop-"));' . "\n/* -- loop start output */\n".Dwoo_Compiler::PHP_CLOSE; + + // build post processing output and cache it + $post = Dwoo_Compiler::PHP_OPEN . "\n".'/* -- loop end output */'."\n\t\t".'$this->setScope($_loop'.$cnt.'_scope, true);'; + // update properties + if ($usesIndex) { + $post.="\n\t\t".'$_loop'.$cnt.'_glob["index"]+=1;'; + } + if ($usesIteration) { + $post.="\n\t\t".'$_loop'.$cnt.'_glob["iteration"]+=1;'; + } + // end loop + $post .= "\n\t}\n}\n" . Dwoo_Compiler::PHP_CLOSE; + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/section.php b/system/libs/dwoo/plugins/builtin/blocks/section.php new file mode 100644 index 00000000..7daba515 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/section.php @@ -0,0 +1,131 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_section extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + public static $cnt=0; + + public function init($name, $loop, $start = null, $step = null, $max = null, $show = true) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $output = Dwoo_Compiler::PHP_OPEN; + $params = $compiler->getCompiledParams($params); + + // assigns params + $loop = $params['loop']; + $start = $params['start']; + $max = $params['max']; + $name = $params['name']; + $step = $params['step']; + $show = $params['show']; + + // gets unique id + $cnt = self::$cnt++; + + $output .= '$this->globals[\'section\']['.$name.'] = array();'."\n". + '$_section'.$cnt.' =& $this->globals[\'section\']['.$name.'];'."\n"; + + if ($loop !== 'null') { + $output .= '$_section'.$cnt.'[\'loop\'] = is_array($tmp = '.$loop.') ? count($tmp) : max(0, (int) $tmp);'."\n"; + } else { + $output .= '$_section'.$cnt.'[\'loop\'] = 1;'."\n"; + } + + if ($show !== 'null') { + $output .= '$_section'.$cnt.'[\'show\'] = '.$show.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'show\'] = true;'."\n"; + } + + if ($name !== 'null') { + $output .= '$_section'.$cnt.'[\'name\'] = '.$name.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'name\'] = true;'."\n"; + } + + if ($max !== 'null') { + $output .= '$_section'.$cnt.'[\'max\'] = (int)'.$max.";\n". + 'if($_section'.$cnt.'[\'max\'] < 0) { $_section'.$cnt.'[\'max\'] = $_section'.$cnt.'[\'loop\']; }'."\n"; + } else { + $output .= '$_section'.$cnt.'[\'max\'] = $_section'.$cnt.'[\'loop\'];'."\n"; + } + + if ($step !== 'null') { + $output .= '$_section'.$cnt.'[\'step\'] = (int)'.$step.' == 0 ? 1 : (int) '.$step.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'step\'] = 1;'."\n"; + } + + if ($start !== 'null') { + $output .= '$_section'.$cnt.'[\'start\'] = (int)'.$start.";\n"; + } else { + $output .= '$_section'.$cnt.'[\'start\'] = $_section'.$cnt.'[\'step\'] > 0 ? 0 : $_section'.$cnt.'[\'loop\'] - 1;'."\n". + 'if ($_section'.$cnt.'[\'start\'] < 0) { $_section'.$cnt.'[\'start\'] = max($_section'.$cnt.'[\'step\'] > 0 ? 0 : -1, $_section'.$cnt.'[\'loop\'] + $_section'.$cnt.'[\'start\']); } '."\n". + 'else { $_section'.$cnt.'[\'start\'] = min($_section'.$cnt.'[\'start\'], $_section'.$cnt.'[\'step\'] > 0 ? $_section'.$cnt.'[\'loop\'] : $_section'.$cnt.'[\'loop\'] -1); }'."\n"; + } + +/* if ($usesAny) { + $output .= "\n".'$this->globals["section"]['.$name.'] = array'."\n("; + if ($usesIndex) $output .="\n\t".'"index" => 0,'; + if ($usesIteration) $output .="\n\t".'"iteration" => 1,'; + if ($usesFirst) $output .="\n\t".'"first" => null,'; + if ($usesLast) $output .="\n\t".'"last" => null,'; + if ($usesShow) $output .="\n\t".'"show" => ($this->isArray($_for'.$cnt.'_from, true)) || (is_numeric($_for'.$cnt.'_from) && $_for'.$cnt.'_from != $_for'.$cnt.'_to),'; + if ($usesTotal) $output .="\n\t".'"total" => $this->isArray($_for'.$cnt.'_from) ? count($_for'.$cnt.'_from) - $_for'.$cnt.'_skip : (is_numeric($_for'.$cnt.'_from) ? abs(($_for'.$cnt.'_to + 1 - $_for'.$cnt.'_from)/$_for'.$cnt.'_step) : 0),'; + $out.="\n);\n".'$_section'.$cnt.'[\'glob\'] =& $this->globals["section"]['.$name.'];'."\n\n"; + } +*/ + + $output .= 'if ($_section'.$cnt.'[\'show\']) {'."\n"; + if ($start === 'null' && $step === 'null' && $max === 'null') { + $output .= ' $_section'.$cnt.'[\'total\'] = $_section'.$cnt.'[\'loop\'];'."\n"; + } else { + $output .= ' $_section'.$cnt.'[\'total\'] = min(ceil(($_section'.$cnt.'[\'step\'] > 0 ? $_section'.$cnt.'[\'loop\'] - $_section'.$cnt.'[\'start\'] : $_section'.$cnt.'[\'start\'] + 1) / abs($_section'.$cnt.'[\'step\'])), $_section'.$cnt.'[\'max\']);'."\n"; + } + $output .= ' if ($_section'.$cnt.'[\'total\'] == 0) {'."\n". + ' $_section'.$cnt.'[\'show\'] = false;'."\n". + ' }'."\n". + '} else {'."\n". + ' $_section'.$cnt.'[\'total\'] = 0;'."\n}\n"; + $output .= 'if ($_section'.$cnt.'[\'show\']) {'."\n"; + $output .= "\t".'for ($this->scope['.$name.'] = $_section'.$cnt.'[\'start\'], $_section'.$cnt.'[\'iteration\'] = 1; '. + '$_section'.$cnt.'[\'iteration\'] <= $_section'.$cnt.'[\'total\']; '. + '$this->scope['.$name.'] += $_section'.$cnt.'[\'step\'], $_section'.$cnt.'[\'iteration\']++) {'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'rownum\'] = $_section'.$cnt.'[\'iteration\'];'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'index_prev\'] = $this->scope['.$name.'] - $_section'.$cnt.'[\'step\'];'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'index_next\'] = $this->scope['.$name.'] + $_section'.$cnt.'[\'step\'];'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'first\'] = ($_section'.$cnt.'[\'iteration\'] == 1);'."\n"; + $output .= "\t\t".'$_section'.$cnt.'[\'last\'] = ($_section'.$cnt.'[\'iteration\'] == $_section'.$cnt.'[\'total\']);'."\n"; + + $output .= Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN; + + $output .= "\n\t}\n} " . Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $output .= $params['hasElse']; + } + + return $output; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/smartyinterface.php b/system/libs/dwoo/plugins/builtin/blocks/smartyinterface.php new file mode 100644 index 00000000..d0e495d4 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/smartyinterface.php @@ -0,0 +1,59 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_smartyinterface extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($__funcname, $__functype, array $rest=array()) {} + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $params = $compiler->getCompiledParams($params); + $func = $params['__funcname']; + $pluginType = $params['__functype']; + $params = $params['*']; + + if ($pluginType & Dwoo::CUSTOM_PLUGIN) { + $customPlugins = $compiler->getDwoo()->getCustomPlugins(); + $callback = $customPlugins[$func]['callback']; + if (is_array($callback)) { + if (is_object($callback[0])) { + $callback = '$this->customPlugins[\''.$func.'\'][0]->'.$callback[1].'('; + } else { + $callback = ''.$callback[0].'::'.$callback[1].'('; + } + } else { + $callback = $callback.'('; + } + } else { + $callback = 'smarty_block_'.$func.'('; + } + + $paramsOut = ''; + foreach ($params as $i=>$p) { + $paramsOut .= var_export($i, true).' => '.$p.','; + } + + $curBlock =& $compiler->getCurrentBlock(); + $curBlock['params']['postOut'] = Dwoo_Compiler::PHP_OPEN.' $_block_content = ob_get_clean(); $_block_repeat=false; echo '.$callback.'$_tag_stack[count($_tag_stack)-1], $_block_content, $this, $_block_repeat); } array_pop($_tag_stack);'.Dwoo_Compiler::PHP_CLOSE; + + return Dwoo_Compiler::PHP_OPEN.$prepend.' if (!isset($_tag_stack)){ $_tag_stack = array(); } $_tag_stack[] = array('.$paramsOut.'); $_block_repeat=true; '.$callback.'$_tag_stack[count($_tag_stack)-1], null, $this, $_block_repeat); while ($_block_repeat) { ob_start();'.Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content . $params['postOut']; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/strip.php b/system/libs/dwoo/plugins/builtin/blocks/strip.php new file mode 100644 index 00000000..dc02933b --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/strip.php @@ -0,0 +1,50 @@ + + * * mode : sets the content being stripped, available mode are 'default' or 'js' + * for javascript, which strips the comments to prevent syntax errors + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Plugin_strip extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($mode = "default") + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $params = $compiler->getCompiledParams($params); + + $mode = trim($params['mode'], '"\''); + switch ($mode) { + case 'js': + case 'javascript': + $content = preg_replace('#(? + * * name : template name + * * rest : list of arguments and optional default values + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.1.0 + * @date 2009-07-18 + * @package Dwoo + */ +class Dwoo_Plugin_template extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init($name, array $rest = array()) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $params = $compiler->getCompiledParams($params); + $parsedParams = array(); + if (!isset($params['*'])) + $params['*'] = array(); + foreach ($params['*'] as $param=>$defValue) { + if (is_numeric($param)) { + $param = $defValue; + $defValue = null; + } + $param = trim($param, '\'"'); + if (!preg_match('#^[a-z0-9_]+$#i', $param)) { + throw new Dwoo_Compilation_Exception($compiler, 'Function : parameter names must contain only A-Z, 0-9 or _'); + } + $parsedParams[$param] = $defValue; + } + $params['name'] = substr($params['name'], 1, -1); + $params['*'] = $parsedParams; + $params['uuid'] = uniqid(); + $compiler->addTemplatePlugin($params['name'], $parsedParams, $params['uuid']); + $currentBlock =& $compiler->getCurrentBlock(); + $currentBlock['params'] = $params; + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $paramstr = 'Dwoo $dwoo'; + $init = 'static $_callCnt = 0;'."\n". + '$dwoo->scope[\' '.$params['uuid'].'\'.$_callCnt] = array();'."\n". + '$_scope = $dwoo->setScope(array(\' '.$params['uuid'].'\'.($_callCnt++)));'."\n"; + $cleanup = '/* -- template end output */ $dwoo->setScope($_scope, true);'; + foreach ($params['*'] as $param=>$defValue) { + if ($defValue === null) { + $paramstr.=', $'.$param; + } else { + $paramstr.=', $'.$param.' = '.$defValue; + } + $init .= '$dwoo->scope[\''.$param.'\'] = $'.$param.";\n"; + } + $init .= '/* -- template start output */'; + + $funcName = 'Dwoo_Plugin_'.$params['name'].'_'.$params['uuid']; + + $search = array( + '$this->charset', + '$this->', + '$this,', + ); + $replacement = array( + '$dwoo->getCharset()', + '$dwoo->', + '$dwoo,', + ); + $content = str_replace($search, $replacement, $content); + + $body = 'if (!function_exists(\''.$funcName."')) {\nfunction ".$funcName.'('.$paramstr.') {'."\n$init".Dwoo_Compiler::PHP_CLOSE. + $prepend.$content.$append. + Dwoo_Compiler::PHP_OPEN.$cleanup."\n}\n}"; + $compiler->addTemplatePlugin($params['name'], $params['*'], $params['uuid'], $body); + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/textformat.php b/system/libs/dwoo/plugins/builtin/blocks/textformat.php new file mode 100644 index 00000000..fb0f4229 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/textformat.php @@ -0,0 +1,94 @@ + + * * wrap : maximum line length + * * wrap_char : the character(s) to use to break the line + * * wrap_cut : if true, the words that are longer than $wrap are cut instead of overflowing + * * indent : amount of $indent_char to insert before every line + * * indent_char : character(s) to insert before every line + * * indent_first : amount of additional $indent_char to insert before the first line of each paragraphs + * * style : some predefined formatting styles that set up every required variables, can be "email" or "html" + * * assign : if set, the formatted text is assigned to that variable instead of being output + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_textformat extends Dwoo_Block_Plugin +{ + protected $wrap; + protected $wrapChar; + protected $wrapCut; + protected $indent; + protected $indChar; + protected $indFirst; + protected $assign; + + public function init($wrap=80, $wrap_char="\r\n", $wrap_cut=false, $indent=0, $indent_char=" ", $indent_first=0, $style="", $assign="") + { + if ($indent_char === 'tab') { + $indent_char = "\t"; + } + + switch($style) { + + case 'email': + $wrap = 72; + $indent_first = 0; + break; + case 'html': + $wrap_char = '
'; + $indent_char = $indent_char == "\t" ? '    ':' '; + break; + + } + + $this->wrap = (int) $wrap; + $this->wrapChar = (string) $wrap_char; + $this->wrapCut = (bool) $wrap_cut; + $this->indent = (int) $indent; + $this->indChar = (string) $indent_char; + $this->indFirst = (int) $indent_first + $this->indent; + $this->assign = (string) $assign; + } + + public function process() + { + // gets paragraphs + $pgs = explode("\n", str_replace(array("\r\n", "\r"), "\n", $this->buffer)); + + while (list($i,) = each($pgs)) { + if (empty($pgs[$i])) { + continue; + } + + // removes line breaks and extensive white space + $pgs[$i] = preg_replace(array('#\s+#', '#^\s*(.+?)\s*$#m'), array(' ', '$1'), str_replace("\n", '', $pgs[$i])); + + // wordwraps + indents lines + $pgs[$i] = str_repeat($this->indChar, $this->indFirst) . + wordwrap( + $pgs[$i], + max($this->wrap - $this->indent, 1), + $this->wrapChar . str_repeat($this->indChar, $this->indent), + $this->wrapCut + ); + } + + if ($this->assign !== '') { + $this->dwoo->assignInScope(implode($this->wrapChar . $this->wrapChar, $pgs), $this->assign); + } else { + return implode($this->wrapChar . $this->wrapChar, $pgs); + } + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/topLevelBlock.php b/system/libs/dwoo/plugins/builtin/blocks/topLevelBlock.php new file mode 100644 index 00000000..95e55767 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/topLevelBlock.php @@ -0,0 +1,32 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +final class Dwoo_Plugin_topLevelBlock extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return '/* end template head */ ob_start(); /* template body */ '.Dwoo_Compiler::PHP_CLOSE; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + return $content . Dwoo_Compiler::PHP_OPEN.' /* end template body */'."\n".'return $this->buffer . ob_get_clean();'; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/with.php b/system/libs/dwoo/plugins/builtin/blocks/with.php new file mode 100644 index 00000000..8bd46dfc --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/with.php @@ -0,0 +1,76 @@ + + * * var : the variable name to move into + * + * Example : + * + * instead of the following : + * + * + * {if $long.boring.prefix} + * {$long.boring.prefix.val} - {$long.boring.prefix.secondVal} - {$long.boring.prefix.thirdVal} + * {/if} + * + * + * you can use : + * + * + * {with $long.boring.prefix} + * {$val} - {$secondVal} - {$thirdVal} + * {/with} + * + * + * This software is provided 'as-is', without any express or implied warranty. + * In no event will the authors be held liable for any damages arising from the use of this software. + * + * @author Jordi Boggiano + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_with extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block, Dwoo_IElseable +{ + protected static $cnt=0; + + public function init($var) + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + $rparams = $compiler->getRealParams($params); + $cparams = $compiler->getCompiledParams($params); + + $compiler->setScope($rparams['var']); + + + $pre = Dwoo_Compiler::PHP_OPEN. 'if ('.$cparams['var'].')'."\n{\n". + '$_with'.(self::$cnt).' = $this->setScope("'.$rparams['var'].'");'. + "\n/* -- start with output */\n".Dwoo_Compiler::PHP_CLOSE; + + $post = Dwoo_Compiler::PHP_OPEN. "\n/* -- end with output */\n". + '$this->setScope($_with'.(self::$cnt++).', true);'. + "\n}\n".Dwoo_Compiler::PHP_CLOSE; + + if (isset($params['hasElse'])) { + $post .= $params['hasElse']; + } + + return $pre . $content . $post; + } +} diff --git a/system/libs/dwoo/plugins/builtin/blocks/withelse.php b/system/libs/dwoo/plugins/builtin/blocks/withelse.php new file mode 100644 index 00000000..deffe574 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/blocks/withelse.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Plugin_withelse extends Dwoo_Block_Plugin implements Dwoo_ICompilable_Block +{ + public function init() + { + } + + public static function preProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $type) + { + $with =& $compiler->findBlock('with', true); + + $params['initialized'] = true; + $compiler->injectBlock($type, $params); + + return ''; + } + + public static function postProcessing(Dwoo_Compiler $compiler, array $params, $prepend, $append, $content) + { + if (!isset($params['initialized'])) { + return ''; + } + + $block =& $compiler->getCurrentBlock(); + $block['params']['hasElse'] = Dwoo_Compiler::PHP_OPEN."else {\n".Dwoo_Compiler::PHP_CLOSE . $content . Dwoo_Compiler::PHP_OPEN."\n}".Dwoo_Compiler::PHP_CLOSE; + return ''; + } +} diff --git a/system/libs/dwoo/plugins/builtin/filters/html_format.php b/system/libs/dwoo/plugins/builtin/filters/html_format.php new file mode 100644 index 00000000..18970f48 --- /dev/null +++ b/system/libs/dwoo/plugins/builtin/filters/html_format.php @@ -0,0 +1,175 @@ + + * @copyright Copyright (c) 2008, Jordi Boggiano + * @license http://dwoo.org/LICENSE Modified BSD License + * @link http://dwoo.org/ + * @version 1.0.0 + * @date 2008-10-23 + * @package Dwoo + */ +class Dwoo_Filter_html_format extends Dwoo_Filter +{ + /** + * tab count to auto-indent the source + * + * @var int + */ + protected static $tabCount = -1; + + /** + * stores the additional data (following a tag) of the last call to open/close/singleTag + * + * @var string + */ + protected static $lastCallAdd = ''; + + /** + * formats the input using the singleTag/closeTag/openTag functions + * + * It is auto indenting the whole code, excluding + + + +
Test will include two attachments.
+ + +
+
+ Mail Test Specs + + + + + +
Test Type +
+ + + required> +
+
+ + + required> +
+
+ + + required> +
+
+ + + required> +
+
+
"> + SMTP Specific Options: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+ +
+ + value=""> +
+ +
+ +
+
+
+
+
+ +
+
+ +
+ +
+ + + + diff --git a/system/libs/phpmailer/examples/contactform.phps b/system/libs/phpmailer/examples/contactform.phps new file mode 100644 index 00000000..d85e2045 --- /dev/null +++ b/system/libs/phpmailer/examples/contactform.phps @@ -0,0 +1,71 @@ +isSMTP(); + $mail->Host = 'localhost'; + $mail->Port = 25; + + //Use a fixed address in your own domain as the from address + //**DO NOT** use the submitter's address here as it will be forgery + //and will cause your messages to fail SPF checks + $mail->setFrom('from@example.com', 'First Last'); + //Send the message to yourself, or whoever should receive contact for submissions + $mail->addAddress('whoto@example.com', 'John Doe'); + //Put the submitter's address in a reply-to header + //This will fail if the address provided is invalid, + //in which case we should ignore the whole request + if ($mail->addReplyTo($_POST['email'], $_POST['name'])) { + $mail->Subject = 'PHPMailer contact form'; + //Keep it simple - don't use HTML + $mail->isHTML(false); + //Build a simple message body + $mail->Body = <<send()) { + //The reason for failing to send will be in $mail->ErrorInfo + //but you shouldn't display errors to users - process the error, log it on your server. + $msg = 'Sorry, something went wrong. Please try again later.'; + } else { + $msg = 'Message sent! Thanks for contacting us.'; + } + } else { + $msg = 'Invalid email address, message ignored.'; + } +} +?> + + + + + Contact form + + +

Contact us

+$msg"; +} ?> +
+
+
+
+ +
+ + diff --git a/system/libs/phpmailer/examples/contents.html b/system/libs/phpmailer/examples/contents.html new file mode 100644 index 00000000..dc3fc667 --- /dev/null +++ b/system/libs/phpmailer/examples/contents.html @@ -0,0 +1,17 @@ + + + + + PHPMailer Test + + +
+

This is a test of PHPMailer.

+
+ PHPMailer rocks +
+

This example uses HTML.

+

ISO-8859-1 text:

+
+ + diff --git a/system/libs/phpmailer/examples/contentsutf8.html b/system/libs/phpmailer/examples/contentsutf8.html new file mode 100644 index 00000000..035d10c8 --- /dev/null +++ b/system/libs/phpmailer/examples/contentsutf8.html @@ -0,0 +1,21 @@ + + + + + PHPMailer Test + + +
+

This is a test of PHPMailer.

+
+ PHPMailer rocks +
+

This example uses HTML.

+

Chinese text: 郵件內容為空

+

Russian text: Пустое тело сообщения

+

Armenian text: Հաղորդագրությունը դատարկ է

+

Czech text: Prázdné tělo zprávy

+

Emoji: 😂 🦄 💥 📤 📧

+
+ + diff --git a/system/libs/phpmailer/examples/exceptions.phps b/system/libs/phpmailer/examples/exceptions.phps new file mode 100644 index 00000000..0e941e73 --- /dev/null +++ b/system/libs/phpmailer/examples/exceptions.phps @@ -0,0 +1,35 @@ +setFrom('from@example.com', 'First Last'); + //Set an alternative reply-to address + $mail->addReplyTo('replyto@example.com', 'First Last'); + //Set who the message is to be sent to + $mail->addAddress('whoto@example.com', 'John Doe'); + //Set the subject line + $mail->Subject = 'PHPMailer Exceptions test'; + //Read an HTML message body from an external file, convert referenced images to embedded, + //and convert the HTML into a basic plain-text alternative body + $mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); + //Replace the plain text body with one created manually + $mail->AltBody = 'This is a plain-text message body'; + //Attach an image file + $mail->addAttachment('images/phpmailer_mini.png'); + //send the message + //Note that we don't need check the response from this because it will throw an exception if it has trouble + $mail->send(); + echo "Message sent!"; +} catch (phpmailerException $e) { + echo $e->errorMessage(); //Pretty error messages from PHPMailer +} catch (Exception $e) { + echo $e->getMessage(); //Boring error messages from anything else! +} diff --git a/system/libs/phpmailer/examples/gmail.phps b/system/libs/phpmailer/examples/gmail.phps new file mode 100644 index 00000000..b3cc02d5 --- /dev/null +++ b/system/libs/phpmailer/examples/gmail.phps @@ -0,0 +1,75 @@ +isSMTP(); + +//Enable SMTP debugging +// 0 = off (for production use) +// 1 = client messages +// 2 = client and server messages +$mail->SMTPDebug = 2; + +//Ask for HTML-friendly debug output +$mail->Debugoutput = 'html'; + +//Set the hostname of the mail server +$mail->Host = 'smtp.gmail.com'; +// use +// $mail->Host = gethostbyname('smtp.gmail.com'); +// if your network does not support SMTP over IPv6 + +//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission +$mail->Port = 587; + +//Set the encryption system to use - ssl (deprecated) or tls +$mail->SMTPSecure = 'tls'; + +//Whether to use SMTP authentication +$mail->SMTPAuth = true; + +//Username to use for SMTP authentication - use full email address for gmail +$mail->Username = "username@gmail.com"; + +//Password to use for SMTP authentication +$mail->Password = "yourpassword"; + +//Set who the message is to be sent from +$mail->setFrom('from@example.com', 'First Last'); + +//Set an alternative reply-to address +$mail->addReplyTo('replyto@example.com', 'First Last'); + +//Set who the message is to be sent to +$mail->addAddress('whoto@example.com', 'John Doe'); + +//Set the subject line +$mail->Subject = 'PHPMailer GMail SMTP test'; + +//Read an HTML message body from an external file, convert referenced images to embedded, +//convert HTML into a basic plain-text alternative body +$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); + +//Replace the plain text body with one created manually +$mail->AltBody = 'This is a plain-text message body'; + +//Attach an image file +$mail->addAttachment('images/phpmailer_mini.png'); + +//send the message, check for errors +if (!$mail->send()) { + echo "Mailer Error: " . $mail->ErrorInfo; +} else { + echo "Message sent!"; +} diff --git a/system/libs/phpmailer/examples/gmail_xoauth.phps b/system/libs/phpmailer/examples/gmail_xoauth.phps new file mode 100644 index 00000000..d64483a4 --- /dev/null +++ b/system/libs/phpmailer/examples/gmail_xoauth.phps @@ -0,0 +1,85 @@ +isSMTP(); + +//Enable SMTP debugging +// 0 = off (for production use) +// 1 = client messages +// 2 = client and server messages +$mail->SMTPDebug = 0; + +//Ask for HTML-friendly debug output +$mail->Debugoutput = 'html'; + +//Set the hostname of the mail server +$mail->Host = 'smtp.gmail.com'; + +//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission +$mail->Port = 587; + +//Set the encryption system to use - ssl (deprecated) or tls +$mail->SMTPSecure = 'tls'; + +//Whether to use SMTP authentication +$mail->SMTPAuth = true; + +//Set AuthType +$mail->AuthType = 'XOAUTH2'; + +//User Email to use for SMTP authentication - Use the same Email used in Google Developer Console +$mail->oauthUserEmail = "someone@gmail.com"; + +//Obtained From Google Developer Console +$mail->oauthClientId = "RANDOMCHARS-----duv1n2.apps.googleusercontent.com"; + +//Obtained From Google Developer Console +$mail->oauthClientSecret = "RANDOMCHARS-----lGyjPcRtvP"; + +//Obtained By running get_oauth_token.php after setting up APP in Google Developer Console. +//Set Redirect URI in Developer Console as [https/http]:////get_oauth_token.php +// eg: http://localhost/phpmail/get_oauth_token.php +$mail->oauthRefreshToken = "RANDOMCHARS-----DWxgOvPT003r-yFUV49TQYag7_Aod7y0"; + +//Set who the message is to be sent from +//For gmail, this generally needs to be the same as the user you logged in as +$mail->setFrom('from@example.com', 'First Last'); + +//Set who the message is to be sent to +$mail->addAddress('whoto@example.com', 'John Doe'); + +//Set the subject line +$mail->Subject = 'PHPMailer GMail SMTP test'; + +//Read an HTML message body from an external file, convert referenced images to embedded, +//convert HTML into a basic plain-text alternative body +$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); + +//Replace the plain text body with one created manually +$mail->AltBody = 'This is a plain-text message body'; + +//Attach an image file +$mail->addAttachment('images/phpmailer_mini.png'); + +//send the message, check for errors +if (!$mail->send()) { + echo "Mailer Error: " . $mail->ErrorInfo; +} else { + echo "Message sent!"; +} diff --git a/system/libs/phpmailer/examples/images/phpmailer.png b/system/libs/phpmailer/examples/images/phpmailer.png new file mode 100644 index 00000000..9bdd83c8 Binary files /dev/null and b/system/libs/phpmailer/examples/images/phpmailer.png differ diff --git a/system/libs/phpmailer/examples/images/phpmailer_mini.png b/system/libs/phpmailer/examples/images/phpmailer_mini.png new file mode 100644 index 00000000..e6915f43 Binary files /dev/null and b/system/libs/phpmailer/examples/images/phpmailer_mini.png differ diff --git a/system/libs/phpmailer/examples/index.html b/system/libs/phpmailer/examples/index.html new file mode 100644 index 00000000..bbb830d1 --- /dev/null +++ b/system/libs/phpmailer/examples/index.html @@ -0,0 +1,48 @@ + + + + + PHPMailer Examples + + +

PHPMailer code examplesPHPMailer logo

+

This folder contains a collection of examples of using PHPMailer.

+

About testing email sending

+

When working on email sending code you'll find yourself worrying about what might happen if all these test emails got sent to your mailing list. The solution is to use a fake mail server, one that acts just like the real thing, but just doesn't actually send anything out. Some offer web interfaces, feedback, logging, the ability to return specific error codes, all things that are useful for testing error handling, authentication etc. Here's a selection of mail testing tools you might like to try:

+
    +
  • FakeSMTP, a Java desktop app with the ability to show an SMTP log and save messages to a folder.
  • +
  • FakeEmail, a Python-based fake mail server with a web interface.
  • +
  • smtp-sink, part of the Postfix mail server, so you probably already have this installed. This is used in the Travis-CI configuration to run PHPMailer's unit tests.
  • +
  • smtp4dev, a dummy SMTP server for Windows.
  • +
  • fakesendmail.sh, part of PHPMailer's test setup, this is a shell script that emulates sendmail for testing 'mail' or 'sendmail' methods in PHPMailer.
  • +
  • msglint, not a mail server, the IETF's MIME structure analyser checks the formatting of your messages.
  • +
+
+

Security note

+

Before running these examples you'll need to rename them with '.php' extensions. They are supplied as '.phps' files which will usually be displayed with syntax highlighting by PHP instead of running them. This prevents potential security issues with running potential spam-gateway code if you happen to deploy these code examples on a live site - please don't do that! Similarly, don't leave your passwords in these files as they will be visible to the world!

+
+

code_generator.phps

+

This script is a simple code generator - fill in the form and hit submit, and it will use when you entered to email you a message, and will also generate PHP code using your settings that you can copy and paste to use in your own apps. If you need to get going quickly, this is probably the best place to start.

+

mail.phps

+

This script is a basic example which creates an email message from an external HTML file, creates a plain text body, sets various addresses, adds an attachment and sends the message. It uses PHP's built-in mail() function which is the simplest to use, but relies on the presence of a local mail server, something which is not usually available on Windows. If you find yourself in that situation, either install a local mail server, or use a remote one and send using SMTP instead.

+

exceptions.phps

+

The same as the mail example, but shows how to use PHPMailer's optional exceptions for error handling.

+

smtp.phps

+

A simple example sending using SMTP with authentication.

+

smtp_no_auth.phps

+

A simple example sending using SMTP without authentication.

+

sendmail.phps

+

A simple example using sendmail. Sendmail is a program (usually found on Linux/BSD, OS X and other UNIX-alikes) that can be used to submit messages to a local mail server without a lengthy SMTP conversation. It's probably the fastest sending mechanism, but lacks some error reporting features. There are sendmail emulators for most popular mail servers including postfix, qmail, exim etc.

+

gmail.phps

+

Submitting email via Google's Gmail service is a popular use of PHPMailer. It's much the same as normal SMTP sending, just with some specific settings, namely using TLS encryption, authentication is enabled, and it connects to the SMTP submission port 587 on the smtp.gmail.com host. This example does all that.

+

pop_before_smtp.phps

+

Before effective SMTP authentication mechanisms were available, it was common for ISPs to use POP-before-SMTP authentication. As it implies, you authenticate using the POP3 protocol (an older protocol now mostly replaced by the far superior IMAP), and then the SMTP server will allow send access from your IP address for a short while, usually 5-15 minutes. PHPMailer includes a POP3 protocol client, so it can carry out this sequence - it's just like a normal SMTP conversation (without authentication), but connects via POP first.

+

mailing_list.phps

+

This is a somewhat naïve example of sending similar emails to a list of different addresses. It sets up a PHPMailer instance using SMTP, then connects to a MySQL database to retrieve a list of recipients. The code loops over this list, sending email to each person using their info and marks them as sent in the database. It makes use of SMTP keepalive which saves reconnecting and re-authenticating between each message.

+
+

smtp_check.phps

+

This is an example showing how to use the SMTP class by itself (without PHPMailer) to check an SMTP connection.

+
+

Most of these examples use the 'example.com' domain. This domain is reserved by IANA for illustrative purposes, as documented in RFC 2606. Don't use made-up domains like 'mydomain.com' or 'somedomain.com' in examples as someone, somewhere, probably owns them!

+ + diff --git a/system/libs/phpmailer/examples/mail.phps b/system/libs/phpmailer/examples/mail.phps new file mode 100644 index 00000000..8e129f47 --- /dev/null +++ b/system/libs/phpmailer/examples/mail.phps @@ -0,0 +1,31 @@ +setFrom('from@example.com', 'First Last'); +//Set an alternative reply-to address +$mail->addReplyTo('replyto@example.com', 'First Last'); +//Set who the message is to be sent to +$mail->addAddress('whoto@example.com', 'John Doe'); +//Set the subject line +$mail->Subject = 'PHPMailer mail() test'; +//Read an HTML message body from an external file, convert referenced images to embedded, +//convert HTML into a basic plain-text alternative body +$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); +//Replace the plain text body with one created manually +$mail->AltBody = 'This is a plain-text message body'; +//Attach an image file +$mail->addAttachment('images/phpmailer_mini.png'); + +//send the message, check for errors +if (!$mail->send()) { + echo "Mailer Error: " . $mail->ErrorInfo; +} else { + echo "Message sent!"; +} diff --git a/system/libs/phpmailer/examples/mailing_list.phps b/system/libs/phpmailer/examples/mailing_list.phps new file mode 100644 index 00000000..8644bb59 --- /dev/null +++ b/system/libs/phpmailer/examples/mailing_list.phps @@ -0,0 +1,59 @@ +isSMTP(); +$mail->Host = 'smtp.example.com'; +$mail->SMTPAuth = true; +$mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent, reduces SMTP overhead +$mail->Port = 25; +$mail->Username = 'yourname@example.com'; +$mail->Password = 'yourpassword'; +$mail->setFrom('list@example.com', 'List manager'); +$mail->addReplyTo('list@example.com', 'List manager'); + +$mail->Subject = "PHPMailer Simple database mailing list test"; + +//Same body for all messages, so set this before the sending loop +//If you generate a different body for each recipient (e.g. you're using a templating system), +//set it inside the loop +$mail->msgHTML($body); +//msgHTML also sets AltBody, but if you want a custom one, set it afterwards +$mail->AltBody = 'To view the message, please use an HTML compatible email viewer!'; + +//Connect to the database and select the recipients from your mailing list that have not yet been sent to +//You'll need to alter this to match your database +$mysql = mysqli_connect('localhost', 'username', 'password'); +mysqli_select_db($mysql, 'mydb'); +$result = mysqli_query($mysql, 'SELECT full_name, email, photo FROM mailinglist WHERE sent = false'); + +foreach ($result as $row) { //This iterator syntax only works in PHP 5.4+ + $mail->addAddress($row['email'], $row['full_name']); + if (!empty($row['photo'])) { + $mail->addStringAttachment($row['photo'], 'YourPhoto.jpg'); //Assumes the image data is stored in the DB + } + + if (!$mail->send()) { + echo "Mailer Error (" . str_replace("@", "@", $row["email"]) . ') ' . $mail->ErrorInfo . '
'; + break; //Abandon sending + } else { + echo "Message sent to :" . $row['full_name'] . ' (' . str_replace("@", "@", $row['email']) . ')
'; + //Mark it as sent in the DB + mysqli_query( + $mysql, + "UPDATE mailinglist SET sent = true WHERE email = '" . + mysqli_real_escape_string($mysql, $row['email']) . "'" + ); + } + // Clear all addresses and attachments for next loop + $mail->clearAddresses(); + $mail->clearAttachments(); +} diff --git a/system/libs/phpmailer/examples/pop_before_smtp.phps b/system/libs/phpmailer/examples/pop_before_smtp.phps new file mode 100644 index 00000000..164dfe8d --- /dev/null +++ b/system/libs/phpmailer/examples/pop_before_smtp.phps @@ -0,0 +1,54 @@ +isSMTP(); + //Enable SMTP debugging + // 0 = off (for production use) + // 1 = client messages + // 2 = client and server messages + $mail->SMTPDebug = 2; + //Ask for HTML-friendly debug output + $mail->Debugoutput = 'html'; + //Set the hostname of the mail server + $mail->Host = "mail.example.com"; + //Set the SMTP port number - likely to be 25, 465 or 587 + $mail->Port = 25; + //Whether to use SMTP authentication + $mail->SMTPAuth = false; + //Set who the message is to be sent from + $mail->setFrom('from@example.com', 'First Last'); + //Set an alternative reply-to address + $mail->addReplyTo('replyto@example.com', 'First Last'); + //Set who the message is to be sent to + $mail->addAddress('whoto@example.com', 'John Doe'); + //Set the subject line + $mail->Subject = 'PHPMailer POP-before-SMTP test'; + //Read an HTML message body from an external file, convert referenced images to embedded, + //and convert the HTML into a basic plain-text alternative body + $mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); + //Replace the plain text body with one created manually + $mail->AltBody = 'This is a plain-text message body'; + //Attach an image file + $mail->addAttachment('images/phpmailer_mini.png'); + //send the message + //Note that we don't need check the response from this because it will throw an exception if it has trouble + $mail->send(); + echo "Message sent!"; +} catch (phpmailerException $e) { + echo $e->errorMessage(); //Pretty error messages from PHPMailer +} catch (Exception $e) { + echo $e->getMessage(); //Boring error messages from anything else! +} diff --git a/system/libs/phpmailer/examples/scripts/XRegExp.js b/system/libs/phpmailer/examples/scripts/XRegExp.js new file mode 100644 index 00000000..feb66798 --- /dev/null +++ b/system/libs/phpmailer/examples/scripts/XRegExp.js @@ -0,0 +1,664 @@ +// XRegExp 1.5.1 +// (c) 2007-2012 Steven Levithan +// MIT License +// +// Provides an augmented, extensible, cross-browser implementation of regular expressions, +// including support for additional syntax, flags, and methods + +var XRegExp; + +if (XRegExp) { + // Avoid running twice, since that would break references to native globals + throw Error("can't load XRegExp twice in the same frame"); +} + +// Run within an anonymous function to protect variables and avoid new globals +(function (undefined) { + + //--------------------------------- + // Constructor + //--------------------------------- + + // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native + // regular expression in that additional syntax and flags are supported and cross-browser + // syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and + // converts to type XRegExp + XRegExp = function (pattern, flags) { + var output = [], + currScope = XRegExp.OUTSIDE_CLASS, + pos = 0, + context, tokenResult, match, chr, regex; + + if (XRegExp.isRegExp(pattern)) { + if (flags !== undefined) + throw TypeError("can't supply flags when constructing one RegExp from another"); + return clone(pattern); + } + // Tokens become part of the regex construction process, so protect against infinite + // recursion when an XRegExp is constructed within a token handler or trigger + if (isInsideConstructor) + throw Error("can't call the XRegExp constructor within token definition functions"); + + flags = flags || ""; + context = { // `this` object for custom tokens + hasNamedCapture: false, + captureNames: [], + hasFlag: function (flag) {return flags.indexOf(flag) > -1;}, + setFlag: function (flag) {flags += flag;} + }; + + while (pos < pattern.length) { + // Check for custom tokens at the current position + tokenResult = runTokens(pattern, pos, currScope, context); + + if (tokenResult) { + output.push(tokenResult.output); + pos += (tokenResult.match[0].length || 1); + } else { + // Check for native multicharacter metasequences (excluding character classes) at + // the current position + if (match = nativ.exec.call(nativeTokens[currScope], pattern.slice(pos))) { + output.push(match[0]); + pos += match[0].length; + } else { + chr = pattern.charAt(pos); + if (chr === "[") + currScope = XRegExp.INSIDE_CLASS; + else if (chr === "]") + currScope = XRegExp.OUTSIDE_CLASS; + // Advance position one character + output.push(chr); + pos++; + } + } + } + + regex = RegExp(output.join(""), nativ.replace.call(flags, flagClip, "")); + regex._xregexp = { + source: pattern, + captureNames: context.hasNamedCapture ? context.captureNames : null + }; + return regex; + }; + + + //--------------------------------- + // Public properties + //--------------------------------- + + XRegExp.version = "1.5.1"; + + // Token scope bitflags + XRegExp.INSIDE_CLASS = 1; + XRegExp.OUTSIDE_CLASS = 2; + + + //--------------------------------- + // Private variables + //--------------------------------- + + var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g, + flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags + quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/, + isInsideConstructor = false, + tokens = [], + // Copy native globals for reference ("native" is an ES3 reserved keyword) + nativ = { + exec: RegExp.prototype.exec, + test: RegExp.prototype.test, + match: String.prototype.match, + replace: String.prototype.replace, + split: String.prototype.split + }, + compliantExecNpcg = nativ.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups + compliantLastIndexIncrement = function () { + var x = /^/g; + nativ.test.call(x, ""); + return !x.lastIndex; + }(), + hasNativeY = RegExp.prototype.sticky !== undefined, + nativeTokens = {}; + + // `nativeTokens` match native multicharacter metasequences only (including deprecated octals, + // excluding character classes) + nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/; + nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/; + + + //--------------------------------- + // Public methods + //--------------------------------- + + // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by + // the XRegExp library and can be used to create XRegExp plugins. This function is intended for + // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can + // be disabled by `XRegExp.freezeTokens` + XRegExp.addToken = function (regex, handler, scope, trigger) { + tokens.push({ + pattern: clone(regex, "g" + (hasNativeY ? "y" : "")), + handler: handler, + scope: scope || XRegExp.OUTSIDE_CLASS, + trigger: trigger || null + }); + }; + + // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag + // combination has previously been cached, the cached copy is returned; otherwise the newly + // created regex is cached + XRegExp.cache = function (pattern, flags) { + var key = pattern + "/" + (flags || ""); + return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags)); + }; + + // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh + // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global` + // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve + // special properties required for named capture + XRegExp.copyAsGlobal = function (regex) { + return clone(regex, "g"); + }; + + // Accepts a string; returns the string with regex metacharacters escaped. The returned string + // can safely be used at any point within a regex to match the provided literal string. Escaped + // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace + XRegExp.escape = function (str) { + return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + }; + + // Accepts a string to search, regex to search with, position to start the search within the + // string (default: 0), and an optional Boolean indicating whether matches must start at-or- + // after the position or at the specified position only. This function ignores the `lastIndex` + // of the provided regex in its own handling, but updates the property for compatibility + XRegExp.execAt = function (str, regex, pos, anchored) { + var r2 = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")), + match; + r2.lastIndex = pos = pos || 0; + match = r2.exec(str); // Run the altered `exec` (required for `lastIndex` fix, etc.) + if (anchored && match && match.index !== pos) + match = null; + if (regex.global) + regex.lastIndex = match ? r2.lastIndex : 0; + return match; + }; + + // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing + // syntax and flag changes. Should be run after XRegExp and any plugins are loaded + XRegExp.freezeTokens = function () { + XRegExp.addToken = function () { + throw Error("can't run addToken after freezeTokens"); + }; + }; + + // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object. + // Note that this is also `true` for regex literals and regexes created by the `XRegExp` + // constructor. This works correctly for variables created in another frame, when `instanceof` + // and `constructor` checks would fail to work as intended + XRegExp.isRegExp = function (o) { + return Object.prototype.toString.call(o) === "[object RegExp]"; + }; + + // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to + // iterate over regex matches compared to the traditional approaches of subverting + // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop + XRegExp.iterate = function (str, regex, callback, context) { + var r2 = clone(regex, "g"), + i = -1, match; + while (match = r2.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.) + if (regex.global) + regex.lastIndex = r2.lastIndex; // Doing this to follow expectations if `lastIndex` is checked within `callback` + callback.call(context, match, ++i, str, regex); + if (r2.lastIndex === match.index) + r2.lastIndex++; + } + if (regex.global) + regex.lastIndex = 0; + }; + + // Accepts a string and an array of regexes; returns the result of using each successive regex + // to search within the matches of the previous regex. The array of regexes can also contain + // objects with `regex` and `backref` properties, in which case the named or numbered back- + // references specified are passed forward to the next regex or returned. E.g.: + // var xregexpImgFileNames = XRegExp.matchChain(html, [ + // {regex: /]+)>/i, backref: 1}, // tag attributes + // {regex: XRegExp('(?ix) \\s src=" (? [^"]+ )'), backref: "src"}, // src attribute values + // {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths + // /[^\/]+$/ // filenames (strip directory paths) + // ]); + XRegExp.matchChain = function (str, chain) { + return function recurseChain (values, level) { + var item = chain[level].regex ? chain[level] : {regex: chain[level]}, + regex = clone(item.regex, "g"), + matches = [], i; + for (i = 0; i < values.length; i++) { + XRegExp.iterate(values[i], regex, function (match) { + matches.push(item.backref ? (match[item.backref] || "") : match[0]); + }); + } + return ((level === chain.length - 1) || !matches.length) ? + matches : recurseChain(matches, level + 1); + }([str], 0); + }; + + + //--------------------------------- + // New RegExp prototype methods + //--------------------------------- + + // Accepts a context object and arguments array; returns the result of calling `exec` with the + // first value in the arguments array. the context is ignored but is accepted for congruity + // with `Function.prototype.apply` + RegExp.prototype.apply = function (context, args) { + return this.exec(args[0]); + }; + + // Accepts a context object and string; returns the result of calling `exec` with the provided + // string. the context is ignored but is accepted for congruity with `Function.prototype.call` + RegExp.prototype.call = function (context, str) { + return this.exec(str); + }; + + + //--------------------------------- + // Overridden native methods + //--------------------------------- + + // Adds named capture support (with backreferences returned as `result.name`), and fixes two + // cross-browser issues per ES3: + // - Captured values for nonparticipating capturing groups should be returned as `undefined`, + // rather than the empty string. + // - `lastIndex` should not be incremented after zero-length matches. + RegExp.prototype.exec = function (str) { + var match, name, r2, origLastIndex; + if (!this.global) + origLastIndex = this.lastIndex; + match = nativ.exec.apply(this, arguments); + if (match) { + // Fix browsers whose `exec` methods don't consistently return `undefined` for + // nonparticipating capturing groups + if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { + r2 = RegExp(this.source, nativ.replace.call(getNativeFlags(this), "g", "")); + // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed + // matching due to characters outside the match + nativ.replace.call((str + "").slice(match.index), r2, function () { + for (var i = 1; i < arguments.length - 2; i++) { + if (arguments[i] === undefined) + match[i] = undefined; + } + }); + } + // Attach named capture properties + if (this._xregexp && this._xregexp.captureNames) { + for (var i = 1; i < match.length; i++) { + name = this._xregexp.captureNames[i - 1]; + if (name) + match[name] = match[i]; + } + } + // Fix browsers that increment `lastIndex` after zero-length matches + if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + } + if (!this.global) + this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows) + return match; + }; + + // Fix browser bugs in native method + RegExp.prototype.test = function (str) { + // Use the native `exec` to skip some processing overhead, even though the altered + // `exec` would take care of the `lastIndex` fixes + var match, origLastIndex; + if (!this.global) + origLastIndex = this.lastIndex; + match = nativ.exec.call(this, str); + // Fix browsers that increment `lastIndex` after zero-length matches + if (match && !compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + if (!this.global) + this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows) + return !!match; + }; + + // Adds named capture support and fixes browser bugs in native method + String.prototype.match = function (regex) { + if (!XRegExp.isRegExp(regex)) + regex = RegExp(regex); // Native `RegExp` + if (regex.global) { + var result = nativ.match.apply(this, arguments); + regex.lastIndex = 0; // Fix IE bug + return result; + } + return regex.exec(this); // Run the altered `exec` + }; + + // Adds support for `${n}` tokens for named and numbered backreferences in replacement text, + // and provides named backreferences to replacement functions as `arguments[0].name`. Also + // fixes cross-browser differences in replacement text syntax when performing a replacement + // using a nonregex search value, and the value of replacement regexes' `lastIndex` property + // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary + // third (`flags`) parameter + String.prototype.replace = function (search, replacement) { + var isRegex = XRegExp.isRegExp(search), + captureNames, result, str, origLastIndex; + + // There are too many combinations of search/replacement types/values and browser bugs that + // preclude passing to native `replace`, so don't try + //if (...) + // return nativ.replace.apply(this, arguments); + + if (isRegex) { + if (search._xregexp) + captureNames = search._xregexp.captureNames; // Array or `null` + if (!search.global) + origLastIndex = search.lastIndex; + } else { + search = search + ""; // Type conversion + } + + if (Object.prototype.toString.call(replacement) === "[object Function]") { + result = nativ.replace.call(this + "", search, function () { + if (captureNames) { + // Change the `arguments[0]` string primitive to a String object which can store properties + arguments[0] = new String(arguments[0]); + // Store named backreferences on `arguments[0]` + for (var i = 0; i < captureNames.length; i++) { + if (captureNames[i]) + arguments[0][captureNames[i]] = arguments[i + 1]; + } + } + // Update `lastIndex` before calling `replacement` (fix browsers) + if (isRegex && search.global) + search.lastIndex = arguments[arguments.length - 2] + arguments[0].length; + return replacement.apply(null, arguments); + }); + } else { + str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`) + result = nativ.replace.call(str, search, function () { + var args = arguments; // Keep this function's `arguments` available through closure + return nativ.replace.call(replacement + "", replacementToken, function ($0, $1, $2) { + // Numbered backreference (without delimiters) or special variable + if ($1) { + switch ($1) { + case "$": return "$"; + case "&": return args[0]; + case "`": return args[args.length - 1].slice(0, args[args.length - 2]); + case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length); + // Numbered backreference + default: + // What does "$10" mean? + // - Backreference 10, if 10 or more capturing groups exist + // - Backreference 1 followed by "0", if 1-9 capturing groups exist + // - Otherwise, it's the string "$10" + // Also note: + // - Backreferences cannot be more than two digits (enforced by `replacementToken`) + // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01" + // - There is no "$0" token ("$&" is the entire match) + var literalNumbers = ""; + $1 = +$1; // Type conversion; drop leading zero + if (!$1) // `$1` was "0" or "00" + return $0; + while ($1 > args.length - 3) { + literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers; + $1 = Math.floor($1 / 10); // Drop the last digit + } + return ($1 ? args[$1] || "" : "$") + literalNumbers; + } + // Named backreference or delimited numbered backreference + } else { + // What does "${n}" mean? + // - Backreference to numbered capture n. Two differences from "$n": + // - n can be more than two digits + // - Backreference 0 is allowed, and is the entire match + // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture + // - Otherwise, it's the string "${n}" + var n = +$2; // Type conversion; drop leading zeros + if (n <= args.length - 3) + return args[n]; + n = captureNames ? indexOf(captureNames, $2) : -1; + return n > -1 ? args[n + 1] : $0; + } + }); + }); + } + + if (isRegex) { + if (search.global) + search.lastIndex = 0; // Fix IE, Safari bug (last tested IE 9.0.5, Safari 5.1.2 on Windows) + else + search.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows) + } + + return result; + }; + + // A consistent cross-browser, ES3 compliant `split` + String.prototype.split = function (s /* separator */, limit) { + // If separator `s` is not a regex, use the native `split` + if (!XRegExp.isRegExp(s)) + return nativ.split.apply(this, arguments); + + var str = this + "", // Type conversion + output = [], + lastLastIndex = 0, + match, lastLength; + + // Behavior for `limit`: if it's... + // - `undefined`: No limit + // - `NaN` or zero: Return an empty array + // - A positive number: Use `Math.floor(limit)` + // - A negative number: No limit + // - Other: Type-convert, then use the above rules + if (limit === undefined || +limit < 0) { + limit = Infinity; + } else { + limit = Math.floor(+limit); + if (!limit) + return []; + } + + // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero + // and restore it to its original value when we're done using the regex + s = XRegExp.copyAsGlobal(s); + + while (match = s.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.) + if (s.lastIndex > lastLastIndex) { + output.push(str.slice(lastLastIndex, match.index)); + + if (match.length > 1 && match.index < str.length) + Array.prototype.push.apply(output, match.slice(1)); + + lastLength = match[0].length; + lastLastIndex = s.lastIndex; + + if (output.length >= limit) + break; + } + + if (s.lastIndex === match.index) + s.lastIndex++; + } + + if (lastLastIndex === str.length) { + if (!nativ.test.call(s, "") || lastLength) + output.push(""); + } else { + output.push(str.slice(lastLastIndex)); + } + + return output.length > limit ? output.slice(0, limit) : output; + }; + + + //--------------------------------- + // Private helper functions + //--------------------------------- + + // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp` + // instance with a fresh `lastIndex` (set to zero), preserving properties required for named + // capture. Also allows adding new flags in the process of copying the regex + function clone (regex, additionalFlags) { + if (!XRegExp.isRegExp(regex)) + throw TypeError("type RegExp expected"); + var x = regex._xregexp; + regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || "")); + if (x) { + regex._xregexp = { + source: x.source, + captureNames: x.captureNames ? x.captureNames.slice(0) : null + }; + } + return regex; + } + + function getNativeFlags (regex) { + return (regex.global ? "g" : "") + + (regex.ignoreCase ? "i" : "") + + (regex.multiline ? "m" : "") + + (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 + (regex.sticky ? "y" : ""); + } + + function runTokens (pattern, index, scope, context) { + var i = tokens.length, + result, match, t; + // Protect against constructing XRegExps within token handler and trigger functions + isInsideConstructor = true; + // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws + try { + while (i--) { // Run in reverse order + t = tokens[i]; + if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) { + t.pattern.lastIndex = index; + match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc. + if (match && match.index === index) { + result = { + output: t.handler.call(context, match, scope), + match: match + }; + break; + } + } + } + } catch (err) { + throw err; + } finally { + isInsideConstructor = false; + } + return result; + } + + function indexOf (array, item, from) { + if (Array.prototype.indexOf) // Use the native array method if available + return array.indexOf(item, from); + for (var i = from || 0; i < array.length; i++) { + if (array[i] === item) + return i; + } + return -1; + } + + + //--------------------------------- + // Built-in tokens + //--------------------------------- + + // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the + // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS` + + // Comment pattern: (?# ) + XRegExp.addToken( + /\(\?#[^)]*\)/, + function (match) { + // Keep tokens separated unless the following token is a quantifier + return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)"; + } + ); + + // Capturing group (match the opening parenthesis only). + // Required for support of named capturing groups + XRegExp.addToken( + /\((?!\?)/, + function () { + this.captureNames.push(null); + return "("; + } + ); + + // Named capturing group (match the opening delimiter only): (? + XRegExp.addToken( + /\(\?<([$\w]+)>/, + function (match) { + this.captureNames.push(match[1]); + this.hasNamedCapture = true; + return "("; + } + ); + + // Named backreference: \k + XRegExp.addToken( + /\\k<([\w$]+)>/, + function (match) { + var index = indexOf(this.captureNames, match[1]); + // Keep backreferences separate from subsequent literal numbers. Preserve back- + // references to named groups that are undefined at this point as literal strings + return index > -1 ? + "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") : + match[0]; + } + ); + + // Empty character class: [] or [^] + XRegExp.addToken( + /\[\^?]/, + function (match) { + // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S]. + // (?!) should work like \b\B, but is unreliable in Firefox + return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]"; + } + ); + + // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx) + // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc. + XRegExp.addToken( + /^\(\?([imsx]+)\)/, + function (match) { + this.setFlag(match[1]); + return ""; + } + ); + + // Whitespace and comments, in free-spacing (aka extended) mode only + XRegExp.addToken( + /(?:\s+|#.*)+/, + function (match) { + // Keep tokens separated unless the following token is a quantifier + return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)"; + }, + XRegExp.OUTSIDE_CLASS, + function () {return this.hasFlag("x");} + ); + + // Dot, in dotall (aka singleline) mode only + XRegExp.addToken( + /\./, + function () {return "[\\s\\S]";}, + XRegExp.OUTSIDE_CLASS, + function () {return this.hasFlag("s");} + ); + + + //--------------------------------- + // Backward compatibility + //--------------------------------- + + // Uncomment the following block for compatibility with XRegExp 1.0-1.2: + /* + XRegExp.matchWithinChain = XRegExp.matchChain; + RegExp.prototype.addFlags = function (s) {return clone(this, s);}; + RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;}; + RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);}; + RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;}; + */ + +})(); + diff --git a/system/libs/phpmailer/examples/scripts/shAutoloader.js b/system/libs/phpmailer/examples/scripts/shAutoloader.js new file mode 100644 index 00000000..9f5942ee --- /dev/null +++ b/system/libs/phpmailer/examples/scripts/shAutoloader.js @@ -0,0 +1,122 @@ +(function() { + +var sh = SyntaxHighlighter; + +/** + * Provides functionality to dynamically load only the brushes that a needed to render the current page. + * + * There are two syntaxes that autoload understands. For example: + * + * SyntaxHighlighter.autoloader( + * [ 'applescript', 'Scripts/shBrushAppleScript.js' ], + * [ 'actionscript3', 'as3', 'Scripts/shBrushAS3.js' ] + * ); + * + * or a more easily comprehendable one: + * + * SyntaxHighlighter.autoloader( + * 'applescript Scripts/shBrushAppleScript.js', + * 'actionscript3 as3 Scripts/shBrushAS3.js' + * ); + */ +sh.autoloader = function() +{ + var list = arguments, + elements = sh.findElements(), + brushes = {}, + scripts = {}, + all = SyntaxHighlighter.all, + allCalled = false, + allParams = null, + i + ; + + SyntaxHighlighter.all = function(params) + { + allParams = params; + allCalled = true; + }; + + function addBrush(aliases, url) + { + for (var i = 0; i < aliases.length; i++) + brushes[aliases[i]] = url; + }; + + function getAliases(item) + { + return item.pop + ? item + : item.split(/\s+/) + ; + } + + // create table of aliases and script urls + for (i = 0; i < list.length; i++) + { + var aliases = getAliases(list[i]), + url = aliases.pop() + ; + + addBrush(aliases, url); + } + + // dynamically add + +
+ +
+
+ + + + +
Login Successful
+ + + + +
+
+ +
+
+ + + + +
You have logged in.
Press here if you are not returned automatically.
+
+
+
+ + + + +getCustomField("key"); + if(!$account_logged->isPremium()) + $account_status = 'Free Account'; + else + $account_status = 'Premium Account, '.$account_logged->getPremDays().' days left'; + if(empty($account_reckey)) + $account_registred = 'No'; + else + { + if($config['generate_new_reckey'] && $config['mail_enabled']) + $account_registred = 'Yes ( Buy new Recovery Key )'; + else + $account_registred = 'Yes'; + } + + $account_created = $account_logged->getCustomField("created"); + $account_email = $account_logged->getEMail(); + $account_email_new_time = $account_logged->getCustomField("email_new_time"); + if($account_email_new_time > 1) + $account_email_new = $account_logged->getCustomField("email_new"); + $account_rlname = $account_logged->getRLName(); + $account_location = $account_logged->getLocation(); + if($account_logged->isBanned()) + if($account_logged->getBanTime() > 0) + $welcome_msg = 'Your account is banished until '.date("j F Y, G:i:s", $account_logged->getBanTime()).'!'; + else + $welcome_msg = 'Your account is banished FOREVER!'; + else + $welcome_msg = 'Welcome to your account!'; + echo '

'.$welcome_msg.'

'; + //if account dont have recovery key show hint + if(empty($account_reckey)) + echo '
Hint:You can register your account for increased protection. Click on "Register Account" and get your free recovery key today!

'; + + $account_email_change = ''; + if($account_email_new_time > 1) + { + if($account_email_new_time < time()) + $account_email_change = '
(You can accept '.$account_email_new.' as a new email.)'; + else + { + $account_email_change = '
You can accept new e-mail after '.date("j F Y", $account_email_new_time)."."; + echo '
Note:A request has been submitted to change the email address of this account to '.$account_email_new.'. After '.date("j F Y, G:i:s", $account_email_new_time).' you can accept the new email address and finish the process. Please cancel the request if you do not want your email address to be changed! Also cancel the request if you have no access to the new email address!


'; + } + } + echo '
General Information
Email Address:'.$account_email.''.$account_email_change.'
Created:'.date("j F Y, G:i:s", $account_created).'
Last Login:'.date("j F Y, G:i:s", time()).'
Account Status:'.$account_status.'
Registred:'.$account_registred.'
'; + //show button "register account" + if(empty($account_reckey)) + echo ''; + echo '

Public Information
Real Name:'.$account_rlname.'
Location:'.$account_location.'
'; + echo '
Account logs
+ '; + + $player_number_counter = 0; + foreach($account_logged->getActionsLog(0, 1000) as $action) + { + echo ' + '; + } + echo '
ActionDateIP
'.$action['action'] . '' . date("jS F Y H:i:s",$action['date']) . '' . long2ip($action['ip']) . '
+ + +

'; + echo '
Characters
'; + $account_players = $account_logged->getPlayersList(); + $account_players->orderBy('id'); + //show list of players on account + $player_number_counter = 0; + foreach($account_players as $account_player) + { + echo ''; + if(!$account_player->isOnline()) + echo ''; + else + echo ''; + echo ''; + } + echo '
NameLevelStatus 
'.$player_number_counter.'. '.$account_player->getName(); + if($account_player->isDeleted()) + echo ' [ DELETED ] '; + echo ''.$account_player->getLevel().' '.$config['vocations'][$account_player->getVocation()].'OfflineOnline[Edit]


'; + } +//########### CHANGE PASSWORD ########## + if($action == "changepassword") { + $new_password = isset($_POST['newpassword']) ? $_POST['newpassword'] : NULL; + $new_password2 = isset($_POST['newpassword2']) ? $_POST['newpassword2'] : NULL; + $old_password = isset($_POST['oldpassword']) ? $_POST['oldpassword'] : NULL; + if(empty($new_password) && empty($new_password2) && empty($old_password)) { + echo 'Please enter your current password and a new password. For your security, please enter the new password twice.

Change Password
New Password:
New Password Again:
Current Password:

'; + } + else + { + if(empty($new_password) || empty($new_password2) || empty($old_password)){ + $show_msgs[] = "Please fill in form."; + } + if($new_password != $new_password2) { + $show_msgs[] = "The new passwords do not match!"; + } + if(empty($show_msgs)) { + if(!check_password($new_password)) { + $show_msgs[] = "New password contains illegal chars (a-z, A-Z and 0-9 only!). Minimum password length is 7 characters and maximum 32."; + } + $old_password = encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $old_password); + if($old_password != $account_logged->getPassword()) { + $show_msgs[] = "Current password is incorrect!"; + } + } + if(!empty($show_msgs)){ + //show errors + echo '
The Following Errors Have Occurred:
'; + foreach($show_msgs as $show_msg) { + echo '
  • '.$show_msg; + } + echo '

  • '; + //show form + echo 'Please enter your current password and a new password. For your security, please enter the new password twice.

    Change Password
    New Password:
    New Password Again:
    Current Password:

    '; + } + else + { + $org_pass = $new_password; + + if($config_salt_enabled) + { + $salt = generateRandomString(10, false, true, true); + $new_password = $salt . $new_password; + $account_logged->setSalt($salt); + } + + $new_password = encrypt($new_password); + $account_logged->setPassword($new_password); + $account_logged->save(); + $account_logged->logAction('Account password changed.'); + echo '
    Password Changed
    Your password has been changed.'; + if($config['mail_enabled'] && $config['send_mail_when_change_password']) + { + $mailBody = ' +

    Password to account changed!

    +

    You or someone else changed password to your account on server '.$config['lua']['serverName'].'.

    +

    New password: '.$org_pass.'

    '; + + if(_mail($account_logged->getEMail(), $config['lua']['serverName']." - Changed password", $mailBody)) + echo '
    Your new password were send on email address '.$account_logged->getEMail().'.'; + else + echo '

    An error occorred while sending email with password:
    ' . $mailer->ErrorInfo . '

    '; + } + echo '

    '; + $_SESSION['password'] = $new_password; + } + } + } + +//############# CHANGE E-MAIL ################### + if($action == "changeemail") { + $account_email_new_time = $account_logged->getCustomField("email_new_time"); + if($account_email_new_time > 10) {$account_email_new = $account_logged->getCustomField("email_new"); } + if($account_email_new_time < 10){ + if(isset($_POST['changeemailsave']) && $_POST['changeemailsave'] == 1) { + $account_email_new = $_POST['new_email']; + $post_password = $_POST['password']; + if(empty($account_email_new)) { + $change_email_errors[] = "Please enter your new email address."; + } + else + { + if(!check_mail($account_email_new)) { + $change_email_errors[] = "E-mail address is not correct."; + } + } + if(empty($post_password)) { + $change_email_errors[] = "Please enter password to your account."; + } + else + { + $post_password = encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $post_password); + if($post_password != $account_logged->getPassword()) { + $change_email_errors[] = "Wrong password to account."; + } + } + if(empty($change_email_errors)) { + $account_email_new_time = time() + $config['account_mail_change'] * 24 * 3600; + $account_logged->setCustomField("email_new", $account_email_new); + $account_logged->setCustomField("email_new_time", $account_email_new_time); + echo '
    New Email Address Requested
    You have requested to change your email address to '.$account_email_new.'. The actual change will take place after '.date("j F Y, G:i:s", $account_email_new_time).', during which you can cancel the request at any time.

    '; + } + else + { + //show errors + echo '
    The Following Errors Have Occurred:
    '; + foreach($change_email_errors as $change_email_error) { + echo '
  • '.$change_email_error; + } + echo '

  • '; + //show form + echo 'Please enter your password and the new email address. Make sure that you enter a valid email address which you have access to. For security reasons, the actual change will be finalised after a waiting period of '.$config['account_mail_change'].' days.

    Change Email Address
    New Email Address:
    Password:

    '; + } + } + else + { + echo 'Please enter your password and the new email address. Make sure that you enter a valid email address which you have access to. For security reasons, the actual change will be finalised after a waiting period of '.$config['account_mail_change'].' days.

    Change Email Address
    New Email Address:
    Password:

    '; + } + } + else + { + if($account_email_new_time < time()) { + if($_POST['changeemailsave'] == 1) { + $account_logged->setCustomField("email_new", ""); + $account_logged->setCustomField("email_new_time", 0); + $account_logged->setEmail($account_email_new); + $account_logged->save(); + $account_logged->logAction('Account email changed to ' . $account_email_new . ''); + echo '
    Email Address Change Accepted
    You have accepted '.$account_logged->getEmail().' as your new email adress.

    '; + } + else + { + echo '
    Email Address Change Accepted
    Do you accept '.$account_email_new.' as your new email adress?

     
     
    '; + } + } + else + { + echo '
    Change of Email Address
    A request has been submitted to change the email address of this account to '.$account_email_new.'.
    The actual change will take place on '.date("j F Y, G:i:s", $account_email_new_time).'.
    If you do not want to change your email address, please click on "Cancel".

    '; + } + } + if(isset($_POST['emailchangecancel']) && $_POST['emailchangecancel'] == 1) { + $account_logged->setCustomField("email_new", ""); + $account_logged->setCustomField("email_new_time", 0); + echo '
    Email Address Change Cancelled
    Your request to change the email address of your account has been cancelled. The email address will not be changed.

    '; + } + } + +//########### CHANGE PUBLIC INFORMATION (about account owner) ###################### + if($action == "changeinfo") { + $new_rlname = isset($_POST['info_rlname']) ? htmlspecialchars(stripslashes($_POST['info_rlname'])) : NULL; + $new_location = isset($_POST['info_location']) ? htmlspecialchars(stripslashes($_POST['info_location'])) : NULL; + $new_country = isset($_POST['info_country']) ? htmlspecialchars(stripslashes($_POST['info_country'])) : NULL; + if(isset($_POST['changeinfosave']) && $_POST['changeinfosave'] == 1) { + //save data from form + $account_logged->setCustomField("rlname", $new_rlname); + $account_logged->setCustomField("location", $new_location); + $account_logged->setCustomField("country", $new_country); + $account_logged->logAction('Changed Real Name to ' . $new_rlname . ', Location to ' . $new_location . ' and Country to ' . $config['countries'][$new_country] . '.'); + echo '
    Public Information Changed
    Your public information has been changed.

    '; + } + else + { + //show form + $account_rlname = $account_logged->getCustomField("rlname"); + $account_location = $account_logged->getCustomField("location"); + if($config['account_country']) + $account_country = $account_logged->getCustomField("country"); + ?> + Here you can tell other players about yourself. This information will be displayed alongside the data of your characters. If you do not want to fill in a certain field, just leave it blank.

    +
    +
    + +
    +
    + + + + +
    Change Public Information
    + + + + +
    +
    + +
    +
    + + + + + + + + + + + + + + + +
    Real Name: + +
    Location: + +
    Country: + + + +
    +

    + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + getCustomField('salt') : '') . $_POST['reg_password']); + $old_key = $account_logged->getCustomField("key"); + if(isset($_POST['registeraccountsave']) && $_POST['registeraccountsave'] == "1") { + if($reg_password == $account_logged->getPassword()) { + if(empty($old_key)) { + $dontshowtableagain = true; + $new_rec_key = generateRandomString(10, false, true, true); + + $account_logged->setCustomField("key", $new_rec_key); + $account_logged->logAction('Generated recovery key.'); + echo '
    Account Registered
    Thank you for registering your account! You can now recover your account if you have lost access to the assigned email address by using the following

       Recovery Key: '.$new_rec_key.'


    Important:
    • Write down this recovery key carefully.
    • Store it at a safe place!
    • '; + if($config['mail_enabled'] && $config['send_mail_when_generate_reckey']) + { + $mailBody = ' +

      New recovery key!

      +

      You or someone else generated recovery key to your account on server '.$config['lua']['serverName'].'.

      +

      Recovery key: '.$new_rec_key.'

      '; + if(_mail($account_logged->getEMail(), $config['lua']['serverName']." - recovery key", $mailBody)) + echo '
      Your recovery key were send on email address '.$account_logged->getEMail().'.'; + else + echo '

      An error occorred while sending email with recovery key! You will not receive e-mail with this key. Error:
      ' . $mailer->ErrorInfo . '

      '; + } + echo '

    '; + } + else + $reg_errors[] = 'Your account is already registred.'; + } + else + $reg_errors[] = 'Wrong password to account.'; + } + if(!$dontshowtableagain) + { + //show errors if not empty + if(!empty($reg_errors)) + { + echo '
    The Following Errors Have Occurred:
    '; + foreach($reg_errors as $reg_error) + echo '
  • '.$reg_error . '
  • '; + echo '

    '; + } + //show form + echo 'To generate recovery key for your account please enter your password.

    Generate recovery key
    Password:

    '; + } + } + +//############## GENERATE NEW RECOVERY KEY ########### + if($action == "newreckey") + { + if(isset($_POST['reg_password'])) + $reg_password = encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $_POST['reg_password']); + + $reckey = $account_logged->getCustomField('key'); + if((!$config['generate_new_reckey'] || !$config['mail_enabled']) || empty($reckey)) + echo 'You cant get new rec key'; + else + { + $points = $account_logged->getCustomField('premium_points'); + if(isset($_POST['registeraccountsave']) && $_POST['registeraccountsave'] == '1') + { + if($reg_password == $account_logged->getPassword()) + { + if($points >= $config['generate_new_reckey_price']) + { + $dontshowtableagain = true; + $new_rec_key = generateRandomString(10, false, true, true); + + echo '
    Account Registered
      '; + + $mailBody = ' +

      New recovery key!

      +

      You or someone else generated recovery key to your account on server '.$config['lua']['serverName'].'.

      +

      Recovery key: '.$new_rec_key.'

      '; + if(_mail($account_logged->getEMail(), $config['lua']['serverName']." - new recovery key", $mailBody)) + { + $account_logged->setCustomField("key", $new_rec_key); + $account_logged->setCustomField("premium_points", $account_logged->getCustomField("premium_points") - $config['generate_new_reckey_price']); + $account_logged->logAction('Generated new recovery key for ' . $config['generate_new_reckey_price'] . ' premium points.'); + echo '
      Your recovery key were send on email address '.$account_logged->getEMail().' for '.$config['generate_new_reckey_price'].' premium points.'; + } + else + echo '

      An error occorred while sending email ( '.$account_logged->getEMail().' ) with recovery key! Recovery key not changed. Try again. Error:
      ' . $mailer->ErrorInfo . '

      '; + echo '

    '; + } + else + $reg_errors[] = 'You need '.$config['generate_new_reckey_price'].' premium points to generate new recovery key. You have '.$points.' premium points.'; + } + else + $reg_errors[] = 'Wrong password to account.'; + } + if(!$dontshowtableagain) + { + //show errors if not empty + if(!empty($reg_errors)) + { + echo '
    The Following Errors Have Occurred:
    '; + foreach($reg_errors as $reg_error) + echo '
  • '.$reg_error; + echo '

  • '; + } + //show form + echo 'To generate NEW recovery key for your account please enter your password.
    New recovery key cost '.$config['generate_new_reckey_price'].' Premium Points. You have '.$points.' premium points. You will receive e-mail with this recovery key.
    Generate recovery key
    Password:

    '; + } + } + } + + + +//###### CHANGE CHARACTER COMMENT ###### + if($action == "changecomment") { + $player_name = stripslashes($_REQUEST['name']); + $new_comment = isset($_POST['comment']) ? htmlspecialchars(stripslashes(substr($_POST['comment'],0,2000))) : NULL; + $new_hideacc = isset($_POST['accountvisible']) ? (int)$_POST['accountvisible'] : NULL; + if(check_name($player_name)) { + $player = $ots->createObject('Player'); + $player->find($player_name); + if($player->isLoaded()) { + $player_account = $player->getAccount(); + if($account_logged->getId() == $player_account->getId()) { + if(isset($_POST['changecommentsave']) && $_POST['changecommentsave'] == 1) { + $player->setCustomField("hidden", $new_hideacc); + $player->setCustomField("comment", $new_comment); + $account_logged->logAction('Changed comment for character ' . $player->getName() . '.'); + echo '
    Character Information Changed
    The character information has been changed.

    '; + } + else + { + echo 'Here you can see and edit the information about your character.
    If you do not want to specify a certain field, just leave it blank.

    Edit Character Information
    Name:'.$player_name.'
    Hide Account:'; + if($player->getCustomField("hidden") == 1) { + echo ''; + } + else + { + echo ''; + } + + echo ' check to hide your account information'; + if((int)$player->getCustomField('group_id') > 1) + echo ' (you will be also hidden on the Team page!)'; + + echo '
    Comment:
    [max. length: 2000 chars, 50 lines (ENTERs)]

    '; + } + } + else + { + echo "Error. Character ".$player_name." is not on your account."; + } + } + else + { + echo "Error. Character with this name doesn't exist."; + } + } + else + { + echo "Error. Name contain illegal characters."; + } + } + +//### DELETE character from account ### + if($action == "deletecharacter") { + $player_name = isset($_POST['delete_name']) ? stripslashes($_POST['delete_name']) : NULL; + $password_verify = isset($_POST['delete_password']) ? $_POST['delete_password'] : NULL; + $password_verify = encrypt(($config_salt_enabled ? $account_logged->getCustomField('salt') : '') . $password_verify); + if(isset($_POST['deletecharactersave']) && $_POST['deletecharactersave'] == 1) { + if(!empty($player_name) && !empty($password_verify)) { + if(check_name($player_name)) { + $player = $ots->createObject('Player'); + $player->find($player_name); + if($player->isLoaded()) { + $player_account = $player->getAccount(); + if($account_logged->getId() == $player_account->getId()) { + if($password_verify == $account_logged->getPassword()) { + if(!$player->isOnline()) + { + //dont show table "delete character" again + $dontshowtableagain = true; + //delete player + if(fieldExist('deletion', 'players')) + $player->setCustomField('deletion', 1); + else + $player->setCustomField('deleted', 1); + $account_logged->logAction('Deleted character ' . $player->getName() . '.'); + echo '
    Character Deleted
    The character '.$player_name.' has been deleted.

    '; + } + else + $delete_errors[] = 'This character is online.'; + } + else + { + $delete_errors[] = 'Wrong password to account.'; + } + } + else + { + $delete_errors[] = 'Character '.$player_name.' is not on your account.'; + } + } + else + { + $delete_errors[] = 'Character with this name doesn\'t exist.'; + } + } + else + { + $delete_errors[] = 'Name contain illegal characters.'; + } + } + else + { + $delete_errors[] = 'Character name or/and password is empty. Please fill in form.'; + } + } + if(!$dontshowtableagain) { + if(!empty($delete_errors)) { + echo '
    The Following Errors Have Occurred:
    '; + foreach($delete_errors as $delete_error) { + echo '
  • '.$delete_error; + } + echo '

  • '; + } + echo 'To delete a character enter the name of the character and your password.

    Delete Character
    Character Name:
    Password:

    '; + } + } + +//## CREATE CHARACTER on account ### + if($action == "createcharacter") { + echo ''; + $newchar_name = isset($_POST['newcharname']) ? stripslashes(ucwords(strtolower($_POST['newcharname']))) : NULL; + $newchar_sex = isset($_POST['newcharsex']) ? $_POST['newcharsex'] : NULL; + $newchar_vocation = isset($_POST['newcharvocation']) ? $_POST['newcharvocation'] : NULL; + $newchar_town = isset($_POST['newchartown']) ? $_POST['newchartown'] : NULL; + $newchar_errors = array(); + if(isset($_POST['savecharacter']) && $_POST['savecharacter'] == 1) { + if(empty($newchar_name)) + $newchar_errors[] = 'Please enter a name for your character!'; + + if(strlen($newchar_name) > 25) + $newchar_errors[] = 'Name is too long. Max. lenght 25 letters.'; + else if(strlen($newchar_name) < 3) + $newchar_errors[] = 'Name is too short. Min. lenght 25 letters.'; + + if(empty($newchar_sex) && $newchar_sex != "0") + $newchar_errors[] = 'Please select the sex for your character!'; + + if(count($config['character_samples']) > 1) + { + if(!isset($newchar_vocation)) + $newchar_errors[] = 'Please select a vocation for your character.'; + } + else + $newchar_vocation = $config['character_samples'][0]; + + if(count($config['character_towns']) > 1) + { + if(empty($newchar_town)) + $newchar_errors[] = 'Please select a town for your character.'; + } + else + $newchar_town = $config['character_towns'][0]; + + //check if was namelocked previously + if(tableExist('player_namelocks') && fieldExist('name', 'player_namelocks')) { + $namelockSQL = $db->query('SELECT `player_id` FROM `player_namelocks` WHERE `name` = ' . $db->quote($newchar_name)); + if($namelockSQL->rowCount() > 0) + $newchar_errors[] = 'Character with this name has been namelocked.'; + } + + if(empty($newchar_errors)) + { + if(!check_name_new_char($newchar_name)) + $newchar_errors[] = 'This name contains invalid letters, words or format. Please use only a-Z, - , \' and space.'; + if($newchar_sex != 1 && $newchar_sex != "0") + $newchar_errors[] = 'Sex must be equal 0 (female) or 1 (male).'; + if(!in_array($newchar_town, $config['character_towns'])) + $newchar_errors[] = 'Please select valid town.'; + if(count($config['character_samples']) > 1) + { + $newchar_vocation_check = false; + foreach($config['character_samples'] as $char_vocation_key => $sample_char) + if($newchar_vocation == $char_vocation_key) + $newchar_vocation_check = true; + if(!$newchar_vocation_check) + $newchar_errors[] = 'Unknown vocation. Please fill in form again.'; + } + else + $newchar_vocation = 0; + } + + if(empty($newchar_errors)) + { + $check_name_in_database = $ots->createObject('Player'); + $check_name_in_database->find($newchar_name); + if($check_name_in_database->isLoaded()) + $newchar_errors[] .= 'This name is already used. Please choose another name!'; + $number_of_players_on_account = $account_logged->getPlayersList()->count(); + if($number_of_players_on_account >= $config['characters_per_account']) + $newchar_errors[] .= 'You have too many characters on your account ('.$number_of_players_on_account.'/'.$config['characters_per_account'].')!'; + } + + if(empty($newchar_errors)) + { + $char_to_copy_name = $config['character_samples'][$newchar_vocation]; + $char_to_copy = new OTS_Player(); + $char_to_copy->find($char_to_copy_name); + if(!$char_to_copy->isLoaded()) + $newchar_errors[] .= 'Wrong characters configuration. Try again or contact with admin. ADMIN: Edit file config/config.php and set valid characters to copy names. Character to copy'.$char_to_copy_name.'
    doesn\'t exist.'; + } + + if(empty($newchar_errors)) + { + if($newchar_sex == "0") + $char_to_copy->setLookType(136); + $player = $ots->createObject('Player'); + $player->setName($newchar_name); + $player->setAccount($account_logged); + //$player->setGroupId($char_to_copy->getGroup()->getId()); + $player->setGroupId(1); + $player->setSex($newchar_sex); + $player->setVocation($char_to_copy->getVocation()); + if(fieldExist('promotion', 'players')) + $player->setPromotion($char_to_copy->getPromotion()); + + $player->setConditions($char_to_copy->getConditions()); + if(fieldExist('rank_id', 'players')) + $player->setRank($char_to_copy->getRank()); + $player->setLookAddons($char_to_copy->getLookAddons()); + $player->setTownId($newchar_town); + $player->setExperience($char_to_copy->getExperience()); + $player->setLevel($char_to_copy->getLevel()); + $player->setMagLevel($char_to_copy->getMagLevel()); + $player->setHealth($char_to_copy->getHealth()); + $player->setHealthMax($char_to_copy->getHealthMax()); + $player->setMana($char_to_copy->getMana()); + $player->setManaMax($char_to_copy->getManaMax()); + $player->setManaSpent($char_to_copy->getManaSpent()); + $player->setSoul($char_to_copy->getSoul()); + if(fieldExist('direction', 'players')) + $player->setDirection($char_to_copy->getDirection()); + + $player->setLookBody($char_to_copy->getLookBody()); + $player->setLookFeet($char_to_copy->getLookFeet()); + $player->setLookHead($char_to_copy->getLookHead()); + $player->setLookLegs($char_to_copy->getLookLegs()); + $player->setLookType($char_to_copy->getLookType()); + $player->setCap($char_to_copy->getCap()); + $player->setBalance(0); + $player->setPosX(0); + $player->setPosY(0); + $player->setPosZ(0); + $player->setStamina($config['otserv_version'] == TFS_03 ? 151200000 : 2520); + if(fieldExist('loss_experience', 'players')) { + $player->setLossExperience($char_to_copy->getLossExperience()); + $player->setLossMana($char_to_copy->getLossMana()); + $player->setLossSkills($char_to_copy->getLossSkills()); + $player->setLossItems($char_to_copy->getLossItems()); + } + $player->save(); + $player->setCustomField("created", time()); + $account_logged->logAction('Created character ' . $player->getName() . '.'); + unset($player); + $player = $ots->createObject('Player'); + $player->find($newchar_name); + if($player->isLoaded()) + { + if(tableExist('player_skills')) { + for($i=0;$i<7;$i++) + { + $skillExists = $db->query('SELECT `skillid` FROM `player_skills` WHERE `player_id` = ' . $player->getId() . ' AND `skillid` = ' . $i); + if($skillExists->rowCount() <= 0) + { + $db->query('INSERT INTO `player_skills` (`player_id`, `skillid`, `value`, `count`) VALUES ('.$player->getId().', '.$i.', 10, 0)'); + } + } + } + + $loaded_items_to_copy = $db->query("SELECT * FROM player_items WHERE player_id = ".$char_to_copy->getId().""); + foreach($loaded_items_to_copy as $save_item) + $db->query("INSERT INTO `player_items` (`player_id` ,`pid` ,`sid` ,`itemtype`, `count`, `attributes`) VALUES ('".$player->getId()."', '".$save_item['pid']."', '".$save_item['sid']."', '".$save_item['itemtype']."', '".$save_item['count']."', '".$save_item['attributes']."');"); + echo '
    Character Created
    The character '.$newchar_name.' has been created.
    Please select the outfit when you log in for the first time.

    See you on '.$config['lua']['serverName'].'!

    '; + } + else + { + echo "Error. Can\'t create character. Probably problem with database. Try again or contact with admin."; + exit; + } + } + } + else + { + if(count($newchar_errors) > 0) { + echo '
    '; + echo 'The Following Errors Have Occurred:
    '; + foreach($newchar_errors as $newchar_error) + echo '
  • '.$newchar_error . '
  • '; + echo '

    '; + } + echo 'Please choose a name'; + if(count($config['character_samples']) > 1) + echo ', vocation'; + echo ' and sex for your character.
    In any case the name must not violate the naming conventions stated in the '.$config['lua']['serverName'].' Rules, or your character might get deleted or name locked.'; + if($account_logged->getPlayersList()->count() >= $config['characters_per_account']) { + echo ' You have maximum number of characters per account on your account. Delete one before you make new.'; + } + echo '

    Create Character
    NameSex

    Please enter your character name.
    '; + echo '
    '; + echo '
    '; + echo '
    '; + if(count($config['character_samples']) > 1) + { + echo '

    Select your vocation:
    '; + foreach($config['character_samples'] as $char_vocation_key => $sample_char) + { + echo ''; + } + echo '
    '; + } + if(count($config['character_towns']) > 1) + { + echo '

    Select your city:
    '; + foreach($config['character_towns'] as $town_id) + { + echo ''; + } + echo '
    '; + } + else + echo '
    '; + echo '
    '; + } + } +?> diff --git a/system/pages/admin/.htaccess b/system/pages/admin/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/system/pages/admin/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/pages/admin/changelog.php b/system/pages/admin/changelog.php new file mode 100644 index 00000000..3a92a3fb --- /dev/null +++ b/system/pages/admin/changelog.php @@ -0,0 +1,27 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'MyAAC - CHANGELOG'; + +$data = file_get_contents(SYSTEM . 'docs/CHANGELOG'); + +// replace special characters with HTML entities +// replace line breaks with
    +$data = nl2br(htmlspecialchars($data)); + +// replace multiple spaces with single spaces +$data = preg_replace('/\s\s+/', ' ', $data); + +// replace URLs with elements +$data = preg_replace('/\s(\w+:\/\/)(\S+)/', ' \\1\\2', $data); + +echo '
    ' . $data . '
    '; +?> diff --git a/system/pages/admin/dashboard.php b/system/pages/admin/dashboard.php new file mode 100644 index 00000000..a138e6b2 --- /dev/null +++ b/system/pages/admin/dashboard.php @@ -0,0 +1,64 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Dashboard'; +?> +
    + +

    Status: Online
    +
    + +

    + + +
    + Server:

    + Version:

    + + Monsters:
    + Map: , author: , size:
    + MOTD:


    + + Last updated: +
    +

    + +

    Status: Offline

    + +
    + + + + diff --git a/system/pages/admin/login.php b/system/pages/admin/login.php new file mode 100644 index 00000000..ccc318fe --- /dev/null +++ b/system/pages/admin/login.php @@ -0,0 +1,32 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Login'; + +if($action == 'logout') + echo 'You have been logout.
    '; + +if(isset($errors)) { + foreach($errors as $error) { + error($error); + } +} +?> + +Please login. +
    +
    +
    + +
    + + +
    \ No newline at end of file diff --git a/system/pages/admin/logs.php b/system/pages/admin/logs.php new file mode 100644 index 00000000..f6ed815c --- /dev/null +++ b/system/pages/admin/logs.php @@ -0,0 +1,78 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Logs viewer'; +?> + + + + + + + + + + +
    Log name + Last updated +
    +', 3) . '' . $file . ':

    ' . nl2br(file_get_contents($aac_path_logs . $file)); + else if(file_exists($server_path_logs . $file)) + echo str_repeat('
    ', 3) . '' . $file . ':

    ' . nl2br(file_get_contents($server_path_logs . $file)); + + else + echo 'Specified file does not exist.'; + } + else + echo 'Invalid file name specified.'; +} +?> diff --git a/system/pages/admin/mailer.php b/system/pages/admin/mailer.php new file mode 100644 index 00000000..05018cca --- /dev/null +++ b/system/pages/admin/mailer.php @@ -0,0 +1,111 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Mailer'; + +if(!hasFlag(FLAG_CONTENT_MAILER) && !superAdmin()) +{ + echo 'Access denied.'; + return; +} + +if(!$config['mail_enabled']) +{ + echo 'Mail support disabled.'; + return; +} + +$mail_content = isset($_POST['mail_content']) ? stripslashes($_POST['mail_content']) : NULL; +$mail_subject = isset($_POST['mail_subject']) ? stripslashes($_POST['mail_subject']) : NULL; +$preview = isset($_REQUEST['preview']); + +$preview_done = false; +if($preview) { + if(!empty($mail_content) && !empty($mail_subject)) + $preview_done = _mail($account_logged->getCustomField('email'), $mail_subject, $mail_content); + + if(!$preview_done) + error('Error while sending preview mail: ' . $mailer->ErrorInfo); +} + +?> + + + + + + + + + + + + + + + + + +
    +

    Sending mails may take some time if there are much users in db.

    +
    + + + +
    + +
    + Done.' : ''); ?>
    +
    +fieldName('email_verified') . ' = 1'; + + $query = $db->query('SELECT ' . $db->fieldName('email') . ' FROM ' . $db->tableName('accounts') . ' WHERE ' . $db->fieldName('email') . ' != ""' . $add); + foreach($query as $email) + { + if(_mail($email['email'], $mail_subject, $mail_content)) + $success++; + else + { + $failed++; + echo '
    '; + error('An error occorred while sending email to ' . $email['email'] . '. Error: ' . $mailer->ErrorInfo); + } + } +?> + Mailing finished.
    +

    emails delivered.


    +

    emails failed.


    diff --git a/system/pages/admin/notepad.php b/system/pages/admin/notepad.php new file mode 100644 index 00000000..611f06a1 --- /dev/null +++ b/system/pages/admin/notepad.php @@ -0,0 +1,108 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Notepad'; + +$notepad_content = Notepad::get($account_logged->getId()); +if(isset($_POST['content'])) +{ + $_content = html_entity_decode(stripslashes($_POST['content'])); + if(!$notepad_content) + Notepad::create($account_logged->getId(), $_content); + else + Notepad::update($account_logged->getId(), $_content); + + echo '
    Saved at ' . date('g:i A') . '
    '; +} +else +{ + if($notepad_content !== false) + $_content = $notepad_content; +} +?> + + + + + + + + + + + + + +
    +

    This is your personal notepad. Be sure to save it each time you modify something.

    +
    + +
    + +
    + + + + +select(TABLE_PREFIX . 'notepad', array('account_id' => $account_id)); + if($query !== false) + return $query['content']; + + return false; + } + + static public function create($account_id, $content = '') + { + global $db; + $db->insert(TABLE_PREFIX . 'notepad', array('account_id' => $account_id, 'content' => $content)); + } + + static public function update($account_id, $content = '') + { + global $db; + $db->update(TABLE_PREFIX . 'notepad', array('content' => $content), array('account_id' => $account_id)); + } +} diff --git a/system/pages/admin/pages.php b/system/pages/admin/pages.php new file mode 100644 index 00000000..68b0a001 --- /dev/null +++ b/system/pages/admin/pages.php @@ -0,0 +1,294 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'Pages'; + +if(!hasFlag(FLAG_CONTENT_PAGES) && !superAdmin()) +{ + echo 'Access denied.'; + return; +} + +$name = $p_title = ''; +$groups = new OTS_Groups_List(); + +$php = false; +$access = 0; + +if(!empty($action)) +{ + if($action == 'delete' || $action == 'edit' || $action == 'hide') + $id = $_REQUEST['id']; + + if(isset($_REQUEST['name'])) + $name = $_REQUEST['name']; + + if(isset($_REQUEST['title'])) + $p_title = $_REQUEST['title']; + + $php = isset($_REQUEST['php']); + //if($php) + // $body = $_REQUEST['body']; + //else + if(isset($_REQUEST['body'])) + $body = html_entity_decode(stripslashes($_REQUEST['body'])); + + if(isset($_REQUEST['access'])) + $access = $_REQUEST['access']; + + $errors = array(); + $player_id = 1; + + if($action == 'add') { + if(Pages::add($name, $p_title, $body, $player_id, $php, $access, $errors)) + { + $name = $p_title = $body = ''; + $player_id = $access = 0; + $php = false; + } + } + else if($action == 'delete') { + Pages::delete($id, $errors); + } + else if($action == 'edit') + { + if(isset($id) && !isset($_REQUEST['name'])) { + $_page = Pages::get($id); + $name = $_page['name']; + $p_title = $_page['title']; + $body = $_page['body']; + $php = $_page['php'] == '1'; + $access = $_page['access']; + } + else { + Pages::update($id, $name, $p_title, $body, $player_id, $php, $access); + $action = $name = $p_title = $body = ''; + $player_id = 1; + $access = 0; + $php = false; + } + } + else if($action == 'hide') { + Pages::toggleHidden($id, $errors); + } + + if(!empty($errors)) + output_errors($errors); +} +?> + + + + + +
    + + + + + + + + + + +
    page
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Link/name:
    Title:
    PHP:/>
    Content: + + +
    + [Hide] + [Show] + +
    Access: + +
    + +
    +
    +
    + + + + + + +query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'pages')); + +$i = 0; +foreach($pages as $_page): ?> + + + + + + +
    NameTitleOptions
    + + + Edit + + + + Delete + + + + + +
    + +select(TABLE_PREFIX . 'pages', array('id' => $id)); + if($query !== false) + return $query; + + return false; + } + + static public function add($name, $title, $body, $player_id, $php, $access, &$errors) + { + global $db; + if(isset($name[0]) && isset($title[0]) && isset($body[0]) && $player_id != 0) + { + $query = $db->select(TABLE_PREFIX . 'pages', array('name' => $name)); + if($query === false) + $db->insert(TABLE_PREFIX . 'pages', array('name' => $name, 'title' => $title, 'body' => $body, 'player_id' => $player_id, 'php' => $php, 'access' => $access)); + else + $errors[] = 'Page with this words already exists.'; + } + else + $errors[] = 'Please fill all inputs.'; + + return !count($errors); + } + + static public function update($id, $name, $title, $body, $player_id, $php, $access) { + global $db; + $db->update(TABLE_PREFIX . 'pages', array('name' => $name, 'title' => $title, 'body' => $body, 'player_id' => $player_id, 'php' => $php ? '1' : '0', 'access' => $access), array('id' => $id)); + } + + static public function delete($id, &$errors) + { + global $db; + if(isset($id)) + { + if($db->select(TABLE_PREFIX . 'pages', array('id' => $id)) !== false) + $db->delete(TABLE_PREFIX . 'pages', array('id' => $id)); + else + $errors[] = 'Page with id ' . $id . ' does not exists.'; + } + else + $errors[] = 'id not set'; + + return !count($errors); + } + + static public function toggleHidden($id, &$errors) + { + global $db; + if(isset($id)) + { + $query = $db->select(TABLE_PREFIX . 'pages', array('id' => $id)); + if($query !== false) + $db->update(TABLE_PREFIX . 'pages', array('hidden' => ($query['hidden'] == 1 ? 0 : 1)), array('id' => $id)); + else + $errors[] = 'Page with id ' . $id . ' does not exists.'; + } + else + $errors[] = 'id not set'; + + return !count($errors); + } +} +?> \ No newline at end of file diff --git a/system/pages/admin/phpinfo.php b/system/pages/admin/phpinfo.php new file mode 100644 index 00000000..162dc06f --- /dev/null +++ b/system/pages/admin/phpinfo.php @@ -0,0 +1,20 @@ + + * @copyright 2017 MyAAC + * @version 0.0.1 + * @link http://my-aac.org + */ +defined('MYAAC') or die('Direct access not allowed!'); +$title = 'PHP Info'; + +if(!function_exists('phpinfo')) { ?> +phpinfo() function is disabled in your webserver config.
    +You can enable it by editing php.ini file. + +'; + ifr = document.getElementById('iframe'); + doc = ifr.contentWindow.document; + + // Force absolute CSS urls + css = [ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css")]; + css = css.concat(tinymce.explode(ed.settings.content_css) || []); + tinymce.each(css, function(u) { + cssHTML += ''; + }); + + // Write content into iframe + doc.open(); + doc.write('' + cssHTML + ''); + doc.close(); + + doc.designMode = 'on'; + this.resize(); + + window.setTimeout(function() { + ifr.contentWindow.focus(); + }, 10); + }, + + insert : function() { + var h = document.getElementById('iframe').contentWindow.document.body.innerHTML; + + tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, {content : h, wordContent : true}); + tinyMCEPopup.close(); + }, + + resize : function() { + var vp = tinyMCEPopup.dom.getViewPort(window), el; + + el = document.getElementById('iframe'); + + if (el) { + el.style.width = (vp.w - 20) + 'px'; + el.style.height = (vp.h - 90) + 'px'; + } + } +}; + +tinyMCEPopup.onInit.add(PasteWordDialog.init, PasteWordDialog); diff --git a/tools/tiny_mce/plugins/paste/langs/en_dlg.js b/tools/tiny_mce/plugins/paste/langs/en_dlg.js new file mode 100644 index 00000000..823eb16a --- /dev/null +++ b/tools/tiny_mce/plugins/paste/langs/en_dlg.js @@ -0,0 +1,5 @@ +tinyMCE.addI18n('en.paste_dlg',{ +text_title:"Use CTRL+V on your keyboard to paste the text into the window.", +text_linebreaks:"Keep linebreaks", +word_title:"Use CTRL+V on your keyboard to paste the text into the window." +}); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/paste/pastetext.htm b/tools/tiny_mce/plugins/paste/pastetext.htm new file mode 100644 index 00000000..8ccfbb97 --- /dev/null +++ b/tools/tiny_mce/plugins/paste/pastetext.htm @@ -0,0 +1,27 @@ + + + {#paste.paste_text_desc} + + + + +
    +
    {#paste.paste_text_desc}
    + +
    + +
    + +
    + +
    {#paste_dlg.text_title}
    + + + +
    + + +
    +
    + + \ No newline at end of file diff --git a/tools/tiny_mce/plugins/paste/pasteword.htm b/tools/tiny_mce/plugins/paste/pasteword.htm new file mode 100644 index 00000000..7731f39c --- /dev/null +++ b/tools/tiny_mce/plugins/paste/pasteword.htm @@ -0,0 +1,21 @@ + + + {#paste.paste_word_desc} + + + + +
    +
    {#paste.paste_word_desc}
    + +
    {#paste_dlg.word_title}
    + +
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/preview/editor_plugin.js b/tools/tiny_mce/plugins/preview/editor_plugin.js new file mode 100644 index 00000000..507909c5 --- /dev/null +++ b/tools/tiny_mce/plugins/preview/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.Preview",{init:function(a,b){var d=this,c=tinymce.explode(a.settings.content_css);d.editor=a;tinymce.each(c,function(f,e){c[e]=a.documentBaseURI.toAbsolute(f)});a.addCommand("mcePreview",function(){a.windowManager.open({file:a.getParam("plugin_preview_pageurl",b+"/preview.html"),width:parseInt(a.getParam("plugin_preview_width","550")),height:parseInt(a.getParam("plugin_preview_height","600")),resizable:"yes",scrollbars:"yes",popup_css:c?c.join(","):a.baseURI.toAbsolute("themes/"+a.settings.theme+"/skins/"+a.settings.skin+"/content.css"),inline:a.getParam("plugin_preview_inline",1)},{base:a.documentBaseURI.getURI()})});a.addButton("preview",{title:"preview.preview_desc",cmd:"mcePreview"})},getInfo:function(){return{longname:"Preview",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("preview",tinymce.plugins.Preview)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/preview/editor_plugin_src.js b/tools/tiny_mce/plugins/preview/editor_plugin_src.js new file mode 100644 index 00000000..80f00f0d --- /dev/null +++ b/tools/tiny_mce/plugins/preview/editor_plugin_src.js @@ -0,0 +1,53 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.Preview', { + init : function(ed, url) { + var t = this, css = tinymce.explode(ed.settings.content_css); + + t.editor = ed; + + // Force absolute CSS urls + tinymce.each(css, function(u, k) { + css[k] = ed.documentBaseURI.toAbsolute(u); + }); + + ed.addCommand('mcePreview', function() { + ed.windowManager.open({ + file : ed.getParam("plugin_preview_pageurl", url + "/preview.html"), + width : parseInt(ed.getParam("plugin_preview_width", "550")), + height : parseInt(ed.getParam("plugin_preview_height", "600")), + resizable : "yes", + scrollbars : "yes", + popup_css : css ? css.join(',') : ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css"), + inline : ed.getParam("plugin_preview_inline", 1) + }, { + base : ed.documentBaseURI.getURI() + }); + }); + + ed.addButton('preview', {title : 'preview.preview_desc', cmd : 'mcePreview'}); + }, + + getInfo : function() { + return { + longname : 'Preview', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('preview', tinymce.plugins.Preview); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/preview/example.html b/tools/tiny_mce/plugins/preview/example.html new file mode 100644 index 00000000..48202224 --- /dev/null +++ b/tools/tiny_mce/plugins/preview/example.html @@ -0,0 +1,28 @@ + + + + + +Example of a custom preview page + + + +Editor contents:
    +
    + +
    + + + diff --git a/tools/tiny_mce/plugins/preview/jscripts/embed.js b/tools/tiny_mce/plugins/preview/jscripts/embed.js new file mode 100644 index 00000000..6fe25de0 --- /dev/null +++ b/tools/tiny_mce/plugins/preview/jscripts/embed.js @@ -0,0 +1,73 @@ +/** + * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose. + */ + +function writeFlash(p) { + writeEmbed( + 'D27CDB6E-AE6D-11cf-96B8-444553540000', + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', + 'application/x-shockwave-flash', + p + ); +} + +function writeShockWave(p) { + writeEmbed( + '166B1BCA-3F9C-11CF-8075-444553540000', + 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0', + 'application/x-director', + p + ); +} + +function writeQuickTime(p) { + writeEmbed( + '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B', + 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0', + 'video/quicktime', + p + ); +} + +function writeRealMedia(p) { + writeEmbed( + 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA', + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', + 'audio/x-pn-realaudio-plugin', + p + ); +} + +function writeWindowsMedia(p) { + p.url = p.src; + writeEmbed( + '6BF52A52-394A-11D3-B153-00C04F79FAA6', + 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701', + 'application/x-mplayer2', + p + ); +} + +function writeEmbed(cls, cb, mt, p) { + var h = '', n; + + h += ''; + + h += ' + + + + + +{#preview.preview_desc} + + + + + diff --git a/tools/tiny_mce/plugins/print/editor_plugin.js b/tools/tiny_mce/plugins/print/editor_plugin.js new file mode 100644 index 00000000..b5b3a55e --- /dev/null +++ b/tools/tiny_mce/plugins/print/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.Print",{init:function(a,b){a.addCommand("mcePrint",function(){a.getWin().print()});a.addButton("print",{title:"print.print_desc",cmd:"mcePrint"})},getInfo:function(){return{longname:"Print",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("print",tinymce.plugins.Print)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/print/editor_plugin_src.js b/tools/tiny_mce/plugins/print/editor_plugin_src.js new file mode 100644 index 00000000..47e666a3 --- /dev/null +++ b/tools/tiny_mce/plugins/print/editor_plugin_src.js @@ -0,0 +1,34 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.Print', { + init : function(ed, url) { + ed.addCommand('mcePrint', function() { + ed.getWin().print(); + }); + + ed.addButton('print', {title : 'print.print_desc', cmd : 'mcePrint'}); + }, + + getInfo : function() { + return { + longname : 'Print', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('print', tinymce.plugins.Print); +})(); diff --git a/tools/tiny_mce/plugins/save/editor_plugin.js b/tools/tiny_mce/plugins/save/editor_plugin.js new file mode 100644 index 00000000..8e939966 --- /dev/null +++ b/tools/tiny_mce/plugins/save/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.Save",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceSave",c._save,c);a.addCommand("mceCancel",c._cancel,c);a.addButton("save",{title:"save.save_desc",cmd:"mceSave"});a.addButton("cancel",{title:"save.cancel_desc",cmd:"mceCancel"});a.onNodeChange.add(c._nodeChange,c);a.addShortcut("ctrl+s",a.getLang("save.save_desc"),"mceSave")},getInfo:function(){return{longname:"Save",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(b,a,c){var b=this.editor;if(b.getParam("save_enablewhendirty")){a.setDisabled("save",!b.isDirty());a.setDisabled("cancel",!b.isDirty())}},_save:function(){var c=this.editor,a,e,d,b;a=tinymce.DOM.get(c.id).form||tinymce.DOM.getParent(c.id,"form");if(c.getParam("save_enablewhendirty")&&!c.isDirty()){return}tinyMCE.triggerSave();if(e=c.getParam("save_onsavecallback")){if(c.execCallback("save_onsavecallback",c)){c.startContent=tinymce.trim(c.getContent({format:"raw"}));c.nodeChanged()}return}if(a){c.isNotDirty=true;if(a.onsubmit==null||a.onsubmit()!=false){a.submit()}c.nodeChanged()}else{c.windowManager.alert("Error: No form element found.")}},_cancel:function(){var a=this.editor,c,b=tinymce.trim(a.startContent);if(c=a.getParam("save_oncancelcallback")){a.execCallback("save_oncancelcallback",a);return}a.setContent(b);a.undoManager.clear();a.nodeChanged()}});tinymce.PluginManager.add("save",tinymce.plugins.Save)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/save/editor_plugin_src.js b/tools/tiny_mce/plugins/save/editor_plugin_src.js new file mode 100644 index 00000000..5ab6491c --- /dev/null +++ b/tools/tiny_mce/plugins/save/editor_plugin_src.js @@ -0,0 +1,101 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.Save', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + // Register commands + ed.addCommand('mceSave', t._save, t); + ed.addCommand('mceCancel', t._cancel, t); + + // Register buttons + ed.addButton('save', {title : 'save.save_desc', cmd : 'mceSave'}); + ed.addButton('cancel', {title : 'save.cancel_desc', cmd : 'mceCancel'}); + + ed.onNodeChange.add(t._nodeChange, t); + ed.addShortcut('ctrl+s', ed.getLang('save.save_desc'), 'mceSave'); + }, + + getInfo : function() { + return { + longname : 'Save', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private methods + + _nodeChange : function(ed, cm, n) { + var ed = this.editor; + + if (ed.getParam('save_enablewhendirty')) { + cm.setDisabled('save', !ed.isDirty()); + cm.setDisabled('cancel', !ed.isDirty()); + } + }, + + // Private methods + + _save : function() { + var ed = this.editor, formObj, os, i, elementId; + + formObj = tinymce.DOM.get(ed.id).form || tinymce.DOM.getParent(ed.id, 'form'); + + if (ed.getParam("save_enablewhendirty") && !ed.isDirty()) + return; + + tinyMCE.triggerSave(); + + // Use callback instead + if (os = ed.getParam("save_onsavecallback")) { + if (ed.execCallback('save_onsavecallback', ed)) { + ed.startContent = tinymce.trim(ed.getContent({format : 'raw'})); + ed.nodeChanged(); + } + + return; + } + + if (formObj) { + ed.isNotDirty = true; + + if (formObj.onsubmit == null || formObj.onsubmit() != false) + formObj.submit(); + + ed.nodeChanged(); + } else + ed.windowManager.alert("Error: No form element found."); + }, + + _cancel : function() { + var ed = this.editor, os, h = tinymce.trim(ed.startContent); + + // Use callback instead + if (os = ed.getParam("save_oncancelcallback")) { + ed.execCallback('save_oncancelcallback', ed); + return; + } + + ed.setContent(h); + ed.undoManager.clear(); + ed.nodeChanged(); + } + }); + + // Register plugin + tinymce.PluginManager.add('save', tinymce.plugins.Save); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/searchreplace/css/searchreplace.css b/tools/tiny_mce/plugins/searchreplace/css/searchreplace.css new file mode 100644 index 00000000..3e2eaf34 --- /dev/null +++ b/tools/tiny_mce/plugins/searchreplace/css/searchreplace.css @@ -0,0 +1,6 @@ +.panel_wrapper {height:85px;} +.panel_wrapper div.current {height:85px;} + +/* IE */ +* html .panel_wrapper {height:100px;} +* html .panel_wrapper div.current {height:100px;} diff --git a/tools/tiny_mce/plugins/searchreplace/editor_plugin.js b/tools/tiny_mce/plugins/searchreplace/editor_plugin.js new file mode 100644 index 00000000..cd9c985b --- /dev/null +++ b/tools/tiny_mce/plugins/searchreplace/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.SearchReplacePlugin",{init:function(a,c){function b(d){a.windowManager.open({file:c+"/searchreplace.htm",width:420+parseInt(a.getLang("searchreplace.delta_width",0)),height:170+parseInt(a.getLang("searchreplace.delta_height",0)),inline:1,auto_focus:0},{mode:d,search_string:a.selection.getContent({format:"text"}),plugin_url:c})}a.addCommand("mceSearch",function(){b("search")});a.addCommand("mceReplace",function(){b("replace")});a.addButton("search",{title:"searchreplace.search_desc",cmd:"mceSearch"});a.addButton("replace",{title:"searchreplace.replace_desc",cmd:"mceReplace"});a.addShortcut("ctrl+f","searchreplace.search_desc","mceSearch")},getInfo:function(){return{longname:"Search/Replace",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("searchreplace",tinymce.plugins.SearchReplacePlugin)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/searchreplace/editor_plugin_src.js b/tools/tiny_mce/plugins/searchreplace/editor_plugin_src.js new file mode 100644 index 00000000..e9b3ee81 --- /dev/null +++ b/tools/tiny_mce/plugins/searchreplace/editor_plugin_src.js @@ -0,0 +1,57 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.SearchReplacePlugin', { + init : function(ed, url) { + function open(m) { + ed.windowManager.open({ + file : url + '/searchreplace.htm', + width : 420 + parseInt(ed.getLang('searchreplace.delta_width', 0)), + height : 170 + parseInt(ed.getLang('searchreplace.delta_height', 0)), + inline : 1, + auto_focus : 0 + }, { + mode : m, + search_string : ed.selection.getContent({format : 'text'}), + plugin_url : url + }); + }; + + // Register commands + ed.addCommand('mceSearch', function() { + open('search'); + }); + + ed.addCommand('mceReplace', function() { + open('replace'); + }); + + // Register buttons + ed.addButton('search', {title : 'searchreplace.search_desc', cmd : 'mceSearch'}); + ed.addButton('replace', {title : 'searchreplace.replace_desc', cmd : 'mceReplace'}); + + ed.addShortcut('ctrl+f', 'searchreplace.search_desc', 'mceSearch'); + }, + + getInfo : function() { + return { + longname : 'Search/Replace', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('searchreplace', tinymce.plugins.SearchReplacePlugin); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/searchreplace/js/searchreplace.js b/tools/tiny_mce/plugins/searchreplace/js/searchreplace.js new file mode 100644 index 00000000..1426783c --- /dev/null +++ b/tools/tiny_mce/plugins/searchreplace/js/searchreplace.js @@ -0,0 +1,140 @@ +tinyMCEPopup.requireLangPack(); + +var SearchReplaceDialog = { + init : function(ed) { + var t = this, f = document.forms[0], m = tinyMCEPopup.getWindowArg("mode"); + + t.switchMode(m); + + f[m + '_panel_searchstring'].value = tinyMCEPopup.getWindowArg("search_string"); + + // Focus input field + f[m + '_panel_searchstring'].focus(); + + mcTabs.onChange.add(function(tab_id, panel_id) { + t.switchMode(tab_id.substring(0, tab_id.indexOf('_'))); + }); + }, + + switchMode : function(m) { + var f, lm = this.lastMode; + + if (lm != m) { + f = document.forms[0]; + + if (lm) { + f[m + '_panel_searchstring'].value = f[lm + '_panel_searchstring'].value; + f[m + '_panel_backwardsu'].checked = f[lm + '_panel_backwardsu'].checked; + f[m + '_panel_backwardsd'].checked = f[lm + '_panel_backwardsd'].checked; + f[m + '_panel_casesensitivebox'].checked = f[lm + '_panel_casesensitivebox'].checked; + } + + mcTabs.displayTab(m + '_tab', m + '_panel'); + document.getElementById("replaceBtn").style.display = (m == "replace") ? "inline" : "none"; + document.getElementById("replaceAllBtn").style.display = (m == "replace") ? "inline" : "none"; + this.lastMode = m; + } + }, + + searchNext : function(a) { + var ed = tinyMCEPopup.editor, se = ed.selection, r = se.getRng(), f, m = this.lastMode, s, b, fl = 0, w = ed.getWin(), wm = ed.windowManager, fo = 0; + + // Get input + f = document.forms[0]; + s = f[m + '_panel_searchstring'].value; + b = f[m + '_panel_backwardsu'].checked; + ca = f[m + '_panel_casesensitivebox'].checked; + rs = f['replace_panel_replacestring'].value; + + if (tinymce.isIE) { + r = ed.getDoc().selection.createRange(); + } + + if (s == '') + return; + + function fix() { + // Correct Firefox graphics glitches + // TODO: Verify if this is actually needed any more, maybe it was for very old FF versions? + r = se.getRng().cloneRange(); + ed.getDoc().execCommand('SelectAll', false, null); + se.setRng(r); + }; + + function replace() { + ed.selection.setContent(rs); // Needs to be duplicated due to selection bug in IE + }; + + // IE flags + if (ca) + fl = fl | 4; + + switch (a) { + case 'all': + // Move caret to beginning of text + ed.execCommand('SelectAll'); + ed.selection.collapse(true); + + if (tinymce.isIE) { + while (r.findText(s, b ? -1 : 1, fl)) { + r.scrollIntoView(); + r.select(); + replace(); + fo = 1; + + if (b) { + r.moveEnd("character", -(rs.length)); // Otherwise will loop forever + } + } + + tinyMCEPopup.storeSelection(); + } else { + while (w.find(s, ca, b, false, false, false, false)) { + replace(); + fo = 1; + } + } + + if (fo) + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.allreplaced')); + else + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound')); + + return; + + case 'current': + if (!ed.selection.isCollapsed()) + replace(); + + break; + } + + se.collapse(b); + r = se.getRng(); + + if (tinymce.isIE) { + r = ed.getDoc().selection.createRange(); + } + + // Whats the point + if (!s) + return; + + if (tinymce.isIE) { + if (r.findText(s, b ? -1 : 1, fl)) { + r.scrollIntoView(); + r.select(); + } else + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound')); + + tinyMCEPopup.storeSelection(); + } else { + if (!w.find(s, ca, b, false, false, false, false)) + tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound')); + else + fix(); + } + } +}; + +tinyMCEPopup.onInit.add(SearchReplaceDialog.init, SearchReplaceDialog); diff --git a/tools/tiny_mce/plugins/searchreplace/langs/en_dlg.js b/tools/tiny_mce/plugins/searchreplace/langs/en_dlg.js new file mode 100644 index 00000000..3dd3453d --- /dev/null +++ b/tools/tiny_mce/plugins/searchreplace/langs/en_dlg.js @@ -0,0 +1,16 @@ +tinyMCE.addI18n('en.searchreplace_dlg',{ +searchnext_desc:"Find again", +notfound:"The search has been completed. The search string could not be found.", +search_title:"Find", +replace_title:"Find/Replace", +allreplaced:"All occurrences of the search string were replaced.", +findwhat:"Find what", +replacewith:"Replace with", +direction:"Direction", +up:"Up", +down:"Down", +mcase:"Match case", +findnext:"Find next", +replace:"Replace", +replaceall:"Replace all" +}); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/searchreplace/searchreplace.htm b/tools/tiny_mce/plugins/searchreplace/searchreplace.htm new file mode 100644 index 00000000..bac5a184 --- /dev/null +++ b/tools/tiny_mce/plugins/searchreplace/searchreplace.htm @@ -0,0 +1,100 @@ + + + + {#searchreplace_dlg.replace_title} + + + + + + + + +
    + + +
    +
    + + + + + + + + + + + +
    + + + + + + + + + +
    + + + + + +
    +
    +
    + +
    + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    + + + + + +
    +
    +
    + +
    + +
    + + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/spellchecker/css/content.css b/tools/tiny_mce/plugins/spellchecker/css/content.css new file mode 100644 index 00000000..656ce1ee --- /dev/null +++ b/tools/tiny_mce/plugins/spellchecker/css/content.css @@ -0,0 +1 @@ +.mceItemHiddenSpellWord {background:url(../img/wline.gif) repeat-x bottom left; cursor:default;} diff --git a/tools/tiny_mce/plugins/spellchecker/editor_plugin.js b/tools/tiny_mce/plugins/spellchecker/editor_plugin.js new file mode 100644 index 00000000..a9ec3b9c --- /dev/null +++ b/tools/tiny_mce/plugins/spellchecker/editor_plugin.js @@ -0,0 +1 @@ +(function(){var a=tinymce.util.JSONRequest,c=tinymce.each,b=tinymce.DOM;tinymce.create("tinymce.plugins.SpellcheckerPlugin",{getInfo:function(){return{longname:"Spellchecker",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker",version:tinymce.majorVersion+"."+tinymce.minorVersion}},init:function(e,f){var g=this,d;g.url=f;g.editor=e;g.rpcUrl=e.getParam("spellchecker_rpc_url","{backend}");if(g.rpcUrl=="{backend}"){if(tinymce.isIE){return}g.hasSupport=true;e.onContextMenu.addToTop(function(h,i){if(g.active){return false}})}e.addCommand("mceSpellCheck",function(){if(g.rpcUrl=="{backend}"){g.editor.getBody().spellcheck=g.active=!g.active;return}if(!g.active){e.setProgressState(1);g._sendRPC("checkWords",[g.selectedLang,g._getWords()],function(h){if(h.length>0){g.active=1;g._markWords(h);e.setProgressState(0);e.nodeChanged()}else{e.setProgressState(0);if(e.getParam("spellchecker_report_no_misspellings",true)){e.windowManager.alert("spellchecker.no_mpell")}}})}else{g._done()}});e.onInit.add(function(){if(e.settings.content_css!==false){e.dom.loadCSS(f+"/css/content.css")}});e.onClick.add(g._showMenu,g);e.onContextMenu.add(g._showMenu,g);e.onBeforeGetContent.add(function(){if(g.active){g._removeWords()}});e.onNodeChange.add(function(i,h){h.setActive("spellchecker",g.active)});e.onSetContent.add(function(){g._done()});e.onBeforeGetContent.add(function(){g._done()});e.onBeforeExecCommand.add(function(h,i){if(i=="mceFullScreen"){g._done()}});g.languages={};c(e.getParam("spellchecker_languages","+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv","hash"),function(i,h){if(h.indexOf("+")===0){h=h.substring(1);g.selectedLang=i}g.languages[h]=i})},createControl:function(h,d){var f=this,g,e=f.editor;if(h=="spellchecker"){if(f.rpcUrl=="{backend}"){if(f.hasSupport){g=d.createButton(h,{title:"spellchecker.desc",cmd:"mceSpellCheck",scope:f})}return g}g=d.createSplitButton(h,{title:"spellchecker.desc",cmd:"mceSpellCheck",scope:f});g.onRenderMenu.add(function(j,i){i.add({title:"spellchecker.langs","class":"mceMenuItemTitle"}).setDisabled(1);c(f.languages,function(n,m){var p={icon:1},l;p.onclick=function(){l.setSelected(1);f.selectedItem.setSelected(0);f.selectedItem=l;f.selectedLang=n};p.title=m;l=i.add(p);l.setSelected(n==f.selectedLang);if(n==f.selectedLang){f.selectedItem=l}})});return g}},_walk:function(i,g){var h=this.editor.getDoc(),e;if(h.createTreeWalker){e=h.createTreeWalker(i,NodeFilter.SHOW_TEXT,null,false);while((i=e.nextNode())!=null){g.call(this,i)}}else{tinymce.walk(i,g,"childNodes")}},_getSeparators:function(){var e="",d,f=this.editor.getParam("spellchecker_word_separator_chars",'\\s!"#$%&()*+,-./:;<=>?@[]^_{|}\u201d\u201c');for(d=0;d$1$2');q=q.replace(g,'$1$2');j.replace(j.create("span",{"class":"mceItemHidden"},q),r)}}});l.moveToBookmark(m)},_showMenu:function(h,j){var i=this,h=i.editor,d=i._menu,l,k=h.dom,g=k.getViewPort(h.getWin()),f=j.target;j=0;if(!d){l=b.getPos(h.getContentAreaContainer());d=h.controlManager.createDropMenu("spellcheckermenu",{offset_x:l.x,offset_y:l.y,"class":"mceNoIcons"});i._menu=d}if(k.hasClass(f,"mceItemHiddenSpellWord")){d.removeAll();d.add({title:"spellchecker.wait","class":"mceMenuItemTitle"}).setDisabled(1);i._sendRPC("getSuggestions",[i.selectedLang,k.decode(f.innerHTML)],function(m){var e;d.removeAll();if(m.length>0){d.add({title:"spellchecker.sug","class":"mceMenuItemTitle"}).setDisabled(1);c(m,function(n){d.add({title:n,onclick:function(){k.replace(h.getDoc().createTextNode(n),f);i._checkDone()}})});d.addSeparator()}else{d.add({title:"spellchecker.no_sug","class":"mceMenuItemTitle"}).setDisabled(1)}e=i.editor.getParam("spellchecker_enable_ignore_rpc","");d.add({title:"spellchecker.ignore_word",onclick:function(){var n=f.innerHTML;k.remove(f,1);i._checkDone();if(e){h.setProgressState(1);i._sendRPC("ignoreWord",[i.selectedLang,n],function(o){h.setProgressState(0)})}}});d.add({title:"spellchecker.ignore_words",onclick:function(){var n=f.innerHTML;i._removeWords(k.decode(n));i._checkDone();if(e){h.setProgressState(1);i._sendRPC("ignoreWords",[i.selectedLang,n],function(o){h.setProgressState(0)})}}});if(i.editor.getParam("spellchecker_enable_learn_rpc")){d.add({title:"spellchecker.learn_word",onclick:function(){var n=f.innerHTML;k.remove(f,1);i._checkDone();h.setProgressState(1);i._sendRPC("learnWord",[i.selectedLang,n],function(o){h.setProgressState(0)})}})}d.update()});h.selection.select(f);l=k.getPos(f);d.showMenu(l.x,l.y+f.offsetHeight-g.y);return tinymce.dom.Event.cancel(j)}else{d.hideMenu()}},_checkDone:function(){var e=this,d=e.editor,g=d.dom,f;c(g.select("span"),function(h){if(h&&g.hasClass(h,"mceItemHiddenSpellWord")){f=true;return false}});if(!f){e._done()}},_done:function(){var d=this,e=d.active;if(d.active){d.active=0;d._removeWords();if(d._menu){d._menu.hideMenu()}if(e){d.editor.nodeChanged()}}},_sendRPC:function(e,g,d){var f=this;a.sendRPC({url:f.rpcUrl,method:e,params:g,success:d,error:function(i,h){f.editor.setProgressState(0);f.editor.windowManager.alert(i.errstr||("Error response: "+h.responseText))}})}});tinymce.PluginManager.add("spellchecker",tinymce.plugins.SpellcheckerPlugin)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/spellchecker/editor_plugin_src.js b/tools/tiny_mce/plugins/spellchecker/editor_plugin_src.js new file mode 100644 index 00000000..bd501d3d --- /dev/null +++ b/tools/tiny_mce/plugins/spellchecker/editor_plugin_src.js @@ -0,0 +1,417 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM; + + tinymce.create('tinymce.plugins.SpellcheckerPlugin', { + getInfo : function() { + return { + longname : 'Spellchecker', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + init : function(ed, url) { + var t = this, cm; + + t.url = url; + t.editor = ed; + t.rpcUrl = ed.getParam("spellchecker_rpc_url", "{backend}"); + + if (t.rpcUrl == '{backend}') { + // Sniff if the browser supports native spellchecking (Don't know of a better way) + if (tinymce.isIE) + return; + + t.hasSupport = true; + + // Disable the context menu when spellchecking is active + ed.onContextMenu.addToTop(function(ed, e) { + if (t.active) + return false; + }); + } + + // Register commands + ed.addCommand('mceSpellCheck', function() { + if (t.rpcUrl == '{backend}') { + // Enable/disable native spellchecker + t.editor.getBody().spellcheck = t.active = !t.active; + return; + } + + if (!t.active) { + ed.setProgressState(1); + t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) { + if (r.length > 0) { + t.active = 1; + t._markWords(r); + ed.setProgressState(0); + ed.nodeChanged(); + } else { + ed.setProgressState(0); + + if (ed.getParam('spellchecker_report_no_misspellings', true)) + ed.windowManager.alert('spellchecker.no_mpell'); + } + }); + } else + t._done(); + }); + + ed.onInit.add(function() { + if (ed.settings.content_css !== false) + ed.dom.loadCSS(url + '/css/content.css'); + }); + + ed.onClick.add(t._showMenu, t); + ed.onContextMenu.add(t._showMenu, t); + ed.onBeforeGetContent.add(function() { + if (t.active) + t._removeWords(); + }); + + ed.onNodeChange.add(function(ed, cm) { + cm.setActive('spellchecker', t.active); + }); + + ed.onSetContent.add(function() { + t._done(); + }); + + ed.onBeforeGetContent.add(function() { + t._done(); + }); + + ed.onBeforeExecCommand.add(function(ed, cmd) { + if (cmd == 'mceFullScreen') + t._done(); + }); + + // Find selected language + t.languages = {}; + each(ed.getParam('spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv', 'hash'), function(v, k) { + if (k.indexOf('+') === 0) { + k = k.substring(1); + t.selectedLang = v; + } + + t.languages[k] = v; + }); + }, + + createControl : function(n, cm) { + var t = this, c, ed = t.editor; + + if (n == 'spellchecker') { + // Use basic button if we use the native spellchecker + if (t.rpcUrl == '{backend}') { + // Create simple toggle button if we have native support + if (t.hasSupport) + c = cm.createButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); + + return c; + } + + c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); + + c.onRenderMenu.add(function(c, m) { + m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + each(t.languages, function(v, k) { + var o = {icon : 1}, mi; + + o.onclick = function() { + mi.setSelected(1); + t.selectedItem.setSelected(0); + t.selectedItem = mi; + t.selectedLang = v; + }; + + o.title = k; + mi = m.add(o); + mi.setSelected(v == t.selectedLang); + + if (v == t.selectedLang) + t.selectedItem = mi; + }) + }); + + return c; + } + }, + + // Internal functions + + _walk : function(n, f) { + var d = this.editor.getDoc(), w; + + if (d.createTreeWalker) { + w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); + + while ((n = w.nextNode()) != null) + f.call(this, n); + } else + tinymce.walk(n, f, 'childNodes'); + }, + + _getSeparators : function() { + var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}\u201d\u201c'); + + // Build word separator regexp + for (i=0; i$1$2'); + v = v.replace(r3, '$1$2'); + + dom.replace(dom.create('span', {'class' : 'mceItemHidden'}, v), n); + } + } + }); + + se.moveToBookmark(b); + }, + + _showMenu : function(ed, e) { + var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()), wordSpan = e.target; + + e = 0; // Fixes IE memory leak + + if (!m) { + p1 = DOM.getPos(ed.getContentAreaContainer()); + //p2 = DOM.getPos(ed.getContainer()); + + m = ed.controlManager.createDropMenu('spellcheckermenu', { + offset_x : p1.x, + offset_y : p1.y, + 'class' : 'mceNoIcons' + }); + + t._menu = m; + } + + if (dom.hasClass(wordSpan, 'mceItemHiddenSpellWord')) { + m.removeAll(); + m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + + t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(wordSpan.innerHTML)], function(r) { + var ignoreRpc; + + m.removeAll(); + + if (r.length > 0) { + m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + each(r, function(v) { + m.add({title : v, onclick : function() { + dom.replace(ed.getDoc().createTextNode(v), wordSpan); + t._checkDone(); + }}); + }); + + m.addSeparator(); + } else + m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + + ignoreRpc = t.editor.getParam("spellchecker_enable_ignore_rpc", ''); + m.add({ + title : 'spellchecker.ignore_word', + onclick : function() { + var word = wordSpan.innerHTML; + + dom.remove(wordSpan, 1); + t._checkDone(); + + // tell the server if we need to + if (ignoreRpc) { + ed.setProgressState(1); + t._sendRPC('ignoreWord', [t.selectedLang, word], function(r) { + ed.setProgressState(0); + }); + } + } + }); + + m.add({ + title : 'spellchecker.ignore_words', + onclick : function() { + var word = wordSpan.innerHTML; + + t._removeWords(dom.decode(word)); + t._checkDone(); + + // tell the server if we need to + if (ignoreRpc) { + ed.setProgressState(1); + t._sendRPC('ignoreWords', [t.selectedLang, word], function(r) { + ed.setProgressState(0); + }); + } + } + }); + + + if (t.editor.getParam("spellchecker_enable_learn_rpc")) { + m.add({ + title : 'spellchecker.learn_word', + onclick : function() { + var word = wordSpan.innerHTML; + + dom.remove(wordSpan, 1); + t._checkDone(); + + ed.setProgressState(1); + t._sendRPC('learnWord', [t.selectedLang, word], function(r) { + ed.setProgressState(0); + }); + } + }); + } + + m.update(); + }); + + ed.selection.select(wordSpan); + p1 = dom.getPos(wordSpan); + m.showMenu(p1.x, p1.y + wordSpan.offsetHeight - vp.y); + + return tinymce.dom.Event.cancel(e); + } else + m.hideMenu(); + }, + + _checkDone : function() { + var t = this, ed = t.editor, dom = ed.dom, o; + + each(dom.select('span'), function(n) { + if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) { + o = true; + return false; + } + }); + + if (!o) + t._done(); + }, + + _done : function() { + var t = this, la = t.active; + + if (t.active) { + t.active = 0; + t._removeWords(); + + if (t._menu) + t._menu.hideMenu(); + + if (la) + t.editor.nodeChanged(); + } + }, + + _sendRPC : function(m, p, cb) { + var t = this; + + JSONRequest.sendRPC({ + url : t.rpcUrl, + method : m, + params : p, + success : cb, + error : function(e, x) { + t.editor.setProgressState(0); + t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText)); + } + }); + } + }); + + // Register plugin + tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin); +})(); diff --git a/tools/tiny_mce/plugins/spellchecker/img/wline.gif b/tools/tiny_mce/plugins/spellchecker/img/wline.gif new file mode 100644 index 00000000..7d0a4dbc Binary files /dev/null and b/tools/tiny_mce/plugins/spellchecker/img/wline.gif differ diff --git a/tools/tiny_mce/plugins/style/css/props.css b/tools/tiny_mce/plugins/style/css/props.css new file mode 100644 index 00000000..5550b093 --- /dev/null +++ b/tools/tiny_mce/plugins/style/css/props.css @@ -0,0 +1,13 @@ +#text_font {width:250px;} +#text_size {width:70px;} +.mceAddSelectValue {background:#DDD;} +select, #block_text_indent, #box_width, #box_height, #box_padding_top, #box_padding_right, #box_padding_bottom, #box_padding_left {width:70px;} +#box_margin_top, #box_margin_right, #box_margin_bottom, #box_margin_left, #positioning_width, #positioning_height, #positioning_zindex {width:70px;} +#positioning_placement_top, #positioning_placement_right, #positioning_placement_bottom, #positioning_placement_left {width:70px;} +#positioning_clip_top, #positioning_clip_right, #positioning_clip_bottom, #positioning_clip_left {width:70px;} +.panel_wrapper div.current {padding-top:10px;height:230px;} +.delim {border-left:1px solid gray;} +.tdelim {border-bottom:1px solid gray;} +#block_display {width:145px;} +#list_type {width:115px;} +.disabled {background:#EEE;} diff --git a/tools/tiny_mce/plugins/style/editor_plugin.js b/tools/tiny_mce/plugins/style/editor_plugin.js new file mode 100644 index 00000000..cab2153c --- /dev/null +++ b/tools/tiny_mce/plugins/style/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.StylePlugin",{init:function(a,b){a.addCommand("mceStyleProps",function(){a.windowManager.open({file:b+"/props.htm",width:480+parseInt(a.getLang("style.delta_width",0)),height:320+parseInt(a.getLang("style.delta_height",0)),inline:1},{plugin_url:b,style_text:a.selection.getNode().style.cssText})});a.addCommand("mceSetElementStyle",function(d,c){if(e=a.selection.getNode()){a.dom.setAttrib(e,"style",c);a.execCommand("mceRepaint")}});a.onNodeChange.add(function(d,c,f){c.setDisabled("styleprops",f.nodeName==="BODY")});a.addButton("styleprops",{title:"style.desc",cmd:"mceStyleProps"})},getInfo:function(){return{longname:"Style",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("style",tinymce.plugins.StylePlugin)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/style/editor_plugin_src.js b/tools/tiny_mce/plugins/style/editor_plugin_src.js new file mode 100644 index 00000000..c09d5e81 --- /dev/null +++ b/tools/tiny_mce/plugins/style/editor_plugin_src.js @@ -0,0 +1,55 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.StylePlugin', { + init : function(ed, url) { + // Register commands + ed.addCommand('mceStyleProps', function() { + ed.windowManager.open({ + file : url + '/props.htm', + width : 480 + parseInt(ed.getLang('style.delta_width', 0)), + height : 320 + parseInt(ed.getLang('style.delta_height', 0)), + inline : 1 + }, { + plugin_url : url, + style_text : ed.selection.getNode().style.cssText + }); + }); + + ed.addCommand('mceSetElementStyle', function(ui, v) { + if (e = ed.selection.getNode()) { + ed.dom.setAttrib(e, 'style', v); + ed.execCommand('mceRepaint'); + } + }); + + ed.onNodeChange.add(function(ed, cm, n) { + cm.setDisabled('styleprops', n.nodeName === 'BODY'); + }); + + // Register buttons + ed.addButton('styleprops', {title : 'style.desc', cmd : 'mceStyleProps'}); + }, + + getInfo : function() { + return { + longname : 'Style', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('style', tinymce.plugins.StylePlugin); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/style/js/props.js b/tools/tiny_mce/plugins/style/js/props.js new file mode 100644 index 00000000..1e73806d --- /dev/null +++ b/tools/tiny_mce/plugins/style/js/props.js @@ -0,0 +1,641 @@ +tinyMCEPopup.requireLangPack(); + +var defaultFonts = "" + + "Arial, Helvetica, sans-serif=Arial, Helvetica, sans-serif;" + + "Times New Roman, Times, serif=Times New Roman, Times, serif;" + + "Courier New, Courier, mono=Courier New, Courier, mono;" + + "Times New Roman, Times, serif=Times New Roman, Times, serif;" + + "Georgia, Times New Roman, Times, serif=Georgia, Times New Roman, Times, serif;" + + "Verdana, Arial, Helvetica, sans-serif=Verdana, Arial, Helvetica, sans-serif;" + + "Geneva, Arial, Helvetica, sans-serif=Geneva, Arial, Helvetica, sans-serif"; + +var defaultSizes = "9;10;12;14;16;18;24;xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger"; +var defaultMeasurement = "+pixels=px;points=pt;inches=in;centimetres=cm;millimetres=mm;picas=pc;ems=em;exs=ex;%"; +var defaultSpacingMeasurement = "pixels=px;points=pt;inches=in;centimetres=cm;millimetres=mm;picas=pc;+ems=em;exs=ex;%"; +var defaultIndentMeasurement = "pixels=px;+points=pt;inches=in;centimetres=cm;millimetres=mm;picas=pc;ems=em;exs=ex;%"; +var defaultWeight = "normal;bold;bolder;lighter;100;200;300;400;500;600;700;800;900"; +var defaultTextStyle = "normal;italic;oblique"; +var defaultVariant = "normal;small-caps"; +var defaultLineHeight = "normal"; +var defaultAttachment = "fixed;scroll"; +var defaultRepeat = "no-repeat;repeat;repeat-x;repeat-y"; +var defaultPosH = "left;center;right"; +var defaultPosV = "top;center;bottom"; +var defaultVAlign = "baseline;sub;super;top;text-top;middle;bottom;text-bottom"; +var defaultDisplay = "inline;block;list-item;run-in;compact;marker;table;inline-table;table-row-group;table-header-group;table-footer-group;table-row;table-column-group;table-column;table-cell;table-caption;none"; +var defaultBorderStyle = "none;solid;dashed;dotted;double;groove;ridge;inset;outset"; +var defaultBorderWidth = "thin;medium;thick"; +var defaultListType = "disc;circle;square;decimal;lower-roman;upper-roman;lower-alpha;upper-alpha;none"; + +function init() { + var ce = document.getElementById('container'), h; + + ce.style.cssText = tinyMCEPopup.getWindowArg('style_text'); + + h = getBrowserHTML('background_image_browser','background_image','image','advimage'); + document.getElementById("background_image_browser").innerHTML = h; + + document.getElementById('text_color_pickcontainer').innerHTML = getColorPickerHTML('text_color_pick','text_color'); + document.getElementById('background_color_pickcontainer').innerHTML = getColorPickerHTML('background_color_pick','background_color'); + document.getElementById('border_color_top_pickcontainer').innerHTML = getColorPickerHTML('border_color_top_pick','border_color_top'); + document.getElementById('border_color_right_pickcontainer').innerHTML = getColorPickerHTML('border_color_right_pick','border_color_right'); + document.getElementById('border_color_bottom_pickcontainer').innerHTML = getColorPickerHTML('border_color_bottom_pick','border_color_bottom'); + document.getElementById('border_color_left_pickcontainer').innerHTML = getColorPickerHTML('border_color_left_pick','border_color_left'); + + fillSelect(0, 'text_font', 'style_font', defaultFonts, ';', true); + fillSelect(0, 'text_size', 'style_font_size', defaultSizes, ';', true); + fillSelect(0, 'text_size_measurement', 'style_font_size_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'text_case', 'style_text_case', "capitalize;uppercase;lowercase", ';', true); + fillSelect(0, 'text_weight', 'style_font_weight', defaultWeight, ';', true); + fillSelect(0, 'text_style', 'style_font_style', defaultTextStyle, ';', true); + fillSelect(0, 'text_variant', 'style_font_variant', defaultVariant, ';', true); + fillSelect(0, 'text_lineheight', 'style_font_line_height', defaultLineHeight, ';', true); + fillSelect(0, 'text_lineheight_measurement', 'style_font_line_height_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'background_attachment', 'style_background_attachment', defaultAttachment, ';', true); + fillSelect(0, 'background_repeat', 'style_background_repeat', defaultRepeat, ';', true); + + fillSelect(0, 'background_hpos_measurement', 'style_background_hpos_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'background_vpos_measurement', 'style_background_vpos_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'background_hpos', 'style_background_hpos', defaultPosH, ';', true); + fillSelect(0, 'background_vpos', 'style_background_vpos', defaultPosV, ';', true); + + fillSelect(0, 'block_wordspacing', 'style_wordspacing', 'normal', ';', true); + fillSelect(0, 'block_wordspacing_measurement', 'style_wordspacing_measurement', defaultSpacingMeasurement, ';', true); + fillSelect(0, 'block_letterspacing', 'style_letterspacing', 'normal', ';', true); + fillSelect(0, 'block_letterspacing_measurement', 'style_letterspacing_measurement', defaultSpacingMeasurement, ';', true); + fillSelect(0, 'block_vertical_alignment', 'style_vertical_alignment', defaultVAlign, ';', true); + fillSelect(0, 'block_text_align', 'style_text_align', "left;right;center;justify", ';', true); + fillSelect(0, 'block_whitespace', 'style_whitespace', "normal;pre;nowrap", ';', true); + fillSelect(0, 'block_display', 'style_display', defaultDisplay, ';', true); + fillSelect(0, 'block_text_indent_measurement', 'style_text_indent_measurement', defaultIndentMeasurement, ';', true); + + fillSelect(0, 'box_width_measurement', 'style_box_width_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_height_measurement', 'style_box_height_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_float', 'style_float', 'left;right;none', ';', true); + fillSelect(0, 'box_clear', 'style_clear', 'left;right;both;none', ';', true); + fillSelect(0, 'box_padding_left_measurement', 'style_padding_left_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_padding_top_measurement', 'style_padding_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_padding_bottom_measurement', 'style_padding_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_padding_right_measurement', 'style_padding_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_left_measurement', 'style_margin_left_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_top_measurement', 'style_margin_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_bottom_measurement', 'style_margin_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_right_measurement', 'style_margin_right_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'border_style_top', 'style_border_style_top', defaultBorderStyle, ';', true); + fillSelect(0, 'border_style_right', 'style_border_style_right', defaultBorderStyle, ';', true); + fillSelect(0, 'border_style_bottom', 'style_border_style_bottom', defaultBorderStyle, ';', true); + fillSelect(0, 'border_style_left', 'style_border_style_left', defaultBorderStyle, ';', true); + + fillSelect(0, 'border_width_top', 'style_border_width_top', defaultBorderWidth, ';', true); + fillSelect(0, 'border_width_right', 'style_border_width_right', defaultBorderWidth, ';', true); + fillSelect(0, 'border_width_bottom', 'style_border_width_bottom', defaultBorderWidth, ';', true); + fillSelect(0, 'border_width_left', 'style_border_width_left', defaultBorderWidth, ';', true); + + fillSelect(0, 'border_width_top_measurement', 'style_border_width_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'border_width_right_measurement', 'style_border_width_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'border_width_bottom_measurement', 'style_border_width_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'border_width_left_measurement', 'style_border_width_left_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'list_type', 'style_list_type', defaultListType, ';', true); + fillSelect(0, 'list_position', 'style_list_position', "inside;outside", ';', true); + + fillSelect(0, 'positioning_type', 'style_positioning_type', "absolute;relative;static", ';', true); + fillSelect(0, 'positioning_visibility', 'style_positioning_visibility', "inherit;visible;hidden", ';', true); + + fillSelect(0, 'positioning_width_measurement', 'style_positioning_width_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_height_measurement', 'style_positioning_height_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_overflow', 'style_positioning_overflow', "visible;hidden;scroll;auto", ';', true); + + fillSelect(0, 'positioning_placement_top_measurement', 'style_positioning_placement_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_placement_right_measurement', 'style_positioning_placement_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_placement_bottom_measurement', 'style_positioning_placement_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_placement_left_measurement', 'style_positioning_placement_left_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'positioning_clip_top_measurement', 'style_positioning_clip_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_clip_right_measurement', 'style_positioning_clip_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_clip_bottom_measurement', 'style_positioning_clip_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_clip_left_measurement', 'style_positioning_clip_left_measurement', defaultMeasurement, ';', true); + + TinyMCE_EditableSelects.init(); + setupFormData(); + showDisabledControls(); +} + +function setupFormData() { + var ce = document.getElementById('container'), f = document.forms[0], s, b, i; + + // Setup text fields + + selectByValue(f, 'text_font', ce.style.fontFamily, true, true); + selectByValue(f, 'text_size', getNum(ce.style.fontSize), true, true); + selectByValue(f, 'text_size_measurement', getMeasurement(ce.style.fontSize)); + selectByValue(f, 'text_weight', ce.style.fontWeight, true, true); + selectByValue(f, 'text_style', ce.style.fontStyle, true, true); + selectByValue(f, 'text_lineheight', getNum(ce.style.lineHeight), true, true); + selectByValue(f, 'text_lineheight_measurement', getMeasurement(ce.style.lineHeight)); + selectByValue(f, 'text_case', ce.style.textTransform, true, true); + selectByValue(f, 'text_variant', ce.style.fontVariant, true, true); + f.text_color.value = tinyMCEPopup.editor.dom.toHex(ce.style.color); + updateColor('text_color_pick', 'text_color'); + f.text_underline.checked = inStr(ce.style.textDecoration, 'underline'); + f.text_overline.checked = inStr(ce.style.textDecoration, 'overline'); + f.text_linethrough.checked = inStr(ce.style.textDecoration, 'line-through'); + f.text_blink.checked = inStr(ce.style.textDecoration, 'blink'); + + // Setup background fields + + f.background_color.value = tinyMCEPopup.editor.dom.toHex(ce.style.backgroundColor); + updateColor('background_color_pick', 'background_color'); + f.background_image.value = ce.style.backgroundImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"); + selectByValue(f, 'background_repeat', ce.style.backgroundRepeat, true, true); + selectByValue(f, 'background_attachment', ce.style.backgroundAttachment, true, true); + selectByValue(f, 'background_hpos', getNum(getVal(ce.style.backgroundPosition, 0)), true, true); + selectByValue(f, 'background_hpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 0))); + selectByValue(f, 'background_vpos', getNum(getVal(ce.style.backgroundPosition, 1)), true, true); + selectByValue(f, 'background_vpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 1))); + + // Setup block fields + + selectByValue(f, 'block_wordspacing', getNum(ce.style.wordSpacing), true, true); + selectByValue(f, 'block_wordspacing_measurement', getMeasurement(ce.style.wordSpacing)); + selectByValue(f, 'block_letterspacing', getNum(ce.style.letterSpacing), true, true); + selectByValue(f, 'block_letterspacing_measurement', getMeasurement(ce.style.letterSpacing)); + selectByValue(f, 'block_vertical_alignment', ce.style.verticalAlign, true, true); + selectByValue(f, 'block_text_align', ce.style.textAlign, true, true); + f.block_text_indent.value = getNum(ce.style.textIndent); + selectByValue(f, 'block_text_indent_measurement', getMeasurement(ce.style.textIndent)); + selectByValue(f, 'block_whitespace', ce.style.whiteSpace, true, true); + selectByValue(f, 'block_display', ce.style.display, true, true); + + // Setup box fields + + f.box_width.value = getNum(ce.style.width); + selectByValue(f, 'box_width_measurement', getMeasurement(ce.style.width)); + + f.box_height.value = getNum(ce.style.height); + selectByValue(f, 'box_height_measurement', getMeasurement(ce.style.height)); + + if (tinymce.isGecko) + selectByValue(f, 'box_float', ce.style.cssFloat, true, true); + else + selectByValue(f, 'box_float', ce.style.styleFloat, true, true); + + selectByValue(f, 'box_clear', ce.style.clear, true, true); + + setupBox(f, ce, 'box_padding', 'padding', ''); + setupBox(f, ce, 'box_margin', 'margin', ''); + + // Setup border fields + + setupBox(f, ce, 'border_style', 'border', 'Style'); + setupBox(f, ce, 'border_width', 'border', 'Width'); + setupBox(f, ce, 'border_color', 'border', 'Color'); + + updateColor('border_color_top_pick', 'border_color_top'); + updateColor('border_color_right_pick', 'border_color_right'); + updateColor('border_color_bottom_pick', 'border_color_bottom'); + updateColor('border_color_left_pick', 'border_color_left'); + + f.elements.border_color_top.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_top.value); + f.elements.border_color_right.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_right.value); + f.elements.border_color_bottom.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_bottom.value); + f.elements.border_color_left.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_left.value); + + // Setup list fields + + selectByValue(f, 'list_type', ce.style.listStyleType, true, true); + selectByValue(f, 'list_position', ce.style.listStylePosition, true, true); + f.list_bullet_image.value = ce.style.listStyleImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"); + + // Setup box fields + + selectByValue(f, 'positioning_type', ce.style.position, true, true); + selectByValue(f, 'positioning_visibility', ce.style.visibility, true, true); + selectByValue(f, 'positioning_overflow', ce.style.overflow, true, true); + f.positioning_zindex.value = ce.style.zIndex ? ce.style.zIndex : ""; + + f.positioning_width.value = getNum(ce.style.width); + selectByValue(f, 'positioning_width_measurement', getMeasurement(ce.style.width)); + + f.positioning_height.value = getNum(ce.style.height); + selectByValue(f, 'positioning_height_measurement', getMeasurement(ce.style.height)); + + setupBox(f, ce, 'positioning_placement', '', '', ['top', 'right', 'bottom', 'left']); + + s = ce.style.clip.replace(new RegExp("rect\\('?([^']*)'?\\)", 'gi'), "$1"); + s = s.replace(/,/g, ' '); + + if (!hasEqualValues([getVal(s, 0), getVal(s, 1), getVal(s, 2), getVal(s, 3)])) { + f.positioning_clip_top.value = getNum(getVal(s, 0)); + selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0))); + f.positioning_clip_right.value = getNum(getVal(s, 1)); + selectByValue(f, 'positioning_clip_right_measurement', getMeasurement(getVal(s, 1))); + f.positioning_clip_bottom.value = getNum(getVal(s, 2)); + selectByValue(f, 'positioning_clip_bottom_measurement', getMeasurement(getVal(s, 2))); + f.positioning_clip_left.value = getNum(getVal(s, 3)); + selectByValue(f, 'positioning_clip_left_measurement', getMeasurement(getVal(s, 3))); + } else { + f.positioning_clip_top.value = getNum(getVal(s, 0)); + selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0))); + f.positioning_clip_right.value = f.positioning_clip_bottom.value = f.positioning_clip_left.value; + } + +// setupBox(f, ce, '', 'border', 'Color'); +} + +function getMeasurement(s) { + return s.replace(/^([0-9.]+)(.*)$/, "$2"); +} + +function getNum(s) { + if (new RegExp('^(?:[0-9.]+)(?:[a-z%]+)$', 'gi').test(s)) + return s.replace(/[^0-9.]/g, ''); + + return s; +} + +function inStr(s, n) { + return new RegExp(n, 'gi').test(s); +} + +function getVal(s, i) { + var a = s.split(' '); + + if (a.length > 1) + return a[i]; + + return ""; +} + +function setValue(f, n, v) { + if (f.elements[n].type == "text") + f.elements[n].value = v; + else + selectByValue(f, n, v, true, true); +} + +function setupBox(f, ce, fp, pr, sf, b) { + if (typeof(b) == "undefined") + b = ['Top', 'Right', 'Bottom', 'Left']; + + if (isSame(ce, pr, sf, b)) { + f.elements[fp + "_same"].checked = true; + + setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf])); + f.elements[fp + "_top"].disabled = false; + + f.elements[fp + "_right"].value = ""; + f.elements[fp + "_right"].disabled = true; + f.elements[fp + "_bottom"].value = ""; + f.elements[fp + "_bottom"].disabled = true; + f.elements[fp + "_left"].value = ""; + f.elements[fp + "_left"].disabled = true; + + if (f.elements[fp + "_top_measurement"]) { + selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf])); + f.elements[fp + "_left_measurement"].disabled = true; + f.elements[fp + "_bottom_measurement"].disabled = true; + f.elements[fp + "_right_measurement"].disabled = true; + } + } else { + f.elements[fp + "_same"].checked = false; + + setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf])); + f.elements[fp + "_top"].disabled = false; + + setValue(f, fp + "_right", getNum(ce.style[pr + b[1] + sf])); + f.elements[fp + "_right"].disabled = false; + + setValue(f, fp + "_bottom", getNum(ce.style[pr + b[2] + sf])); + f.elements[fp + "_bottom"].disabled = false; + + setValue(f, fp + "_left", getNum(ce.style[pr + b[3] + sf])); + f.elements[fp + "_left"].disabled = false; + + if (f.elements[fp + "_top_measurement"]) { + selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf])); + selectByValue(f, fp + '_right_measurement', getMeasurement(ce.style[pr + b[1] + sf])); + selectByValue(f, fp + '_bottom_measurement', getMeasurement(ce.style[pr + b[2] + sf])); + selectByValue(f, fp + '_left_measurement', getMeasurement(ce.style[pr + b[3] + sf])); + f.elements[fp + "_left_measurement"].disabled = false; + f.elements[fp + "_bottom_measurement"].disabled = false; + f.elements[fp + "_right_measurement"].disabled = false; + } + } +} + +function isSame(e, pr, sf, b) { + var a = [], i, x; + + if (typeof(b) == "undefined") + b = ['Top', 'Right', 'Bottom', 'Left']; + + if (typeof(sf) == "undefined" || sf == null) + sf = ""; + + a[0] = e.style[pr + b[0] + sf]; + a[1] = e.style[pr + b[1] + sf]; + a[2] = e.style[pr + b[2] + sf]; + a[3] = e.style[pr + b[3] + sf]; + + for (i=0; i 0 ? s.substring(1) : s; + + if (f.text_none.checked) + s = "none"; + + ce.style.textDecoration = s; + + // Build background styles + + ce.style.backgroundColor = f.background_color.value; + ce.style.backgroundImage = f.background_image.value != "" ? "url(" + f.background_image.value + ")" : ""; + ce.style.backgroundRepeat = f.background_repeat.value; + ce.style.backgroundAttachment = f.background_attachment.value; + + if (f.background_hpos.value != "") { + s = ""; + s += f.background_hpos.value + (isNum(f.background_hpos.value) ? f.background_hpos_measurement.value : "") + " "; + s += f.background_vpos.value + (isNum(f.background_vpos.value) ? f.background_vpos_measurement.value : ""); + ce.style.backgroundPosition = s; + } + + // Build block styles + + ce.style.wordSpacing = f.block_wordspacing.value + (isNum(f.block_wordspacing.value) ? f.block_wordspacing_measurement.value : ""); + ce.style.letterSpacing = f.block_letterspacing.value + (isNum(f.block_letterspacing.value) ? f.block_letterspacing_measurement.value : ""); + ce.style.verticalAlign = f.block_vertical_alignment.value; + ce.style.textAlign = f.block_text_align.value; + ce.style.textIndent = f.block_text_indent.value + (isNum(f.block_text_indent.value) ? f.block_text_indent_measurement.value : ""); + ce.style.whiteSpace = f.block_whitespace.value; + ce.style.display = f.block_display.value; + + // Build box styles + + ce.style.width = f.box_width.value + (isNum(f.box_width.value) ? f.box_width_measurement.value : ""); + ce.style.height = f.box_height.value + (isNum(f.box_height.value) ? f.box_height_measurement.value : ""); + ce.style.styleFloat = f.box_float.value; + + if (tinymce.isGecko) + ce.style.cssFloat = f.box_float.value; + + ce.style.clear = f.box_clear.value; + + if (!f.box_padding_same.checked) { + ce.style.paddingTop = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : ""); + ce.style.paddingRight = f.box_padding_right.value + (isNum(f.box_padding_right.value) ? f.box_padding_right_measurement.value : ""); + ce.style.paddingBottom = f.box_padding_bottom.value + (isNum(f.box_padding_bottom.value) ? f.box_padding_bottom_measurement.value : ""); + ce.style.paddingLeft = f.box_padding_left.value + (isNum(f.box_padding_left.value) ? f.box_padding_left_measurement.value : ""); + } else + ce.style.padding = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : ""); + + if (!f.box_margin_same.checked) { + ce.style.marginTop = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : ""); + ce.style.marginRight = f.box_margin_right.value + (isNum(f.box_margin_right.value) ? f.box_margin_right_measurement.value : ""); + ce.style.marginBottom = f.box_margin_bottom.value + (isNum(f.box_margin_bottom.value) ? f.box_margin_bottom_measurement.value : ""); + ce.style.marginLeft = f.box_margin_left.value + (isNum(f.box_margin_left.value) ? f.box_margin_left_measurement.value : ""); + } else + ce.style.margin = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : ""); + + // Build border styles + + if (!f.border_style_same.checked) { + ce.style.borderTopStyle = f.border_style_top.value; + ce.style.borderRightStyle = f.border_style_right.value; + ce.style.borderBottomStyle = f.border_style_bottom.value; + ce.style.borderLeftStyle = f.border_style_left.value; + } else + ce.style.borderStyle = f.border_style_top.value; + + if (!f.border_width_same.checked) { + ce.style.borderTopWidth = f.border_width_top.value + (isNum(f.border_width_top.value) ? f.border_width_top_measurement.value : ""); + ce.style.borderRightWidth = f.border_width_right.value + (isNum(f.border_width_right.value) ? f.border_width_right_measurement.value : ""); + ce.style.borderBottomWidth = f.border_width_bottom.value + (isNum(f.border_width_bottom.value) ? f.border_width_bottom_measurement.value : ""); + ce.style.borderLeftWidth = f.border_width_left.value + (isNum(f.border_width_left.value) ? f.border_width_left_measurement.value : ""); + } else + ce.style.borderWidth = f.border_width_top.value + (isNum(f.border_width_top.value) ? f.border_width_top_measurement.value : ""); + + if (!f.border_color_same.checked) { + ce.style.borderTopColor = f.border_color_top.value; + ce.style.borderRightColor = f.border_color_right.value; + ce.style.borderBottomColor = f.border_color_bottom.value; + ce.style.borderLeftColor = f.border_color_left.value; + } else + ce.style.borderColor = f.border_color_top.value; + + // Build list styles + + ce.style.listStyleType = f.list_type.value; + ce.style.listStylePosition = f.list_position.value; + ce.style.listStyleImage = f.list_bullet_image.value != "" ? "url(" + f.list_bullet_image.value + ")" : ""; + + // Build positioning styles + + ce.style.position = f.positioning_type.value; + ce.style.visibility = f.positioning_visibility.value; + + if (ce.style.width == "") + ce.style.width = f.positioning_width.value + (isNum(f.positioning_width.value) ? f.positioning_width_measurement.value : ""); + + if (ce.style.height == "") + ce.style.height = f.positioning_height.value + (isNum(f.positioning_height.value) ? f.positioning_height_measurement.value : ""); + + ce.style.zIndex = f.positioning_zindex.value; + ce.style.overflow = f.positioning_overflow.value; + + if (!f.positioning_placement_same.checked) { + ce.style.top = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : ""); + ce.style.right = f.positioning_placement_right.value + (isNum(f.positioning_placement_right.value) ? f.positioning_placement_right_measurement.value : ""); + ce.style.bottom = f.positioning_placement_bottom.value + (isNum(f.positioning_placement_bottom.value) ? f.positioning_placement_bottom_measurement.value : ""); + ce.style.left = f.positioning_placement_left.value + (isNum(f.positioning_placement_left.value) ? f.positioning_placement_left_measurement.value : ""); + } else { + s = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : ""); + ce.style.top = s; + ce.style.right = s; + ce.style.bottom = s; + ce.style.left = s; + } + + if (!f.positioning_clip_same.checked) { + s = "rect("; + s += (isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto") + " "; + s += (isNum(f.positioning_clip_right.value) ? f.positioning_clip_right.value + f.positioning_clip_right_measurement.value : "auto") + " "; + s += (isNum(f.positioning_clip_bottom.value) ? f.positioning_clip_bottom.value + f.positioning_clip_bottom_measurement.value : "auto") + " "; + s += (isNum(f.positioning_clip_left.value) ? f.positioning_clip_left.value + f.positioning_clip_left_measurement.value : "auto"); + s += ")"; + + if (s != "rect(auto auto auto auto)") + ce.style.clip = s; + } else { + s = "rect("; + t = isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto"; + s += t + " "; + s += t + " "; + s += t + " "; + s += t + ")"; + + if (s != "rect(auto auto auto auto)") + ce.style.clip = s; + } + + ce.style.cssText = ce.style.cssText; +} + +function isNum(s) { + return new RegExp('[0-9]+', 'g').test(s); +} + +function showDisabledControls() { + var f = document.forms, i, a; + + for (i=0; i 1) { + addSelectValue(f, s, p[0], p[1]); + + if (se) + selectByValue(f, s, p[1]); + } else { + addSelectValue(f, s, p[0], p[0]); + + if (se) + selectByValue(f, s, p[0]); + } + } +} + +function toggleSame(ce, pre) { + var el = document.forms[0].elements, i; + + if (ce.checked) { + el[pre + "_top"].disabled = false; + el[pre + "_right"].disabled = true; + el[pre + "_bottom"].disabled = true; + el[pre + "_left"].disabled = true; + + if (el[pre + "_top_measurement"]) { + el[pre + "_top_measurement"].disabled = false; + el[pre + "_right_measurement"].disabled = true; + el[pre + "_bottom_measurement"].disabled = true; + el[pre + "_left_measurement"].disabled = true; + } + } else { + el[pre + "_top"].disabled = false; + el[pre + "_right"].disabled = false; + el[pre + "_bottom"].disabled = false; + el[pre + "_left"].disabled = false; + + if (el[pre + "_top_measurement"]) { + el[pre + "_top_measurement"].disabled = false; + el[pre + "_right_measurement"].disabled = false; + el[pre + "_bottom_measurement"].disabled = false; + el[pre + "_left_measurement"].disabled = false; + } + } + + showDisabledControls(); +} + +function synch(fr, to) { + var f = document.forms[0]; + + f.elements[to].value = f.elements[fr].value; + + if (f.elements[fr + "_measurement"]) + selectByValue(f, to + "_measurement", f.elements[fr + "_measurement"].value); +} + +tinyMCEPopup.onInit.add(init); diff --git a/tools/tiny_mce/plugins/style/langs/en_dlg.js b/tools/tiny_mce/plugins/style/langs/en_dlg.js new file mode 100644 index 00000000..f311421f --- /dev/null +++ b/tools/tiny_mce/plugins/style/langs/en_dlg.js @@ -0,0 +1,70 @@ +tinyMCE.addI18n('en.style_dlg',{ +title:"Edit CSS Style", +apply:"Apply", +text_tab:"Text", +background_tab:"Background", +block_tab:"Block", +box_tab:"Box", +border_tab:"Border", +list_tab:"List", +positioning_tab:"Positioning", +text_props:"Text", +text_font:"Font", +text_size:"Size", +text_weight:"Weight", +text_style:"Style", +text_variant:"Variant", +text_lineheight:"Line height", +text_case:"Case", +text_color:"Color", +text_decoration:"Decoration", +text_overline:"overline", +text_underline:"underline", +text_striketrough:"strikethrough", +text_blink:"blink", +text_none:"none", +background_color:"Background color", +background_image:"Background image", +background_repeat:"Repeat", +background_attachment:"Attachment", +background_hpos:"Horizontal position", +background_vpos:"Vertical position", +block_wordspacing:"Word spacing", +block_letterspacing:"Letter spacing", +block_vertical_alignment:"Vertical alignment", +block_text_align:"Text align", +block_text_indent:"Text indent", +block_whitespace:"Whitespace", +block_display:"Display", +box_width:"Width", +box_height:"Height", +box_float:"Float", +box_clear:"Clear", +padding:"Padding", +same:"Same for all", +top:"Top", +right:"Right", +bottom:"Bottom", +left:"Left", +margin:"Margin", +style:"Style", +width:"Width", +height:"Height", +color:"Color", +list_type:"Type", +bullet_image:"Bullet image", +position:"Position", +positioning_type:"Type", +visibility:"Visibility", +zindex:"Z-index", +overflow:"Overflow", +placement:"Placement", +clip:"Clip", +text:"Text", +background:"Background", +block:"Block", +box:"Box", +border:"Border", +list:"List", +position:"Position" +}); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/style/props.htm b/tools/tiny_mce/plugins/style/props.htm new file mode 100644 index 00000000..5e6b3566 --- /dev/null +++ b/tools/tiny_mce/plugins/style/props.htm @@ -0,0 +1,838 @@ + + + + {#style_dlg.title} + + + + + + + + + + +
    + + +
    +
    +
    + {#style_dlg.text} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + +
      + + +
    +
    + +
    + + + +
    + + + + + + +
    + +   + + +
    +
    + +
    + + + + + +
     
    +
    {#style_dlg.text_decoration} + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    + {#style_dlg.background} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
     
    +
    + + + + +
     
    +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    +
    +
    + +
    +
    + {#style_dlg.block} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + + +
    +
    +
    +
    + +
    +
    + {#style_dlg.box} + + + + + + + + + + + + + + +
    + + + + + + +
      + + +
    +
       
    + + + + + + +
      + + +
    +
       
    +
    +
    + {#style_dlg.padding} + + + + + + + + + + + + + + + + + + + + + + +
     
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    +
    +
    + +
    +
    + {#style_dlg.margin} + + + + + + + + + + + + + + + + + + + + + + +
     
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    + + + + + + +
      + + +
    +
    +
    +
    +
    +
    + +
    +
    + {#style_dlg.border} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#style_dlg.style} {#style_dlg.width} {#style_dlg.color}
          
    {#style_dlg.top}   + + + + + + +
      + + +
    +
      + + + + + +
     
    +
    {#style_dlg.right}   + + + + + + +
      + + +
    +
      + + + + + +
     
    +
    {#style_dlg.bottom}   + + + + + + +
      + + +
    +
      + + + + + +
     
    +
    {#style_dlg.left}   + + + + + + +
      + + +
    +
      + + + + + +
     
    +
    +
    +
    + +
    +
    + {#style_dlg.list} + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    + {#style_dlg.position} + + + + + + + + + + + + + + + + + + + + + +
       
    + + + + + + +
      + + +
    +
       
    + + + + + + +
      + + +
    +
       
    + +
    +
    + {#style_dlg.placement} + + + + + + + + + + + + + + + + + + + + + + +
     
    {#style_dlg.top} + + + + + + +
      + + +
    +
    {#style_dlg.right} + + + + + + +
      + + +
    +
    {#style_dlg.bottom} + + + + + + +
      + + +
    +
    {#style_dlg.left} + + + + + + +
      + + +
    +
    +
    +
    + +
    +
    + {#style_dlg.clip} + + + + + + + + + + + + + + + + + + + + + + +
     
    {#style_dlg.top} + + + + + + +
      + + +
    +
    {#style_dlg.right} + + + + + + +
      + + +
    +
    {#style_dlg.bottom} + + + + + + +
      + + +
    +
    {#style_dlg.left} + + + + + + +
      + + +
    +
    +
    +
    +
    +
    + +
    + +
    + + + +
    +
    + +
    +
    +
    + + + diff --git a/tools/tiny_mce/plugins/tabfocus/editor_plugin.js b/tools/tiny_mce/plugins/tabfocus/editor_plugin.js new file mode 100644 index 00000000..d18689dd --- /dev/null +++ b/tools/tiny_mce/plugins/tabfocus/editor_plugin.js @@ -0,0 +1 @@ +(function(){var c=tinymce.DOM,a=tinymce.dom.Event,d=tinymce.each,b=tinymce.explode;tinymce.create("tinymce.plugins.TabFocusPlugin",{init:function(f,g){function e(i,j){if(j.keyCode===9){return a.cancel(j)}}function h(l,p){var j,m,o,n,k;function q(r){n=c.select(":input:enabled,*[tabindex]");function i(s){return s.type!="hidden"&&s.tabIndex!="-1"&&!(n[m].style.display=="none")&&!(n[m].style.visibility=="hidden")}d(n,function(t,s){if(t.id==l.id){j=s;return false}});if(r>0){for(m=j+1;m=0;m--){if(i(n[m])){return n[m]}}}return null}if(p.keyCode===9){k=b(l.getParam("tab_focus",l.getParam("tabfocus_elements",":prev,:next")));if(k.length==1){k[1]=k[0];k[0]=":prev"}if(p.shiftKey){if(k[0]==":prev"){n=q(-1)}else{n=c.get(k[0])}}else{if(k[1]==":next"){n=q(1)}else{n=c.get(k[1])}}if(n){if(n.id&&(l=tinymce.get(n.id||n.name))){l.focus()}else{window.setTimeout(function(){if(!tinymce.isWebKit){window.focus()}n.focus()},10)}return a.cancel(p)}}}f.onKeyUp.add(e);if(tinymce.isGecko){f.onKeyPress.add(h);f.onKeyDown.add(e)}else{f.onKeyDown.add(h)}},getInfo:function(){return{longname:"Tabfocus",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("tabfocus",tinymce.plugins.TabFocusPlugin)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/tabfocus/editor_plugin_src.js b/tools/tiny_mce/plugins/tabfocus/editor_plugin_src.js new file mode 100644 index 00000000..1be152c7 --- /dev/null +++ b/tools/tiny_mce/plugins/tabfocus/editor_plugin_src.js @@ -0,0 +1,114 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, explode = tinymce.explode; + + tinymce.create('tinymce.plugins.TabFocusPlugin', { + init : function(ed, url) { + function tabCancel(ed, e) { + if (e.keyCode === 9) + return Event.cancel(e); + }; + + function tabHandler(ed, e) { + var x, i, f, el, v; + + function find(d) { + el = DOM.select(':input:enabled,*[tabindex]'); + function canSelect(e) { + return e.type != 'hidden' && + e.tabIndex != '-1' && + !(el[i].style.display == "none") && + !(el[i].style.visibility == "hidden"); + } + + each(el, function(e, i) { + if (e.id == ed.id) { + x = i; + return false; + } + }); + + if (d > 0) { + for (i = x + 1; i < el.length; i++) { + if (canSelect(el[i])) + return el[i]; + } + } else { + for (i = x - 1; i >= 0; i--) { + if (canSelect(el[i])) + return el[i]; + } + } + + return null; + }; + + if (e.keyCode === 9) { + v = explode(ed.getParam('tab_focus', ed.getParam('tabfocus_elements', ':prev,:next'))); + + if (v.length == 1) { + v[1] = v[0]; + v[0] = ':prev'; + } + + // Find element to focus + if (e.shiftKey) { + if (v[0] == ':prev') + el = find(-1); + else + el = DOM.get(v[0]); + } else { + if (v[1] == ':next') + el = find(1); + else + el = DOM.get(v[1]); + } + + if (el) { + if (el.id && (ed = tinymce.get(el.id || el.name))) + ed.focus(); + else + window.setTimeout(function() { + if (!tinymce.isWebKit) + window.focus(); + el.focus(); + }, 10); + + return Event.cancel(e); + } + } + }; + + ed.onKeyUp.add(tabCancel); + + if (tinymce.isGecko) { + ed.onKeyPress.add(tabHandler); + ed.onKeyDown.add(tabCancel); + } else + ed.onKeyDown.add(tabHandler); + + }, + + getInfo : function() { + return { + longname : 'Tabfocus', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('tabfocus', tinymce.plugins.TabFocusPlugin); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/table/cell.htm b/tools/tiny_mce/plugins/table/cell.htm new file mode 100644 index 00000000..b62fa547 --- /dev/null +++ b/tools/tiny_mce/plugins/table/cell.htm @@ -0,0 +1,178 @@ + + + + {#table_dlg.cell_title} + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    +
    +
    + +
    +
    + +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/table/css/cell.css b/tools/tiny_mce/plugins/table/css/cell.css new file mode 100644 index 00000000..a47cc1a1 --- /dev/null +++ b/tools/tiny_mce/plugins/table/css/cell.css @@ -0,0 +1,17 @@ +/* CSS file for cell dialog in the table plugin */ + +.panel_wrapper div.current { + height: 200px; +} + +.advfield { + width: 200px; +} + +#action { + margin-bottom: 3px; +} + +#class { + width: 150px; +} \ No newline at end of file diff --git a/tools/tiny_mce/plugins/table/css/row.css b/tools/tiny_mce/plugins/table/css/row.css new file mode 100644 index 00000000..0e397db3 --- /dev/null +++ b/tools/tiny_mce/plugins/table/css/row.css @@ -0,0 +1,25 @@ +/* CSS file for row dialog in the table plugin */ + +.panel_wrapper div.current { + height: 200px; +} + +.advfield { + width: 200px; +} + +#action { + margin-bottom: 3px; +} + +#rowtype,#align,#valign,#class,#height { + width: 150px; +} + +#height { + width: 50px; +} + +.col2 { + padding-left: 20px; +} diff --git a/tools/tiny_mce/plugins/table/css/table.css b/tools/tiny_mce/plugins/table/css/table.css new file mode 100644 index 00000000..8f107831 --- /dev/null +++ b/tools/tiny_mce/plugins/table/css/table.css @@ -0,0 +1,13 @@ +/* CSS file for table dialog in the table plugin */ + +.panel_wrapper div.current { + height: 245px; +} + +.advfield { + width: 200px; +} + +#class { + width: 150px; +} diff --git a/tools/tiny_mce/plugins/table/editor_plugin.js b/tools/tiny_mce/plugins/table/editor_plugin.js new file mode 100644 index 00000000..484f81c3 --- /dev/null +++ b/tools/tiny_mce/plugins/table/editor_plugin.js @@ -0,0 +1 @@ +(function(c){var d=c.each;function b(f,g){var h=g.ownerDocument,e=h.createRange(),j;e.setStartBefore(g);e.setEnd(f.endContainer,f.endOffset);j=h.createElement("body");j.appendChild(e.cloneContents());return j.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length==0}function a(G,F,J){var f,K,C,o;s();o=F.getParent(J.getStart(),"th,td");if(o){K=E(o);C=H();o=w(K.x,K.y)}function z(M,L){M=M.cloneNode(L);M.removeAttribute("id");return M}function s(){var L=0;f=[];d(["thead","tbody","tfoot"],function(M){var N=F.select("> "+M+" tr",G);d(N,function(O,P){P+=L;d(F.select("> td, > th",O),function(V,Q){var R,S,T,U;if(f[P]){while(f[P][Q]){Q++}}T=h(V,"rowspan");U=h(V,"colspan");for(S=P;S'}return false}},"childNodes");L=z(L,false);L.rowSpan=L.colSpan=1;if(M){L.appendChild(M)}else{if(!c.isIE){L.innerHTML='
    '}}return L}function q(){var L=F.createRng();d(F.select("tr",G),function(M){if(M.cells.length==0){F.remove(M)}});if(F.select("tr",G).length==0){L.setStartAfter(G);L.setEndAfter(G);J.setRng(L);F.remove(G);return}d(F.select("thead,tbody,tfoot",G),function(M){if(M.rows.length==0){F.remove(M)}});s();row=f[Math.min(f.length-1,K.y)];if(row){J.select(row[Math.min(row.length-1,K.x)].elm,true);J.collapse(true)}}function t(R,P,T,Q){var O,M,L,N,S;O=f[P][R].elm.parentNode;for(L=1;L<=T;L++){O=F.getNext(O,"tr");if(O){for(M=R;M>=0;M--){S=f[P+L][M].elm;if(S.parentNode==O){for(N=1;N<=Q;N++){F.insertAfter(e(S),S)}break}}if(M==-1){for(N=1;N<=Q;N++){O.insertBefore(e(O.cells[0]),O.cells[0])}}}}}function B(){d(f,function(L,M){d(L,function(O,N){var R,Q,S,P;if(j(O)){O=O.elm;R=h(O,"colspan");Q=h(O,"rowspan");if(R>1||Q>1){O.colSpan=O.rowSpan=1;for(P=0;P1){Q.rowSpan=rowSpan+1;continue}}else{if(L>0&&f[L-1][P]){T=f[L-1][P].elm;rowSpan=h(T,"rowspan");if(rowSpan>1){T.rowSpan=rowSpan+1;continue}}}M=e(Q);M.colSpan=Q.colSpan;S.appendChild(M);N=Q}}if(S.hasChildNodes()){if(!O){F.insertAfter(S,R)}else{R.parentNode.insertBefore(S,R)}}}function g(M){var N,L;d(f,function(O,P){d(O,function(R,Q){if(j(R)){N=Q;if(M){return false}}});if(M){return !N}});d(f,function(R,S){var O=R[N].elm,P,Q;if(O!=L){Q=h(O,"colspan");P=h(O,"rowspan");if(Q==1){if(!M){F.insertAfter(e(O),O);t(N,S,P-1,Q)}else{O.parentNode.insertBefore(e(O),O);t(N,S,P-1,Q)}}else{O.colSpan++}L=O}})}function n(){var L=[];d(f,function(M,N){d(M,function(P,O){if(j(P)&&c.inArray(L,O)===-1){d(f,function(S){var Q=S[O].elm,R;R=h(Q,"colspan");if(R>1){Q.colSpan=R-1}else{F.remove(Q)}});L.push(O)}})});q()}function m(){var M;function L(P){var O,Q,N;O=F.getNext(P,"tr");d(P.cells,function(R){var S=h(R,"rowspan");if(S>1){R.rowSpan=S-1;Q=E(R);t(Q.x,Q.y,1,1)}});Q=E(P.cells[0]);d(f[Q.y],function(R){var S;R=R.elm;if(R!=N){S=h(R,"rowspan");if(S<=1){F.remove(R)}else{R.rowSpan=S-1}N=R}})}M=k();d(M.reverse(),function(N){L(N)});q()}function D(){var L=k();F.remove(L);q();return L}function I(){var L=k();d(L,function(N,M){L[M]=z(N,true)});return L}function A(N,M){var O=k(),L=O[M?0:O.length-1],P=L.cells.length;d(f,function(R){var Q;P=0;d(R,function(T,S){if(T.real){P+=T.colspan}if(T.elm.parentNode==L){Q=1}});if(Q){return false}});if(!M){N.reverse()}d(N,function(S){var R=S.cells.length,Q;for(i=0;iM){M=Q}if(P>L){L=P}if(R.real){T=R.colspan-1;S=R.rowspan-1;if(T){if(Q+T>M){M=Q+T}}if(S){if(P+S>L){L=P+S}}}}})});return{x:M,y:L}}function u(R){var O,N,T,S,M,L,P,Q;C=E(R);if(K&&C){O=Math.min(K.x,C.x);N=Math.min(K.y,C.y);T=Math.max(K.x,C.x);S=Math.max(K.y,C.y);M=T;L=S;for(y=N;y<=L;y++){R=f[y][O];if(!R.real){if(O-(R.colspan-1)M){M=x+P}}if(Q){if(y+Q>L){L=y+Q}}}}}F.removeClass(F.select("td.mceSelected,th.mceSelected"),"mceSelected");for(y=N;y<=L;y++){for(x=O;x<=M;x++){F.addClass(f[y][x].elm,"mceSelected")}}}}c.extend(this,{deleteTable:r,split:B,merge:p,insertRow:l,insertCol:g,deleteCols:n,deleteRows:m,cutRows:D,copyRows:I,pasteRows:A,getPos:E,setStartCell:v,setEndCell:u})}c.create("tinymce.plugins.TablePlugin",{init:function(f,g){var e,k;function j(n){var m=f.selection,l=f.dom.getParent(n||m.getNode(),"table");if(l){return new a(l,f.dom,m)}}function h(){f.getBody().style.webkitUserSelect="";f.dom.removeClass(f.dom.select("td.mceSelected,th.mceSelected"),"mceSelected")}d([["table","table.desc","mceInsertTable",true],["delete_table","table.del","mceTableDelete"],["delete_col","table.delete_col_desc","mceTableDeleteCol"],["delete_row","table.delete_row_desc","mceTableDeleteRow"],["col_after","table.col_after_desc","mceTableInsertColAfter"],["col_before","table.col_before_desc","mceTableInsertColBefore"],["row_after","table.row_after_desc","mceTableInsertRowAfter"],["row_before","table.row_before_desc","mceTableInsertRowBefore"],["row_props","table.row_desc","mceTableRowProps",true],["cell_props","table.cell_desc","mceTableCellProps",true],["split_cells","table.split_cells_desc","mceTableSplitCells",true],["merge_cells","table.merge_cells_desc","mceTableMergeCells",true]],function(l){f.addButton(l[0],{title:l[1],cmd:l[2],ui:l[3]})});if(!c.isIE){f.onClick.add(function(l,m){m=m.target;if(m.nodeName==="TABLE"){l.selection.select(m)}})}f.onNodeChange.add(function(m,l,q){var o;q=m.selection.getStart();o=m.dom.getParent(q,"td,th,caption");l.setActive("table",q.nodeName==="TABLE"||!!o);if(o&&o.nodeName==="CAPTION"){o=0}l.setDisabled("delete_table",!o);l.setDisabled("delete_col",!o);l.setDisabled("delete_table",!o);l.setDisabled("delete_row",!o);l.setDisabled("col_after",!o);l.setDisabled("col_before",!o);l.setDisabled("row_after",!o);l.setDisabled("row_before",!o);l.setDisabled("row_props",!o);l.setDisabled("cell_props",!o);l.setDisabled("split_cells",!o);l.setDisabled("merge_cells",!o)});f.onInit.add(function(m){var l,p,q=m.dom,n;e=m.windowManager;m.onMouseDown.add(function(r,s){if(s.button!=2){h();p=q.getParent(s.target,"td,th");l=q.getParent(p,"table")}});q.bind(m.getDoc(),"mouseover",function(u){var s,r,t=u.target;if(p&&(n||t!=p)&&(t.nodeName=="TD"||t.nodeName=="TH")){r=q.getParent(t,"table");if(r==l){if(!n){n=j(r);n.setStartCell(p);m.getBody().style.webkitUserSelect="none"}n.setEndCell(t)}s=m.selection.getSel();if(s.removeAllRanges){s.removeAllRanges()}else{s.empty()}u.preventDefault()}});m.onMouseUp.add(function(A,B){var s,u=A.selection,C,D=u.getSel(),r,v,t,z;if(p){if(n){A.getBody().style.webkitUserSelect=""}function w(E,G){var F=new c.dom.TreeWalker(E,E);do{if(E.nodeType==3&&c.trim(E.nodeValue).length!=0){if(G){s.setStart(E,0)}else{s.setEnd(E,E.nodeValue.length)}return}if(E.nodeName=="BR"){if(G){s.setStartBefore(E)}else{s.setEndBefore(E)}return}}while(E=(G?F.next():F.prev()))}C=q.select("td.mceSelected,th.mceSelected");if(C.length>0){s=q.createRng();v=C[0];z=C[C.length-1];w(v,1);r=new c.dom.TreeWalker(v,q.getParent(C[0],"table"));do{if(v.nodeName=="TD"||v.nodeName=="TH"){if(!q.hasClass(v,"mceSelected")){break}t=v}}while(v=r.next());w(t);u.setRng(s)}A.nodeChanged();p=n=l=null}});m.onKeyUp.add(function(r,s){h()});if(m&&m.plugins.contextmenu){m.plugins.contextmenu.onContextMenu.add(function(t,r,v){var w,u=m.selection,s=u.getNode()||m.getBody();if(m.dom.getParent(v,"td")||m.dom.getParent(v,"th")||m.dom.select("td.mceSelected,th.mceSelected").length){r.removeAll();if(s.nodeName=="A"&&!m.dom.getAttrib(s,"name")){r.add({title:"advanced.link_desc",icon:"link",cmd:m.plugins.advlink?"mceAdvLink":"mceLink",ui:true});r.add({title:"advanced.unlink_desc",icon:"unlink",cmd:"UnLink"});r.addSeparator()}if(s.nodeName=="IMG"&&s.className.indexOf("mceItem")==-1){r.add({title:"advanced.image_desc",icon:"image",cmd:m.plugins.advimage?"mceAdvImage":"mceImage",ui:true});r.addSeparator()}r.add({title:"table.desc",icon:"table",cmd:"mceInsertTable",value:{action:"insert"}});r.add({title:"table.props_desc",icon:"table_props",cmd:"mceInsertTable"});r.add({title:"table.del",icon:"delete_table",cmd:"mceTableDelete"});r.addSeparator();w=r.addMenu({title:"table.cell"});w.add({title:"table.cell_desc",icon:"cell_props",cmd:"mceTableCellProps"});w.add({title:"table.split_cells_desc",icon:"split_cells",cmd:"mceTableSplitCells"});w.add({title:"table.merge_cells_desc",icon:"merge_cells",cmd:"mceTableMergeCells"});w=r.addMenu({title:"table.row"});w.add({title:"table.row_desc",icon:"row_props",cmd:"mceTableRowProps"});w.add({title:"table.row_before_desc",icon:"row_before",cmd:"mceTableInsertRowBefore"});w.add({title:"table.row_after_desc",icon:"row_after",cmd:"mceTableInsertRowAfter"});w.add({title:"table.delete_row_desc",icon:"delete_row",cmd:"mceTableDeleteRow"});w.addSeparator();w.add({title:"table.cut_row_desc",icon:"cut",cmd:"mceTableCutRow"});w.add({title:"table.copy_row_desc",icon:"copy",cmd:"mceTableCopyRow"});w.add({title:"table.paste_row_before_desc",icon:"paste",cmd:"mceTablePasteRowBefore"}).setDisabled(!k);w.add({title:"table.paste_row_after_desc",icon:"paste",cmd:"mceTablePasteRowAfter"}).setDisabled(!k);w=r.addMenu({title:"table.col"});w.add({title:"table.col_before_desc",icon:"col_before",cmd:"mceTableInsertColBefore"});w.add({title:"table.col_after_desc",icon:"col_after",cmd:"mceTableInsertColAfter"});w.add({title:"table.delete_col_desc",icon:"delete_col",cmd:"mceTableDeleteCol"})}else{r.add({title:"table.desc",icon:"table",cmd:"mceInsertTable"})}})}if(!c.isIE){function o(){var r;for(r=m.getBody().lastChild;r&&r.nodeType==3&&!r.nodeValue.length;r=r.previousSibling){}if(r&&r.nodeName=="TABLE"){m.dom.add(m.getBody(),"p",null,'
    ')}}if(c.isGecko){m.onKeyDown.add(function(s,u){var r,t,v=s.dom;if(u.keyCode==37||u.keyCode==38){r=s.selection.getRng();t=v.getParent(r.startContainer,"table");if(t&&s.getBody().firstChild==t){if(b(r,t)){r=v.createRng();r.setStartBefore(t);r.setEndBefore(t);s.selection.setRng(r);u.preventDefault()}}}})}m.onKeyUp.add(o);m.onSetContent.add(o);m.onVisualAid.add(o);m.onPreProcess.add(function(r,t){var s=t.node.lastChild;if(s&&s.childNodes.length==1&&s.firstChild.nodeName=="BR"){r.dom.remove(s)}});o()}});d({mceTableSplitCells:function(l){l.split()},mceTableMergeCells:function(m){var n,o,l;l=f.dom.getParent(f.selection.getNode(),"th,td");if(l){n=l.rowSpan;o=l.colSpan}if(!f.dom.select("td.mceSelected,th.mceSelected").length){e.open({url:g+"/merge_cells.htm",width:240+parseInt(f.getLang("table.merge_cells_delta_width",0)),height:110+parseInt(f.getLang("table.merge_cells_delta_height",0)),inline:1},{rows:n,cols:o,onaction:function(p){m.merge(l,p.cols,p.rows)},plugin_url:g})}else{m.merge()}},mceTableInsertRowBefore:function(l){l.insertRow(true)},mceTableInsertRowAfter:function(l){l.insertRow()},mceTableInsertColBefore:function(l){l.insertCol(true)},mceTableInsertColAfter:function(l){l.insertCol()},mceTableDeleteCol:function(l){l.deleteCols()},mceTableDeleteRow:function(l){l.deleteRows()},mceTableCutRow:function(l){k=l.cutRows()},mceTableCopyRow:function(l){k=l.copyRows()},mceTablePasteRowBefore:function(l){l.pasteRows(k,true)},mceTablePasteRowAfter:function(l){l.pasteRows(k)},mceTableDelete:function(l){l.deleteTable()}},function(m,l){f.addCommand(l,function(){var n=j();if(n){m(n);f.execCommand("mceRepaint");h()}})});d({mceInsertTable:function(l){e.open({url:g+"/table.htm",width:400+parseInt(f.getLang("table.table_delta_width",0)),height:320+parseInt(f.getLang("table.table_delta_height",0)),inline:1},{plugin_url:g,action:l?l.action:0})},mceTableRowProps:function(){e.open({url:g+"/row.htm",width:400+parseInt(f.getLang("table.rowprops_delta_width",0)),height:295+parseInt(f.getLang("table.rowprops_delta_height",0)),inline:1},{plugin_url:g})},mceTableCellProps:function(){e.open({url:g+"/cell.htm",width:400+parseInt(f.getLang("table.cellprops_delta_width",0)),height:295+parseInt(f.getLang("table.cellprops_delta_height",0)),inline:1},{plugin_url:g})}},function(m,l){f.addCommand(l,function(n,o){m(o)})})}});c.PluginManager.add("table",c.plugins.TablePlugin)})(tinymce); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/table/editor_plugin_src.js b/tools/tiny_mce/plugins/table/editor_plugin_src.js new file mode 100644 index 00000000..a41f38e8 --- /dev/null +++ b/tools/tiny_mce/plugins/table/editor_plugin_src.js @@ -0,0 +1,1139 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function(tinymce) { + var each = tinymce.each; + + // Checks if the selection/caret is at the start of the specified block element + function isAtStart(rng, par) { + var doc = par.ownerDocument, rng2 = doc.createRange(), elm; + + rng2.setStartBefore(par); + rng2.setEnd(rng.endContainer, rng.endOffset); + + elm = doc.createElement('body'); + elm.appendChild(rng2.cloneContents()); + + // Check for text characters of other elements that should be treated as content + return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0; + }; + + /** + * Table Grid class. + */ + function TableGrid(table, dom, selection) { + var grid, startPos, endPos, selectedCell; + + buildGrid(); + selectedCell = dom.getParent(selection.getStart(), 'th,td'); + if (selectedCell) { + startPos = getPos(selectedCell); + endPos = findEndPos(); + selectedCell = getCell(startPos.x, startPos.y); + } + + function cloneNode(node, children) { + node = node.cloneNode(children); + node.removeAttribute('id'); + + return node; + } + + function buildGrid() { + var startY = 0; + + grid = []; + + each(['thead', 'tbody', 'tfoot'], function(part) { + var rows = dom.select('> ' + part + ' tr', table); + + each(rows, function(tr, y) { + y += startY; + + each(dom.select('> td, > th', tr), function(td, x) { + var x2, y2, rowspan, colspan; + + // Skip over existing cells produced by rowspan + if (grid[y]) { + while (grid[y][x]) + x++; + } + + // Get col/rowspan from cell + rowspan = getSpanVal(td, 'rowspan'); + colspan = getSpanVal(td, 'colspan'); + + // Fill out rowspan/colspan right and down + for (y2 = y; y2 < y + rowspan; y2++) { + if (!grid[y2]) + grid[y2] = []; + + for (x2 = x; x2 < x + colspan; x2++) { + grid[y2][x2] = { + part : part, + real : y2 == y && x2 == x, + elm : td, + rowspan : rowspan, + colspan : colspan + }; + } + } + }); + }); + + startY += rows.length; + }); + }; + + function getCell(x, y) { + var row; + + row = grid[y]; + if (row) + return row[x]; + }; + + function getSpanVal(td, name) { + return parseInt(td.getAttribute(name) || 1); + }; + + function isCellSelected(cell) { + return dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell; + }; + + function getSelectedRows() { + var rows = []; + + each(table.rows, function(row) { + each(row.cells, function(cell) { + if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) { + rows.push(row); + return false; + } + }); + }); + + return rows; + }; + + function deleteTable() { + var rng = dom.createRng(); + + rng.setStartAfter(table); + rng.setEndAfter(table); + + selection.setRng(rng); + + dom.remove(table); + }; + + function cloneCell(cell) { + var formatNode; + + // Clone formats + tinymce.walk(cell, function(node) { + var curNode; + + if (node.nodeType == 3) { + each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) { + node = cloneNode(node, false); + + if (!formatNode) + formatNode = curNode = node; + else if (curNode) + curNode.appendChild(node); + + curNode = node; + }); + + // Add something to the inner node + if (curNode) + curNode.innerHTML = tinymce.isIE ? ' ' : '
    '; + + return false; + } + }, 'childNodes'); + + cell = cloneNode(cell, false); + cell.rowSpan = cell.colSpan = 1; + + if (formatNode) { + cell.appendChild(formatNode); + } else { + if (!tinymce.isIE) + cell.innerHTML = '
    '; + } + + return cell; + }; + + function cleanup() { + var rng = dom.createRng(); + + // Empty rows + each(dom.select('tr', table), function(tr) { + if (tr.cells.length == 0) + dom.remove(tr); + }); + + // Empty table + if (dom.select('tr', table).length == 0) { + rng.setStartAfter(table); + rng.setEndAfter(table); + selection.setRng(rng); + dom.remove(table); + return; + } + + // Empty header/body/footer + each(dom.select('thead,tbody,tfoot', table), function(part) { + if (part.rows.length == 0) + dom.remove(part); + }); + + // Restore selection to start position if it still exists + buildGrid(); + + // Restore the selection to the closest table position + row = grid[Math.min(grid.length - 1, startPos.y)]; + if (row) { + selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true); + selection.collapse(true); + } + }; + + function fillLeftDown(x, y, rows, cols) { + var tr, x2, r, c, cell; + + tr = grid[y][x].elm.parentNode; + for (r = 1; r <= rows; r++) { + tr = dom.getNext(tr, 'tr'); + + if (tr) { + // Loop left to find real cell + for (x2 = x; x2 >= 0; x2--) { + cell = grid[y + r][x2].elm; + + if (cell.parentNode == tr) { + // Append clones after + for (c = 1; c <= cols; c++) + dom.insertAfter(cloneCell(cell), cell); + + break; + } + } + + if (x2 == -1) { + // Insert nodes before first cell + for (c = 1; c <= cols; c++) + tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]); + } + } + } + }; + + function split() { + each(grid, function(row, y) { + each(row, function(cell, x) { + var colSpan, rowSpan, newCell, i; + + if (isCellSelected(cell)) { + cell = cell.elm; + colSpan = getSpanVal(cell, 'colspan'); + rowSpan = getSpanVal(cell, 'rowspan'); + + if (colSpan > 1 || rowSpan > 1) { + cell.colSpan = cell.rowSpan = 1; + + // Insert cells right + for (i = 0; i < colSpan - 1; i++) + dom.insertAfter(cloneCell(cell), cell); + + fillLeftDown(x, y, rowSpan - 1, colSpan); + } + } + }); + }); + }; + + function merge(cell, cols, rows) { + var startX, startY, endX, endY, x, y, startCell, endCell, cell, children; + + // Use specified cell and cols/rows + if (cell) { + pos = getPos(cell); + startX = pos.x; + startY = pos.y; + endX = startX + (cols - 1); + endY = startY + (rows - 1); + } else { + // Use selection + startX = startPos.x; + startY = startPos.y; + endX = endPos.x; + endY = endPos.y; + } + + // Find start/end cells + startCell = getCell(startX, startY); + endCell = getCell(endX, endY); + + // Check if the cells exists and if they are of the same part for example tbody = tbody + if (startCell && endCell && startCell.part == endCell.part) { + // Split and rebuild grid + split(); + buildGrid(); + + // Set row/col span to start cell + startCell = getCell(startX, startY).elm; + startCell.colSpan = (endX - startX) + 1; + startCell.rowSpan = (endY - startY) + 1; + + // Remove other cells and add it's contents to the start cell + for (y = startY; y <= endY; y++) { + for (x = startX; x <= endX; x++) { + cell = grid[y][x].elm; + + if (cell != startCell) { + // Move children to startCell + children = tinymce.grep(cell.childNodes); + each(children, function(node, i) { + // Jump over last BR element + if (node.nodeName != 'BR' || i != children.length - 1) + startCell.appendChild(node); + }); + + // Remove cell + dom.remove(cell); + } + } + } + + // Remove empty rows etc and restore caret location + cleanup(); + } + }; + + function insertRow(before) { + var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell; + + // Find first/last row + each(grid, function(row, y) { + each(row, function(cell, x) { + if (isCellSelected(cell)) { + cell = cell.elm; + rowElm = cell.parentNode; + newRow = cloneNode(rowElm, false); + posY = y; + + if (before) + return false; + } + }); + + if (before) + return !posY; + }); + + for (x = 0; x < grid[0].length; x++) { + cell = grid[posY][x].elm; + + if (cell != lastCell) { + if (!before) { + rowSpan = getSpanVal(cell, 'rowspan'); + if (rowSpan > 1) { + cell.rowSpan = rowSpan + 1; + continue; + } + } else { + // Check if cell above can be expanded + if (posY > 0 && grid[posY - 1][x]) { + otherCell = grid[posY - 1][x].elm; + rowSpan = getSpanVal(otherCell, 'rowspan'); + if (rowSpan > 1) { + otherCell.rowSpan = rowSpan + 1; + continue; + } + } + } + + // Insert new cell into new row + newCell = cloneCell(cell) + newCell.colSpan = cell.colSpan; + newRow.appendChild(newCell); + + lastCell = cell; + } + } + + if (newRow.hasChildNodes()) { + if (!before) + dom.insertAfter(newRow, rowElm); + else + rowElm.parentNode.insertBefore(newRow, rowElm); + } + }; + + function insertCol(before) { + var posX, lastCell; + + // Find first/last column + each(grid, function(row, y) { + each(row, function(cell, x) { + if (isCellSelected(cell)) { + posX = x; + + if (before) + return false; + } + }); + + if (before) + return !posX; + }); + + each(grid, function(row, y) { + var cell = row[posX].elm, rowSpan, colSpan; + + if (cell != lastCell) { + colSpan = getSpanVal(cell, 'colspan'); + rowSpan = getSpanVal(cell, 'rowspan'); + + if (colSpan == 1) { + if (!before) { + dom.insertAfter(cloneCell(cell), cell); + fillLeftDown(posX, y, rowSpan - 1, colSpan); + } else { + cell.parentNode.insertBefore(cloneCell(cell), cell); + fillLeftDown(posX, y, rowSpan - 1, colSpan); + } + } else + cell.colSpan++; + + lastCell = cell; + } + }); + }; + + function deleteCols() { + var cols = []; + + // Get selected column indexes + each(grid, function(row, y) { + each(row, function(cell, x) { + if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) { + each(grid, function(row) { + var cell = row[x].elm, colSpan; + + colSpan = getSpanVal(cell, 'colspan'); + + if (colSpan > 1) + cell.colSpan = colSpan - 1; + else + dom.remove(cell); + }); + + cols.push(x); + } + }); + }); + + cleanup(); + }; + + function deleteRows() { + var rows; + + function deleteRow(tr) { + var nextTr, pos, lastCell; + + nextTr = dom.getNext(tr, 'tr'); + + // Move down row spanned cells + each(tr.cells, function(cell) { + var rowSpan = getSpanVal(cell, 'rowspan'); + + if (rowSpan > 1) { + cell.rowSpan = rowSpan - 1; + pos = getPos(cell); + fillLeftDown(pos.x, pos.y, 1, 1); + } + }); + + // Delete cells + pos = getPos(tr.cells[0]); + each(grid[pos.y], function(cell) { + var rowSpan; + + cell = cell.elm; + + if (cell != lastCell) { + rowSpan = getSpanVal(cell, 'rowspan'); + + if (rowSpan <= 1) + dom.remove(cell); + else + cell.rowSpan = rowSpan - 1; + + lastCell = cell; + } + }); + }; + + // Get selected rows and move selection out of scope + rows = getSelectedRows(); + + // Delete all selected rows + each(rows.reverse(), function(tr) { + deleteRow(tr); + }); + + cleanup(); + }; + + function cutRows() { + var rows = getSelectedRows(); + + dom.remove(rows); + cleanup(); + + return rows; + }; + + function copyRows() { + var rows = getSelectedRows(); + + each(rows, function(row, i) { + rows[i] = cloneNode(row, true); + }); + + return rows; + }; + + function pasteRows(rows, before) { + var selectedRows = getSelectedRows(), + targetRow = selectedRows[before ? 0 : selectedRows.length - 1], + targetCellCount = targetRow.cells.length; + + // Calc target cell count + each(grid, function(row) { + var match; + + targetCellCount = 0; + each(row, function(cell, x) { + if (cell.real) + targetCellCount += cell.colspan; + + if (cell.elm.parentNode == targetRow) + match = 1; + }); + + if (match) + return false; + }); + + if (!before) + rows.reverse(); + + each(rows, function(row) { + var cellCount = row.cells.length, cell; + + // Remove col/rowspans + for (i = 0; i < cellCount; i++) { + cell = row.cells[i]; + cell.colSpan = cell.rowSpan = 1; + } + + // Needs more cells + for (i = cellCount; i < targetCellCount; i++) + row.appendChild(cloneCell(row.cells[cellCount - 1])); + + // Needs less cells + for (i = targetCellCount; i < cellCount; i++) + dom.remove(row.cells[i]); + + // Add before/after + if (before) + targetRow.parentNode.insertBefore(row, targetRow); + else + dom.insertAfter(row, targetRow); + }); + }; + + function getPos(target) { + var pos; + + each(grid, function(row, y) { + each(row, function(cell, x) { + if (cell.elm == target) { + pos = {x : x, y : y}; + return false; + } + }); + + return !pos; + }); + + return pos; + }; + + function setStartCell(cell) { + startPos = getPos(cell); + }; + + function findEndPos() { + var pos, maxX, maxY; + + maxX = maxY = 0; + + each(grid, function(row, y) { + each(row, function(cell, x) { + var colSpan, rowSpan; + + if (isCellSelected(cell)) { + cell = grid[y][x]; + + if (x > maxX) + maxX = x; + + if (y > maxY) + maxY = y; + + if (cell.real) { + colSpan = cell.colspan - 1; + rowSpan = cell.rowspan - 1; + + if (colSpan) { + if (x + colSpan > maxX) + maxX = x + colSpan; + } + + if (rowSpan) { + if (y + rowSpan > maxY) + maxY = y + rowSpan; + } + } + } + }); + }); + + return {x : maxX, y : maxY}; + }; + + function setEndCell(cell) { + var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan; + + endPos = getPos(cell); + + if (startPos && endPos) { + // Get start/end positions + startX = Math.min(startPos.x, endPos.x); + startY = Math.min(startPos.y, endPos.y); + endX = Math.max(startPos.x, endPos.x); + endY = Math.max(startPos.y, endPos.y); + + // Expand end positon to include spans + maxX = endX; + maxY = endY; + + // Expand startX + for (y = startY; y <= maxY; y++) { + cell = grid[y][startX]; + + if (!cell.real) { + if (startX - (cell.colspan - 1) < startX) + startX -= cell.colspan - 1; + } + } + + // Expand startY + for (x = startX; x <= maxX; x++) { + cell = grid[startY][x]; + + if (!cell.real) { + if (startY - (cell.rowspan - 1) < startY) + startY -= cell.rowspan - 1; + } + } + + // Find max X, Y + for (y = startY; y <= endY; y++) { + for (x = startX; x <= endX; x++) { + cell = grid[y][x]; + + if (cell.real) { + colSpan = cell.colspan - 1; + rowSpan = cell.rowspan - 1; + + if (colSpan) { + if (x + colSpan > maxX) + maxX = x + colSpan; + } + + if (rowSpan) { + if (y + rowSpan > maxY) + maxY = y + rowSpan; + } + } + } + } + + // Remove current selection + dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected'); + + // Add new selection + for (y = startY; y <= maxY; y++) { + for (x = startX; x <= maxX; x++) + dom.addClass(grid[y][x].elm, 'mceSelected'); + } + } + }; + + // Expose to public + tinymce.extend(this, { + deleteTable : deleteTable, + split : split, + merge : merge, + insertRow : insertRow, + insertCol : insertCol, + deleteCols : deleteCols, + deleteRows : deleteRows, + cutRows : cutRows, + copyRows : copyRows, + pasteRows : pasteRows, + getPos : getPos, + setStartCell : setStartCell, + setEndCell : setEndCell + }); + }; + + tinymce.create('tinymce.plugins.TablePlugin', { + init : function(ed, url) { + var winMan, clipboardRows; + + function createTableGrid(node) { + var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table'); + + if (tblElm) + return new TableGrid(tblElm, ed.dom, selection); + }; + + function cleanup() { + // Restore selection possibilities + ed.getBody().style.webkitUserSelect = ''; + ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected'); + }; + + // Register buttons + each([ + ['table', 'table.desc', 'mceInsertTable', true], + ['delete_table', 'table.del', 'mceTableDelete'], + ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'], + ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'], + ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'], + ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'], + ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'], + ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'], + ['row_props', 'table.row_desc', 'mceTableRowProps', true], + ['cell_props', 'table.cell_desc', 'mceTableCellProps', true], + ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true], + ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true] + ], function(c) { + ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]}); + }); + + // Select whole table is a table border is clicked + if (!tinymce.isIE) { + ed.onClick.add(function(ed, e) { + e = e.target; + + if (e.nodeName === 'TABLE') + ed.selection.select(e); + }); + } + + // Handle node change updates + ed.onNodeChange.add(function(ed, cm, n) { + var p; + + n = ed.selection.getStart(); + p = ed.dom.getParent(n, 'td,th,caption'); + cm.setActive('table', n.nodeName === 'TABLE' || !!p); + + // Disable table tools if we are in caption + if (p && p.nodeName === 'CAPTION') + p = 0; + + cm.setDisabled('delete_table', !p); + cm.setDisabled('delete_col', !p); + cm.setDisabled('delete_table', !p); + cm.setDisabled('delete_row', !p); + cm.setDisabled('col_after', !p); + cm.setDisabled('col_before', !p); + cm.setDisabled('row_after', !p); + cm.setDisabled('row_before', !p); + cm.setDisabled('row_props', !p); + cm.setDisabled('cell_props', !p); + cm.setDisabled('split_cells', !p); + cm.setDisabled('merge_cells', !p); + }); + + ed.onInit.add(function(ed) { + var startTable, startCell, dom = ed.dom, tableGrid; + + winMan = ed.windowManager; + + // Add cell selection logic + ed.onMouseDown.add(function(ed, e) { + if (e.button != 2) { + cleanup(); + + startCell = dom.getParent(e.target, 'td,th'); + startTable = dom.getParent(startCell, 'table'); + } + }); + + dom.bind(ed.getDoc(), 'mouseover', function(e) { + var sel, table, target = e.target; + + if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) { + table = dom.getParent(target, 'table'); + if (table == startTable) { + if (!tableGrid) { + tableGrid = createTableGrid(table); + tableGrid.setStartCell(startCell); + + ed.getBody().style.webkitUserSelect = 'none'; + } + + tableGrid.setEndCell(target); + } + + // Remove current selection + sel = ed.selection.getSel(); + + if (sel.removeAllRanges) + sel.removeAllRanges(); + else + sel.empty(); + + e.preventDefault(); + } + }); + + ed.onMouseUp.add(function(ed, e) { + var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode; + + // Move selection to startCell + if (startCell) { + if (tableGrid) + ed.getBody().style.webkitUserSelect = ''; + + function setPoint(node, start) { + var walker = new tinymce.dom.TreeWalker(node, node); + + do { + // Text node + if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) { + if (start) + rng.setStart(node, 0); + else + rng.setEnd(node, node.nodeValue.length); + + return; + } + + // BR element + if (node.nodeName == 'BR') { + if (start) + rng.setStartBefore(node); + else + rng.setEndBefore(node); + + return; + } + } while (node = (start ? walker.next() : walker.prev())); + }; + + // Try to expand text selection as much as we can only Gecko supports cell selection + selectedCells = dom.select('td.mceSelected,th.mceSelected'); + if (selectedCells.length > 0) { + rng = dom.createRng(); + node = selectedCells[0]; + endNode = selectedCells[selectedCells.length - 1]; + + setPoint(node, 1); + walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table')); + + do { + if (node.nodeName == 'TD' || node.nodeName == 'TH') { + if (!dom.hasClass(node, 'mceSelected')) + break; + + lastNode = node; + } + } while (node = walker.next()); + + setPoint(lastNode); + + sel.setRng(rng); + } + + ed.nodeChanged(); + startCell = tableGrid = startTable = null; + } + }); + + ed.onKeyUp.add(function(ed, e) { + cleanup(); + }); + + // Add context menu + if (ed && ed.plugins.contextmenu) { + ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { + var sm, se = ed.selection, el = se.getNode() || ed.getBody(); + + if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) { + m.removeAll(); + + if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) { + m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true}); + m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'}); + m.addSeparator(); + } + + if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) { + m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true}); + m.addSeparator(); + } + + m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}}); + m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'}); + m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'}); + m.addSeparator(); + + // Cell menu + sm = m.addMenu({title : 'table.cell'}); + sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'}); + sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'}); + sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'}); + + // Row menu + sm = m.addMenu({title : 'table.row'}); + sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'}); + sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'}); + sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'}); + sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'}); + sm.addSeparator(); + sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'}); + sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'}); + sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows); + sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows); + + // Column menu + sm = m.addMenu({title : 'table.col'}); + sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'}); + sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'}); + sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'}); + } else + m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'}); + }); + } + + // Fixes an issue on Gecko where it's impossible to place the caret behind a table + // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled + if (!tinymce.isIE) { + function fixTableCaretPos() { + var last; + + // Skip empty text nodes form the end + for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ; + + if (last && last.nodeName == 'TABLE') + ed.dom.add(ed.getBody(), 'p', null, '
    '); + }; + + // Fixes an bug where it's impossible to place the caret before a table in Gecko + // this fix solves it by detecting when the caret is at the beginning of such a table + // and then manually moves the caret infront of the table + if (tinymce.isGecko) { + ed.onKeyDown.add(function(ed, e) { + var rng, table, dom = ed.dom; + + // On gecko it's not possible to place the caret before a table + if (e.keyCode == 37 || e.keyCode == 38) { + rng = ed.selection.getRng(); + table = dom.getParent(rng.startContainer, 'table'); + + if (table && ed.getBody().firstChild == table) { + if (isAtStart(rng, table)) { + rng = dom.createRng(); + + rng.setStartBefore(table); + rng.setEndBefore(table); + + ed.selection.setRng(rng); + + e.preventDefault(); + } + } + } + }); + } + + ed.onKeyUp.add(fixTableCaretPos); + ed.onSetContent.add(fixTableCaretPos); + ed.onVisualAid.add(fixTableCaretPos); + + ed.onPreProcess.add(function(ed, o) { + var last = o.node.lastChild; + + if (last && last.childNodes.length == 1 && last.firstChild.nodeName == 'BR') + ed.dom.remove(last); + }); + + fixTableCaretPos(); + } + }); + + // Register action commands + each({ + mceTableSplitCells : function(grid) { + grid.split(); + }, + + mceTableMergeCells : function(grid) { + var rowSpan, colSpan, cell; + + cell = ed.dom.getParent(ed.selection.getNode(), 'th,td'); + if (cell) { + rowSpan = cell.rowSpan; + colSpan = cell.colSpan; + } + + if (!ed.dom.select('td.mceSelected,th.mceSelected').length) { + winMan.open({ + url : url + '/merge_cells.htm', + width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)), + height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)), + inline : 1 + }, { + rows : rowSpan, + cols : colSpan, + onaction : function(data) { + grid.merge(cell, data.cols, data.rows); + }, + plugin_url : url + }); + } else + grid.merge(); + }, + + mceTableInsertRowBefore : function(grid) { + grid.insertRow(true); + }, + + mceTableInsertRowAfter : function(grid) { + grid.insertRow(); + }, + + mceTableInsertColBefore : function(grid) { + grid.insertCol(true); + }, + + mceTableInsertColAfter : function(grid) { + grid.insertCol(); + }, + + mceTableDeleteCol : function(grid) { + grid.deleteCols(); + }, + + mceTableDeleteRow : function(grid) { + grid.deleteRows(); + }, + + mceTableCutRow : function(grid) { + clipboardRows = grid.cutRows(); + }, + + mceTableCopyRow : function(grid) { + clipboardRows = grid.copyRows(); + }, + + mceTablePasteRowBefore : function(grid) { + grid.pasteRows(clipboardRows, true); + }, + + mceTablePasteRowAfter : function(grid) { + grid.pasteRows(clipboardRows); + }, + + mceTableDelete : function(grid) { + grid.deleteTable(); + } + }, function(func, name) { + ed.addCommand(name, function() { + var grid = createTableGrid(); + + if (grid) { + func(grid); + ed.execCommand('mceRepaint'); + cleanup(); + } + }); + }); + + // Register dialog commands + each({ + mceInsertTable : function(val) { + winMan.open({ + url : url + '/table.htm', + width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)), + height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)), + inline : 1 + }, { + plugin_url : url, + action : val ? val.action : 0 + }); + }, + + mceTableRowProps : function() { + winMan.open({ + url : url + '/row.htm', + width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)), + height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }, + + mceTableCellProps : function() { + winMan.open({ + url : url + '/cell.htm', + width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)), + height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + } + }, function(func, name) { + ed.addCommand(name, function(ui, val) { + func(val); + }); + }); + } + }); + + // Register plugin + tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin); +})(tinymce); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/table/js/cell.js b/tools/tiny_mce/plugins/table/js/cell.js new file mode 100644 index 00000000..fae7e6fb --- /dev/null +++ b/tools/tiny_mce/plugins/table/js/cell.js @@ -0,0 +1,286 @@ +tinyMCEPopup.requireLangPack(); + +var ed; + +function init() { + ed = tinyMCEPopup.editor; + tinyMCEPopup.resizeToInnerSize(); + + document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table'); + document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor'); + document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor') + + var inst = ed; + var tdElm = ed.dom.getParent(ed.selection.getStart(), "td,th"); + var formObj = document.forms[0]; + var st = ed.dom.parseStyle(ed.dom.getAttrib(tdElm, "style")); + + // Get table cell data + var celltype = tdElm.nodeName.toLowerCase(); + var align = ed.dom.getAttrib(tdElm, 'align'); + var valign = ed.dom.getAttrib(tdElm, 'valign'); + var width = trimSize(getStyle(tdElm, 'width', 'width')); + var height = trimSize(getStyle(tdElm, 'height', 'height')); + var bordercolor = convertRGBToHex(getStyle(tdElm, 'bordercolor', 'borderLeftColor')); + var bgcolor = convertRGBToHex(getStyle(tdElm, 'bgcolor', 'backgroundColor')); + var className = ed.dom.getAttrib(tdElm, 'class'); + var backgroundimage = getStyle(tdElm, 'background', 'backgroundImage').replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1"); + var id = ed.dom.getAttrib(tdElm, 'id'); + var lang = ed.dom.getAttrib(tdElm, 'lang'); + var dir = ed.dom.getAttrib(tdElm, 'dir'); + var scope = ed.dom.getAttrib(tdElm, 'scope'); + + // Setup form + addClassesToList('class', 'table_cell_styles'); + TinyMCE_EditableSelects.init(); + + if (!ed.dom.hasClass(tdElm, 'mceSelected')) { + formObj.bordercolor.value = bordercolor; + formObj.bgcolor.value = bgcolor; + formObj.backgroundimage.value = backgroundimage; + formObj.width.value = width; + formObj.height.value = height; + formObj.id.value = id; + formObj.lang.value = lang; + formObj.style.value = ed.dom.serializeStyle(st); + selectByValue(formObj, 'align', align); + selectByValue(formObj, 'valign', valign); + selectByValue(formObj, 'class', className, true, true); + selectByValue(formObj, 'celltype', celltype); + selectByValue(formObj, 'dir', dir); + selectByValue(formObj, 'scope', scope); + + // Resize some elements + if (isVisible('backgroundimagebrowser')) + document.getElementById('backgroundimage').style.width = '180px'; + + updateColor('bordercolor_pick', 'bordercolor'); + updateColor('bgcolor_pick', 'bgcolor'); + } else + tinyMCEPopup.dom.hide('action'); +} + +function updateAction() { + var el, inst = ed, tdElm, trElm, tableElm, formObj = document.forms[0]; + + tinyMCEPopup.restoreSelection(); + el = ed.selection.getStart(); + tdElm = ed.dom.getParent(el, "td,th"); + trElm = ed.dom.getParent(el, "tr"); + tableElm = ed.dom.getParent(el, "table"); + + // Cell is selected + if (ed.dom.hasClass(tdElm, 'mceSelected')) { + // Update all selected sells + tinymce.each(ed.dom.select('td.mceSelected,th.mceSelected'), function(td) { + updateCell(td); + }); + + ed.addVisual(); + ed.nodeChanged(); + inst.execCommand('mceEndUndoLevel'); + tinyMCEPopup.close(); + return; + } + + ed.execCommand('mceBeginUndoLevel'); + + switch (getSelectValue(formObj, 'action')) { + case "cell": + var celltype = getSelectValue(formObj, 'celltype'); + var scope = getSelectValue(formObj, 'scope'); + + function doUpdate(s) { + if (s) { + updateCell(tdElm); + + ed.addVisual(); + ed.nodeChanged(); + inst.execCommand('mceEndUndoLevel'); + tinyMCEPopup.close(); + } + }; + + if (ed.getParam("accessibility_warnings", 1)) { + if (celltype == "th" && scope == "") + tinyMCEPopup.confirm(ed.getLang('table_dlg.missing_scope', '', true), doUpdate); + else + doUpdate(1); + + return; + } + + updateCell(tdElm); + break; + + case "row": + var cell = trElm.firstChild; + + if (cell.nodeName != "TD" && cell.nodeName != "TH") + cell = nextCell(cell); + + do { + cell = updateCell(cell, true); + } while ((cell = nextCell(cell)) != null); + + break; + + case "all": + var rows = tableElm.getElementsByTagName("tr"); + + for (var i=0; i 0) { + tinymce.each(tableElm.rows, function(tr) { + var i; + + for (i = 0; i < tr.cells.length; i++) { + if (dom.hasClass(tr.cells[i], 'mceSelected')) { + updateRow(tr, true); + return; + } + } + }); + + inst.addVisual(); + inst.nodeChanged(); + inst.execCommand('mceEndUndoLevel'); + tinyMCEPopup.close(); + return; + } + + inst.execCommand('mceBeginUndoLevel'); + + switch (action) { + case "row": + updateRow(trElm); + break; + + case "all": + var rows = tableElm.getElementsByTagName("tr"); + + for (var i=0; i colLimit) { + tinyMCEPopup.alert(inst.getLang('table_dlg.col_limit').replace(/\{\$cols\}/g, colLimit)); + return false; + } else if (rowLimit && rows > rowLimit) { + tinyMCEPopup.alert(inst.getLang('table_dlg.row_limit').replace(/\{\$rows\}/g, rowLimit)); + return false; + } else if (cellLimit && cols * rows > cellLimit) { + tinyMCEPopup.alert(inst.getLang('table_dlg.cell_limit').replace(/\{\$cells\}/g, cellLimit)); + return false; + } + + // Update table + if (action == "update") { + inst.execCommand('mceBeginUndoLevel'); + + dom.setAttrib(elm, 'cellPadding', cellpadding, true); + dom.setAttrib(elm, 'cellSpacing', cellspacing, true); + dom.setAttrib(elm, 'border', border); + dom.setAttrib(elm, 'align', align); + dom.setAttrib(elm, 'frame', frame); + dom.setAttrib(elm, 'rules', rules); + dom.setAttrib(elm, 'class', className); + dom.setAttrib(elm, 'style', style); + dom.setAttrib(elm, 'id', id); + dom.setAttrib(elm, 'summary', summary); + dom.setAttrib(elm, 'dir', dir); + dom.setAttrib(elm, 'lang', lang); + + capEl = inst.dom.select('caption', elm)[0]; + + if (capEl && !caption) + capEl.parentNode.removeChild(capEl); + + if (!capEl && caption) { + capEl = elm.ownerDocument.createElement('caption'); + + if (!tinymce.isIE) + capEl.innerHTML = '
    '; + + elm.insertBefore(capEl, elm.firstChild); + } + + if (width && inst.settings.inline_styles) { + dom.setStyle(elm, 'width', width); + dom.setAttrib(elm, 'width', ''); + } else { + dom.setAttrib(elm, 'width', width, true); + dom.setStyle(elm, 'width', ''); + } + + // Remove these since they are not valid XHTML + dom.setAttrib(elm, 'borderColor', ''); + dom.setAttrib(elm, 'bgColor', ''); + dom.setAttrib(elm, 'background', ''); + + if (height && inst.settings.inline_styles) { + dom.setStyle(elm, 'height', height); + dom.setAttrib(elm, 'height', ''); + } else { + dom.setAttrib(elm, 'height', height, true); + dom.setStyle(elm, 'height', ''); + } + + if (background != '') + elm.style.backgroundImage = "url('" + background + "')"; + else + elm.style.backgroundImage = ''; + +/* if (tinyMCEPopup.getParam("inline_styles")) { + if (width != '') + elm.style.width = getCSSSize(width); + }*/ + + if (bordercolor != "") { + elm.style.borderColor = bordercolor; + elm.style.borderStyle = elm.style.borderStyle == "" ? "solid" : elm.style.borderStyle; + elm.style.borderWidth = border == "" ? "1px" : border; + } else + elm.style.borderColor = ''; + + elm.style.backgroundColor = bgcolor; + elm.style.height = getCSSSize(height); + + inst.addVisual(); + + // Fix for stange MSIE align bug + //elm.outerHTML = elm.outerHTML; + + inst.nodeChanged(); + inst.execCommand('mceEndUndoLevel'); + + // Repaint if dimensions changed + if (formObj.width.value != orgTableWidth || formObj.height.value != orgTableHeight) + inst.execCommand('mceRepaint'); + + tinyMCEPopup.close(); + return true; + } + + // Create new table + html += ''); + + tinymce.each('h1,h2,h3,h4,h5,h6,p'.split(','), function(n) { + if (patt) + patt += ','; + + patt += n + ' ._mce_marker'; + }); + + tinymce.each(inst.dom.select(patt), function(n) { + inst.dom.split(inst.dom.getParent(n, 'h1,h2,h3,h4,h5,h6,p'), n); + }); + + dom.setOuterHTML(dom.select('br._mce_marker')[0], html); + } else + inst.execCommand('mceInsertContent', false, html); + + tinymce.each(dom.select('table[_mce_new]'), function(node) { + var td = dom.select('td', node); + + try { + // IE9 might fail to do this selection + inst.selection.select(td[0], true); + inst.selection.collapse(); + } catch (ex) { + // Ignore + } + + dom.setAttrib(node, '_mce_new', ''); + }); + + inst.addVisual(); + inst.execCommand('mceEndUndoLevel'); + + tinyMCEPopup.close(); +} + +function makeAttrib(attrib, value) { + var formObj = document.forms[0]; + var valueElm = formObj.elements[attrib]; + + if (typeof(value) == "undefined" || value == null) { + value = ""; + + if (valueElm) + value = valueElm.value; + } + + if (value == "") + return ""; + + // XML encode it + value = value.replace(/&/g, '&'); + value = value.replace(/\"/g, '"'); + value = value.replace(//g, '>'); + + return ' ' + attrib + '="' + value + '"'; +} + +function init() { + tinyMCEPopup.resizeToInnerSize(); + + document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table'); + document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table'); + document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor'); + document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor'); + + var cols = 2, rows = 2, border = tinyMCEPopup.getParam('table_default_border', '0'), cellpadding = tinyMCEPopup.getParam('table_default_cellpadding', ''), cellspacing = tinyMCEPopup.getParam('table_default_cellspacing', ''); + var align = "", width = "", height = "", bordercolor = "", bgcolor = "", className = ""; + var id = "", summary = "", style = "", dir = "", lang = "", background = "", bgcolor = "", bordercolor = "", rules = "", frame = ""; + var inst = tinyMCEPopup.editor, dom = inst.dom; + var formObj = document.forms[0]; + var elm = dom.getParent(inst.selection.getNode(), "table"); + + action = tinyMCEPopup.getWindowArg('action'); + + if (!action) + action = elm ? "update" : "insert"; + + if (elm && action != "insert") { + var rowsAr = elm.rows; + var cols = 0; + for (var i=0; i cols) + cols = rowsAr[i].cells.length; + + cols = cols; + rows = rowsAr.length; + + st = dom.parseStyle(dom.getAttrib(elm, "style")); + border = trimSize(getStyle(elm, 'border', 'borderWidth')); + cellpadding = dom.getAttrib(elm, 'cellpadding', ""); + cellspacing = dom.getAttrib(elm, 'cellspacing', ""); + width = trimSize(getStyle(elm, 'width', 'width')); + height = trimSize(getStyle(elm, 'height', 'height')); + bordercolor = convertRGBToHex(getStyle(elm, 'bordercolor', 'borderLeftColor')); + bgcolor = convertRGBToHex(getStyle(elm, 'bgcolor', 'backgroundColor')); + align = dom.getAttrib(elm, 'align', align); + frame = dom.getAttrib(elm, 'frame'); + rules = dom.getAttrib(elm, 'rules'); + className = tinymce.trim(dom.getAttrib(elm, 'class').replace(/mceItem.+/g, '')); + id = dom.getAttrib(elm, 'id'); + summary = dom.getAttrib(elm, 'summary'); + style = dom.serializeStyle(st); + dir = dom.getAttrib(elm, 'dir'); + lang = dom.getAttrib(elm, 'lang'); + background = getStyle(elm, 'background', 'backgroundImage').replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1"); + formObj.caption.checked = elm.getElementsByTagName('caption').length > 0; + + orgTableWidth = width; + orgTableHeight = height; + + action = "update"; + formObj.insert.value = inst.getLang('update'); + } + + addClassesToList('class', "table_styles"); + TinyMCE_EditableSelects.init(); + + // Update form + selectByValue(formObj, 'align', align); + selectByValue(formObj, 'tframe', frame); + selectByValue(formObj, 'rules', rules); + selectByValue(formObj, 'class', className, true, true); + formObj.cols.value = cols; + formObj.rows.value = rows; + formObj.border.value = border; + formObj.cellpadding.value = cellpadding; + formObj.cellspacing.value = cellspacing; + formObj.width.value = width; + formObj.height.value = height; + formObj.bordercolor.value = bordercolor; + formObj.bgcolor.value = bgcolor; + formObj.id.value = id; + formObj.summary.value = summary; + formObj.style.value = style; + formObj.dir.value = dir; + formObj.lang.value = lang; + formObj.backgroundimage.value = background; + + updateColor('bordercolor_pick', 'bordercolor'); + updateColor('bgcolor_pick', 'bgcolor'); + + // Resize some elements + if (isVisible('backgroundimagebrowser')) + document.getElementById('backgroundimage').style.width = '180px'; + + // Disable some fields in update mode + if (action == "update") { + formObj.cols.disabled = true; + formObj.rows.disabled = true; + } +} + +function changedSize() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + +/* var width = formObj.width.value; + if (width != "") + st['width'] = tinyMCEPopup.getParam("inline_styles") ? getCSSSize(width) : ""; + else + st['width'] = "";*/ + + var height = formObj.height.value; + if (height != "") + st['height'] = getCSSSize(height); + else + st['height'] = ""; + + formObj.style.value = dom.serializeStyle(st); +} + +function changedBackgroundImage() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + st['background-image'] = "url('" + formObj.backgroundimage.value + "')"; + + formObj.style.value = dom.serializeStyle(st); +} + +function changedBorder() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + // Update border width if the element has a color + if (formObj.border.value != "" && formObj.bordercolor.value != "") + st['border-width'] = formObj.border.value + "px"; + + formObj.style.value = dom.serializeStyle(st); +} + +function changedColor() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + st['background-color'] = formObj.bgcolor.value; + + if (formObj.bordercolor.value != "") { + st['border-color'] = formObj.bordercolor.value; + + // Add border-width if it's missing + if (!st['border-width']) + st['border-width'] = formObj.border.value == "" ? "1px" : formObj.border.value + "px"; + } + + formObj.style.value = dom.serializeStyle(st); +} + +function changedStyle() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + if (st['background-image']) + formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1"); + else + formObj.backgroundimage.value = ''; + + if (st['width']) + formObj.width.value = trimSize(st['width']); + + if (st['height']) + formObj.height.value = trimSize(st['height']); + + if (st['background-color']) { + formObj.bgcolor.value = st['background-color']; + updateColor('bgcolor_pick','bgcolor'); + } + + if (st['border-color']) { + formObj.bordercolor.value = st['border-color']; + updateColor('bordercolor_pick','bordercolor'); + } +} + +tinyMCEPopup.onInit.add(init); diff --git a/tools/tiny_mce/plugins/table/langs/en_dlg.js b/tools/tiny_mce/plugins/table/langs/en_dlg.js new file mode 100644 index 00000000..db5555c1 --- /dev/null +++ b/tools/tiny_mce/plugins/table/langs/en_dlg.js @@ -0,0 +1,74 @@ +tinyMCE.addI18n('en.table_dlg',{ +general_tab:"General", +advanced_tab:"Advanced", +general_props:"General properties", +advanced_props:"Advanced properties", +rowtype:"Row in table part", +title:"Insert/Modify table", +width:"Width", +height:"Height", +cols:"Columns", +rows:"Rows", +cellspacing:"Cellspacing", +cellpadding:"Cellpadding", +border:"Border", +align:"Alignment", +align_default:"Default", +align_left:"Left", +align_right:"Right", +align_middle:"Center", +row_title:"Table row properties", +cell_title:"Table cell properties", +cell_type:"Cell type", +valign:"Vertical alignment", +align_top:"Top", +align_bottom:"Bottom", +bordercolor:"Border color", +bgcolor:"Background color", +merge_cells_title:"Merge table cells", +id:"Id", +style:"Style", +langdir:"Language direction", +langcode:"Language code", +mime:"Target MIME type", +ltr:"Left to right", +rtl:"Right to left", +bgimage:"Background image", +summary:"Summary", +td:"Data", +th:"Header", +cell_cell:"Update current cell", +cell_row:"Update all cells in row", +cell_all:"Update all cells in table", +row_row:"Update current row", +row_odd:"Update odd rows in table", +row_even:"Update even rows in table", +row_all:"Update all rows in table", +thead:"Table Head", +tbody:"Table Body", +tfoot:"Table Foot", +scope:"Scope", +rowgroup:"Row Group", +colgroup:"Col Group", +col_limit:"You've exceeded the maximum number of columns of {$cols}.", +row_limit:"You've exceeded the maximum number of rows of {$rows}.", +cell_limit:"You've exceeded the maximum number of cells of {$cells}.", +missing_scope:"Are you sure you want to continue without specifying a scope for this table header cell. Without it, it may be difficult for some users with disabilities to understand the content or data displayed of the table.", +caption:"Table caption", +frame:"Frame", +frame_none:"none", +frame_groups:"groups", +frame_rows:"rows", +frame_cols:"cols", +frame_all:"all", +rules:"Rules", +rules_void:"void", +rules_above:"above", +rules_below:"below", +rules_hsides:"hsides", +rules_lhs:"lhs", +rules_rhs:"rhs", +rules_vsides:"vsides", +rules_box:"box", +rules_border:"border" +}); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/table/merge_cells.htm b/tools/tiny_mce/plugins/table/merge_cells.htm new file mode 100644 index 00000000..5e132613 --- /dev/null +++ b/tools/tiny_mce/plugins/table/merge_cells.htm @@ -0,0 +1,32 @@ + + + + {#table_dlg.merge_cells_title} + + + + + + +
    +
    + {#table_dlg.merge_cells_title} + + + + + + + + + +
    :
    :
    +
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/table/row.htm b/tools/tiny_mce/plugins/table/row.htm new file mode 100644 index 00000000..d64e6d03 --- /dev/null +++ b/tools/tiny_mce/plugins/table/row.htm @@ -0,0 +1,157 @@ + + + + {#table_dlg.row_title} + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + +
    + +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + + +
     
    +
    +
    +
    +
    +
    + +
    +
    + +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/table/table.htm b/tools/tiny_mce/plugins/table/table.htm new file mode 100644 index 00000000..d9f2dae7 --- /dev/null +++ b/tools/tiny_mce/plugins/table/table.htm @@ -0,0 +1,188 @@ + + + + {#table_dlg.title} + + + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + +
     
    +
    + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    +
    +
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/template/blank.htm b/tools/tiny_mce/plugins/template/blank.htm new file mode 100644 index 00000000..538a3b12 --- /dev/null +++ b/tools/tiny_mce/plugins/template/blank.htm @@ -0,0 +1,12 @@ + + + blank_page + + + + + + + diff --git a/tools/tiny_mce/plugins/template/css/template.css b/tools/tiny_mce/plugins/template/css/template.css new file mode 100644 index 00000000..0a03f2e5 --- /dev/null +++ b/tools/tiny_mce/plugins/template/css/template.css @@ -0,0 +1,23 @@ +#frmbody { + padding: 10px; + background-color: #FFF; + border: 1px solid #CCC; +} + +.frmRow { + margin-bottom: 10px; +} + +#templatesrc { + border: none; + width: 320px; + height: 240px; +} + +.title { + padding-bottom: 5px; +} + +.mceActionPanel { + padding-top: 5px; +} diff --git a/tools/tiny_mce/plugins/template/editor_plugin.js b/tools/tiny_mce/plugins/template/editor_plugin.js new file mode 100644 index 00000000..ebe3c27d --- /dev/null +++ b/tools/tiny_mce/plugins/template/editor_plugin.js @@ -0,0 +1 @@ +(function(){var a=tinymce.each;tinymce.create("tinymce.plugins.TemplatePlugin",{init:function(b,c){var d=this;d.editor=b;b.addCommand("mceTemplate",function(e){b.windowManager.open({file:c+"/template.htm",width:b.getParam("template_popup_width",750),height:b.getParam("template_popup_height",600),inline:1},{plugin_url:c})});b.addCommand("mceInsertTemplate",d._insertTemplate,d);b.addButton("template",{title:"template.desc",cmd:"mceTemplate"});b.onPreProcess.add(function(e,g){var f=e.dom;a(f.select("div",g.node),function(h){if(f.hasClass(h,"mceTmpl")){a(f.select("*",h),function(i){if(f.hasClass(i,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))){i.innerHTML=d._getDateTime(new Date(),e.getParam("template_mdate_format",e.getLang("template.mdate_format")))}});d._replaceVals(h)}})})},getInfo:function(){return{longname:"Template plugin",author:"Moxiecode Systems AB",authorurl:"http://www.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_insertTemplate:function(i,j){var k=this,g=k.editor,f,c,d=g.dom,b=g.selection.getContent();f=j.content;a(k.editor.getParam("template_replace_values"),function(l,h){if(typeof(l)!="function"){f=f.replace(new RegExp("\\{\\$"+h+"\\}","g"),l)}});c=d.create("div",null,f);n=d.select(".mceTmpl",c);if(n&&n.length>0){c=d.create("div",null);c.appendChild(n[0].cloneNode(true))}function e(l,h){return new RegExp("\\b"+h+"\\b","g").test(l.className)}a(d.select("*",c),function(h){if(e(h,g.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))){h.innerHTML=k._getDateTime(new Date(),g.getParam("template_cdate_format",g.getLang("template.cdate_format")))}if(e(h,g.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))){h.innerHTML=k._getDateTime(new Date(),g.getParam("template_mdate_format",g.getLang("template.mdate_format")))}if(e(h,g.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))){h.innerHTML=b}});k._replaceVals(c);g.execCommand("mceInsertContent",false,c.innerHTML);g.addVisual()},_replaceVals:function(c){var d=this.editor.dom,b=this.editor.getParam("template_replace_values");a(d.select("*",c),function(f){a(b,function(g,e){if(d.hasClass(f,e)){if(typeof(b[e])=="function"){b[e](f)}}})})},_getDateTime:function(e,b){if(!b){return""}function c(g,d){var f;g=""+g;if(g.length 0) { + el = dom.create('div', null); + el.appendChild(n[0].cloneNode(true)); + } + + function hasClass(n, c) { + return new RegExp('\\b' + c + '\\b', 'g').test(n.className); + }; + + each(dom.select('*', el), function(n) { + // Replace cdate + if (hasClass(n, ed.getParam('template_cdate_classes', 'cdate').replace(/\s+/g, '|'))) + n.innerHTML = t._getDateTime(new Date(), ed.getParam("template_cdate_format", ed.getLang("template.cdate_format"))); + + // Replace mdate + if (hasClass(n, ed.getParam('template_mdate_classes', 'mdate').replace(/\s+/g, '|'))) + n.innerHTML = t._getDateTime(new Date(), ed.getParam("template_mdate_format", ed.getLang("template.mdate_format"))); + + // Replace selection + if (hasClass(n, ed.getParam('template_selected_content_classes', 'selcontent').replace(/\s+/g, '|'))) + n.innerHTML = sel; + }); + + t._replaceVals(el); + + ed.execCommand('mceInsertContent', false, el.innerHTML); + ed.addVisual(); + }, + + _replaceVals : function(e) { + var dom = this.editor.dom, vl = this.editor.getParam('template_replace_values'); + + each(dom.select('*', e), function(e) { + each(vl, function(v, k) { + if (dom.hasClass(e, k)) { + if (typeof(vl[k]) == 'function') + vl[k](e); + } + }); + }); + }, + + _getDateTime : function(d, fmt) { + if (!fmt) + return ""; + + function addZeros(value, len) { + var i; + + value = "" + value; + + if (value.length < len) { + for (i=0; i<(len-value.length); i++) + value = "0" + value; + } + + return value; + } + + fmt = fmt.replace("%D", "%m/%d/%y"); + fmt = fmt.replace("%r", "%I:%M:%S %p"); + fmt = fmt.replace("%Y", "" + d.getFullYear()); + fmt = fmt.replace("%y", "" + d.getYear()); + fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2)); + fmt = fmt.replace("%d", addZeros(d.getDate(), 2)); + fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2)); + fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2)); + fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2)); + fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1)); + fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM")); + fmt = fmt.replace("%B", "" + this.editor.getLang("template_months_long").split(',')[d.getMonth()]); + fmt = fmt.replace("%b", "" + this.editor.getLang("template_months_short").split(',')[d.getMonth()]); + fmt = fmt.replace("%A", "" + this.editor.getLang("template_day_long").split(',')[d.getDay()]); + fmt = fmt.replace("%a", "" + this.editor.getLang("template_day_short").split(',')[d.getDay()]); + fmt = fmt.replace("%%", "%"); + + return fmt; + } + }); + + // Register plugin + tinymce.PluginManager.add('template', tinymce.plugins.TemplatePlugin); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/template/js/template.js b/tools/tiny_mce/plugins/template/js/template.js new file mode 100644 index 00000000..7eab2ebb --- /dev/null +++ b/tools/tiny_mce/plugins/template/js/template.js @@ -0,0 +1,106 @@ +tinyMCEPopup.requireLangPack(); + +var TemplateDialog = { + preInit : function() { + var url = tinyMCEPopup.getParam("template_external_list_url"); + + if (url != null) + document.write(''); + }, + + init : function() { + var ed = tinyMCEPopup.editor, tsrc, sel, x, u; + + tsrc = ed.getParam("template_templates", false); + sel = document.getElementById('tpath'); + + // Setup external template list + if (!tsrc && typeof(tinyMCETemplateList) != 'undefined') { + for (x=0, tsrc = []; x'); + }); + }, + + selectTemplate : function(u, ti) { + var d = window.frames['templatesrc'].document, x, tsrc = this.tsrc; + + if (!u) + return; + + d.body.innerHTML = this.templateHTML = this.getFileContents(u); + + for (x=0; x + + {#template_dlg.title} + + + + + +
    +
    +
    {#template_dlg.desc}
    +
    + +
    +
    +
    +
    + {#template_dlg.preview} + +
    +
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/visualchars/editor_plugin.js b/tools/tiny_mce/plugins/visualchars/editor_plugin.js new file mode 100644 index 00000000..94719f93 --- /dev/null +++ b/tools/tiny_mce/plugins/visualchars/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.VisualChars",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceVisualChars",c._toggleVisualChars,c);a.addButton("visualchars",{title:"visualchars.desc",cmd:"mceVisualChars"});a.onBeforeGetContent.add(function(d,e){if(c.state&&e.format!="raw"&&!e.draft){c.state=true;c._toggleVisualChars(false)}})},getInfo:function(){return{longname:"Visual characters",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_toggleVisualChars:function(m){var p=this,k=p.editor,a,g,j,n=k.getDoc(),o=k.getBody(),l,q=k.selection,e,c,f;p.state=!p.state;k.controlManager.setActive("visualchars",p.state);if(m){f=q.getBookmark()}if(p.state){a=[];tinymce.walk(o,function(b){if(b.nodeType==3&&b.nodeValue&&b.nodeValue.indexOf("\u00a0")!=-1){a.push(b)}},"childNodes");for(g=0;g$1');c=k.dom.create("div",null,l);while(node=c.lastChild){k.dom.insertAfter(node,a[g])}k.dom.remove(a[g])}}else{a=k.dom.select("span.mceItemNbsp",o);for(g=a.length-1;g>=0;g--){k.dom.remove(a[g],1)}}q.moveToBookmark(f)}});tinymce.PluginManager.add("visualchars",tinymce.plugins.VisualChars)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/visualchars/editor_plugin_src.js b/tools/tiny_mce/plugins/visualchars/editor_plugin_src.js new file mode 100644 index 00000000..33b687f6 --- /dev/null +++ b/tools/tiny_mce/plugins/visualchars/editor_plugin_src.js @@ -0,0 +1,83 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.VisualChars', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + // Register commands + ed.addCommand('mceVisualChars', t._toggleVisualChars, t); + + // Register buttons + ed.addButton('visualchars', {title : 'visualchars.desc', cmd : 'mceVisualChars'}); + + ed.onBeforeGetContent.add(function(ed, o) { + if (t.state && o.format != 'raw' && !o.draft) { + t.state = true; + t._toggleVisualChars(false); + } + }); + }, + + getInfo : function() { + return { + longname : 'Visual characters', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private methods + + _toggleVisualChars : function(bookmark) { + var t = this, ed = t.editor, nl, i, h, d = ed.getDoc(), b = ed.getBody(), nv, s = ed.selection, bo, div, bm; + + t.state = !t.state; + ed.controlManager.setActive('visualchars', t.state); + + if (bookmark) + bm = s.getBookmark(); + + if (t.state) { + nl = []; + tinymce.walk(b, function(n) { + if (n.nodeType == 3 && n.nodeValue && n.nodeValue.indexOf('\u00a0') != -1) + nl.push(n); + }, 'childNodes'); + + for (i = 0; i < nl.length; i++) { + nv = nl[i].nodeValue; + nv = nv.replace(/(\u00a0)/g, '$1'); + + div = ed.dom.create('div', null, nv); + while (node = div.lastChild) + ed.dom.insertAfter(node, nl[i]); + + ed.dom.remove(nl[i]); + } + } else { + nl = ed.dom.select('span.mceItemNbsp', b); + + for (i = nl.length - 1; i >= 0; i--) + ed.dom.remove(nl[i], 1); + } + + s.moveToBookmark(bm); + } + }); + + // Register plugin + tinymce.PluginManager.add('visualchars', tinymce.plugins.VisualChars); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/wordcount/editor_plugin.js b/tools/tiny_mce/plugins/wordcount/editor_plugin.js new file mode 100644 index 00000000..a099e6a8 --- /dev/null +++ b/tools/tiny_mce/plugins/wordcount/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.WordCount",{block:0,id:null,countre:null,cleanre:null,init:function(a,b){var c=this,d=0;c.countre=a.getParam("wordcount_countregex",/\S\s+/g);c.cleanre=a.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$'"_+=\\\/-]*/g);c.id=a.id+"-word-count";a.onPostRender.add(function(f,e){var g,h;h=f.getParam("wordcount_target_id");if(!h){g=tinymce.DOM.get(f.id+"_path_row");if(g){tinymce.DOM.add(g.parentNode,"div",{style:"float: right"},f.getLang("wordcount.words","Words: ")+'0')}}else{tinymce.DOM.add(h,"span",{},'0')}});a.onInit.add(function(e){e.selection.onSetContent.add(function(){c._count(e)});c._count(e)});a.onSetContent.add(function(e){c._count(e)});a.onKeyUp.add(function(f,g){if(g.keyCode==d){return}if(13==g.keyCode||8==d||46==d){c._count(f)}d=g.keyCode})},_count:function(b){var c=this,a=0;if(c.block){return}c.block=1;setTimeout(function(){var d=b.getContent({format:"raw"});if(d){d=d.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," ");d=d.replace(c.cleanre,"");d.replace(c.countre,function(){a++})}tinymce.DOM.setHTML(c.id,a.toString());setTimeout(function(){c.block=0},2000)},1)},getInfo:function(){return{longname:"Word Count plugin",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/wordcount",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("wordcount",tinymce.plugins.WordCount)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/wordcount/editor_plugin_src.js b/tools/tiny_mce/plugins/wordcount/editor_plugin_src.js new file mode 100644 index 00000000..0dc9e34e --- /dev/null +++ b/tools/tiny_mce/plugins/wordcount/editor_plugin_src.js @@ -0,0 +1,98 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.WordCount', { + block : 0, + id : null, + countre : null, + cleanre : null, + + init : function(ed, url) { + var t = this, last = 0; + + t.countre = ed.getParam('wordcount_countregex', /\S\s+/g); + t.cleanre = ed.getParam('wordcount_cleanregex', /[0-9.(),;:!?%#$'"_+=\\\/-]*/g); + t.id = ed.id + '-word-count'; + + ed.onPostRender.add(function(ed, cm) { + var row, id; + + // Add it to the specified id or the theme advanced path + id = ed.getParam('wordcount_target_id'); + if (!id) { + row = tinymce.DOM.get(ed.id + '_path_row'); + + if (row) + tinymce.DOM.add(row.parentNode, 'div', {'style': 'float: right'}, ed.getLang('wordcount.words', 'Words: ') + '0'); + } else + tinymce.DOM.add(id, 'span', {}, '0'); + }); + + ed.onInit.add(function(ed) { + ed.selection.onSetContent.add(function() { + t._count(ed); + }); + + t._count(ed); + }); + + ed.onSetContent.add(function(ed) { + t._count(ed); + }); + + ed.onKeyUp.add(function(ed, e) { + if (e.keyCode == last) + return; + + if (13 == e.keyCode || 8 == last || 46 == last) + t._count(ed); + + last = e.keyCode; + }); + }, + + _count : function(ed) { + var t = this, tc = 0; + + // Keep multiple calls from happening at the same time + if (t.block) + return; + + t.block = 1; + + setTimeout(function() { + var tx = ed.getContent({format : 'raw'}); + + if (tx) { + tx = tx.replace(/<.[^<>]*?>/g, ' ').replace(/ | /gi, ' '); // remove html tags and space chars + tx = tx.replace(t.cleanre, ''); // remove numbers and punctuation + tx.replace(t.countre, function() {tc++;}); // count the words + } + + tinymce.DOM.setHTML(t.id, tc.toString()); + + setTimeout(function() {t.block = 0;}, 2000); + }, 1); + }, + + getInfo: function() { + return { + longname : 'Word Count plugin', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/wordcount', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + tinymce.PluginManager.add('wordcount', tinymce.plugins.WordCount); +})(); diff --git a/tools/tiny_mce/plugins/xhtmlxtras/abbr.htm b/tools/tiny_mce/plugins/xhtmlxtras/abbr.htm new file mode 100644 index 00000000..d4102180 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/abbr.htm @@ -0,0 +1,142 @@ + + + + {#xhtmlxtras_dlg.title_abbr_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/xhtmlxtras/acronym.htm b/tools/tiny_mce/plugins/xhtmlxtras/acronym.htm new file mode 100644 index 00000000..12b189b4 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/acronym.htm @@ -0,0 +1,142 @@ + + + + {#xhtmlxtras_dlg.title_acronym_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/xhtmlxtras/attributes.htm b/tools/tiny_mce/plugins/xhtmlxtras/attributes.htm new file mode 100644 index 00000000..d84f378b --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/attributes.htm @@ -0,0 +1,149 @@ + + + + {#xhtmlxtras_dlg.attribs_title} + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.attribute_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.attribute_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/xhtmlxtras/cite.htm b/tools/tiny_mce/plugins/xhtmlxtras/cite.htm new file mode 100644 index 00000000..ab61b330 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/cite.htm @@ -0,0 +1,142 @@ + + + + {#xhtmlxtras_dlg.title_cite_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/xhtmlxtras/css/attributes.css b/tools/tiny_mce/plugins/xhtmlxtras/css/attributes.css new file mode 100644 index 00000000..85b1b376 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/css/attributes.css @@ -0,0 +1,11 @@ +.panel_wrapper div.current { + height: 290px; +} + +#id, #style, #title, #dir, #hreflang, #lang, #classlist, #tabindex, #accesskey { + width: 200px; +} + +#events_panel input { + width: 200px; +} diff --git a/tools/tiny_mce/plugins/xhtmlxtras/css/popup.css b/tools/tiny_mce/plugins/xhtmlxtras/css/popup.css new file mode 100644 index 00000000..034b9852 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/css/popup.css @@ -0,0 +1,9 @@ +input.field, select.field {width:200px;} +input.picker {width:179px; margin-left: 5px;} +input.disabled {border-color:#F2F2F2;} +img.picker {vertical-align:text-bottom; cursor:pointer;} +h1 {padding: 0 0 5px 0;} +.panel_wrapper div.current {height:160px;} +#xhtmlxtrasdel .panel_wrapper div.current, #xhtmlxtrasins .panel_wrapper div.current {height: 230px;} +a.browse span {display:block; width:20px; height:20px; background:url('../../../themes/advanced/img/icons.gif') -140px -20px;} +#datetime {width:180px;} diff --git a/tools/tiny_mce/plugins/xhtmlxtras/del.htm b/tools/tiny_mce/plugins/xhtmlxtras/del.htm new file mode 100644 index 00000000..e3f34c7d --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/del.htm @@ -0,0 +1,162 @@ + + + + {#xhtmlxtras_dlg.title_del_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_general_tab} + + + + + + + + + +
    : + + + + + +
    +
    :
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/xhtmlxtras/editor_plugin.js b/tools/tiny_mce/plugins/xhtmlxtras/editor_plugin.js new file mode 100644 index 00000000..a9393ad6 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create("tinymce.plugins.XHTMLXtrasPlugin",{init:function(a,b){a.addCommand("mceCite",function(){a.windowManager.open({file:b+"/cite.htm",width:350+parseInt(a.getLang("xhtmlxtras.cite_delta_width",0)),height:250+parseInt(a.getLang("xhtmlxtras.cite_delta_height",0)),inline:1},{plugin_url:b})});a.addCommand("mceAcronym",function(){a.windowManager.open({file:b+"/acronym.htm",width:350+parseInt(a.getLang("xhtmlxtras.acronym_delta_width",0)),height:250+parseInt(a.getLang("xhtmlxtras.acronym_delta_width",0)),inline:1},{plugin_url:b})});a.addCommand("mceAbbr",function(){a.windowManager.open({file:b+"/abbr.htm",width:350+parseInt(a.getLang("xhtmlxtras.abbr_delta_width",0)),height:250+parseInt(a.getLang("xhtmlxtras.abbr_delta_width",0)),inline:1},{plugin_url:b})});a.addCommand("mceDel",function(){a.windowManager.open({file:b+"/del.htm",width:340+parseInt(a.getLang("xhtmlxtras.del_delta_width",0)),height:310+parseInt(a.getLang("xhtmlxtras.del_delta_width",0)),inline:1},{plugin_url:b})});a.addCommand("mceIns",function(){a.windowManager.open({file:b+"/ins.htm",width:340+parseInt(a.getLang("xhtmlxtras.ins_delta_width",0)),height:310+parseInt(a.getLang("xhtmlxtras.ins_delta_width",0)),inline:1},{plugin_url:b})});a.addCommand("mceAttributes",function(){a.windowManager.open({file:b+"/attributes.htm",width:380,height:370,inline:1},{plugin_url:b})});a.addButton("cite",{title:"xhtmlxtras.cite_desc",cmd:"mceCite"});a.addButton("acronym",{title:"xhtmlxtras.acronym_desc",cmd:"mceAcronym"});a.addButton("abbr",{title:"xhtmlxtras.abbr_desc",cmd:"mceAbbr"});a.addButton("del",{title:"xhtmlxtras.del_desc",cmd:"mceDel"});a.addButton("ins",{title:"xhtmlxtras.ins_desc",cmd:"mceIns"});a.addButton("attribs",{title:"xhtmlxtras.attribs_desc",cmd:"mceAttributes"});a.onNodeChange.add(function(d,c,f,e){f=d.dom.getParent(f,"CITE,ACRONYM,ABBR,DEL,INS");c.setDisabled("cite",e);c.setDisabled("acronym",e);c.setDisabled("abbr",e);c.setDisabled("del",e);c.setDisabled("ins",e);c.setDisabled("attribs",f&&f.nodeName=="BODY");c.setActive("cite",0);c.setActive("acronym",0);c.setActive("abbr",0);c.setActive("del",0);c.setActive("ins",0);if(f){do{c.setDisabled(f.nodeName.toLowerCase(),0);c.setActive(f.nodeName.toLowerCase(),1)}while(f=f.parentNode)}});a.onPreInit.add(function(){a.dom.create("abbr")})},getInfo:function(){return{longname:"XHTML Xtras Plugin",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("xhtmlxtras",tinymce.plugins.XHTMLXtrasPlugin)})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js b/tools/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js new file mode 100644 index 00000000..1f3f7709 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js @@ -0,0 +1,132 @@ +/** + * editor_plugin_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + tinymce.create('tinymce.plugins.XHTMLXtrasPlugin', { + init : function(ed, url) { + // Register commands + ed.addCommand('mceCite', function() { + ed.windowManager.open({ + file : url + '/cite.htm', + width : 350 + parseInt(ed.getLang('xhtmlxtras.cite_delta_width', 0)), + height : 250 + parseInt(ed.getLang('xhtmlxtras.cite_delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceAcronym', function() { + ed.windowManager.open({ + file : url + '/acronym.htm', + width : 350 + parseInt(ed.getLang('xhtmlxtras.acronym_delta_width', 0)), + height : 250 + parseInt(ed.getLang('xhtmlxtras.acronym_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceAbbr', function() { + ed.windowManager.open({ + file : url + '/abbr.htm', + width : 350 + parseInt(ed.getLang('xhtmlxtras.abbr_delta_width', 0)), + height : 250 + parseInt(ed.getLang('xhtmlxtras.abbr_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceDel', function() { + ed.windowManager.open({ + file : url + '/del.htm', + width : 340 + parseInt(ed.getLang('xhtmlxtras.del_delta_width', 0)), + height : 310 + parseInt(ed.getLang('xhtmlxtras.del_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceIns', function() { + ed.windowManager.open({ + file : url + '/ins.htm', + width : 340 + parseInt(ed.getLang('xhtmlxtras.ins_delta_width', 0)), + height : 310 + parseInt(ed.getLang('xhtmlxtras.ins_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceAttributes', function() { + ed.windowManager.open({ + file : url + '/attributes.htm', + width : 380, + height : 370, + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register buttons + ed.addButton('cite', {title : 'xhtmlxtras.cite_desc', cmd : 'mceCite'}); + ed.addButton('acronym', {title : 'xhtmlxtras.acronym_desc', cmd : 'mceAcronym'}); + ed.addButton('abbr', {title : 'xhtmlxtras.abbr_desc', cmd : 'mceAbbr'}); + ed.addButton('del', {title : 'xhtmlxtras.del_desc', cmd : 'mceDel'}); + ed.addButton('ins', {title : 'xhtmlxtras.ins_desc', cmd : 'mceIns'}); + ed.addButton('attribs', {title : 'xhtmlxtras.attribs_desc', cmd : 'mceAttributes'}); + + ed.onNodeChange.add(function(ed, cm, n, co) { + n = ed.dom.getParent(n, 'CITE,ACRONYM,ABBR,DEL,INS'); + + cm.setDisabled('cite', co); + cm.setDisabled('acronym', co); + cm.setDisabled('abbr', co); + cm.setDisabled('del', co); + cm.setDisabled('ins', co); + cm.setDisabled('attribs', n && n.nodeName == 'BODY'); + cm.setActive('cite', 0); + cm.setActive('acronym', 0); + cm.setActive('abbr', 0); + cm.setActive('del', 0); + cm.setActive('ins', 0); + + // Activate all + if (n) { + do { + cm.setDisabled(n.nodeName.toLowerCase(), 0); + cm.setActive(n.nodeName.toLowerCase(), 1); + } while (n = n.parentNode); + } + }); + + ed.onPreInit.add(function() { + // Fixed IE issue where it can't handle these elements correctly + ed.dom.create('abbr'); + }); + }, + + getInfo : function() { + return { + longname : 'XHTML Xtras Plugin', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('xhtmlxtras', tinymce.plugins.XHTMLXtrasPlugin); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/plugins/xhtmlxtras/ins.htm b/tools/tiny_mce/plugins/xhtmlxtras/ins.htm new file mode 100644 index 00000000..1fd668a8 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/ins.htm @@ -0,0 +1,162 @@ + + + + {#xhtmlxtras_dlg.title_ins_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_general_tab} + + + + + + + + + +
    : + + + + + +
    +
    :
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    + + + +
    +
    + + diff --git a/tools/tiny_mce/plugins/xhtmlxtras/js/abbr.js b/tools/tiny_mce/plugins/xhtmlxtras/js/abbr.js new file mode 100644 index 00000000..1790e83d --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/js/abbr.js @@ -0,0 +1,28 @@ +/** + * abbr.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +function init() { + SXE.initElementDialog('abbr'); + if (SXE.currentAction == "update") { + SXE.showRemoveButton(); + } +} + +function insertAbbr() { + SXE.insertElement('abbr'); + tinyMCEPopup.close(); +} + +function removeAbbr() { + SXE.removeElement('abbr'); + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); diff --git a/tools/tiny_mce/plugins/xhtmlxtras/js/acronym.js b/tools/tiny_mce/plugins/xhtmlxtras/js/acronym.js new file mode 100644 index 00000000..93b8d259 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/js/acronym.js @@ -0,0 +1,28 @@ +/** + * acronym.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +function init() { + SXE.initElementDialog('acronym'); + if (SXE.currentAction == "update") { + SXE.showRemoveButton(); + } +} + +function insertAcronym() { + SXE.insertElement('acronym'); + tinyMCEPopup.close(); +} + +function removeAcronym() { + SXE.removeElement('acronym'); + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); diff --git a/tools/tiny_mce/plugins/xhtmlxtras/js/attributes.js b/tools/tiny_mce/plugins/xhtmlxtras/js/attributes.js new file mode 100644 index 00000000..c7e0e7fc --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/js/attributes.js @@ -0,0 +1,126 @@ +/** + * attributes.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +function init() { + tinyMCEPopup.resizeToInnerSize(); + var inst = tinyMCEPopup.editor; + var dom = inst.dom; + var elm = inst.selection.getNode(); + var f = document.forms[0]; + var onclick = dom.getAttrib(elm, 'onclick'); + + setFormValue('title', dom.getAttrib(elm, 'title')); + setFormValue('id', dom.getAttrib(elm, 'id')); + setFormValue('style', dom.getAttrib(elm, "style")); + setFormValue('dir', dom.getAttrib(elm, 'dir')); + setFormValue('lang', dom.getAttrib(elm, 'lang')); + setFormValue('tabindex', dom.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : "")); + setFormValue('accesskey', dom.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : "")); + setFormValue('onfocus', dom.getAttrib(elm, 'onfocus')); + setFormValue('onblur', dom.getAttrib(elm, 'onblur')); + setFormValue('onclick', onclick); + setFormValue('ondblclick', dom.getAttrib(elm, 'ondblclick')); + setFormValue('onmousedown', dom.getAttrib(elm, 'onmousedown')); + setFormValue('onmouseup', dom.getAttrib(elm, 'onmouseup')); + setFormValue('onmouseover', dom.getAttrib(elm, 'onmouseover')); + setFormValue('onmousemove', dom.getAttrib(elm, 'onmousemove')); + setFormValue('onmouseout', dom.getAttrib(elm, 'onmouseout')); + setFormValue('onkeypress', dom.getAttrib(elm, 'onkeypress')); + setFormValue('onkeydown', dom.getAttrib(elm, 'onkeydown')); + setFormValue('onkeyup', dom.getAttrib(elm, 'onkeyup')); + className = dom.getAttrib(elm, 'class'); + + addClassesToList('classlist', 'advlink_styles'); + selectByValue(f, 'classlist', className, true); + + TinyMCE_EditableSelects.init(); +} + +function setFormValue(name, value) { + if(value && document.forms[0].elements[name]){ + document.forms[0].elements[name].value = value; + } +} + +function insertAction() { + var inst = tinyMCEPopup.editor; + var elm = inst.selection.getNode(); + + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + setAllAttribs(elm); + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); +} + +function setAttrib(elm, attrib, value) { + var formObj = document.forms[0]; + var valueElm = formObj.elements[attrib.toLowerCase()]; + var inst = tinyMCEPopup.editor; + var dom = inst.dom; + + if (typeof(value) == "undefined" || value == null) { + value = ""; + + if (valueElm) + value = valueElm.value; + } + + if (value != "") { + dom.setAttrib(elm, attrib.toLowerCase(), value); + + if (attrib == "style") + attrib = "style.cssText"; + + if (attrib.substring(0, 2) == 'on') + value = 'return true;' + value; + + if (attrib == "class") + attrib = "className"; + + elm[attrib]=value; + } else + elm.removeAttribute(attrib); +} + +function setAllAttribs(elm) { + var f = document.forms[0]; + + setAttrib(elm, 'title'); + setAttrib(elm, 'id'); + setAttrib(elm, 'style'); + setAttrib(elm, 'class', getSelectValue(f, 'classlist')); + setAttrib(elm, 'dir'); + setAttrib(elm, 'lang'); + setAttrib(elm, 'tabindex'); + setAttrib(elm, 'accesskey'); + setAttrib(elm, 'onfocus'); + setAttrib(elm, 'onblur'); + setAttrib(elm, 'onclick'); + setAttrib(elm, 'ondblclick'); + setAttrib(elm, 'onmousedown'); + setAttrib(elm, 'onmouseup'); + setAttrib(elm, 'onmouseover'); + setAttrib(elm, 'onmousemove'); + setAttrib(elm, 'onmouseout'); + setAttrib(elm, 'onkeypress'); + setAttrib(elm, 'onkeydown'); + setAttrib(elm, 'onkeyup'); + + // Refresh in old MSIE +// if (tinyMCE.isMSIE5) +// elm.outerHTML = elm.outerHTML; +} + +function insertAttribute() { + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); +tinyMCEPopup.requireLangPack(); diff --git a/tools/tiny_mce/plugins/xhtmlxtras/js/cite.js b/tools/tiny_mce/plugins/xhtmlxtras/js/cite.js new file mode 100644 index 00000000..b73ef473 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/js/cite.js @@ -0,0 +1,28 @@ +/** + * cite.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +function init() { + SXE.initElementDialog('cite'); + if (SXE.currentAction == "update") { + SXE.showRemoveButton(); + } +} + +function insertCite() { + SXE.insertElement('cite'); + tinyMCEPopup.close(); +} + +function removeCite() { + SXE.removeElement('cite'); + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); diff --git a/tools/tiny_mce/plugins/xhtmlxtras/js/del.js b/tools/tiny_mce/plugins/xhtmlxtras/js/del.js new file mode 100644 index 00000000..74e52925 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/js/del.js @@ -0,0 +1,53 @@ +/** + * del.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +function init() { + SXE.initElementDialog('del'); + if (SXE.currentAction == "update") { + setFormValue('datetime', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'datetime')); + setFormValue('cite', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'cite')); + SXE.showRemoveButton(); + } +} + +function setElementAttribs(elm) { + setAllCommonAttribs(elm); + setAttrib(elm, 'datetime'); + setAttrib(elm, 'cite'); +} + +function insertDel() { + var elm = tinyMCEPopup.editor.dom.getParent(SXE.focusElement, 'DEL'); + + tinyMCEPopup.execCommand('mceBeginUndoLevel'); + if (elm == null) { + var s = SXE.inst.selection.getContent(); + if(s.length > 0) { + insertInlineElement('del'); + var elementArray = tinymce.grep(SXE.inst.dom.select('del'), function(n) {return n.id == '#sxe_temp_del#';}); + for (var i=0; i 0) { + tagName = element_name; + + insertInlineElement(element_name); + var elementArray = tinymce.grep(SXE.inst.dom.select(element_name)); + for (var i=0; i -1) ? true : false; +} + +SXE.removeClass = function(elm,cl) { + if(elm.className == null || elm.className == "" || !SXE.containsClass(elm,cl)) { + return true; + } + var classNames = elm.className.split(" "); + var newClassNames = ""; + for (var x = 0, cnl = classNames.length; x < cnl; x++) { + if (classNames[x] != cl) { + newClassNames += (classNames[x] + " "); + } + } + elm.className = newClassNames.substring(0,newClassNames.length-1); //removes extra space at the end +} + +SXE.addClass = function(elm,cl) { + if(!SXE.containsClass(elm,cl)) elm.className ? elm.className += " " + cl : elm.className = cl; + return true; +} + +function insertInlineElement(en) { + var ed = tinyMCEPopup.editor, dom = ed.dom; + + ed.getDoc().execCommand('FontName', false, 'mceinline'); + tinymce.each(dom.select('span,font'), function(n) { + if (n.style.fontFamily == 'mceinline' || n.face == 'mceinline') + dom.replace(dom.create(en, {_mce_new : 1}), n, 1); + }); +} diff --git a/tools/tiny_mce/plugins/xhtmlxtras/js/ins.js b/tools/tiny_mce/plugins/xhtmlxtras/js/ins.js new file mode 100644 index 00000000..8ec84422 --- /dev/null +++ b/tools/tiny_mce/plugins/xhtmlxtras/js/ins.js @@ -0,0 +1,52 @@ +/** + * ins.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +function init() { + SXE.initElementDialog('ins'); + if (SXE.currentAction == "update") { + setFormValue('datetime', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'datetime')); + setFormValue('cite', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'cite')); + SXE.showRemoveButton(); + } +} + +function setElementAttribs(elm) { + setAllCommonAttribs(elm); + setAttrib(elm, 'datetime'); + setAttrib(elm, 'cite'); +} + +function insertIns() { + var elm = tinyMCEPopup.editor.dom.getParent(SXE.focusElement, 'INS'); + tinyMCEPopup.execCommand('mceBeginUndoLevel'); + if (elm == null) { + var s = SXE.inst.selection.getContent(); + if(s.length > 0) { + insertInlineElement('INS'); + var elementArray = tinymce.grep(SXE.inst.dom.select('ins'), function(n) {return n.id == '#sxe_temp_ins#';}); + for (var i=0; i + + + {#advanced_dlg.about_title} + + + + + + + +
    +
    +

    {#advanced_dlg.about_title}

    +

    Version: ()

    +

    TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under LGPL + by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.

    +

    Copyright © 2003-2011, Moxiecode Systems AB, All rights reserved.

    +

    For more information about this software visit the TinyMCE website.

    +
    + +
    +
    +

    {#advanced_dlg.about_loaded}

    + +
    +
    + +

     

    +
    +
    + +
    +
    +
    +
    + +
    + +
    + + diff --git a/tools/tiny_mce/themes/advanced/anchor.htm b/tools/tiny_mce/themes/advanced/anchor.htm new file mode 100644 index 00000000..dc53312d --- /dev/null +++ b/tools/tiny_mce/themes/advanced/anchor.htm @@ -0,0 +1,26 @@ + + + + {#advanced_dlg.anchor_title} + + + + +
    + + + + + + + + +
    {#advanced_dlg.anchor_title}
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/themes/advanced/charmap.htm b/tools/tiny_mce/themes/advanced/charmap.htm new file mode 100644 index 00000000..8b7de8b8 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/charmap.htm @@ -0,0 +1,53 @@ + + + + {#advanced_dlg.charmap_title} + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
     
     
    +
    + + + + + + + + + + + + + + + + +
     
     
     
    +
    + + + diff --git a/tools/tiny_mce/themes/advanced/color_picker.htm b/tools/tiny_mce/themes/advanced/color_picker.htm new file mode 100644 index 00000000..e7f19aba --- /dev/null +++ b/tools/tiny_mce/themes/advanced/color_picker.htm @@ -0,0 +1,74 @@ + + + + {#advanced_dlg.colorpicker_title} + + + + + + +
    + + +
    +
    +
    + {#advanced_dlg.colorpicker_picker_title} +
    + + +
    + +
    + +
    +
    +
    +
    + +
    +
    + {#advanced_dlg.colorpicker_palette_title} +
    + +
    + +
    +
    +
    + +
    +
    + {#advanced_dlg.colorpicker_named_title} +
    + +
    + +
    + +
    + {#advanced_dlg.colorpicker_name} +
    +
    +
    +
    + +
    + + +
    + +
    + +
    +
    +
    + + diff --git a/tools/tiny_mce/themes/advanced/editor_template.js b/tools/tiny_mce/themes/advanced/editor_template.js new file mode 100644 index 00000000..325471ab --- /dev/null +++ b/tools/tiny_mce/themes/advanced/editor_template.js @@ -0,0 +1 @@ +(function(e){var d=e.DOM,b=e.dom.Event,h=e.extend,f=e.each,a=e.util.Cookie,g,c=e.explode;e.ThemeManager.requireLangPack("advanced");e.create("tinymce.themes.AdvancedTheme",{sizes:[8,10,12,14,18,24,36],controls:{bold:["bold_desc","Bold"],italic:["italic_desc","Italic"],underline:["underline_desc","Underline"],strikethrough:["striketrough_desc","Strikethrough"],justifyleft:["justifyleft_desc","JustifyLeft"],justifycenter:["justifycenter_desc","JustifyCenter"],justifyright:["justifyright_desc","JustifyRight"],justifyfull:["justifyfull_desc","JustifyFull"],bullist:["bullist_desc","InsertUnorderedList"],numlist:["numlist_desc","InsertOrderedList"],outdent:["outdent_desc","Outdent"],indent:["indent_desc","Indent"],cut:["cut_desc","Cut"],copy:["copy_desc","Copy"],paste:["paste_desc","Paste"],undo:["undo_desc","Undo"],redo:["redo_desc","Redo"],link:["link_desc","mceLink"],unlink:["unlink_desc","unlink"],image:["image_desc","mceImage"],cleanup:["cleanup_desc","mceCleanup"],help:["help_desc","mceHelp"],shortcuts:["shortcuts_desc","mceShortcuts"],code:["code_desc","mceCodeEditor"],hr:["hr_desc","InsertHorizontalRule"],removeformat:["removeformat_desc","RemoveFormat"],sub:["sub_desc","subscript"],sup:["sup_desc","superscript"],forecolor:["forecolor_desc","ForeColor"],forecolorpicker:["forecolor_desc","mceForeColor"],backcolor:["backcolor_desc","HiliteColor"],backcolorpicker:["backcolor_desc","mceBackColor"],charmap:["charmap_desc","mceCharMap"],visualaid:["visualaid_desc","mceToggleVisualAid"],anchor:["anchor_desc","mceInsertAnchor"],newdocument:["newdocument_desc","mceNewDocument"],blockquote:["blockquote_desc","mceBlockQuote"]},stateControls:["bold","italic","underline","strikethrough","bullist","numlist","justifyleft","justifycenter","justifyright","justifyfull","sub","sup","blockquote"],init:function(j,k){var l=this,m,i,n;l.editor=j;l.url=k;l.onResolveName=new e.util.Dispatcher(this);j.forcedHighContrastMode=j.settings.detect_highcontrast&&l._isHighContrast();j.settings.skin=j.forcedHighContrastMode?"highcontrast":j.settings.skin;l.settings=m=h({theme_advanced_path:true,theme_advanced_toolbar_location:"bottom",theme_advanced_buttons1:"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect",theme_advanced_buttons2:"bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code",theme_advanced_buttons3:"hr,removeformat,visualaid,|,sub,sup,|,charmap",theme_advanced_blockformats:"p,address,pre,h1,h2,h3,h4,h5,h6",theme_advanced_toolbar_align:"center",theme_advanced_fonts:"Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",theme_advanced_more_colors:1,theme_advanced_row_height:23,theme_advanced_resize_horizontal:1,theme_advanced_resizing_use_cookie:1,theme_advanced_font_sizes:"1,2,3,4,5,6,7",theme_advanced_font_selector:"span",theme_advanced_show_current_color:0,readonly:j.settings.readonly},j.settings);if(!m.font_size_style_values){m.font_size_style_values="8pt,10pt,12pt,14pt,18pt,24pt,36pt"}if(e.is(m.theme_advanced_font_sizes,"string")){m.font_size_style_values=e.explode(m.font_size_style_values);m.font_size_classes=e.explode(m.font_size_classes||"");n={};j.settings.theme_advanced_font_sizes=m.theme_advanced_font_sizes;f(j.getParam("theme_advanced_font_sizes","","hash"),function(q,p){var o;if(p==q&&q>=1&&q<=7){p=q+" ("+l.sizes[q-1]+"pt)";o=m.font_size_classes[q-1];q=m.font_size_style_values[q-1]||(l.sizes[q-1]+"pt")}if(/^\s*\./.test(q)){o=q.replace(/\./g,"")}n[p]=o?{"class":o}:{fontSize:q}});m.theme_advanced_font_sizes=n}if((i=m.theme_advanced_path_location)&&i!="none"){m.theme_advanced_statusbar_location=m.theme_advanced_path_location}if(m.theme_advanced_statusbar_location=="none"){m.theme_advanced_statusbar_location=0}j.onInit.add(function(){if(!j.settings.readonly){j.onNodeChange.add(l._nodeChanged,l);j.onKeyUp.add(l._updateUndoStatus,l);j.onMouseUp.add(l._updateUndoStatus,l);j.dom.bind(j.dom.getRoot(),"dragend",function(){l._updateUndoStatus(j)})}if(j.settings.content_css!==false){j.dom.loadCSS(j.baseURI.toAbsolute(k+"/skins/"+j.settings.skin+"/content.css"))}});j.onSetProgressState.add(function(q,o,r){var s,t=q.id,p;if(o){l.progressTimer=setTimeout(function(){s=q.getContainer();s=s.insertBefore(d.create("DIV",{style:"position:relative"}),s.firstChild);p=d.get(q.id+"_tbl");d.add(s,"div",{id:t+"_blocker","class":"mceBlocker",style:{width:p.clientWidth+2,height:p.clientHeight+2}});d.add(s,"div",{id:t+"_progress","class":"mceProgress",style:{left:p.clientWidth/2,top:p.clientHeight/2}})},r||0)}else{d.remove(t+"_blocker");d.remove(t+"_progress");clearTimeout(l.progressTimer)}});d.loadCSS(m.editor_css?j.documentBaseURI.toAbsolute(m.editor_css):k+"/skins/"+j.settings.skin+"/ui.css");if(m.skin_variant){d.loadCSS(k+"/skins/"+j.settings.skin+"/ui_"+m.skin_variant+".css")}},_isHighContrast:function(){var i,j=d.add(d.getRoot(),"div",{style:"background-color: rgb(171,239,86);"});i=(d.getStyle(j,"background-color",true)+"").toLowerCase().replace(/ /g,"");d.remove(j);return i!="rgb(171,239,86)"&&i!="#abef56"},createControl:function(l,i){var j,k;if(k=i.createControl(l)){return k}switch(l){case"styleselect":return this._createStyleSelect();case"formatselect":return this._createBlockFormats();case"fontselect":return this._createFontSelect();case"fontsizeselect":return this._createFontSizeSelect();case"forecolor":return this._createForeColorMenu();case"backcolor":return this._createBackColorMenu()}if((j=this.controls[l])){return i.createButton(l,{title:"advanced."+j[0],cmd:j[1],ui:j[2],value:j[3]})}},execCommand:function(k,j,l){var i=this["_"+k];if(i){i.call(this,j,l);return true}return false},_importClasses:function(k){var i=this.editor,j=i.controlManager.get("styleselect");if(j.getLength()==0){f(i.dom.getClasses(),function(n,l){var m="style_"+l;i.formatter.register(m,{inline:"span",attributes:{"class":n["class"]},selector:"*"});j.add(n["class"],m)})}},_createStyleSelect:function(m){var k=this,i=k.editor,j=i.controlManager,l;l=j.createListBox("styleselect",{title:"advanced.style_select",onselect:function(o){var p,n=[];f(l.items,function(q){n.push(q.value)});i.focus();i.undoManager.add();p=i.formatter.matchAll(n);if(!o||p[0]==o){i.formatter.remove(p[0])}else{i.formatter.apply(o)}i.undoManager.add();i.nodeChanged();return false}});i.onInit.add(function(){var o=0,n=i.getParam("style_formats");if(n){f(n,function(p){var q,r=0;f(p,function(){r++});if(r>1){q=p.name=p.name||"style_"+(o++);i.formatter.register(q,p);l.add(p.title,q)}else{l.add(p.title)}})}else{f(i.getParam("theme_advanced_styles","","hash"),function(r,q){var p;if(r){p="style_"+(o++);i.formatter.register(p,{inline:"span",classes:r,selector:"*"});l.add(k.editor.translate(q),p)}})}});if(l.getLength()==0){l.onPostRender.add(function(o,p){if(!l.NativeListBox){b.add(p.id+"_text","focus",k._importClasses,k);b.add(p.id+"_text","mousedown",k._importClasses,k);b.add(p.id+"_open","focus",k._importClasses,k);b.add(p.id+"_open","mousedown",k._importClasses,k)}else{b.add(p.id,"focus",k._importClasses,k)}})}return l},_createFontSelect:function(){var k,j=this,i=j.editor;k=i.controlManager.createListBox("fontselect",{title:"advanced.fontdefault",onselect:function(l){var m=k.items[k.selectedIndex];if(!l&&m){i.execCommand("FontName",false,m.value);return}i.execCommand("FontName",false,l);k.select(function(n){return l==n});return false}});if(k){f(i.getParam("theme_advanced_fonts",j.settings.theme_advanced_fonts,"hash"),function(m,l){k.add(i.translate(l),m,{style:m.indexOf("dings")==-1?"font-family:"+m:""})})}return k},_createFontSizeSelect:function(){var m=this,k=m.editor,n,l=0,j=[];n=k.controlManager.createListBox("fontsizeselect",{title:"advanced.font_size",onselect:function(i){var o=n.items[n.selectedIndex];if(!i&&o){o=o.value;if(o["class"]){k.formatter.toggle("fontsize_class",{value:o["class"]});k.undoManager.add();k.nodeChanged()}else{k.execCommand("FontSize",false,o.fontSize)}return}if(i["class"]){k.focus();k.undoManager.add();k.formatter.toggle("fontsize_class",{value:i["class"]});k.undoManager.add();k.nodeChanged()}else{k.execCommand("FontSize",false,i.fontSize)}n.select(function(p){return i==p});return false}});if(n){f(m.settings.theme_advanced_font_sizes,function(o,i){var p=o.fontSize;if(p>=1&&p<=7){p=m.sizes[parseInt(p)-1]+"pt"}n.add(i,o,{style:"font-size:"+p,"class":"mceFontSize"+(l++)+(" "+(o["class"]||""))})})}return n},_createBlockFormats:function(){var k,i={p:"advanced.paragraph",address:"advanced.address",pre:"advanced.pre",h1:"advanced.h1",h2:"advanced.h2",h3:"advanced.h3",h4:"advanced.h4",h5:"advanced.h5",h6:"advanced.h6",div:"advanced.div",blockquote:"advanced.blockquote",code:"advanced.code",dt:"advanced.dt",dd:"advanced.dd",samp:"advanced.samp"},j=this;k=j.editor.controlManager.createListBox("formatselect",{title:"advanced.block",cmd:"FormatBlock"});if(k){f(j.editor.getParam("theme_advanced_blockformats",j.settings.theme_advanced_blockformats,"hash"),function(m,l){k.add(j.editor.translate(l!=m?l:i[m]),m,{"class":"mce_formatPreview mce_"+m})})}return k},_createForeColorMenu:function(){var m,j=this,k=j.settings,l={},i;if(k.theme_advanced_more_colors){l.more_colors_func=function(){j._mceColorPicker(0,{color:m.value,func:function(n){m.setColor(n)}})}}if(i=k.theme_advanced_text_colors){l.colors=i}if(k.theme_advanced_default_foreground_color){l.default_color=k.theme_advanced_default_foreground_color}l.title="advanced.forecolor_desc";l.cmd="ForeColor";l.scope=this;m=j.editor.controlManager.createColorSplitButton("forecolor",l);return m},_createBackColorMenu:function(){var m,j=this,k=j.settings,l={},i;if(k.theme_advanced_more_colors){l.more_colors_func=function(){j._mceColorPicker(0,{color:m.value,func:function(n){m.setColor(n)}})}}if(i=k.theme_advanced_background_colors){l.colors=i}if(k.theme_advanced_default_background_color){l.default_color=k.theme_advanced_default_background_color}l.title="advanced.backcolor_desc";l.cmd="HiliteColor";l.scope=this;m=j.editor.controlManager.createColorSplitButton("backcolor",l);return m},renderUI:function(k){var m,l,q,v=this,r=v.editor,w=v.settings,u,j,i;if(r.settings){r.settings.aria_label=w.aria_label+r.getLang("advanced.help_shortcut")}m=j=d.create("span",{role:"application","aria-labelledby":r.id+"_voice",id:r.id+"_parent","class":"mceEditor "+r.settings.skin+"Skin"+(w.skin_variant?" "+r.settings.skin+"Skin"+v._ufirst(w.skin_variant):"")});d.add(m,"span",{"class":"mceVoiceLabel",style:"display:none;",id:r.id+"_voice"},w.aria_label);if(!d.boxModel){m=d.add(m,"div",{"class":"mceOldBoxModel"})}m=u=d.add(m,"table",{role:"presentation",id:r.id+"_tbl","class":"mceLayout",cellSpacing:0,cellPadding:0});m=q=d.add(m,"tbody");switch((w.theme_advanced_layout_manager||"").toLowerCase()){case"rowlayout":l=v._rowLayout(w,q,k);break;case"customlayout":l=r.execCallback("theme_advanced_custom_layout",w,q,k,j);break;default:l=v._simpleLayout(w,q,k,j)}m=k.targetNode;i=d.stdMode?u.getElementsByTagName("tr"):u.rows;d.addClass(i[0],"mceFirst");d.addClass(i[i.length-1],"mceLast");f(d.select("tr",q),function(o){d.addClass(o.firstChild,"mceFirst");d.addClass(o.childNodes[o.childNodes.length-1],"mceLast")});if(d.get(w.theme_advanced_toolbar_container)){d.get(w.theme_advanced_toolbar_container).appendChild(j)}else{d.insertAfter(j,m)}b.add(r.id+"_path_row","click",function(n){n=n.target;if(n.nodeName=="A"){v._sel(n.className.replace(/^.*mcePath_([0-9]+).*$/,"$1"));return b.cancel(n)}});if(w.theme_advanced_toolbar_location=="external"){k.deltaHeight=0}v.deltaHeight=k.deltaHeight;k.targetNode=null;r.onKeyDown.add(function(p,n){var s=121,o=122;if(n.altKey){if(n.keyCode===s){v.toolbarGroup.focus();return b.cancel(n)}else{if(n.keyCode===o){d.get(p.id+"_path_row").focus();return b.cancel(n)}}}});r.addShortcut("alt+0","","mceShortcuts",v);return{iframeContainer:l,editorContainer:r.id+"_parent",sizeContainer:u,deltaHeight:k.deltaHeight}},getInfo:function(){return{longname:"Advanced theme",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",version:e.majorVersion+"."+e.minorVersion}},resizeBy:function(i,j){var k=d.get(this.editor.id+"_tbl");this.resizeTo(k.clientWidth+i,k.clientHeight+j)},resizeTo:function(i,m,k){var j=this.editor,l=this.settings,n=d.get(j.id+"_tbl"),o=d.get(j.id+"_ifr");i=Math.max(l.theme_advanced_resizing_min_width||100,i);m=Math.max(l.theme_advanced_resizing_min_height||100,m);i=Math.min(l.theme_advanced_resizing_max_width||65535,i);m=Math.min(l.theme_advanced_resizing_max_height||65535,m);d.setStyle(n,"height","");d.setStyle(o,"height",m);if(l.theme_advanced_resize_horizontal){d.setStyle(n,"width","");d.setStyle(o,"width",i);if(i0){y.statusKeyboardNavigation=new e.ui.KeyboardNavigation({root:m.id+"_path_row",items:d.select("a",C),excludeFromTabOrder:true,onCancel:function(){m.focus()}},d)}}},_sel:function(i){this.editor.execCommand("mceSelectNodeDepth",false,i)},_mceInsertAnchor:function(k,j){var i=this.editor;i.windowManager.open({url:this.url+"/anchor.htm",width:320+parseInt(i.getLang("advanced.anchor_delta_width",0)),height:90+parseInt(i.getLang("advanced.anchor_delta_height",0)),inline:true},{theme_url:this.url})},_mceCharMap:function(){var i=this.editor;i.windowManager.open({url:this.url+"/charmap.htm",width:550+parseInt(i.getLang("advanced.charmap_delta_width",0)),height:250+parseInt(i.getLang("advanced.charmap_delta_height",0)),inline:true},{theme_url:this.url})},_mceHelp:function(){var i=this.editor;i.windowManager.open({url:this.url+"/about.htm",width:480,height:380,inline:true},{theme_url:this.url})},_mceShortcuts:function(){var i=this.editor;i.windowManager.open({url:this.url+"/shortcuts.htm",width:480,height:380,inline:true},{theme_url:this.url})},_mceColorPicker:function(k,j){var i=this.editor;j=j||{};i.windowManager.open({url:this.url+"/color_picker.htm",width:375+parseInt(i.getLang("advanced.colorpicker_delta_width",0)),height:250+parseInt(i.getLang("advanced.colorpicker_delta_height",0)),close_previous:false,inline:true},{input_color:j.color,func:j.func,theme_url:this.url})},_mceCodeEditor:function(j,k){var i=this.editor;i.windowManager.open({url:this.url+"/source_editor.htm",width:parseInt(i.getParam("theme_advanced_source_editor_width",720)),height:parseInt(i.getParam("theme_advanced_source_editor_height",580)),inline:true,resizable:true,maximizable:true},{theme_url:this.url})},_mceImage:function(j,k){var i=this.editor;if(i.dom.getAttrib(i.selection.getNode(),"class").indexOf("mceItem")!=-1){return}i.windowManager.open({url:this.url+"/image.htm",width:355+parseInt(i.getLang("advanced.image_delta_width",0)),height:275+parseInt(i.getLang("advanced.image_delta_height",0)),inline:true},{theme_url:this.url})},_mceLink:function(j,k){var i=this.editor;i.windowManager.open({url:this.url+"/link.htm",width:310+parseInt(i.getLang("advanced.link_delta_width",0)),height:200+parseInt(i.getLang("advanced.link_delta_height",0)),inline:true},{theme_url:this.url})},_mceNewDocument:function(){var i=this.editor;i.windowManager.confirm("advanced.newdocument",function(j){if(j){i.execCommand("mceSetContent",false,"")}})},_mceForeColor:function(){var i=this;this._mceColorPicker(0,{color:i.fgColor,func:function(j){i.fgColor=j;i.editor.execCommand("ForeColor",false,j)}})},_mceBackColor:function(){var i=this;this._mceColorPicker(0,{color:i.bgColor,func:function(j){i.bgColor=j;i.editor.execCommand("HiliteColor",false,j)}})},_ufirst:function(i){return i.substring(0,1).toUpperCase()+i.substring(1)}});e.ThemeManager.add("advanced",e.themes.AdvancedTheme)}(tinymce)); \ No newline at end of file diff --git a/tools/tiny_mce/themes/advanced/editor_template_src.js b/tools/tiny_mce/themes/advanced/editor_template_src.js new file mode 100644 index 00000000..1fb08097 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/editor_template_src.js @@ -0,0 +1,1326 @@ +/** + * editor_template_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function(tinymce) { + var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode; + + // Tell it to load theme specific language pack(s) + tinymce.ThemeManager.requireLangPack('advanced'); + + tinymce.create('tinymce.themes.AdvancedTheme', { + sizes : [8, 10, 12, 14, 18, 24, 36], + + // Control name lookup, format: title, command + controls : { + bold : ['bold_desc', 'Bold'], + italic : ['italic_desc', 'Italic'], + underline : ['underline_desc', 'Underline'], + strikethrough : ['striketrough_desc', 'Strikethrough'], + justifyleft : ['justifyleft_desc', 'JustifyLeft'], + justifycenter : ['justifycenter_desc', 'JustifyCenter'], + justifyright : ['justifyright_desc', 'JustifyRight'], + justifyfull : ['justifyfull_desc', 'JustifyFull'], + bullist : ['bullist_desc', 'InsertUnorderedList'], + numlist : ['numlist_desc', 'InsertOrderedList'], + outdent : ['outdent_desc', 'Outdent'], + indent : ['indent_desc', 'Indent'], + cut : ['cut_desc', 'Cut'], + copy : ['copy_desc', 'Copy'], + paste : ['paste_desc', 'Paste'], + undo : ['undo_desc', 'Undo'], + redo : ['redo_desc', 'Redo'], + link : ['link_desc', 'mceLink'], + unlink : ['unlink_desc', 'unlink'], + image : ['image_desc', 'mceImage'], + cleanup : ['cleanup_desc', 'mceCleanup'], + help : ['help_desc', 'mceHelp'], + shortcuts : ['shortcuts_desc', 'mceShortcuts'], + code : ['code_desc', 'mceCodeEditor'], + hr : ['hr_desc', 'InsertHorizontalRule'], + removeformat : ['removeformat_desc', 'RemoveFormat'], + sub : ['sub_desc', 'subscript'], + sup : ['sup_desc', 'superscript'], + forecolor : ['forecolor_desc', 'ForeColor'], + forecolorpicker : ['forecolor_desc', 'mceForeColor'], + backcolor : ['backcolor_desc', 'HiliteColor'], + backcolorpicker : ['backcolor_desc', 'mceBackColor'], + charmap : ['charmap_desc', 'mceCharMap'], + visualaid : ['visualaid_desc', 'mceToggleVisualAid'], + anchor : ['anchor_desc', 'mceInsertAnchor'], + newdocument : ['newdocument_desc', 'mceNewDocument'], + blockquote : ['blockquote_desc', 'mceBlockQuote'] + }, + + stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'], + + init : function(ed, url) { + var t = this, s, v, o; + + t.editor = ed; + t.url = url; + t.onResolveName = new tinymce.util.Dispatcher(this); + + ed.forcedHighContrastMode = ed.settings.detect_highcontrast && t._isHighContrast(); + ed.settings.skin = ed.forcedHighContrastMode ? 'highcontrast' : ed.settings.skin; + + // Default settings + t.settings = s = extend({ + theme_advanced_path : true, + theme_advanced_toolbar_location : 'bottom', + theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect", + theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code", + theme_advanced_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap", + theme_advanced_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6", + theme_advanced_toolbar_align : "center", + theme_advanced_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats", + theme_advanced_more_colors : 1, + theme_advanced_row_height : 23, + theme_advanced_resize_horizontal : 1, + theme_advanced_resizing_use_cookie : 1, + theme_advanced_font_sizes : "1,2,3,4,5,6,7", + theme_advanced_font_selector : "span", + theme_advanced_show_current_color: 0, + readonly : ed.settings.readonly + }, ed.settings); + + // Setup default font_size_style_values + if (!s.font_size_style_values) + s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt"; + + if (tinymce.is(s.theme_advanced_font_sizes, 'string')) { + s.font_size_style_values = tinymce.explode(s.font_size_style_values); + s.font_size_classes = tinymce.explode(s.font_size_classes || ''); + + // Parse string value + o = {}; + ed.settings.theme_advanced_font_sizes = s.theme_advanced_font_sizes; + each(ed.getParam('theme_advanced_font_sizes', '', 'hash'), function(v, k) { + var cl; + + if (k == v && v >= 1 && v <= 7) { + k = v + ' (' + t.sizes[v - 1] + 'pt)'; + cl = s.font_size_classes[v - 1]; + v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt'); + } + + if (/^\s*\./.test(v)) + cl = v.replace(/\./g, ''); + + o[k] = cl ? {'class' : cl} : {fontSize : v}; + }); + + s.theme_advanced_font_sizes = o; + } + + if ((v = s.theme_advanced_path_location) && v != 'none') + s.theme_advanced_statusbar_location = s.theme_advanced_path_location; + + if (s.theme_advanced_statusbar_location == 'none') + s.theme_advanced_statusbar_location = 0; + + // Init editor + ed.onInit.add(function() { + if (!ed.settings.readonly) { + ed.onNodeChange.add(t._nodeChanged, t); + ed.onKeyUp.add(t._updateUndoStatus, t); + ed.onMouseUp.add(t._updateUndoStatus, t); + ed.dom.bind(ed.dom.getRoot(), 'dragend', function() { + t._updateUndoStatus(ed); + }); + } + + if (ed.settings.content_css !== false) + ed.dom.loadCSS(ed.baseURI.toAbsolute(url + "/skins/" + ed.settings.skin + "/content.css")); + }); + + ed.onSetProgressState.add(function(ed, b, ti) { + var co, id = ed.id, tb; + + if (b) { + t.progressTimer = setTimeout(function() { + co = ed.getContainer(); + co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild); + tb = DOM.get(ed.id + '_tbl'); + + DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}}); + DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}}); + }, ti || 0); + } else { + DOM.remove(id + '_blocker'); + DOM.remove(id + '_progress'); + clearTimeout(t.progressTimer); + } + }); + + DOM.loadCSS(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css"); + + if (s.skin_variant) + DOM.loadCSS(url + "/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css"); + }, + + _isHighContrast : function() { + var actualColor, div = DOM.add(DOM.getRoot(), 'div', {'style': 'background-color: rgb(171,239,86);'}); + + actualColor = (DOM.getStyle(div, 'background-color', true) + '').toLowerCase().replace(/ /g, ''); + DOM.remove(div); + + return actualColor != 'rgb(171,239,86)' && actualColor != '#abef56'; + }, + + createControl : function(n, cf) { + var cd, c; + + if (c = cf.createControl(n)) + return c; + + switch (n) { + case "styleselect": + return this._createStyleSelect(); + + case "formatselect": + return this._createBlockFormats(); + + case "fontselect": + return this._createFontSelect(); + + case "fontsizeselect": + return this._createFontSizeSelect(); + + case "forecolor": + return this._createForeColorMenu(); + + case "backcolor": + return this._createBackColorMenu(); + } + + if ((cd = this.controls[n])) + return cf.createButton(n, {title : "advanced." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]}); + }, + + execCommand : function(cmd, ui, val) { + var f = this['_' + cmd]; + + if (f) { + f.call(this, ui, val); + return true; + } + + return false; + }, + + _importClasses : function(e) { + var ed = this.editor, ctrl = ed.controlManager.get('styleselect'); + + if (ctrl.getLength() == 0) { + each(ed.dom.getClasses(), function(o, idx) { + var name = 'style_' + idx; + + ed.formatter.register(name, { + inline : 'span', + attributes : {'class' : o['class']}, + selector : '*' + }); + + ctrl.add(o['class'], name); + }); + } + }, + + _createStyleSelect : function(n) { + var t = this, ed = t.editor, ctrlMan = ed.controlManager, ctrl; + + // Setup style select box + ctrl = ctrlMan.createListBox('styleselect', { + title : 'advanced.style_select', + onselect : function(name) { + var matches, formatNames = []; + + each(ctrl.items, function(item) { + formatNames.push(item.value); + }); + + ed.focus(); + ed.undoManager.add(); + + // Toggle off the current format + matches = ed.formatter.matchAll(formatNames); + if (!name || matches[0] == name) + ed.formatter.remove(matches[0]); + else + ed.formatter.apply(name); + + ed.undoManager.add(); + ed.nodeChanged(); + + return false; // No auto select + } + }); + + // Handle specified format + ed.onInit.add(function() { + var counter = 0, formats = ed.getParam('style_formats'); + + if (formats) { + each(formats, function(fmt) { + var name, keys = 0; + + each(fmt, function() {keys++;}); + + if (keys > 1) { + name = fmt.name = fmt.name || 'style_' + (counter++); + ed.formatter.register(name, fmt); + ctrl.add(fmt.title, name); + } else + ctrl.add(fmt.title); + }); + } else { + each(ed.getParam('theme_advanced_styles', '', 'hash'), function(val, key) { + var name; + + if (val) { + name = 'style_' + (counter++); + + ed.formatter.register(name, { + inline : 'span', + classes : val, + selector : '*' + }); + + ctrl.add(t.editor.translate(key), name); + } + }); + } + }); + + // Auto import classes if the ctrl box is empty + if (ctrl.getLength() == 0) { + ctrl.onPostRender.add(function(ed, n) { + if (!ctrl.NativeListBox) { + Event.add(n.id + '_text', 'focus', t._importClasses, t); + Event.add(n.id + '_text', 'mousedown', t._importClasses, t); + Event.add(n.id + '_open', 'focus', t._importClasses, t); + Event.add(n.id + '_open', 'mousedown', t._importClasses, t); + } else + Event.add(n.id, 'focus', t._importClasses, t); + }); + } + + return ctrl; + }, + + _createFontSelect : function() { + var c, t = this, ed = t.editor; + + c = ed.controlManager.createListBox('fontselect', { + title : 'advanced.fontdefault', + onselect : function(v) { + var cur = c.items[c.selectedIndex]; + + if (!v && cur) { + ed.execCommand('FontName', false, cur.value); + return; + } + + ed.execCommand('FontName', false, v); + + // Fake selection, execCommand will fire a nodeChange and update the selection + c.select(function(sv) { + return v == sv; + }); + + return false; // No auto select + } + }); + + if (c) { + each(ed.getParam('theme_advanced_fonts', t.settings.theme_advanced_fonts, 'hash'), function(v, k) { + c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''}); + }); + } + + return c; + }, + + _createFontSizeSelect : function() { + var t = this, ed = t.editor, c, i = 0, cl = []; + + c = ed.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', onselect : function(v) { + var cur = c.items[c.selectedIndex]; + + if (!v && cur) { + cur = cur.value; + + if (cur['class']) { + ed.formatter.toggle('fontsize_class', {value : cur['class']}); + ed.undoManager.add(); + ed.nodeChanged(); + } else { + ed.execCommand('FontSize', false, cur.fontSize); + } + + return; + } + + if (v['class']) { + ed.focus(); + ed.undoManager.add(); + ed.formatter.toggle('fontsize_class', {value : v['class']}); + ed.undoManager.add(); + ed.nodeChanged(); + } else + ed.execCommand('FontSize', false, v.fontSize); + + // Fake selection, execCommand will fire a nodeChange and update the selection + c.select(function(sv) { + return v == sv; + }); + + return false; // No auto select + }}); + + if (c) { + each(t.settings.theme_advanced_font_sizes, function(v, k) { + var fz = v.fontSize; + + if (fz >= 1 && fz <= 7) + fz = t.sizes[parseInt(fz) - 1] + 'pt'; + + c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))}); + }); + } + + return c; + }, + + _createBlockFormats : function() { + var c, fmts = { + p : 'advanced.paragraph', + address : 'advanced.address', + pre : 'advanced.pre', + h1 : 'advanced.h1', + h2 : 'advanced.h2', + h3 : 'advanced.h3', + h4 : 'advanced.h4', + h5 : 'advanced.h5', + h6 : 'advanced.h6', + div : 'advanced.div', + blockquote : 'advanced.blockquote', + code : 'advanced.code', + dt : 'advanced.dt', + dd : 'advanced.dd', + samp : 'advanced.samp' + }, t = this; + + c = t.editor.controlManager.createListBox('formatselect', {title : 'advanced.block', cmd : 'FormatBlock'}); + if (c) { + each(t.editor.getParam('theme_advanced_blockformats', t.settings.theme_advanced_blockformats, 'hash'), function(v, k) { + c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v}); + }); + } + + return c; + }, + + _createForeColorMenu : function() { + var c, t = this, s = t.settings, o = {}, v; + + if (s.theme_advanced_more_colors) { + o.more_colors_func = function() { + t._mceColorPicker(0, { + color : c.value, + func : function(co) { + c.setColor(co); + } + }); + }; + } + + if (v = s.theme_advanced_text_colors) + o.colors = v; + + if (s.theme_advanced_default_foreground_color) + o.default_color = s.theme_advanced_default_foreground_color; + + o.title = 'advanced.forecolor_desc'; + o.cmd = 'ForeColor'; + o.scope = this; + + c = t.editor.controlManager.createColorSplitButton('forecolor', o); + + return c; + }, + + _createBackColorMenu : function() { + var c, t = this, s = t.settings, o = {}, v; + + if (s.theme_advanced_more_colors) { + o.more_colors_func = function() { + t._mceColorPicker(0, { + color : c.value, + func : function(co) { + c.setColor(co); + } + }); + }; + } + + if (v = s.theme_advanced_background_colors) + o.colors = v; + + if (s.theme_advanced_default_background_color) + o.default_color = s.theme_advanced_default_background_color; + + o.title = 'advanced.backcolor_desc'; + o.cmd = 'HiliteColor'; + o.scope = this; + + c = t.editor.controlManager.createColorSplitButton('backcolor', o); + + return c; + }, + + renderUI : function(o) { + var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl; + + if (ed.settings) { + ed.settings.aria_label = s.aria_label + ed.getLang('advanced.help_shortcut'); + } + // TODO: ACC Should have an aria-describedby attribute which is user-configurable to describe what this field is actually for. + // Maybe actually inherit it from the original textara? + n = p = DOM.create('span', {role : 'application', 'aria-labelledby' : ed.id + '_voice', id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '')}); + DOM.add(n, 'span', {'class': 'mceVoiceLabel', 'style': 'display:none;', id: ed.id + '_voice'}, s.aria_label); + if (!DOM.boxModel) + n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'}); + + n = sc = DOM.add(n, 'table', {role : "presentation", id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0}); + n = tb = DOM.add(n, 'tbody'); + + switch ((s.theme_advanced_layout_manager || '').toLowerCase()) { + case "rowlayout": + ic = t._rowLayout(s, tb, o); + break; + + case "customlayout": + ic = ed.execCallback("theme_advanced_custom_layout", s, tb, o, p); + break; + + default: + ic = t._simpleLayout(s, tb, o, p); + } + + n = o.targetNode; + + // Add classes to first and last TRs + nl = DOM.stdMode ? sc.getElementsByTagName('tr') : sc.rows; // Quick fix for IE 8 + DOM.addClass(nl[0], 'mceFirst'); + DOM.addClass(nl[nl.length - 1], 'mceLast'); + + // Add classes to first and last TDs + each(DOM.select('tr', tb), function(n) { + DOM.addClass(n.firstChild, 'mceFirst'); + DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast'); + }); + + if (DOM.get(s.theme_advanced_toolbar_container)) + DOM.get(s.theme_advanced_toolbar_container).appendChild(p); + else + DOM.insertAfter(p, n); + + Event.add(ed.id + '_path_row', 'click', function(e) { + e = e.target; + + if (e.nodeName == 'A') { + t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1')); + + return Event.cancel(e); + } + }); +/* + if (DOM.get(ed.id + '_path_row')) { + Event.add(ed.id + '_tbl', 'mouseover', function(e) { + var re; + + e = e.target; + + if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) { + re = DOM.get(ed.id + '_path_row'); + t.lastPath = re.innerHTML; + DOM.setHTML(re, e.parentNode.title); + } + }); + + Event.add(ed.id + '_tbl', 'mouseout', function(e) { + if (t.lastPath) { + DOM.setHTML(ed.id + '_path_row', t.lastPath); + t.lastPath = 0; + } + }); + } +*/ + + if (s.theme_advanced_toolbar_location == 'external') + o.deltaHeight = 0; + + t.deltaHeight = o.deltaHeight; + o.targetNode = null; + + ed.onKeyDown.add(function(ed, evt) { + var DOM_VK_F10 = 121, DOM_VK_F11 = 122; + if (evt.altKey) { + if (evt.keyCode === DOM_VK_F10) { + t.toolbarGroup.focus(); + return Event.cancel(evt); + } else if (evt.keyCode === DOM_VK_F11) { + DOM.get(ed.id + '_path_row').focus(); + return Event.cancel(evt); + } + } + }); + + // alt+0 is the UK recommended shortcut for accessing the list of access controls. + ed.addShortcut('alt+0', '', 'mceShortcuts', t); + + return { + iframeContainer : ic, + editorContainer : ed.id + '_parent', + sizeContainer : sc, + deltaHeight : o.deltaHeight + }; + }, + + getInfo : function() { + return { + longname : 'Advanced theme', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + version : tinymce.majorVersion + "." + tinymce.minorVersion + } + }, + + resizeBy : function(dw, dh) { + var e = DOM.get(this.editor.id + '_tbl'); + + this.resizeTo(e.clientWidth + dw, e.clientHeight + dh); + }, + + resizeTo : function(w, h, store) { + var ed = this.editor, s = this.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr'); + + // Boundery fix box + w = Math.max(s.theme_advanced_resizing_min_width || 100, w); + h = Math.max(s.theme_advanced_resizing_min_height || 100, h); + w = Math.min(s.theme_advanced_resizing_max_width || 0xFFFF, w); + h = Math.min(s.theme_advanced_resizing_max_height || 0xFFFF, h); + + // Resize iframe and container + DOM.setStyle(e, 'height', ''); + DOM.setStyle(ifr, 'height', h); + + if (s.theme_advanced_resize_horizontal) { + DOM.setStyle(e, 'width', ''); + DOM.setStyle(ifr, 'width', w); + + // Make sure that the size is never smaller than the over all ui + if (w < e.clientWidth) { + w = e.clientWidth; + DOM.setStyle(ifr, 'width', e.clientWidth); + } + } + + // Store away the size + if (store && s.theme_advanced_resizing_use_cookie) { + Cookie.setHash("TinyMCE_" + ed.id + "_size", { + cw : w, + ch : h + }); + } + }, + + destroy : function() { + var id = this.editor.id; + + Event.clear(id + '_resize'); + Event.clear(id + '_path_row'); + Event.clear(id + '_external_close'); + }, + + // Internal functions + + _simpleLayout : function(s, tb, o, p) { + var t = this, ed = t.editor, lo = s.theme_advanced_toolbar_location, sl = s.theme_advanced_statusbar_location, n, ic, etb, c; + + if (s.readonly) { + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); + return ic; + } + + // Create toolbar container at top + if (lo == 'top') + t._addToolbars(tb, o); + + // Create external toolbar + if (lo == 'external') { + n = c = DOM.create('div', {style : 'position:relative'}); + n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'}); + DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'}); + n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0}); + etb = DOM.add(n, 'tbody'); + + if (p.firstChild.className == 'mceOldBoxModel') + p.firstChild.appendChild(c); + else + p.insertBefore(c, p.firstChild); + + t._addToolbars(etb, o); + + ed.onMouseUp.add(function() { + var e = DOM.get(ed.id + '_external'); + DOM.show(e); + + DOM.hide(lastExtID); + + var f = Event.add(ed.id + '_external_close', 'click', function() { + DOM.hide(ed.id + '_external'); + Event.remove(ed.id + '_external_close', 'click', f); + }); + + DOM.show(e); + DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1); + + // Fixes IE rendering bug + DOM.hide(e); + DOM.show(e); + e.style.filter = ''; + + lastExtID = ed.id + '_external'; + + e = null; + }); + } + + if (sl == 'top') + t._addStatusBar(tb, o); + + // Create iframe container + if (!s.theme_advanced_toolbar_container) { + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); + } + + // Create toolbar container at bottom + if (lo == 'bottom') + t._addToolbars(tb, o); + + if (sl == 'bottom') + t._addStatusBar(tb, o); + + return ic; + }, + + _rowLayout : function(s, tb, o) { + var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a; + + dc = s.theme_advanced_containers_default_class || ''; + da = s.theme_advanced_containers_default_align || 'center'; + + each(explode(s.theme_advanced_containers || ''), function(c, i) { + var v = s['theme_advanced_container_' + c] || ''; + + switch (v.toLowerCase()) { + case 'mceeditor': + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); + break; + + case 'mceelementpath': + t._addStatusBar(tb, o); + break; + + default: + a = (s['theme_advanced_container_' + c + '_align'] || da).toLowerCase(); + a = 'mce' + t._ufirst(a); + + n = DOM.add(DOM.add(tb, 'tr'), 'td', { + 'class' : 'mceToolbar ' + (s['theme_advanced_container_' + c + '_class'] || dc) + ' ' + a || da + }); + + to = cf.createToolbar("toolbar" + i); + t._addControls(v, to); + DOM.setHTML(n, to.renderHTML()); + o.deltaHeight -= s.theme_advanced_row_height; + } + }); + + return ic; + }, + + _addControls : function(v, tb) { + var t = this, s = t.settings, di, cf = t.editor.controlManager; + + if (s.theme_advanced_disable && !t._disabled) { + di = {}; + + each(explode(s.theme_advanced_disable), function(v) { + di[v] = 1; + }); + + t._disabled = di; + } else + di = t._disabled; + + each(explode(v), function(n) { + var c; + + if (di && di[n]) + return; + + // Compatiblity with 2.x + if (n == 'tablecontrols') { + each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) { + n = t.createControl(n, cf); + + if (n) + tb.add(n); + }); + + return; + } + + c = t.createControl(n, cf); + + if (c) + tb.add(c); + }); + }, + + _addToolbars : function(c, o) { + var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, a, toolbarGroup; + + toolbarGroup = cf.createToolbarGroup('toolbargroup', { + 'name': ed.getLang('advanced.toolbar'), + 'tab_focus_toolbar':ed.getParam('theme_advanced_tab_focus_toolbar') + }); + t.toolbarGroup = toolbarGroup; + + a = s.theme_advanced_toolbar_align.toLowerCase(); + a = 'mce' + t._ufirst(a); + + n = DOM.add(DOM.add(c, 'tr'), 'td', {'class' : 'mceToolbar ' + a}); + + // Create toolbar and add the controls + for (i=1; (v = s['theme_advanced_buttons' + i]); i++) { + tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i}); + + if (s['theme_advanced_buttons' + i + '_add']) + v += ',' + s['theme_advanced_buttons' + i + '_add']; + + if (s['theme_advanced_buttons' + i + '_add_before']) + v = s['theme_advanced_buttons' + i + '_add_before'] + ',' + v; + + t._addControls(v, tb); + toolbarGroup.add(tb); + + o.deltaHeight -= s.theme_advanced_row_height; + } + + DOM.setHTML(n, toolbarGroup.renderHTML()); + }, + + _addStatusBar : function(tb, o) { + var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td; + + n = DOM.add(tb, 'tr'); + n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'}); + n = DOM.add(n, 'div', {id : ed.id + '_path_row', 'role': 'group', 'aria-labelledby': ed.id + '_path_voice'}); + if (s.theme_advanced_path) { + DOM.add(n, 'span', {id: ed.id + '_path_voice'}, ed.translate('advanced.path')); + DOM.add(n, 'span', {}, ': '); + } else { + DOM.add(n, 'span', {}, ' '); + } + + if (s.theme_advanced_resizing) { + DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize'}); + + if (s.theme_advanced_resizing_use_cookie) { + ed.onPostRender.add(function() { + var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl'); + + if (!o) + return; + + t.resizeTo(o.cw, o.ch); + }); + } + + ed.onPostRender.add(function() { + Event.add(ed.id + '_resize', 'click', function(e) { + e.preventDefault(); + }); + + Event.add(ed.id + '_resize', 'mousedown', function(e) { + var mouseMoveHandler1, mouseMoveHandler2, + mouseUpHandler1, mouseUpHandler2, + startX, startY, startWidth, startHeight, width, height, ifrElm; + + function resizeOnMove(e) { + e.preventDefault(); + + width = startWidth + (e.screenX - startX); + height = startHeight + (e.screenY - startY); + + t.resizeTo(width, height); + }; + + function endResize(e) { + // Stop listening + Event.remove(DOM.doc, 'mousemove', mouseMoveHandler1); + Event.remove(ed.getDoc(), 'mousemove', mouseMoveHandler2); + Event.remove(DOM.doc, 'mouseup', mouseUpHandler1); + Event.remove(ed.getDoc(), 'mouseup', mouseUpHandler2); + + width = startWidth + (e.screenX - startX); + height = startHeight + (e.screenY - startY); + t.resizeTo(width, height, true); + }; + + e.preventDefault(); + + // Get the current rect size + startX = e.screenX; + startY = e.screenY; + ifrElm = DOM.get(t.editor.id + '_ifr'); + startWidth = width = ifrElm.clientWidth; + startHeight = height = ifrElm.clientHeight; + + // Register envent handlers + mouseMoveHandler1 = Event.add(DOM.doc, 'mousemove', resizeOnMove); + mouseMoveHandler2 = Event.add(ed.getDoc(), 'mousemove', resizeOnMove); + mouseUpHandler1 = Event.add(DOM.doc, 'mouseup', endResize); + mouseUpHandler2 = Event.add(ed.getDoc(), 'mouseup', endResize); + }); + }); + } + + o.deltaHeight -= 21; + n = tb = null; + }, + + _updateUndoStatus : function(ed) { + var cm = ed.controlManager; + cm.setDisabled('undo', !ed.undoManager.hasUndo() && !ed.typing); + cm.setDisabled('redo', !ed.undoManager.hasRedo()); + }, + + _nodeChanged : function(ed, cm, n, co, ob) { + var t = this, p, de = 0, v, c, s = t.settings, cl, fz, fn, fc, bc, formatNames, matches; + + tinymce.each(t.stateControls, function(c) { + cm.setActive(c, ed.queryCommandState(t.controls[c][1])); + }); + + function getParent(name) { + var i, parents = ob.parents, func = name; + + if (typeof(name) == 'string') { + func = function(node) { + return node.nodeName == name; + }; + } + + for (i = 0; i < parents.length; i++) { + if (func(parents[i])) + return parents[i]; + } + }; + + cm.setActive('visualaid', ed.hasVisual); + t._updateUndoStatus(ed); + cm.setDisabled('outdent', !ed.queryCommandState('Outdent')); + + p = getParent('A'); + if (c = cm.get('link')) { + if (!p || !p.name) { + c.setDisabled(!p && co); + c.setActive(!!p); + } + } + + if (c = cm.get('unlink')) { + c.setDisabled(!p && co); + c.setActive(!!p && !p.name); + } + + if (c = cm.get('anchor')) { + c.setActive(!!p && p.name); + } + + p = getParent('IMG'); + if (c = cm.get('image')) + c.setActive(!!p && n.className.indexOf('mceItem') == -1); + + if (c = cm.get('styleselect')) { + t._importClasses(); + + formatNames = []; + each(c.items, function(item) { + formatNames.push(item.value); + }); + + matches = ed.formatter.matchAll(formatNames); + c.select(matches[0]); + } + + if (c = cm.get('formatselect')) { + p = getParent(DOM.isBlock); + + if (p) + c.select(p.nodeName.toLowerCase()); + } + + // Find out current fontSize, fontFamily and fontClass + getParent(function(n) { + if (n.nodeName === 'SPAN') { + if (!cl && n.className) + cl = n.className; + } + + if (ed.dom.is(n, s.theme_advanced_font_selector)) { + if (!fz && n.style.fontSize) + fz = n.style.fontSize; + + if (!fn && n.style.fontFamily) + fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase(); + + if (!fc && n.style.color) + fc = n.style.color; + + if (!bc && n.style.backgroundColor) + bc = n.style.backgroundColor; + } + + return false; + }); + + if (c = cm.get('fontselect')) { + c.select(function(v) { + return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn; + }); + } + + // Select font size + if (c = cm.get('fontsizeselect')) { + // Use computed style + if (s.theme_advanced_runtime_fontsize && !fz && !cl) + fz = ed.dom.getStyle(n, 'fontSize', true); + + c.select(function(v) { + if (v.fontSize && v.fontSize === fz) + return true; + + if (v['class'] && v['class'] === cl) + return true; + }); + } + + if (s.theme_advanced_show_current_color) { + function updateColor(controlId, color) { + if (c = cm.get(controlId)) { + if (!color) + color = c.settings.default_color; + if (color !== c.value) { + c.displayColor(color); + } + } + } + updateColor('forecolor', fc); + updateColor('backcolor', bc); + } + + if (s.theme_advanced_path && s.theme_advanced_statusbar_location) { + p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'}); + if (t.statusKeyboardNavigation) { + t.statusKeyboardNavigation.destroy(); + t.statusKeyboardNavigation = null; + } + DOM.setHTML(p, ''); + + getParent(function(n) { + var na = n.nodeName.toLowerCase(), u, pi, ti = ''; + + /*if (n.getAttribute('_mce_bogus')) + return; +*/ + // Ignore non element and hidden elements + if (n.nodeType != 1 || n.nodeName === 'BR' || (DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved'))) + return; + + // Fake name + if (v = DOM.getAttrib(n, 'mce_name')) + na = v; + + // Handle prefix + if (tinymce.isIE && n.scopeName !== 'HTML') + na = n.scopeName + ':' + na; + + // Remove internal prefix + na = na.replace(/mce\:/g, ''); + + // Handle node name + switch (na) { + case 'b': + na = 'strong'; + break; + + case 'i': + na = 'em'; + break; + + case 'img': + if (v = DOM.getAttrib(n, 'src')) + ti += 'src: ' + v + ' '; + + break; + + case 'a': + if (v = DOM.getAttrib(n, 'name')) { + ti += 'name: ' + v + ' '; + na += '#' + v; + } + + if (v = DOM.getAttrib(n, 'href')) + ti += 'href: ' + v + ' '; + + break; + + case 'font': + if (v = DOM.getAttrib(n, 'face')) + ti += 'font: ' + v + ' '; + + if (v = DOM.getAttrib(n, 'size')) + ti += 'size: ' + v + ' '; + + if (v = DOM.getAttrib(n, 'color')) + ti += 'color: ' + v + ' '; + + break; + + case 'span': + if (v = DOM.getAttrib(n, 'style')) + ti += 'style: ' + v + ' '; + + break; + } + + if (v = DOM.getAttrib(n, 'id')) + ti += 'id: ' + v + ' '; + + if (v = n.className) { + v = v.replace(/\b\s*(webkit|mce|Apple-)\w+\s*\b/g, '') + + if (v) { + ti += 'class: ' + v + ' '; + + if (DOM.isBlock(n) || na == 'img' || na == 'span') + na += '.' + v; + } + } + + na = na.replace(/(html:)/g, ''); + na = {name : na, node : n, title : ti}; + t.onResolveName.dispatch(t, na); + ti = na.title; + na = na.name; + + //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');"; + pi = DOM.create('a', {'href' : "javascript:;", role: 'button', onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na); + + if (p.hasChildNodes()) { + p.insertBefore(DOM.create('span', { 'aria-hidden': 'true' }, ' \u00bb '), p.firstChild); + p.insertBefore(pi, p.firstChild); + } else + p.appendChild(pi); + + }, ed.getBody()); + + if (DOM.select('a', p).length > 0) { + t.statusKeyboardNavigation = new tinymce.ui.KeyboardNavigation({ + root: ed.id + "_path_row", + items: DOM.select('a', p), + excludeFromTabOrder: true, + onCancel: function() { + ed.focus(); + } + }, DOM); + } + } + }, + + // Commands gets called by execCommand + + _sel : function(v) { + this.editor.execCommand('mceSelectNodeDepth', false, v); + }, + + _mceInsertAnchor : function(ui, v) { + var ed = this.editor; + + ed.windowManager.open({ + url : this.url + '/anchor.htm', + width : 320 + parseInt(ed.getLang('advanced.anchor_delta_width', 0)), + height : 90 + parseInt(ed.getLang('advanced.anchor_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceCharMap : function() { + var ed = this.editor; + + ed.windowManager.open({ + url : this.url + '/charmap.htm', + width : 550 + parseInt(ed.getLang('advanced.charmap_delta_width', 0)), + height : 250 + parseInt(ed.getLang('advanced.charmap_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceHelp : function() { + var ed = this.editor; + + ed.windowManager.open({ + url : this.url + '/about.htm', + width : 480, + height : 380, + inline : true + }, { + theme_url : this.url + }); + }, + + _mceShortcuts : function() { + var ed = this.editor; + ed.windowManager.open({ + url: this.url + '/shortcuts.htm', + width: 480, + height: 380, + inline: true + }, { + theme_url: this.url + }); + }, + + _mceColorPicker : function(u, v) { + var ed = this.editor; + + v = v || {}; + + ed.windowManager.open({ + url : this.url + '/color_picker.htm', + width : 375 + parseInt(ed.getLang('advanced.colorpicker_delta_width', 0)), + height : 250 + parseInt(ed.getLang('advanced.colorpicker_delta_height', 0)), + close_previous : false, + inline : true + }, { + input_color : v.color, + func : v.func, + theme_url : this.url + }); + }, + + _mceCodeEditor : function(ui, val) { + var ed = this.editor; + + ed.windowManager.open({ + url : this.url + '/source_editor.htm', + width : parseInt(ed.getParam("theme_advanced_source_editor_width", 720)), + height : parseInt(ed.getParam("theme_advanced_source_editor_height", 580)), + inline : true, + resizable : true, + maximizable : true + }, { + theme_url : this.url + }); + }, + + _mceImage : function(ui, val) { + var ed = this.editor; + + // Internal image object like a flash placeholder + if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1) + return; + + ed.windowManager.open({ + url : this.url + '/image.htm', + width : 355 + parseInt(ed.getLang('advanced.image_delta_width', 0)), + height : 275 + parseInt(ed.getLang('advanced.image_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceLink : function(ui, val) { + var ed = this.editor; + + ed.windowManager.open({ + url : this.url + '/link.htm', + width : 310 + parseInt(ed.getLang('advanced.link_delta_width', 0)), + height : 200 + parseInt(ed.getLang('advanced.link_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceNewDocument : function() { + var ed = this.editor; + + ed.windowManager.confirm('advanced.newdocument', function(s) { + if (s) + ed.execCommand('mceSetContent', false, ''); + }); + }, + + _mceForeColor : function() { + var t = this; + + this._mceColorPicker(0, { + color: t.fgColor, + func : function(co) { + t.fgColor = co; + t.editor.execCommand('ForeColor', false, co); + } + }); + }, + + _mceBackColor : function() { + var t = this; + + this._mceColorPicker(0, { + color: t.bgColor, + func : function(co) { + t.bgColor = co; + t.editor.execCommand('HiliteColor', false, co); + } + }); + }, + + _ufirst : function(s) { + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + }); + + tinymce.ThemeManager.add('advanced', tinymce.themes.AdvancedTheme); +}(tinymce)); diff --git a/tools/tiny_mce/themes/advanced/image.htm b/tools/tiny_mce/themes/advanced/image.htm new file mode 100644 index 00000000..98fd2cd0 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/image.htm @@ -0,0 +1,80 @@ + + + + {#advanced_dlg.image_title} + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    + x +
    +
    +
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/themes/advanced/img/colorpicker.jpg b/tools/tiny_mce/themes/advanced/img/colorpicker.jpg new file mode 100644 index 00000000..b4c542d1 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/img/colorpicker.jpg differ diff --git a/tools/tiny_mce/themes/advanced/img/icons.gif b/tools/tiny_mce/themes/advanced/img/icons.gif new file mode 100644 index 00000000..e46de533 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/img/icons.gif differ diff --git a/tools/tiny_mce/themes/advanced/js/about.js b/tools/tiny_mce/themes/advanced/js/about.js new file mode 100644 index 00000000..daf4909a --- /dev/null +++ b/tools/tiny_mce/themes/advanced/js/about.js @@ -0,0 +1,73 @@ +tinyMCEPopup.requireLangPack(); + +function init() { + var ed, tcont; + + tinyMCEPopup.resizeToInnerSize(); + ed = tinyMCEPopup.editor; + + // Give FF some time + window.setTimeout(insertHelpIFrame, 10); + + tcont = document.getElementById('plugintablecontainer'); + document.getElementById('plugins_tab').style.display = 'none'; + + var html = ""; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + + tinymce.each(ed.plugins, function(p, n) { + var info; + + if (!p.getInfo) + return; + + html += ''; + + info = p.getInfo(); + + if (info.infourl != null && info.infourl != '') + html += ''; + else + html += ''; + + if (info.authorurl != null && info.authorurl != '') + html += ''; + else + html += ''; + + html += ''; + html += ''; + + document.getElementById('plugins_tab').style.display = ''; + + }); + + html += ''; + html += '
    ' + ed.getLang('advanced_dlg.about_plugin') + '' + ed.getLang('advanced_dlg.about_author') + '' + ed.getLang('advanced_dlg.about_version') + '
    ' + info.longname + '' + info.longname + '' + info.author + '' + info.author + '' + info.version + '
    '; + + tcont.innerHTML = html; + + tinyMCEPopup.dom.get('version').innerHTML = tinymce.majorVersion + "." + tinymce.minorVersion; + tinyMCEPopup.dom.get('date').innerHTML = tinymce.releaseDate; +} + +function insertHelpIFrame() { + var html; + + if (tinyMCEPopup.getParam('docs_url')) { + html = ''; + document.getElementById('iframecontainer').innerHTML = html; + document.getElementById('help_tab').style.display = 'block'; + document.getElementById('help_tab').setAttribute("aria-hidden", "false"); + } +} + +tinyMCEPopup.onInit.add(init); diff --git a/tools/tiny_mce/themes/advanced/js/anchor.js b/tools/tiny_mce/themes/advanced/js/anchor.js new file mode 100644 index 00000000..d7a854e9 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/js/anchor.js @@ -0,0 +1,37 @@ +tinyMCEPopup.requireLangPack(); + +var AnchorDialog = { + init : function(ed) { + var action, elm, f = document.forms[0]; + + this.editor = ed; + elm = ed.dom.getParent(ed.selection.getNode(), 'A'); + v = ed.dom.getAttrib(elm, 'name'); + + if (v) { + this.action = 'update'; + f.anchorName.value = v; + } + + f.insert.value = ed.getLang(elm ? 'update' : 'insert'); + }, + + update : function() { + var ed = this.editor, elm, name = document.forms[0].anchorName.value; + + tinyMCEPopup.restoreSelection(); + + if (this.action != 'update') + ed.selection.collapse(1); + + elm = ed.dom.getParent(ed.selection.getNode(), 'A'); + if (elm) + elm.name = name; + else + ed.execCommand('mceInsertContent', 0, ed.dom.createHTML('a', {name : name, 'class' : 'mceItemAnchor'}, '')); + + tinyMCEPopup.close(); + } +}; + +tinyMCEPopup.onInit.add(AnchorDialog.init, AnchorDialog); diff --git a/tools/tiny_mce/themes/advanced/js/charmap.js b/tools/tiny_mce/themes/advanced/js/charmap.js new file mode 100644 index 00000000..f4a5b1d1 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/js/charmap.js @@ -0,0 +1,353 @@ +/** + * charmap.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +tinyMCEPopup.requireLangPack(); + +var charmap = [ + [' ', ' ', true, 'no-break space'], + ['&', '&', true, 'ampersand'], + ['"', '"', true, 'quotation mark'], +// finance + ['¢', '¢', true, 'cent sign'], + ['€', '€', true, 'euro sign'], + ['£', '£', true, 'pound sign'], + ['¥', '¥', true, 'yen sign'], +// signs + ['©', '©', true, 'copyright sign'], + ['®', '®', true, 'registered sign'], + ['™', '™', true, 'trade mark sign'], + ['‰', '‰', true, 'per mille sign'], + ['µ', 'µ', true, 'micro sign'], + ['·', '·', true, 'middle dot'], + ['•', '•', true, 'bullet'], + ['…', '…', true, 'three dot leader'], + ['′', '′', true, 'minutes / feet'], + ['″', '″', true, 'seconds / inches'], + ['§', '§', true, 'section sign'], + ['¶', '¶', true, 'paragraph sign'], + ['ß', 'ß', true, 'sharp s / ess-zed'], +// quotations + ['‹', '‹', true, 'single left-pointing angle quotation mark'], + ['›', '›', true, 'single right-pointing angle quotation mark'], + ['«', '«', true, 'left pointing guillemet'], + ['»', '»', true, 'right pointing guillemet'], + ['‘', '‘', true, 'left single quotation mark'], + ['’', '’', true, 'right single quotation mark'], + ['“', '“', true, 'left double quotation mark'], + ['”', '”', true, 'right double quotation mark'], + ['‚', '‚', true, 'single low-9 quotation mark'], + ['„', '„', true, 'double low-9 quotation mark'], + ['<', '<', true, 'less-than sign'], + ['>', '>', true, 'greater-than sign'], + ['≤', '≤', true, 'less-than or equal to'], + ['≥', '≥', true, 'greater-than or equal to'], + ['–', '–', true, 'en dash'], + ['—', '—', true, 'em dash'], + ['¯', '¯', true, 'macron'], + ['‾', '‾', true, 'overline'], + ['¤', '¤', true, 'currency sign'], + ['¦', '¦', true, 'broken bar'], + ['¨', '¨', true, 'diaeresis'], + ['¡', '¡', true, 'inverted exclamation mark'], + ['¿', '¿', true, 'turned question mark'], + ['ˆ', 'ˆ', true, 'circumflex accent'], + ['˜', '˜', true, 'small tilde'], + ['°', '°', true, 'degree sign'], + ['−', '−', true, 'minus sign'], + ['±', '±', true, 'plus-minus sign'], + ['÷', '÷', true, 'division sign'], + ['⁄', '⁄', true, 'fraction slash'], + ['×', '×', true, 'multiplication sign'], + ['¹', '¹', true, 'superscript one'], + ['²', '²', true, 'superscript two'], + ['³', '³', true, 'superscript three'], + ['¼', '¼', true, 'fraction one quarter'], + ['½', '½', true, 'fraction one half'], + ['¾', '¾', true, 'fraction three quarters'], +// math / logical + ['ƒ', 'ƒ', true, 'function / florin'], + ['∫', '∫', true, 'integral'], + ['∑', '∑', true, 'n-ary sumation'], + ['∞', '∞', true, 'infinity'], + ['√', '√', true, 'square root'], + ['∼', '∼', false,'similar to'], + ['≅', '≅', false,'approximately equal to'], + ['≈', '≈', true, 'almost equal to'], + ['≠', '≠', true, 'not equal to'], + ['≡', '≡', true, 'identical to'], + ['∈', '∈', false,'element of'], + ['∉', '∉', false,'not an element of'], + ['∋', '∋', false,'contains as member'], + ['∏', '∏', true, 'n-ary product'], + ['∧', '∧', false,'logical and'], + ['∨', '∨', false,'logical or'], + ['¬', '¬', true, 'not sign'], + ['∩', '∩', true, 'intersection'], + ['∪', '∪', false,'union'], + ['∂', '∂', true, 'partial differential'], + ['∀', '∀', false,'for all'], + ['∃', '∃', false,'there exists'], + ['∅', '∅', false,'diameter'], + ['∇', '∇', false,'backward difference'], + ['∗', '∗', false,'asterisk operator'], + ['∝', '∝', false,'proportional to'], + ['∠', '∠', false,'angle'], +// undefined + ['´', '´', true, 'acute accent'], + ['¸', '¸', true, 'cedilla'], + ['ª', 'ª', true, 'feminine ordinal indicator'], + ['º', 'º', true, 'masculine ordinal indicator'], + ['†', '†', true, 'dagger'], + ['‡', '‡', true, 'double dagger'], +// alphabetical special chars + ['À', 'À', true, 'A - grave'], + ['Á', 'Á', true, 'A - acute'], + ['Â', 'Â', true, 'A - circumflex'], + ['Ã', 'Ã', true, 'A - tilde'], + ['Ä', 'Ä', true, 'A - diaeresis'], + ['Å', 'Å', true, 'A - ring above'], + ['Æ', 'Æ', true, 'ligature AE'], + ['Ç', 'Ç', true, 'C - cedilla'], + ['È', 'È', true, 'E - grave'], + ['É', 'É', true, 'E - acute'], + ['Ê', 'Ê', true, 'E - circumflex'], + ['Ë', 'Ë', true, 'E - diaeresis'], + ['Ì', 'Ì', true, 'I - grave'], + ['Í', 'Í', true, 'I - acute'], + ['Î', 'Î', true, 'I - circumflex'], + ['Ï', 'Ï', true, 'I - diaeresis'], + ['Ð', 'Ð', true, 'ETH'], + ['Ñ', 'Ñ', true, 'N - tilde'], + ['Ò', 'Ò', true, 'O - grave'], + ['Ó', 'Ó', true, 'O - acute'], + ['Ô', 'Ô', true, 'O - circumflex'], + ['Õ', 'Õ', true, 'O - tilde'], + ['Ö', 'Ö', true, 'O - diaeresis'], + ['Ø', 'Ø', true, 'O - slash'], + ['Œ', 'Œ', true, 'ligature OE'], + ['Š', 'Š', true, 'S - caron'], + ['Ù', 'Ù', true, 'U - grave'], + ['Ú', 'Ú', true, 'U - acute'], + ['Û', 'Û', true, 'U - circumflex'], + ['Ü', 'Ü', true, 'U - diaeresis'], + ['Ý', 'Ý', true, 'Y - acute'], + ['Ÿ', 'Ÿ', true, 'Y - diaeresis'], + ['Þ', 'Þ', true, 'THORN'], + ['à', 'à', true, 'a - grave'], + ['á', 'á', true, 'a - acute'], + ['â', 'â', true, 'a - circumflex'], + ['ã', 'ã', true, 'a - tilde'], + ['ä', 'ä', true, 'a - diaeresis'], + ['å', 'å', true, 'a - ring above'], + ['æ', 'æ', true, 'ligature ae'], + ['ç', 'ç', true, 'c - cedilla'], + ['è', 'è', true, 'e - grave'], + ['é', 'é', true, 'e - acute'], + ['ê', 'ê', true, 'e - circumflex'], + ['ë', 'ë', true, 'e - diaeresis'], + ['ì', 'ì', true, 'i - grave'], + ['í', 'í', true, 'i - acute'], + ['î', 'î', true, 'i - circumflex'], + ['ï', 'ï', true, 'i - diaeresis'], + ['ð', 'ð', true, 'eth'], + ['ñ', 'ñ', true, 'n - tilde'], + ['ò', 'ò', true, 'o - grave'], + ['ó', 'ó', true, 'o - acute'], + ['ô', 'ô', true, 'o - circumflex'], + ['õ', 'õ', true, 'o - tilde'], + ['ö', 'ö', true, 'o - diaeresis'], + ['ø', 'ø', true, 'o slash'], + ['œ', 'œ', true, 'ligature oe'], + ['š', 'š', true, 's - caron'], + ['ù', 'ù', true, 'u - grave'], + ['ú', 'ú', true, 'u - acute'], + ['û', 'û', true, 'u - circumflex'], + ['ü', 'ü', true, 'u - diaeresis'], + ['ý', 'ý', true, 'y - acute'], + ['þ', 'þ', true, 'thorn'], + ['ÿ', 'ÿ', true, 'y - diaeresis'], + ['Α', 'Α', true, 'Alpha'], + ['Β', 'Β', true, 'Beta'], + ['Γ', 'Γ', true, 'Gamma'], + ['Δ', 'Δ', true, 'Delta'], + ['Ε', 'Ε', true, 'Epsilon'], + ['Ζ', 'Ζ', true, 'Zeta'], + ['Η', 'Η', true, 'Eta'], + ['Θ', 'Θ', true, 'Theta'], + ['Ι', 'Ι', true, 'Iota'], + ['Κ', 'Κ', true, 'Kappa'], + ['Λ', 'Λ', true, 'Lambda'], + ['Μ', 'Μ', true, 'Mu'], + ['Ν', 'Ν', true, 'Nu'], + ['Ξ', 'Ξ', true, 'Xi'], + ['Ο', 'Ο', true, 'Omicron'], + ['Π', 'Π', true, 'Pi'], + ['Ρ', 'Ρ', true, 'Rho'], + ['Σ', 'Σ', true, 'Sigma'], + ['Τ', 'Τ', true, 'Tau'], + ['Υ', 'Υ', true, 'Upsilon'], + ['Φ', 'Φ', true, 'Phi'], + ['Χ', 'Χ', true, 'Chi'], + ['Ψ', 'Ψ', true, 'Psi'], + ['Ω', 'Ω', true, 'Omega'], + ['α', 'α', true, 'alpha'], + ['β', 'β', true, 'beta'], + ['γ', 'γ', true, 'gamma'], + ['δ', 'δ', true, 'delta'], + ['ε', 'ε', true, 'epsilon'], + ['ζ', 'ζ', true, 'zeta'], + ['η', 'η', true, 'eta'], + ['θ', 'θ', true, 'theta'], + ['ι', 'ι', true, 'iota'], + ['κ', 'κ', true, 'kappa'], + ['λ', 'λ', true, 'lambda'], + ['μ', 'μ', true, 'mu'], + ['ν', 'ν', true, 'nu'], + ['ξ', 'ξ', true, 'xi'], + ['ο', 'ο', true, 'omicron'], + ['π', 'π', true, 'pi'], + ['ρ', 'ρ', true, 'rho'], + ['ς', 'ς', true, 'final sigma'], + ['σ', 'σ', true, 'sigma'], + ['τ', 'τ', true, 'tau'], + ['υ', 'υ', true, 'upsilon'], + ['φ', 'φ', true, 'phi'], + ['χ', 'χ', true, 'chi'], + ['ψ', 'ψ', true, 'psi'], + ['ω', 'ω', true, 'omega'], +// symbols + ['ℵ', 'ℵ', false,'alef symbol'], + ['ϖ', 'ϖ', false,'pi symbol'], + ['ℜ', 'ℜ', false,'real part symbol'], + ['ϑ','ϑ', false,'theta symbol'], + ['ϒ', 'ϒ', false,'upsilon - hook symbol'], + ['℘', '℘', false,'Weierstrass p'], + ['ℑ', 'ℑ', false,'imaginary part'], +// arrows + ['←', '←', true, 'leftwards arrow'], + ['↑', '↑', true, 'upwards arrow'], + ['→', '→', true, 'rightwards arrow'], + ['↓', '↓', true, 'downwards arrow'], + ['↔', '↔', true, 'left right arrow'], + ['↵', '↵', false,'carriage return'], + ['⇐', '⇐', false,'leftwards double arrow'], + ['⇑', '⇑', false,'upwards double arrow'], + ['⇒', '⇒', false,'rightwards double arrow'], + ['⇓', '⇓', false,'downwards double arrow'], + ['⇔', '⇔', false,'left right double arrow'], + ['∴', '∴', false,'therefore'], + ['⊂', '⊂', false,'subset of'], + ['⊃', '⊃', false,'superset of'], + ['⊄', '⊄', false,'not a subset of'], + ['⊆', '⊆', false,'subset of or equal to'], + ['⊇', '⊇', false,'superset of or equal to'], + ['⊕', '⊕', false,'circled plus'], + ['⊗', '⊗', false,'circled times'], + ['⊥', '⊥', false,'perpendicular'], + ['⋅', '⋅', false,'dot operator'], + ['⌈', '⌈', false,'left ceiling'], + ['⌉', '⌉', false,'right ceiling'], + ['⌊', '⌊', false,'left floor'], + ['⌋', '⌋', false,'right floor'], + ['⟨', '〈', false,'left-pointing angle bracket'], + ['⟩', '〉', false,'right-pointing angle bracket'], + ['◊', '◊', true,'lozenge'], + ['♠', '♠', false,'black spade suit'], + ['♣', '♣', true, 'black club suit'], + ['♥', '♥', true, 'black heart suit'], + ['♦', '♦', true, 'black diamond suit'], + [' ', ' ', false,'en space'], + [' ', ' ', false,'em space'], + [' ', ' ', false,'thin space'], + ['‌', '‌', false,'zero width non-joiner'], + ['‍', '‍', false,'zero width joiner'], + ['‎', '‎', false,'left-to-right mark'], + ['‏', '‏', false,'right-to-left mark'], + ['­', '­', false,'soft hyphen'] +]; + +tinyMCEPopup.onInit.add(function() { + tinyMCEPopup.dom.setHTML('charmapView', renderCharMapHTML()); + addKeyboardNavigation(); +}); + +function addKeyboardNavigation(){ + var tableElm, cells, settings; + cells = tinyMCEPopup.dom.select(".charmaplink", "charmapgroup"); + + settings ={ + root: "charmapgroup", + items: cells + }; + tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', settings, tinyMCEPopup.dom); + +} + +function renderCharMapHTML() { + var charsPerRow = 20, tdWidth=20, tdHeight=20, i; + var html = '
    '+ + ''; + var cols=-1; + + for (i=0; i' + + '' + + charmap[i][1] + + ''; + if ((cols+1) % charsPerRow == 0) + html += ''; + } + } + + if (cols % charsPerRow > 0) { + var padd = charsPerRow - (cols % charsPerRow); + for (var i=0; i '; + } + + html += '
    '; + + return html; +} + +function insertChar(chr) { + tinyMCEPopup.execCommand('mceInsertContent', false, '&#' + chr + ';'); + + // Refocus in window + if (tinyMCEPopup.isWindow) + window.focus(); + + tinyMCEPopup.editor.focus(); + tinyMCEPopup.close(); +} + +function previewChar(codeA, codeB, codeN) { + var elmA = document.getElementById('codeA'); + var elmB = document.getElementById('codeB'); + var elmV = document.getElementById('codeV'); + var elmN = document.getElementById('codeN'); + + if (codeA=='#160;') { + elmV.innerHTML = '__'; + } else { + elmV.innerHTML = '&' + codeA; + } + + elmB.innerHTML = '&' + codeA; + elmA.innerHTML = '&' + codeB; + elmN.innerHTML = codeN; +} diff --git a/tools/tiny_mce/themes/advanced/js/color_picker.js b/tools/tiny_mce/themes/advanced/js/color_picker.js new file mode 100644 index 00000000..c491ffd8 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/js/color_picker.js @@ -0,0 +1,329 @@ +tinyMCEPopup.requireLangPack(); + +var detail = 50, strhex = "0123456789ABCDEF", i, isMouseDown = false, isMouseOver = false; + +var colors = [ + "#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033", + "#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099", + "#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff", + "#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033", + "#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399", + "#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff", + "#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333", + "#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399", + "#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff", + "#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633", + "#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699", + "#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff", + "#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633", + "#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999", + "#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff", + "#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933", + "#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999", + "#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff", + "#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33", + "#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99", + "#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff", + "#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33", + "#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99", + "#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff", + "#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33", + "#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99", + "#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff" +]; + +var named = { + '#F0F8FF':'Alice Blue','#FAEBD7':'Antique White','#00FFFF':'Aqua','#7FFFD4':'Aquamarine','#F0FFFF':'Azure','#F5F5DC':'Beige', + '#FFE4C4':'Bisque','#000000':'Black','#FFEBCD':'Blanched Almond','#0000FF':'Blue','#8A2BE2':'Blue Violet','#A52A2A':'Brown', + '#DEB887':'Burly Wood','#5F9EA0':'Cadet Blue','#7FFF00':'Chartreuse','#D2691E':'Chocolate','#FF7F50':'Coral','#6495ED':'Cornflower Blue', + '#FFF8DC':'Cornsilk','#DC143C':'Crimson','#00FFFF':'Cyan','#00008B':'Dark Blue','#008B8B':'Dark Cyan','#B8860B':'Dark Golden Rod', + '#A9A9A9':'Dark Gray','#A9A9A9':'Dark Grey','#006400':'Dark Green','#BDB76B':'Dark Khaki','#8B008B':'Dark Magenta','#556B2F':'Dark Olive Green', + '#FF8C00':'Darkorange','#9932CC':'Dark Orchid','#8B0000':'Dark Red','#E9967A':'Dark Salmon','#8FBC8F':'Dark Sea Green','#483D8B':'Dark Slate Blue', + '#2F4F4F':'Dark Slate Gray','#2F4F4F':'Dark Slate Grey','#00CED1':'Dark Turquoise','#9400D3':'Dark Violet','#FF1493':'Deep Pink','#00BFFF':'Deep Sky Blue', + '#696969':'Dim Gray','#696969':'Dim Grey','#1E90FF':'Dodger Blue','#B22222':'Fire Brick','#FFFAF0':'Floral White','#228B22':'Forest Green', + '#FF00FF':'Fuchsia','#DCDCDC':'Gainsboro','#F8F8FF':'Ghost White','#FFD700':'Gold','#DAA520':'Golden Rod','#808080':'Gray','#808080':'Grey', + '#008000':'Green','#ADFF2F':'Green Yellow','#F0FFF0':'Honey Dew','#FF69B4':'Hot Pink','#CD5C5C':'Indian Red','#4B0082':'Indigo','#FFFFF0':'Ivory', + '#F0E68C':'Khaki','#E6E6FA':'Lavender','#FFF0F5':'Lavender Blush','#7CFC00':'Lawn Green','#FFFACD':'Lemon Chiffon','#ADD8E6':'Light Blue', + '#F08080':'Light Coral','#E0FFFF':'Light Cyan','#FAFAD2':'Light Golden Rod Yellow','#D3D3D3':'Light Gray','#D3D3D3':'Light Grey','#90EE90':'Light Green', + '#FFB6C1':'Light Pink','#FFA07A':'Light Salmon','#20B2AA':'Light Sea Green','#87CEFA':'Light Sky Blue','#778899':'Light Slate Gray','#778899':'Light Slate Grey', + '#B0C4DE':'Light Steel Blue','#FFFFE0':'Light Yellow','#00FF00':'Lime','#32CD32':'Lime Green','#FAF0E6':'Linen','#FF00FF':'Magenta','#800000':'Maroon', + '#66CDAA':'Medium Aqua Marine','#0000CD':'Medium Blue','#BA55D3':'Medium Orchid','#9370D8':'Medium Purple','#3CB371':'Medium Sea Green','#7B68EE':'Medium Slate Blue', + '#00FA9A':'Medium Spring Green','#48D1CC':'Medium Turquoise','#C71585':'Medium Violet Red','#191970':'Midnight Blue','#F5FFFA':'Mint Cream','#FFE4E1':'Misty Rose','#FFE4B5':'Moccasin', + '#FFDEAD':'Navajo White','#000080':'Navy','#FDF5E6':'Old Lace','#808000':'Olive','#6B8E23':'Olive Drab','#FFA500':'Orange','#FF4500':'Orange Red','#DA70D6':'Orchid', + '#EEE8AA':'Pale Golden Rod','#98FB98':'Pale Green','#AFEEEE':'Pale Turquoise','#D87093':'Pale Violet Red','#FFEFD5':'Papaya Whip','#FFDAB9':'Peach Puff', + '#CD853F':'Peru','#FFC0CB':'Pink','#DDA0DD':'Plum','#B0E0E6':'Powder Blue','#800080':'Purple','#FF0000':'Red','#BC8F8F':'Rosy Brown','#4169E1':'Royal Blue', + '#8B4513':'Saddle Brown','#FA8072':'Salmon','#F4A460':'Sandy Brown','#2E8B57':'Sea Green','#FFF5EE':'Sea Shell','#A0522D':'Sienna','#C0C0C0':'Silver', + '#87CEEB':'Sky Blue','#6A5ACD':'Slate Blue','#708090':'Slate Gray','#708090':'Slate Grey','#FFFAFA':'Snow','#00FF7F':'Spring Green', + '#4682B4':'Steel Blue','#D2B48C':'Tan','#008080':'Teal','#D8BFD8':'Thistle','#FF6347':'Tomato','#40E0D0':'Turquoise','#EE82EE':'Violet', + '#F5DEB3':'Wheat','#FFFFFF':'White','#F5F5F5':'White Smoke','#FFFF00':'Yellow','#9ACD32':'Yellow Green' +}; + +var namedLookup = {}; + +function init() { + var inputColor = convertRGBToHex(tinyMCEPopup.getWindowArg('input_color')), key, value; + + tinyMCEPopup.resizeToInnerSize(); + + generatePicker(); + generateWebColors(); + generateNamedColors(); + + if (inputColor) { + changeFinalColor(inputColor); + + col = convertHexToRGB(inputColor); + + if (col) + updateLight(col.r, col.g, col.b); + } + + for (key in named) { + value = named[key]; + namedLookup[value.replace(/\s+/, '').toLowerCase()] = key.replace(/#/, '').toLowerCase(); + } +} + +function toHexColor(color) { + var matches, red, green, blue, toInt = parseInt; + + function hex(value) { + value = parseInt(value).toString(16); + + return value.length > 1 ? value : '0' + value; // Padd with leading zero + }; + + color = color.replace(/[\s#]+/g, '').toLowerCase(); + color = namedLookup[color] || color; + matches = /^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)|([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})|([a-f0-9])([a-f0-9])([a-f0-9])$/.exec(color); + + if (matches) { + if (matches[1]) { + red = toInt(matches[1]); + green = toInt(matches[2]); + blue = toInt(matches[3]); + } else if (matches[4]) { + red = toInt(matches[4], 16); + green = toInt(matches[5], 16); + blue = toInt(matches[6], 16); + } else if (matches[7]) { + red = toInt(matches[7] + matches[7], 16); + green = toInt(matches[8] + matches[8], 16); + blue = toInt(matches[9] + matches[9], 16); + } + + return '#' + hex(red) + hex(green) + hex(blue); + } + + return ''; +} + +function insertAction() { + var color = document.getElementById("color").value, f = tinyMCEPopup.getWindowArg('func'); + + tinyMCEPopup.restoreSelection(); + + if (f) + f(toHexColor(color)); + + tinyMCEPopup.close(); +} + +function showColor(color, name) { + if (name) + document.getElementById("colorname").innerHTML = name; + + document.getElementById("preview").style.backgroundColor = color; + document.getElementById("color").value = color.toUpperCase(); +} + +function convertRGBToHex(col) { + var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi"); + + if (!col) + return col; + + var rgb = col.replace(re, "$1,$2,$3").split(','); + if (rgb.length == 3) { + r = parseInt(rgb[0]).toString(16); + g = parseInt(rgb[1]).toString(16); + b = parseInt(rgb[2]).toString(16); + + r = r.length == 1 ? '0' + r : r; + g = g.length == 1 ? '0' + g : g; + b = b.length == 1 ? '0' + b : b; + + return "#" + r + g + b; + } + + return col; +} + +function convertHexToRGB(col) { + if (col.indexOf('#') != -1) { + col = col.replace(new RegExp('[^0-9A-F]', 'gi'), ''); + + r = parseInt(col.substring(0, 2), 16); + g = parseInt(col.substring(2, 4), 16); + b = parseInt(col.substring(4, 6), 16); + + return {r : r, g : g, b : b}; + } + + return null; +} + +function generatePicker() { + var el = document.getElementById('light'), h = '', i; + + for (i = 0; i < detail; i++){ + h += '
    '; + } + + el.innerHTML = h; +} + +function generateWebColors() { + var el = document.getElementById('webcolors'), h = '', i; + + if (el.className == 'generated') + return; + + // TODO: VoiceOver doesn't seem to support legend as a label referenced by labelledby. + h += '
    ' + + ''; + + for (i=0; i' + + ''; + if (tinyMCEPopup.editor.forcedHighContrastMode) { + h += ''; + } + h += ''; + h += ''; + if ((i+1) % 18 == 0) + h += ''; + } + + h += '
    '; + + el.innerHTML = h; + el.className = 'generated'; + + paintCanvas(el); + enableKeyboardNavigation(el.firstChild); +} + +function paintCanvas(el) { + tinyMCEPopup.getWin().tinymce.each(tinyMCEPopup.dom.select('canvas.mceColorSwatch', el), function(canvas) { + var context; + if (canvas.getContext && (context = canvas.getContext("2d"))) { + context.fillStyle = canvas.getAttribute('data-color'); + context.fillRect(0, 0, 10, 10); + } + }); +} +function generateNamedColors() { + var el = document.getElementById('namedcolors'), h = '', n, v, i = 0; + + if (el.className == 'generated') + return; + + for (n in named) { + v = named[n]; + h += ''; + if (tinyMCEPopup.editor.forcedHighContrastMode) { + h += ''; + } + h += ''; + h += ''; + i++; + } + + el.innerHTML = h; + el.className = 'generated'; + + paintCanvas(el); + enableKeyboardNavigation(el); +} + +function enableKeyboardNavigation(el) { + tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', { + root: el, + items: tinyMCEPopup.dom.select('a', el) + }, tinyMCEPopup.dom); +} + +function dechex(n) { + return strhex.charAt(Math.floor(n / 16)) + strhex.charAt(n % 16); +} + +function computeColor(e) { + var x, y, partWidth, partDetail, imHeight, r, g, b, coef, i, finalCoef, finalR, finalG, finalB; + + x = e.offsetX ? e.offsetX : (e.target ? e.clientX - e.target.x : 0); + y = e.offsetY ? e.offsetY : (e.target ? e.clientY - e.target.y : 0); + + partWidth = document.getElementById('colors').width / 6; + partDetail = detail / 2; + imHeight = document.getElementById('colors').height; + + r = (x >= 0)*(x < partWidth)*255 + (x >= partWidth)*(x < 2*partWidth)*(2*255 - x * 255 / partWidth) + (x >= 4*partWidth)*(x < 5*partWidth)*(-4*255 + x * 255 / partWidth) + (x >= 5*partWidth)*(x < 6*partWidth)*255; + g = (x >= 0)*(x < partWidth)*(x * 255 / partWidth) + (x >= partWidth)*(x < 3*partWidth)*255 + (x >= 3*partWidth)*(x < 4*partWidth)*(4*255 - x * 255 / partWidth); + b = (x >= 2*partWidth)*(x < 3*partWidth)*(-2*255 + x * 255 / partWidth) + (x >= 3*partWidth)*(x < 5*partWidth)*255 + (x >= 5*partWidth)*(x < 6*partWidth)*(6*255 - x * 255 / partWidth); + + coef = (imHeight - y) / imHeight; + r = 128 + (r - 128) * coef; + g = 128 + (g - 128) * coef; + b = 128 + (b - 128) * coef; + + changeFinalColor('#' + dechex(r) + dechex(g) + dechex(b)); + updateLight(r, g, b); +} + +function updateLight(r, g, b) { + var i, partDetail = detail / 2, finalCoef, finalR, finalG, finalB, color; + + for (i=0; i=0) && (i'); + }, + + init : function() { + var f = document.forms[0], ed = tinyMCEPopup.editor; + + // Setup browse button + document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image'); + if (isVisible('srcbrowser')) + document.getElementById('src').style.width = '180px'; + + e = ed.selection.getNode(); + + this.fillFileList('image_list', 'tinyMCEImageList'); + + if (e.nodeName == 'IMG') { + f.src.value = ed.dom.getAttrib(e, 'src'); + f.alt.value = ed.dom.getAttrib(e, 'alt'); + f.border.value = this.getAttrib(e, 'border'); + f.vspace.value = this.getAttrib(e, 'vspace'); + f.hspace.value = this.getAttrib(e, 'hspace'); + f.width.value = ed.dom.getAttrib(e, 'width'); + f.height.value = ed.dom.getAttrib(e, 'height'); + f.insert.value = ed.getLang('update'); + this.styleVal = ed.dom.getAttrib(e, 'style'); + selectByValue(f, 'image_list', f.src.value); + selectByValue(f, 'align', this.getAttrib(e, 'align')); + this.updateStyle(); + } + }, + + fillFileList : function(id, l) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + l = window[l]; + + if (l && l.length > 0) { + lst.options[lst.options.length] = new Option('', ''); + + tinymce.each(l, function(o) { + lst.options[lst.options.length] = new Option(o[0], o[1]); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + update : function() { + var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, args = {}, el; + + tinyMCEPopup.restoreSelection(); + + if (f.src.value === '') { + if (ed.selection.getNode().nodeName == 'IMG') { + ed.dom.remove(ed.selection.getNode()); + ed.execCommand('mceRepaint'); + } + + tinyMCEPopup.close(); + return; + } + + if (!ed.settings.inline_styles) { + args = tinymce.extend(args, { + vspace : nl.vspace.value, + hspace : nl.hspace.value, + border : nl.border.value, + align : getSelectValue(f, 'align') + }); + } else + args.style = this.styleVal; + + tinymce.extend(args, { + src : f.src.value.replace(/ /g, '%20'), + alt : f.alt.value, + width : f.width.value, + height : f.height.value + }); + + el = ed.selection.getNode(); + + if (el && el.nodeName == 'IMG') { + ed.dom.setAttribs(el, args); + tinyMCEPopup.editor.execCommand('mceRepaint'); + tinyMCEPopup.editor.focus(); + } else { + ed.execCommand('mceInsertContent', false, '', {skip_undo : 1}); + ed.dom.setAttribs('__mce_tmp', args); + ed.dom.setAttrib('__mce_tmp', 'id', ''); + ed.undoManager.add(); + } + + tinyMCEPopup.close(); + }, + + updateStyle : function() { + var dom = tinyMCEPopup.dom, st, v, f = document.forms[0]; + + if (tinyMCEPopup.editor.settings.inline_styles) { + st = tinyMCEPopup.dom.parseStyle(this.styleVal); + + // Handle align + v = getSelectValue(f, 'align'); + if (v) { + if (v == 'left' || v == 'right') { + st['float'] = v; + delete st['vertical-align']; + } else { + st['vertical-align'] = v; + delete st['float']; + } + } else { + delete st['float']; + delete st['vertical-align']; + } + + // Handle border + v = f.border.value; + if (v || v == '0') { + if (v == '0') + st['border'] = '0'; + else + st['border'] = v + 'px solid black'; + } else + delete st['border']; + + // Handle hspace + v = f.hspace.value; + if (v) { + delete st['margin']; + st['margin-left'] = v + 'px'; + st['margin-right'] = v + 'px'; + } else { + delete st['margin-left']; + delete st['margin-right']; + } + + // Handle vspace + v = f.vspace.value; + if (v) { + delete st['margin']; + st['margin-top'] = v + 'px'; + st['margin-bottom'] = v + 'px'; + } else { + delete st['margin-top']; + delete st['margin-bottom']; + } + + // Merge + st = tinyMCEPopup.dom.parseStyle(dom.serializeStyle(st), 'img'); + this.styleVal = dom.serializeStyle(st, 'img'); + } + }, + + getAttrib : function(e, at) { + var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2; + + if (ed.settings.inline_styles) { + switch (at) { + case 'align': + if (v = dom.getStyle(e, 'float')) + return v; + + if (v = dom.getStyle(e, 'vertical-align')) + return v; + + break; + + case 'hspace': + v = dom.getStyle(e, 'margin-left') + v2 = dom.getStyle(e, 'margin-right'); + if (v && v == v2) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + + case 'vspace': + v = dom.getStyle(e, 'margin-top') + v2 = dom.getStyle(e, 'margin-bottom'); + if (v && v == v2) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + + case 'border': + v = 0; + + tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) { + sv = dom.getStyle(e, 'border-' + sv + '-width'); + + // False or not the same as prev + if (!sv || (sv != v && v !== 0)) { + v = 0; + return false; + } + + if (sv) + v = sv; + }); + + if (v) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + } + } + + if (v = dom.getAttrib(e, at)) + return v; + + return ''; + }, + + resetImageData : function() { + var f = document.forms[0]; + + f.width.value = f.height.value = ""; + }, + + updateImageData : function() { + var f = document.forms[0], t = ImageDialog; + + if (f.width.value == "") + f.width.value = t.preloadImg.width; + + if (f.height.value == "") + f.height.value = t.preloadImg.height; + }, + + getImageData : function() { + var f = document.forms[0]; + + this.preloadImg = new Image(); + this.preloadImg.onload = this.updateImageData; + this.preloadImg.onerror = this.resetImageData; + this.preloadImg.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(f.src.value); + } +}; + +ImageDialog.preInit(); +tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog); diff --git a/tools/tiny_mce/themes/advanced/js/link.js b/tools/tiny_mce/themes/advanced/js/link.js new file mode 100644 index 00000000..f64a88d9 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/js/link.js @@ -0,0 +1,156 @@ +tinyMCEPopup.requireLangPack(); + +var LinkDialog = { + preInit : function() { + var url; + + if (url = tinyMCEPopup.getParam("external_link_list_url")) + document.write(''); + }, + + init : function() { + var f = document.forms[0], ed = tinyMCEPopup.editor; + + // Setup browse button + document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser', 'href', 'file', 'theme_advanced_link'); + if (isVisible('hrefbrowser')) + document.getElementById('href').style.width = '180px'; + + this.fillClassList('class_list'); + this.fillFileList('link_list', 'tinyMCELinkList'); + this.fillTargetList('target_list'); + + if (e = ed.dom.getParent(ed.selection.getNode(), 'A')) { + f.href.value = ed.dom.getAttrib(e, 'href'); + f.linktitle.value = ed.dom.getAttrib(e, 'title'); + f.insert.value = ed.getLang('update'); + selectByValue(f, 'link_list', f.href.value); + selectByValue(f, 'target_list', ed.dom.getAttrib(e, 'target')); + selectByValue(f, 'class_list', ed.dom.getAttrib(e, 'class')); + } + }, + + update : function() { + var f = document.forms[0], ed = tinyMCEPopup.editor, e, b, href = f.href.value.replace(/ /g, '%20'); + + tinyMCEPopup.restoreSelection(); + e = ed.dom.getParent(ed.selection.getNode(), 'A'); + + // Remove element if there is no href + if (!f.href.value) { + if (e) { + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + b = ed.selection.getBookmark(); + ed.dom.remove(e, 1); + ed.selection.moveToBookmark(b); + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); + return; + } + } + + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + + // Create new anchor elements + if (e == null) { + ed.getDoc().execCommand("unlink", false, null); + tinyMCEPopup.execCommand("CreateLink", false, "#mce_temp_url#", {skip_undo : 1}); + + tinymce.each(ed.dom.select("a"), function(n) { + if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') { + e = n; + + ed.dom.setAttribs(e, { + href : href, + title : f.linktitle.value, + target : f.target_list ? getSelectValue(f, "target_list") : null, + 'class' : f.class_list ? getSelectValue(f, "class_list") : null + }); + } + }); + } else { + ed.dom.setAttribs(e, { + href : href, + title : f.linktitle.value, + target : f.target_list ? getSelectValue(f, "target_list") : null, + 'class' : f.class_list ? getSelectValue(f, "class_list") : null + }); + } + + // Don't move caret if selection was image + if (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') { + ed.focus(); + ed.selection.select(e); + ed.selection.collapse(0); + tinyMCEPopup.storeSelection(); + } + + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); + }, + + checkPrefix : function(n) { + if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_email'))) + n.value = 'mailto:' + n.value; + + if (/^\s*www\./i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_external'))) + n.value = 'http://' + n.value; + }, + + fillFileList : function(id, l) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + l = window[l]; + + if (l && l.length > 0) { + lst.options[lst.options.length] = new Option('', ''); + + tinymce.each(l, function(o) { + lst.options[lst.options.length] = new Option(o[0], o[1]); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + fillClassList : function(id) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + if (v = tinyMCEPopup.getParam('theme_advanced_styles')) { + cl = []; + + tinymce.each(v.split(';'), function(v) { + var p = v.split('='); + + cl.push({'title' : p[0], 'class' : p[1]}); + }); + } else + cl = tinyMCEPopup.editor.dom.getClasses(); + + if (cl.length > 0) { + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), ''); + + tinymce.each(cl, function(o) { + lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + fillTargetList : function(id) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v; + + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), ''); + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_same'), '_self'); + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_blank'), '_blank'); + + if (v = tinyMCEPopup.getParam('theme_advanced_link_targets')) { + tinymce.each(v.split(','), function(v) { + v = v.split('='); + lst.options[lst.options.length] = new Option(v[0], v[1]); + }); + } + } +}; + +LinkDialog.preInit(); +tinyMCEPopup.onInit.add(LinkDialog.init, LinkDialog); diff --git a/tools/tiny_mce/themes/advanced/js/source_editor.js b/tools/tiny_mce/themes/advanced/js/source_editor.js new file mode 100644 index 00000000..4f61d1c7 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/js/source_editor.js @@ -0,0 +1,56 @@ +tinyMCEPopup.requireLangPack(); +tinyMCEPopup.onInit.add(onLoadInit); + +function saveContent() { + tinyMCEPopup.editor.setContent(document.getElementById('htmlSource').value, {source_view : true}); + tinyMCEPopup.close(); +} + +function onLoadInit() { + tinyMCEPopup.resizeToInnerSize(); + + // Remove Gecko spellchecking + if (tinymce.isGecko) + document.body.spellcheck = tinyMCEPopup.editor.getParam("gecko_spellcheck"); + + document.getElementById('htmlSource').value = tinyMCEPopup.editor.getContent({source_view : true}); + + if (tinyMCEPopup.editor.getParam("theme_advanced_source_editor_wrap", true)) { + setWrap('soft'); + document.getElementById('wraped').checked = true; + } + + resizeInputs(); +} + +function setWrap(val) { + var v, n, s = document.getElementById('htmlSource'); + + s.wrap = val; + + if (!tinymce.isIE) { + v = s.value; + n = s.cloneNode(false); + n.setAttribute("wrap", val); + s.parentNode.replaceChild(n, s); + n.value = v; + } +} + +function toggleWordWrap(elm) { + if (elm.checked) + setWrap('soft'); + else + setWrap('off'); +} + +function resizeInputs() { + var vp = tinyMCEPopup.dom.getViewPort(window), el; + + el = document.getElementById('htmlSource'); + + if (el) { + el.style.width = (vp.w - 20) + 'px'; + el.style.height = (vp.h - 65) + 'px'; + } +} diff --git a/tools/tiny_mce/themes/advanced/langs/en.js b/tools/tiny_mce/themes/advanced/langs/en.js new file mode 100644 index 00000000..4c74747e --- /dev/null +++ b/tools/tiny_mce/themes/advanced/langs/en.js @@ -0,0 +1,68 @@ +tinyMCE.addI18n('en.advanced',{ +style_select:"Styles", +font_size:"Font size", +fontdefault:"Font family", +block:"Format", +paragraph:"Paragraph", +div:"Div", +address:"Address", +pre:"Preformatted", +h1:"Heading 1", +h2:"Heading 2", +h3:"Heading 3", +h4:"Heading 4", +h5:"Heading 5", +h6:"Heading 6", +blockquote:"Blockquote", +code:"Code", +samp:"Code sample", +dt:"Definition term ", +dd:"Definition description", +bold_desc:"Bold (Ctrl+B)", +italic_desc:"Italic (Ctrl+I)", +underline_desc:"Underline (Ctrl+U)", +striketrough_desc:"Strikethrough", +justifyleft_desc:"Align left", +justifycenter_desc:"Align center", +justifyright_desc:"Align right", +justifyfull_desc:"Align full", +bullist_desc:"Unordered list", +numlist_desc:"Ordered list", +outdent_desc:"Outdent", +indent_desc:"Indent", +undo_desc:"Undo (Ctrl+Z)", +redo_desc:"Redo (Ctrl+Y)", +link_desc:"Insert/edit link", +unlink_desc:"Unlink", +image_desc:"Insert/edit image", +cleanup_desc:"Cleanup messy code", +code_desc:"Edit HTML Source", +sub_desc:"Subscript", +sup_desc:"Superscript", +hr_desc:"Insert horizontal ruler", +removeformat_desc:"Remove formatting", +custom1_desc:"Your custom description here", +forecolor_desc:"Select text color", +backcolor_desc:"Select background color", +charmap_desc:"Insert custom character", +visualaid_desc:"Toggle guidelines/invisible elements", +anchor_desc:"Insert/edit anchor", +cut_desc:"Cut", +copy_desc:"Copy", +paste_desc:"Paste", +image_props_desc:"Image properties", +newdocument_desc:"New document", +help_desc:"Help", +blockquote_desc:"Blockquote", +clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\r\nDo you want more information about this issue?", +path:"Path", +newdocument:"Are you sure you want clear all contents?", +toolbar_focus:"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X", +more_colors:"More colors", + +// Accessibility Strings +shortcuts_desc:'Accessibility Help', +help_shortcut:'. Press ALT F10 for toolbar. Press ALT 0 for help.', +rich_text_area:"Rich Text Area", +toolbar:"Toolbar" +}); diff --git a/tools/tiny_mce/themes/advanced/langs/en_dlg.js b/tools/tiny_mce/themes/advanced/langs/en_dlg.js new file mode 100644 index 00000000..7f836506 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/langs/en_dlg.js @@ -0,0 +1,53 @@ +tinyMCE.addI18n('en.advanced_dlg',{ +about_title:"About TinyMCE", +about_general:"About", +about_help:"Help", +about_license:"License", +about_plugins:"Plugins", +about_plugin:"Plugin", +about_author:"Author", +about_version:"Version", +about_loaded:"Loaded plugins", +anchor_title:"Insert/edit anchor", +anchor_name:"Anchor name", +code_title:"HTML Source Editor", +code_wordwrap:"Word wrap", +colorpicker_title:"Select a color", +colorpicker_picker_tab:"Picker", +colorpicker_picker_title:"Color picker", +colorpicker_palette_tab:"Palette", +colorpicker_palette_title:"Palette colors", +colorpicker_named_tab:"Named", +colorpicker_named_title:"Named colors", +colorpicker_color:"Color:", +colorpicker_name:"Name:", +charmap_title:"Select custom character", +image_title:"Insert/edit image", +image_src:"Image URL", +image_alt:"Image description", +image_list:"Image list", +image_border:"Border", +image_dimensions:"Dimensions", +image_vspace:"Vertical space", +image_hspace:"Horizontal space", +image_align:"Alignment", +image_align_baseline:"Baseline", +image_align_top:"Top", +image_align_middle:"Middle", +image_align_bottom:"Bottom", +image_align_texttop:"Text top", +image_align_textbottom:"Text bottom", +image_align_left:"Left", +image_align_right:"Right", +link_title:"Insert/edit link", +link_url:"Link URL", +link_target:"Target", +link_target_same:"Open link in the same window", +link_target_blank:"Open link in a new window", +link_titlefield:"Title", +link_is_email:"The URL you entered seems to be an email address, do you want to add the required mailto: prefix?", +link_is_external:"The URL you entered seems to external link, do you want to add the required http:// prefix?", +link_list:"Link list", +accessibility_help:"Accessibility Help", +accessibility_usage_title:"General Usage" +}); \ No newline at end of file diff --git a/tools/tiny_mce/themes/advanced/link.htm b/tools/tiny_mce/themes/advanced/link.htm new file mode 100644 index 00000000..22627ccc --- /dev/null +++ b/tools/tiny_mce/themes/advanced/link.htm @@ -0,0 +1,58 @@ + + + + {#advanced_dlg.link_title} + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    +
    +
    + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/themes/advanced/shortcuts.htm b/tools/tiny_mce/themes/advanced/shortcuts.htm new file mode 100644 index 00000000..436091f1 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/shortcuts.htm @@ -0,0 +1,47 @@ + + + + {#advanced_dlg.accessibility_help} + + + + +

    {#advanced_dlg.accessibility_usage_title}

    +

    Toolbars

    +

    Press ALT-F10 to move focus to the toolbars. Navigate through the buttons using the arrow keys. + Press enter to activate a button and return focus to the editor. + Press escape to return focus to the editor without performing any actions.

    + +

    Status Bar

    +

    To access the editor status bar, press ALT-F11. Use the left and right arrow keys to navigate between elements in the path. + Press enter or space to select an element. Press escape to return focus to the editor without changing the selection.

    + +

    Context Menu

    +

    Press shift-F10 to activate the context menu. Use the up and down arrow keys to move between menu items. To open sub-menus press the right arrow key. + To close submenus press the left arrow key. Press escape to close the context menu.

    + +

    Keyboard Shortcuts

    + + + + + + + + + + + + + + + + + + + + + +
    KeystrokeFunction
    Control-BBold
    Control-IItalic
    Control-ZUndo
    Control-YRedo
    + + diff --git a/tools/tiny_mce/themes/advanced/skins/default/content.css b/tools/tiny_mce/themes/advanced/skins/default/content.css new file mode 100644 index 00000000..adc5569a --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/default/content.css @@ -0,0 +1,37 @@ +body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;} +body {background:#FFF;} +body.mceForceColors {background:#FFF; color:#000;} +body.mceBrowserDefaults {background:transparent; color:inherit; font-size:inherit; font-family:inherit;} +h1 {font-size: 2em} +h2 {font-size: 1.5em} +h3 {font-size: 1.17em} +h4 {font-size: 1em} +h5 {font-size: .83em} +h6 {font-size: .75em} +.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;} +a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(img/items.gif) no-repeat 0 0;} +span.mceItemNbsp {background: #DDD} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +img {border:0;} +table {cursor:default} +table td, table th {cursor:text} +ins {border-bottom:1px solid green; text-decoration: none; color:green} +del {color:red; text-decoration:line-through} +cite {border-bottom:1px dashed blue} +acronym {border-bottom:1px dotted #CCC; cursor:help} +abbr {border-bottom:1px dashed #CCC; cursor:help} + +/* IE */ +* html body { +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} diff --git a/tools/tiny_mce/themes/advanced/skins/default/dialog.css b/tools/tiny_mce/themes/advanced/skins/default/dialog.css new file mode 100644 index 00000000..1f5598c6 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/default/dialog.css @@ -0,0 +1,117 @@ +/* Generic */ +body { +font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDDDDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +background:#F0F0EE; +padding:0; +margin:8px 8px 0 8px; +} + +html {background:#F0F0EE;} +td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +textarea {resize:none;outline:none;} +a:link, a:visited {color:black;} +a:hover {color:#2B6FB6;} +.nowrap {white-space: nowrap} + +/* Forms */ +fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} +legend {color:#2B6FB6; font-weight:bold;} +label.msg {display:none;} +label.invalid {color:#EE0000; display:inline;} +input.invalid {border:1px solid #EE0000;} +input {background:#FFF; border:1px solid #CCC;} +input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +input, select, textarea {border:1px solid #808080;} +input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} +input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} +.input_noborder {border:0;} + +/* Buttons */ +#insert, #cancel, input.button, .updateButton { +border:0; margin:0; padding:0; +font-weight:bold; +width:94px; height:26px; +background:url(img/buttons.png) 0 -26px; +cursor:pointer; +padding-bottom:2px; +float:left; +} + +#insert {background:url(img/buttons.png) 0 -52px} +#cancel {background:url(img/buttons.png) 0 0; float:right} + +/* Browse */ +a.pickcolor, a.browse {text-decoration:none} +a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;} +.mceOldBoxModel a.browse span {width:22px; height:20px;} +a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;} +a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +a.browse:hover span.disabled {border:1px solid white; background-color:transparent;} +a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;} +.mceOldBoxModel a.pickcolor span {width:21px; height:17px;} +a.pickcolor:hover span {background-color:#B2BBD0;} +a.pickcolor:hover span.disabled {} + +/* Charmap */ +table.charmap {border:1px solid #AAA; text-align:center} +td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;} +#charmap a {display:block; color:#000; text-decoration:none; border:0} +#charmap a:hover {background:#CCC;color:#2B6FB6} +#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center} +#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center} + +/* Source */ +.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;} +.mceActionPanel {margin-top:5px;} + +/* Tabs classes */ +.tabs {width:100%; height:18px; line-height:normal; background:url(img/tabs.gif) repeat-x 0 -72px;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; background:url(img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;} +.tabs li.current {background:url(img/tabs.gif) no-repeat 0 -18px; margin-right:2px;} +.tabs span {float:left; display:block; background:url(img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;} +.tabs .current span {background:url(img/tabs.gif) no-repeat right -54px;} +.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} +.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} + +/* Panels */ +.panel_wrapper div.panel {display:none;} +.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} +.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;} + +/* Columns */ +.column {float:left;} +.properties {width:100%;} +.properties .column1 {} +.properties .column2 {text-align:left;} + +/* Titles */ +h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} +h3 {font-size:14px;} +.title {font-size:12px; font-weight:bold; color:#2B6FB6;} + +/* Dialog specific */ +#link .panel_wrapper, #link div.current {height:125px;} +#image .panel_wrapper, #image div.current {height:200px;} +#plugintable thead {font-weight:bold; background:#DDD;} +#plugintable, #about #plugintable td {border:1px solid #919B9C;} +#plugintable {width:96%; margin-top:10px;} +#pluginscontainer {height:290px; overflow:auto;} +#colorpicker #preview {float:right; width:50px; height:14px;line-height:1px; border:1px solid black; margin-left:5px;} +#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;} +#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;} +#colorpicker #light div {overflow:hidden;} +#colorpicker #previewblock {float:right; padding-left:10px; height:20px;} +#colorpicker .panel_wrapper div.current {height:175px;} +#colorpicker #namedcolors {width:150px;} +#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} +#colorpicker #colornamecontainer {margin-top:5px;} +#colorpicker #picker_panel fieldset {margin:auto;width:325px;} diff --git a/tools/tiny_mce/themes/advanced/skins/default/img/buttons.png b/tools/tiny_mce/themes/advanced/skins/default/img/buttons.png new file mode 100644 index 00000000..7dd58418 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/default/img/buttons.png differ diff --git a/tools/tiny_mce/themes/advanced/skins/default/img/items.gif b/tools/tiny_mce/themes/advanced/skins/default/img/items.gif new file mode 100644 index 00000000..2eafd795 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/default/img/items.gif differ diff --git a/tools/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif b/tools/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif new file mode 100644 index 00000000..85e31dfb Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif differ diff --git a/tools/tiny_mce/themes/advanced/skins/default/img/menu_check.gif b/tools/tiny_mce/themes/advanced/skins/default/img/menu_check.gif new file mode 100644 index 00000000..adfdddcc Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/default/img/menu_check.gif differ diff --git a/tools/tiny_mce/themes/advanced/skins/default/img/progress.gif b/tools/tiny_mce/themes/advanced/skins/default/img/progress.gif new file mode 100644 index 00000000..5bb90fd6 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/default/img/progress.gif differ diff --git a/tools/tiny_mce/themes/advanced/skins/default/img/tabs.gif b/tools/tiny_mce/themes/advanced/skins/default/img/tabs.gif new file mode 100644 index 00000000..ce4be635 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/default/img/tabs.gif differ diff --git a/tools/tiny_mce/themes/advanced/skins/default/ui.css b/tools/tiny_mce/themes/advanced/skins/default/ui.css new file mode 100644 index 00000000..e14d36fa --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/default/ui.css @@ -0,0 +1,213 @@ +/* Reset */ +.defaultSkin table, .defaultSkin tbody, .defaultSkin a, .defaultSkin img, .defaultSkin tr, .defaultSkin div, .defaultSkin td, .defaultSkin iframe, .defaultSkin span, .defaultSkin *, .defaultSkin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left} +.defaultSkin a:hover, .defaultSkin a:link, .defaultSkin a:visited, .defaultSkin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000} +.defaultSkin table td {vertical-align:middle} + +/* Containers */ +.defaultSkin table {direction:ltr;background:transparent} +.defaultSkin iframe {display:block;} +.defaultSkin .mceToolbar {height:26px} +.defaultSkin .mceLeft {text-align:left} +.defaultSkin .mceRight {text-align:right} + +/* External */ +.defaultSkin .mceExternalToolbar {position:absolute; border:1px solid #CCC; border-bottom:0; display:none;} +.defaultSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.defaultSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0} + +/* Layout */ +.defaultSkin table.mceLayout {border:0; border-left:1px solid #CCC; border-right:1px solid #CCC} +.defaultSkin table.mceLayout tr.mceFirst td {border-top:1px solid #CCC} +.defaultSkin table.mceLayout tr.mceLast td {border-bottom:1px solid #CCC} +.defaultSkin table.mceToolbar, .defaultSkin tr.mceFirst .mceToolbar tr td, .defaultSkin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0;} +.defaultSkin td.mceToolbar {background:#F0F0EE; padding-top:1px; vertical-align:top} +.defaultSkin .mceIframeContainer {border-top:1px solid #CCC; border-bottom:1px solid #CCC} +.defaultSkin .mceStatusbar {background:#F0F0EE; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; display:block; height:20px} +.defaultSkin .mceStatusbar div {float:left; margin:2px} +.defaultSkin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0} +.defaultSkin .mceStatusbar a:hover {text-decoration:underline} +.defaultSkin table.mceToolbar {margin-left:3px} +.defaultSkin span.mceIcon, .defaultSkin img.mceIcon {display:block; width:20px; height:20px} +.defaultSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} +.defaultSkin td.mceCenter {text-align:center;} +.defaultSkin td.mceCenter table {margin:0 auto; text-align:left;} +.defaultSkin td.mceRight table {margin:0 0 0 auto;} + +/* Button */ +.defaultSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px; margin-right:1px} +.defaultSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0} +.defaultSkin a.mceButtonActive, .defaultSkin a.mceButtonSelected {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSkin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +.defaultSkin .mceButtonLabeled {width:auto} +.defaultSkin .mceButtonLabeled span.mceIcon {float:left} +.defaultSkin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica} +.defaultSkin .mceButtonDisabled .mceButtonLabel {color:#888} + +/* Separator */ +.defaultSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:2px 2px 0 4px} + +/* ListBox */ +.defaultSkin .mceListBox, .defaultSkin .mceListBox a {display:block} +.defaultSkin .mceListBox .mceText {padding-left:4px; width:70px; text-align:left; border:1px solid #CCC; border-right:0; background:#FFF; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden} +.defaultSkin .mceListBox .mceOpen {width:9px; height:20px; background:url(../../img/icons.gif) -741px 0; margin-right:2px; border:1px solid #CCC;} +.defaultSkin table.mceListBoxEnabled:hover .mceText, .defaultSkin .mceListBoxHover .mceText, .defaultSkin .mceListBoxSelected .mceText {border:1px solid #A2ABC0; border-right:0; background:#FFF} +.defaultSkin table.mceListBoxEnabled:hover .mceOpen, .defaultSkin .mceListBoxHover .mceOpen, .defaultSkin .mceListBoxSelected .mceOpen {background-color:#FFF; border:1px solid #A2ABC0} +.defaultSkin .mceListBoxDisabled a.mceText {color:gray; background-color:transparent;} +.defaultSkin .mceListBoxMenu {overflow:auto; overflow-x:hidden} +.defaultSkin .mceOldBoxModel .mceListBox .mceText {height:22px} +.defaultSkin .mceOldBoxModel .mceListBox .mceOpen {width:11px; height:22px;} +.defaultSkin select.mceNativeListBox {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:7pt; background:#F0F0EE; border:1px solid gray; margin-right:2px;} + +/* SplitButton */ +.defaultSkin .mceSplitButton {width:32px; height:20px; direction:ltr} +.defaultSkin .mceSplitButton a, .defaultSkin .mceSplitButton span {height:20px; display:block} +.defaultSkin .mceSplitButton a.mceAction {width:20px; border:1px solid #F0F0EE; border-right:0;} +.defaultSkin .mceSplitButton span.mceAction {width:20px; background-image:url(../../img/icons.gif);} +.defaultSkin .mceSplitButton a.mceOpen {width:9px; background:url(../../img/icons.gif) -741px 0; border:1px solid #F0F0EE;} +.defaultSkin .mceSplitButton span.mceOpen {display:none} +.defaultSkin table.mceSplitButtonEnabled:hover a.mceAction, .defaultSkin .mceSplitButtonHover a.mceAction, .defaultSkin .mceSplitButtonSelected a.mceAction {border:1px solid #0A246A; border-right:0; background-color:#B2BBD0} +.defaultSkin table.mceSplitButtonEnabled:hover a.mceOpen, .defaultSkin .mceSplitButtonHover a.mceOpen, .defaultSkin .mceSplitButtonSelected a.mceOpen {background-color:#B2BBD0; border:1px solid #0A246A;} +.defaultSkin .mceSplitButtonDisabled .mceAction, .defaultSkin .mceSplitButtonDisabled a.mceOpen {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +.defaultSkin .mceSplitButtonActive a.mceAction {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSkin .mceSplitButtonActive a.mceOpen {border-left:0;} + +/* ColorSplitButton */ +.defaultSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray} +.defaultSkin .mceColorSplitMenu td {padding:2px} +.defaultSkin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080} +.defaultSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.defaultSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} +.defaultSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2} +.defaultSkin a.mceMoreColors:hover {border:1px solid #0A246A} +.defaultSkin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a} +.defaultSkin .mce_forecolor span.mceAction, .defaultSkin .mce_backcolor span.mceAction {overflow:hidden; height:16px} + +/* Menu */ +.defaultSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #D4D0C8} +.defaultSkin .mceNoIcons span.mceIcon {width:0;} +.defaultSkin .mceNoIcons a .mceText {padding-left:10px} +.defaultSkin .mceMenu table {background:#FFF} +.defaultSkin .mceMenu a, .defaultSkin .mceMenu span, .defaultSkin .mceMenu {display:block} +.defaultSkin .mceMenu td {height:20px} +.defaultSkin .mceMenu a {position:relative;padding:3px 0 4px 0} +.defaultSkin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block} +.defaultSkin .mceMenu span.mceText, .defaultSkin .mceMenu .mcePreview {font-size:11px} +.defaultSkin .mceMenu pre.mceText {font-family:Monospace} +.defaultSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;} +.defaultSkin .mceMenu .mceMenuItemEnabled a:hover, .defaultSkin .mceMenu .mceMenuItemActive {background-color:#dbecf3} +.defaultSkin td.mceMenuItemSeparator {background:#DDD; height:1px} +.defaultSkin .mceMenuItemTitle a {border:0; background:#EEE; border-bottom:1px solid #DDD} +.defaultSkin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px} +.defaultSkin .mceMenuItemDisabled .mceText {color:#888} +.defaultSkin .mceMenuItemSelected .mceIcon {background:url(img/menu_check.gif)} +.defaultSkin .mceNoIcons .mceMenuItemSelected a {background:url(img/menu_arrow.gif) no-repeat -6px center} +.defaultSkin .mceMenu span.mceMenuLine {display:none} +.defaultSkin .mceMenuItemSub a {background:url(img/menu_arrow.gif) no-repeat top right;} + +/* Progress,Resize */ +.defaultSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50); background:#FFF} +.defaultSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} + +/* Formats */ +.defaultSkin .mce_formatPreview a {font-size:10px} +.defaultSkin .mce_p span.mceText {} +.defaultSkin .mce_address span.mceText {font-style:italic} +.defaultSkin .mce_pre span.mceText {font-family:monospace} +.defaultSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.defaultSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.defaultSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.defaultSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.defaultSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.defaultSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} + +/* Theme */ +.defaultSkin span.mce_bold {background-position:0 0} +.defaultSkin span.mce_italic {background-position:-60px 0} +.defaultSkin span.mce_underline {background-position:-140px 0} +.defaultSkin span.mce_strikethrough {background-position:-120px 0} +.defaultSkin span.mce_undo {background-position:-160px 0} +.defaultSkin span.mce_redo {background-position:-100px 0} +.defaultSkin span.mce_cleanup {background-position:-40px 0} +.defaultSkin span.mce_bullist {background-position:-20px 0} +.defaultSkin span.mce_numlist {background-position:-80px 0} +.defaultSkin span.mce_justifyleft {background-position:-460px 0} +.defaultSkin span.mce_justifyright {background-position:-480px 0} +.defaultSkin span.mce_justifycenter {background-position:-420px 0} +.defaultSkin span.mce_justifyfull {background-position:-440px 0} +.defaultSkin span.mce_anchor {background-position:-200px 0} +.defaultSkin span.mce_indent {background-position:-400px 0} +.defaultSkin span.mce_outdent {background-position:-540px 0} +.defaultSkin span.mce_link {background-position:-500px 0} +.defaultSkin span.mce_unlink {background-position:-640px 0} +.defaultSkin span.mce_sub {background-position:-600px 0} +.defaultSkin span.mce_sup {background-position:-620px 0} +.defaultSkin span.mce_removeformat {background-position:-580px 0} +.defaultSkin span.mce_newdocument {background-position:-520px 0} +.defaultSkin span.mce_image {background-position:-380px 0} +.defaultSkin span.mce_help {background-position:-340px 0} +.defaultSkin span.mce_code {background-position:-260px 0} +.defaultSkin span.mce_hr {background-position:-360px 0} +.defaultSkin span.mce_visualaid {background-position:-660px 0} +.defaultSkin span.mce_charmap {background-position:-240px 0} +.defaultSkin span.mce_paste {background-position:-560px 0} +.defaultSkin span.mce_copy {background-position:-700px 0} +.defaultSkin span.mce_cut {background-position:-680px 0} +.defaultSkin span.mce_blockquote {background-position:-220px 0} +.defaultSkin .mce_forecolor span.mceAction {background-position:-720px 0} +.defaultSkin .mce_backcolor span.mceAction {background-position:-760px 0} +.defaultSkin span.mce_forecolorpicker {background-position:-720px 0} +.defaultSkin span.mce_backcolorpicker {background-position:-760px 0} + +/* Plugins */ +.defaultSkin span.mce_advhr {background-position:-0px -20px} +.defaultSkin span.mce_ltr {background-position:-20px -20px} +.defaultSkin span.mce_rtl {background-position:-40px -20px} +.defaultSkin span.mce_emotions {background-position:-60px -20px} +.defaultSkin span.mce_fullpage {background-position:-80px -20px} +.defaultSkin span.mce_fullscreen {background-position:-100px -20px} +.defaultSkin span.mce_iespell {background-position:-120px -20px} +.defaultSkin span.mce_insertdate {background-position:-140px -20px} +.defaultSkin span.mce_inserttime {background-position:-160px -20px} +.defaultSkin span.mce_absolute {background-position:-180px -20px} +.defaultSkin span.mce_backward {background-position:-200px -20px} +.defaultSkin span.mce_forward {background-position:-220px -20px} +.defaultSkin span.mce_insert_layer {background-position:-240px -20px} +.defaultSkin span.mce_insertlayer {background-position:-260px -20px} +.defaultSkin span.mce_movebackward {background-position:-280px -20px} +.defaultSkin span.mce_moveforward {background-position:-300px -20px} +.defaultSkin span.mce_media {background-position:-320px -20px} +.defaultSkin span.mce_nonbreaking {background-position:-340px -20px} +.defaultSkin span.mce_pastetext {background-position:-360px -20px} +.defaultSkin span.mce_pasteword {background-position:-380px -20px} +.defaultSkin span.mce_selectall {background-position:-400px -20px} +.defaultSkin span.mce_preview {background-position:-420px -20px} +.defaultSkin span.mce_print {background-position:-440px -20px} +.defaultSkin span.mce_cancel {background-position:-460px -20px} +.defaultSkin span.mce_save {background-position:-480px -20px} +.defaultSkin span.mce_replace {background-position:-500px -20px} +.defaultSkin span.mce_search {background-position:-520px -20px} +.defaultSkin span.mce_styleprops {background-position:-560px -20px} +.defaultSkin span.mce_table {background-position:-580px -20px} +.defaultSkin span.mce_cell_props {background-position:-600px -20px} +.defaultSkin span.mce_delete_table {background-position:-620px -20px} +.defaultSkin span.mce_delete_col {background-position:-640px -20px} +.defaultSkin span.mce_delete_row {background-position:-660px -20px} +.defaultSkin span.mce_col_after {background-position:-680px -20px} +.defaultSkin span.mce_col_before {background-position:-700px -20px} +.defaultSkin span.mce_row_after {background-position:-720px -20px} +.defaultSkin span.mce_row_before {background-position:-740px -20px} +.defaultSkin span.mce_merge_cells {background-position:-760px -20px} +.defaultSkin span.mce_table_props {background-position:-980px -20px} +.defaultSkin span.mce_row_props {background-position:-780px -20px} +.defaultSkin span.mce_split_cells {background-position:-800px -20px} +.defaultSkin span.mce_template {background-position:-820px -20px} +.defaultSkin span.mce_visualchars {background-position:-840px -20px} +.defaultSkin span.mce_abbr {background-position:-860px -20px} +.defaultSkin span.mce_acronym {background-position:-880px -20px} +.defaultSkin span.mce_attribs {background-position:-900px -20px} +.defaultSkin span.mce_cite {background-position:-920px -20px} +.defaultSkin span.mce_del {background-position:-940px -20px} +.defaultSkin span.mce_ins {background-position:-960px -20px} +.defaultSkin span.mce_pagebreak {background-position:0 -40px} +.defaultSkin span.mce_restoredraft {background-position:-20px -40px} +.defaultSkin span.mce_spellchecker {background-position:-540px -20px} diff --git a/tools/tiny_mce/themes/advanced/skins/highcontrast/content.css b/tools/tiny_mce/themes/advanced/skins/highcontrast/content.css new file mode 100644 index 00000000..75cfaf18 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/highcontrast/content.css @@ -0,0 +1,23 @@ +body, td, pre { margin:8px;} +body.mceForceColors {background:#FFF; color:#000;} +h1 {font-size: 2em} +h2 {font-size: 1.5em} +h3 {font-size: 1.17em} +h4 {font-size: 1em} +h5 {font-size: .83em} +h6 {font-size: .75em} +.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;} +a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;} +span.mceItemNbsp {background: #DDD} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +img {border:0;} +table {cursor:default} +table td, table th {cursor:text} +ins {border-bottom:1px solid green; text-decoration: none; color:green} +del {color:red; text-decoration:line-through} +cite {border-bottom:1px dashed blue} +acronym {border-bottom:1px dotted #CCC; cursor:help} +abbr {border-bottom:1px dashed #CCC; cursor:help} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} diff --git a/tools/tiny_mce/themes/advanced/skins/highcontrast/dialog.css b/tools/tiny_mce/themes/advanced/skins/highcontrast/dialog.css new file mode 100644 index 00000000..dafcd280 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/highcontrast/dialog.css @@ -0,0 +1,105 @@ +/* Generic */ +body { +font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; +background:#F0F0EE; +color: black; +padding:0; +margin:8px 8px 0 8px; +} + +html {background:#F0F0EE; color:#000;} +td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +textarea {resize:none;outline:none;} +a:link, a:visited {color:black;background-color:transparent;} +a:hover {color:#2B6FB6;background-color:transparent;} +.nowrap {white-space: nowrap} + +/* Forms */ +fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} +legend {color:#2B6FB6; font-weight:bold;} +label.msg {display:none;} +label.invalid {color:#EE0000; display:inline;background-color:transparent;} +input.invalid {border:1px solid #EE0000;background-color:transparent;} +input {background:#FFF; border:1px solid #CCC;color:black;} +input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +input, select, textarea {border:1px solid #808080;} +input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} +input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} +.input_noborder {border:0;} + +/* Buttons */ +#insert, #cancel, input.button, .updateButton { +font-weight:bold; +width:94px; height:23px; +cursor:pointer; +padding-bottom:2px; +float:left; +} + +#cancel {float:right} + +/* Browse */ +a.pickcolor, a.browse {text-decoration:none} +a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;} +.mceOldBoxModel a.browse span {width:22px; height:20px;} +a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;} +a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +a.browse:hover span.disabled {border:1px solid white; background-color:transparent;} +a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;} +.mceOldBoxModel a.pickcolor span {width:21px; height:17px;} +a.pickcolor:hover span {background-color:#B2BBD0;} +a.pickcolor:hover span.disabled {} + +/* Charmap */ +table.charmap {border:1px solid #AAA; text-align:center} +td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;} +#charmap a {display:block; color:#000; text-decoration:none; border:0} +#charmap a:hover {background:#CCC;color:#2B6FB6} +#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center} +#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center} + +/* Source */ +.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;} +.mceActionPanel {margin-top:5px;} + +/* Tabs classes */ +.tabs {width:100%; height:18px; line-height:normal;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; border: 1px solid black; border-bottom:0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block; cursor:pointer;} +.tabs li.current {font-weight: bold; margin-right:2px;} +.tabs span {float:left; display:block; padding:0px 10px 0 0;} +.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} +.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} + +/* Panels */ +.panel_wrapper div.panel {display:none;} +.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} +.panel_wrapper {border:1px solid #919B9C; padding:10px; padding-top:5px; clear:both; background:white;} + +/* Columns */ +.column {float:left;} +.properties {width:100%;} +.properties .column1 {} +.properties .column2 {text-align:left;} + +/* Titles */ +h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} +h3 {font-size:14px;} +.title {font-size:12px; font-weight:bold; color:#2B6FB6;} + +/* Dialog specific */ +#link .panel_wrapper, #link div.current {height:125px;} +#image .panel_wrapper, #image div.current {height:200px;} +#plugintable thead {font-weight:bold; background:#DDD;} +#plugintable, #about #plugintable td {border:1px solid #919B9C;} +#plugintable {width:96%; margin-top:10px;} +#pluginscontainer {height:290px; overflow:auto;} +#colorpicker #preview {float:right; width:50px; height:14px;line-height:1px; border:1px solid black; margin-left:5px;} +#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;} +#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;} +#colorpicker #light div {overflow:hidden;} +#colorpicker #previewblock {float:right; padding-left:10px; height:20px;} +#colorpicker .panel_wrapper div.current {height:175px;} +#colorpicker #namedcolors {width:150px;} +#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} +#colorpicker #colornamecontainer {margin-top:5px;} diff --git a/tools/tiny_mce/themes/advanced/skins/highcontrast/ui.css b/tools/tiny_mce/themes/advanced/skins/highcontrast/ui.css new file mode 100644 index 00000000..5e5b366b --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/highcontrast/ui.css @@ -0,0 +1,101 @@ +/* Reset */ +.highcontrastSkin table, .highcontrastSkin tbody, .highcontrastSkin a, .highcontrastSkin img, .highcontrastSkin tr, .highcontrastSkin div, .highcontrastSkin td, .highcontrastSkin iframe, .highcontrastSkin span, .highcontrastSkin *, .highcontrastSkin .mceText {border:0; margin:0; padding:0; vertical-align:baseline; border-collapse:separate;} +.highcontrastSkin a:hover, .highcontrastSkin a:link, .highcontrastSkin a:visited, .highcontrastSkin a:active {text-decoration:none; font-weight:normal; cursor:default;} +.highcontrastSkin table td {vertical-align:middle} + +.highcontrastSkin .mceIconOnly {display: block !important;} + +/* External */ +.highcontrastSkin .mceExternalToolbar {position:absolute; border:1px solid; border-bottom:0; display:none; background-color: white;} +.highcontrastSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.highcontrastSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px;} + +/* Layout */ +.highcontrastSkin table.mceLayout {border: 1px solid;} +.highcontrastSkin .mceIframeContainer {border-top:1px solid; border-bottom:1px solid} +.highcontrastSkin .mceStatusbar a:hover {text-decoration:underline} +.highcontrastSkin .mceStatusbar {display:block; line-height:1.5em; overflow:visible;} +.highcontrastSkin .mceStatusbar div {float:left} +.highcontrastSkin .mceStatusbar a.mceResize {display:block; float:right; width:20px; height:20px; cursor:se-resize; outline:0} + +.highcontrastSkin .mceToolbar td { display: inline-block; float: left;} +.highcontrastSkin .mceToolbar tr { display: block;} +.highcontrastSkin .mceToolbar table { display: block; } + +/* Button */ + +.highcontrastSkin .mceButton { display:block; margin: 2px; padding: 5px 10px;border: 1px solid; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -ms-border-radius: 3px; height: 2em;} +.highcontrastSkin .mceButton .mceVoiceLabel { height: 100%; vertical-align: center; line-height: 2em} +.highcontrastSkin .mceButtonDisabled .mceVoiceLabel { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);} +.highcontrastSkin .mceButtonActive, .highcontrastSkin .mceButton:focus, .highcontrastSkin .mceButton:active { border: 5px solid; padding: 1px 6px;-webkit-focus-ring-color:none;outline:none;} + +/* Separator */ +.highcontrastSkin .mceSeparator {display:block; width:16px; height:26px;} + +/* ListBox */ +.highcontrastSkin .mceListBox { display: block; margin:2px;-webkit-focus-ring-color:none;outline:none;} +.highcontrastSkin .mceListBox .mceText {padding: 5px 6px; line-height: 2em; width: 15ex; overflow: hidden;} +.highcontrastSkin .mceListBoxDisabled .mceText { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);} +.highcontrastSkin .mceListBox a.mceText { padding: 5px 10px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;} +.highcontrastSkin .mceListBox a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-left: 0; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;} +.highcontrastSkin .mceListBox:focus a.mceText, .highcontrastSkin .mceListBox:active a.mceText { border-width: 5px; padding: 1px 10px 1px 6px;} +.highcontrastSkin .mceListBox:focus a.mceOpen, .highcontrastSkin .mceListBox:active a.mceOpen { border-width: 5px; padding: 1px 0px 1px 4px;} + +.highcontrastSkin .mceListBoxMenu {overflow-y:auto} + +/* SplitButton */ +.highcontrastSkin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} + +.highcontrastSkin .mceSplitButton { border-collapse: collapse; margin: 2px; height: 2em; line-height: 2em;-webkit-focus-ring-color:none;outline:none;} +.highcontrastSkin .mceSplitButton td { display: table-cell; float: none; margin: 0; padding: 0; height: 2em;} +.highcontrastSkin .mceSplitButton tr { display: table-row; } +.highcontrastSkin table.mceSplitButton { display: table; } +.highcontrastSkin .mceSplitButton a.mceAction { padding: 5px 10px; display: block; height: 2em; line-height: 2em; overflow: hidden; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;} +.highcontrastSkin .mceSplitButton a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;} +.highcontrastSkin .mceSplitButton .mceVoiceLabel { height: 2em; vertical-align: center; line-height: 2em; } +.highcontrastSkin .mceSplitButton:focus a.mceAction, .highcontrastSkin .mceSplitButton:active a.mceAction { border-width: 5px; border-right-width: 1px; padding: 1px 10px 1px 6px;-webkit-focus-ring-color:none;outline:none;} +.highcontrastSkin .mceSplitButton:focus a.mceOpen, .highcontrastSkin .mceSplitButton:active a.mceOpen { border-width: 5px; border-left-width: 1px; padding: 1px 0px 1px 4px;-webkit-focus-ring-color:none;outline:none;} + +/* Menu */ +.highcontrastSkin .mceNoIcons span.mceIcon {width:0;} +.highcontrastSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid; } +.highcontrastSkin .mceMenu table {background:white; color: black} +.highcontrastSkin .mceNoIcons a .mceText {padding-left:10px} +.highcontrastSkin .mceMenu a, .highcontrastSkin .mceMenu span, .highcontrastSkin .mceMenu {display:block;background:white; color: black} +.highcontrastSkin .mceMenu td {height:2em} +.highcontrastSkin .mceMenu a {position:relative;padding:3px 0 4px 0; display: block;} +.highcontrastSkin .mceMenu .mceText {position:relative; display:block; cursor:default; margin:0; padding:0 25px 0 25px;} +.highcontrastSkin .mceMenu pre.mceText {font-family:Monospace} +.highcontrastSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:26px;} +.highcontrastSkin td.mceMenuItemSeparator {border-top:1px solid; height:1px} +.highcontrastSkin .mceMenuItemTitle a {border:0; border-bottom:1px solid} +.highcontrastSkin .mceMenuItemTitle span.mceText {font-weight:bold; padding-left:4px} +.highcontrastSkin .mceNoIcons .mceMenuItemSelected span.mceText:before {content: "\2713\A0";} +.highcontrastSkin .mceMenu span.mceMenuLine {display:none} +.highcontrastSkin .mceMenuItemSub a .mceText:after {content: "\A0\25B8"} + +/* ColorSplitButton */ +.highcontrastSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid; color: #000} +.highcontrastSkin .mceColorSplitMenu td {padding:2px} +.highcontrastSkin .mceColorSplitMenu a {display:block; width:16px; height:16px; overflow:hidden; color:#000; margin: 0; padding: 0;} +.highcontrastSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.highcontrastSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} +.highcontrastSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid; background-color:#B6BDD2} +.highcontrastSkin a.mceMoreColors:hover {border:1px solid #0A246A; color: #000;} +.highcontrastSkin .mceColorPreview {display:none;} +.highcontrastSkin .mce_forecolor span.mceAction, .highcontrastSkin .mce_backcolor span.mceAction {height:17px;overflow:hidden} + +/* Progress,Resize */ +.highcontrastSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF} +.highcontrastSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} + +/* Formats */ +.highcontrastSkin .mce_p span.mceText {} +.highcontrastSkin .mce_address span.mceText {font-style:italic} +.highcontrastSkin .mce_pre span.mceText {font-family:monospace} +.highcontrastSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.highcontrastSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.highcontrastSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.highcontrastSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.highcontrastSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.highcontrastSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} \ No newline at end of file diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/content.css b/tools/tiny_mce/themes/advanced/skins/o2k7/content.css new file mode 100644 index 00000000..500fa0de --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/o2k7/content.css @@ -0,0 +1,36 @@ +body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;} +body {background:#FFF;} +body.mceForceColors {background:#FFF; color:#000;} +h1 {font-size: 2em} +h2 {font-size: 1.5em} +h3 {font-size: 1.17em} +h4 {font-size: 1em} +h5 {font-size: .83em} +h6 {font-size: .75em} +.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;} +a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;} +span.mceItemNbsp {background: #DDD} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +img {border:0;} +table {cursor:default} +table td, table th {cursor:text} +ins {border-bottom:1px solid green; text-decoration: none; color:green} +del {color:red; text-decoration:line-through} +cite {border-bottom:1px dashed blue} +acronym {border-bottom:1px dotted #CCC; cursor:help} +abbr {border-bottom:1px dashed #CCC; cursor:help} + +/* IE */ +* html body { +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/dialog.css b/tools/tiny_mce/themes/advanced/skins/o2k7/dialog.css new file mode 100644 index 00000000..3b0760a6 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/o2k7/dialog.css @@ -0,0 +1,116 @@ +/* Generic */ +body { +font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDDDDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +background:#F0F0EE; +padding:0; +margin:8px 8px 0 8px; +} + +html {background:#F0F0EE;} +td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +textarea {resize:none;outline:none;} +a:link, a:visited {color:black;} +a:hover {color:#2B6FB6;} +.nowrap {white-space: nowrap} + +/* Forms */ +fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} +legend {color:#2B6FB6; font-weight:bold;} +label.msg {display:none;} +label.invalid {color:#EE0000; display:inline;} +input.invalid {border:1px solid #EE0000;} +input {background:#FFF; border:1px solid #CCC;} +input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +input, select, textarea {border:1px solid #808080;} +input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} +input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} +.input_noborder {border:0;} + +/* Buttons */ +#insert, #cancel, input.button, .updateButton { +border:0; margin:0; padding:0; +font-weight:bold; +width:94px; height:26px; +background:url(../default/img/buttons.png) 0 -26px; +cursor:pointer; +padding-bottom:2px; +float:left; +} + +#insert {background:url(../default/img/buttons.png) 0 -52px} +#cancel {background:url(../default/img/buttons.png) 0 0; float:right} + +/* Browse */ +a.pickcolor, a.browse {text-decoration:none} +a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;} +.mceOldBoxModel a.browse span {width:22px; height:20px;} +a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;} +a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +a.browse:hover span.disabled {border:1px solid white; background-color:transparent;} +a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;} +.mceOldBoxModel a.pickcolor span {width:21px; height:17px;} +a.pickcolor:hover span {background-color:#B2BBD0;} +a.pickcolor:hover span.disabled {} + +/* Charmap */ +table.charmap {border:1px solid #AAA; text-align:center} +td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;} +#charmap a {display:block; color:#000; text-decoration:none; border:0} +#charmap a:hover {background:#CCC;color:#2B6FB6} +#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center} +#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center} + +/* Source */ +.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;} +.mceActionPanel {margin-top:5px;} + +/* Tabs classes */ +.tabs {width:100%; height:18px; line-height:normal; background:url(../default/img/tabs.gif) repeat-x 0 -72px;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; background:url(../default/img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;} +.tabs li.current {background:url(../default/img/tabs.gif) no-repeat 0 -18px; margin-right:2px;} +.tabs span {float:left; display:block; background:url(../default/img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;} +.tabs .current span {background:url(../default/img/tabs.gif) no-repeat right -54px;} +.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} +.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} + +/* Panels */ +.panel_wrapper div.panel {display:none;} +.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} +.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;} + +/* Columns */ +.column {float:left;} +.properties {width:100%;} +.properties .column1 {} +.properties .column2 {text-align:left;} + +/* Titles */ +h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} +h3 {font-size:14px;} +.title {font-size:12px; font-weight:bold; color:#2B6FB6;} + +/* Dialog specific */ +#link .panel_wrapper, #link div.current {height:125px;} +#image .panel_wrapper, #image div.current {height:200px;} +#plugintable thead {font-weight:bold; background:#DDD;} +#plugintable, #about #plugintable td {border:1px solid #919B9C;} +#plugintable {width:96%; margin-top:10px;} +#pluginscontainer {height:290px; overflow:auto;} +#colorpicker #preview {float:right; width:50px; height:14px;line-height:1px; border:1px solid black; margin-left:5px;} +#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;} +#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;} +#colorpicker #light div {overflow:hidden;} +#colorpicker #previewblock {float:right; padding-left:10px; height:20px;} +#colorpicker .panel_wrapper div.current {height:175px;} +#colorpicker #namedcolors {width:150px;} +#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} +#colorpicker #colornamecontainer {margin-top:5px;} diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png b/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png new file mode 100644 index 00000000..12cfb419 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png differ diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png b/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png new file mode 100644 index 00000000..8996c749 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png differ diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png b/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png new file mode 100644 index 00000000..bd5d2550 Binary files /dev/null and b/tools/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png differ diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/ui.css b/tools/tiny_mce/themes/advanced/skins/o2k7/ui.css new file mode 100644 index 00000000..e881eaf1 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/o2k7/ui.css @@ -0,0 +1,215 @@ +/* Reset */ +.o2k7Skin table, .o2k7Skin tbody, .o2k7Skin a, .o2k7Skin img, .o2k7Skin tr, .o2k7Skin div, .o2k7Skin td, .o2k7Skin iframe, .o2k7Skin span, .o2k7Skin *, .o2k7Skin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left} +.o2k7Skin a:hover, .o2k7Skin a:link, .o2k7Skin a:visited, .o2k7Skin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000} +.o2k7Skin table td {vertical-align:middle} + +/* Containers */ +.o2k7Skin table {background:transparent} +.o2k7Skin iframe {display:block;} +.o2k7Skin .mceToolbar {height:26px} + +/* External */ +.o2k7Skin .mceExternalToolbar {position:absolute; border:1px solid #ABC6DD; border-bottom:0; display:none} +.o2k7Skin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.o2k7Skin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0} + +/* Layout */ +.o2k7Skin table.mceLayout {border:0; border-left:1px solid #ABC6DD; border-right:1px solid #ABC6DD} +.o2k7Skin table.mceLayout tr.mceFirst td {border-top:1px solid #ABC6DD} +.o2k7Skin table.mceLayout tr.mceLast td {border-bottom:1px solid #ABC6DD} +.o2k7Skin table.mceToolbar, .o2k7Skin tr.mceFirst .mceToolbar tr td, .o2k7Skin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0} +.o2k7Skin .mceIframeContainer {border-top:1px solid #ABC6DD; border-bottom:1px solid #ABC6DD} +.o2k7Skin .mceStatusbar {display:block; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; height:20px} +.o2k7Skin .mceStatusbar div {float:left; padding:2px} +.o2k7Skin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0} +.o2k7Skin .mceStatusbar a:hover {text-decoration:underline} +.o2k7Skin table.mceToolbar {margin-left:3px} +.o2k7Skin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; margin-left:3px;} +.o2k7Skin .mceToolbar td.mceFirst span {margin:0} +.o2k7Skin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px} +.o2k7Skin .mceToolbar .mceToolbarEndListBox span, .o2k7Skin .mceToolbar .mceToolbarStartListBox span {display:none} +.o2k7Skin span.mceIcon, .o2k7Skin img.mceIcon {display:block; width:20px; height:20px} +.o2k7Skin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} +.o2k7Skin td.mceCenter {text-align:center;} +.o2k7Skin td.mceCenter table {margin:0 auto; text-align:left;} +.o2k7Skin td.mceRight table {margin:0 0 0 auto;} + +/* Button */ +.o2k7Skin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px} +.o2k7Skin a.mceButton span, .o2k7Skin a.mceButton img {margin-left:1px} +.o2k7Skin .mceOldBoxModel a.mceButton span, .o2k7Skin .mceOldBoxModel a.mceButton img {margin:0 0 0 1px} +.o2k7Skin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px} +.o2k7Skin a.mceButtonActive, .o2k7Skin a.mceButtonSelected {background-position:0 -44px} +.o2k7Skin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +.o2k7Skin .mceButtonLabeled {width:auto} +.o2k7Skin .mceButtonLabeled span.mceIcon {float:left} +.o2k7Skin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica} +.o2k7Skin .mceButtonDisabled .mceButtonLabel {color:#888} + +/* Separator */ +.o2k7Skin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px} + +/* ListBox */ +.o2k7Skin .mceListBox {margin-left:3px} +.o2k7Skin .mceListBox, .o2k7Skin .mceListBox a {display:block} +.o2k7Skin .mceListBox .mceText {padding-left:4px; text-align:left; width:70px; border:1px solid #b3c7e1; border-right:0; background:#eaf2fb; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden} +.o2k7Skin .mceListBox .mceOpen {width:14px; height:22px; background:url(img/button_bg.png) -66px 0} +.o2k7Skin table.mceListBoxEnabled:hover .mceText, .o2k7Skin .mceListBoxHover .mceText, .o2k7Skin .mceListBoxSelected .mceText {background:#FFF} +.o2k7Skin table.mceListBoxEnabled:hover .mceOpen, .o2k7Skin .mceListBoxHover .mceOpen, .o2k7Skin .mceListBoxSelected .mceOpen {background-position:-66px -22px} +.o2k7Skin .mceListBoxDisabled .mceText {color:gray} +.o2k7Skin .mceListBoxMenu {overflow:auto; overflow-x:hidden} +.o2k7Skin .mceOldBoxModel .mceListBox .mceText {height:22px} +.o2k7Skin select.mceListBox {font-family:Tahoma,Verdana,Arial,Helvetica; font-size:12px; border:1px solid #b3c7e1; background:#FFF;} + +/* SplitButton */ +.o2k7Skin .mceSplitButton, .o2k7Skin .mceSplitButton a, .o2k7Skin .mceSplitButton span {display:block; height:22px} +.o2k7Skin .mceSplitButton {background:url(img/button_bg.png)} +.o2k7Skin .mceSplitButton a.mceAction {width:22px} +.o2k7Skin .mceSplitButton span.mceAction {width:22px; background-image:url(../../img/icons.gif)} +.o2k7Skin .mceSplitButton a.mceOpen {width:10px; background:url(img/button_bg.png) -44px 0} +.o2k7Skin .mceSplitButton span.mceOpen {display:none} +.o2k7Skin table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background:url(img/button_bg.png) 0 -22px} +.o2k7Skin table.mceSplitButtonEnabled:hover a.mceOpen, .o2k7Skin .mceSplitButtonHover a.mceOpen, .o2k7Skin .mceSplitButtonSelected a.mceOpen {background-position:-44px -44px} +.o2k7Skin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +.o2k7Skin .mceSplitButtonActive {background-position:0 -44px} + +/* ColorSplitButton */ +.o2k7Skin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray} +.o2k7Skin .mceColorSplitMenu td {padding:2px} +.o2k7Skin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080} +.o2k7Skin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.o2k7Skin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} +.o2k7Skin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2} +.o2k7Skin a.mceMoreColors:hover {border:1px solid #0A246A} +.o2k7Skin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a;overflow:hidden} +.o2k7Skin .mce_forecolor span.mceAction, .o2k7Skin .mce_backcolor span.mceAction {height:15px;overflow:hidden} + +/* Menu */ +.o2k7Skin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #ABC6DD} +.o2k7Skin .mceNoIcons span.mceIcon {width:0;} +.o2k7Skin .mceNoIcons a .mceText {padding-left:10px} +.o2k7Skin .mceMenu table {background:#FFF} +.o2k7Skin .mceMenu a, .o2k7Skin .mceMenu span, .o2k7Skin .mceMenu {display:block} +.o2k7Skin .mceMenu td {height:20px} +.o2k7Skin .mceMenu a {position:relative;padding:3px 0 4px 0} +.o2k7Skin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block} +.o2k7Skin .mceMenu span.mceText, .o2k7Skin .mceMenu .mcePreview {font-size:11px} +.o2k7Skin .mceMenu pre.mceText {font-family:Monospace} +.o2k7Skin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;} +.o2k7Skin .mceMenu .mceMenuItemEnabled a:hover, .o2k7Skin .mceMenu .mceMenuItemActive {background-color:#dbecf3} +.o2k7Skin td.mceMenuItemSeparator {background:#DDD; height:1px} +.o2k7Skin .mceMenuItemTitle a {border:0; background:#E5EFFD; border-bottom:1px solid #ABC6DD} +.o2k7Skin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px} +.o2k7Skin .mceMenuItemDisabled .mceText {color:#888} +.o2k7Skin .mceMenuItemSelected .mceIcon {background:url(../default/img/menu_check.gif)} +.o2k7Skin .mceNoIcons .mceMenuItemSelected a {background:url(../default/img/menu_arrow.gif) no-repeat -6px center} +.o2k7Skin .mceMenu span.mceMenuLine {display:none} +.o2k7Skin .mceMenuItemSub a {background:url(../default/img/menu_arrow.gif) no-repeat top right;} + +/* Progress,Resize */ +.o2k7Skin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF} +.o2k7Skin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} + +/* Formats */ +.o2k7Skin .mce_formatPreview a {font-size:10px} +.o2k7Skin .mce_p span.mceText {} +.o2k7Skin .mce_address span.mceText {font-style:italic} +.o2k7Skin .mce_pre span.mceText {font-family:monospace} +.o2k7Skin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.o2k7Skin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.o2k7Skin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.o2k7Skin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.o2k7Skin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.o2k7Skin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} + +/* Theme */ +.o2k7Skin span.mce_bold {background-position:0 0} +.o2k7Skin span.mce_italic {background-position:-60px 0} +.o2k7Skin span.mce_underline {background-position:-140px 0} +.o2k7Skin span.mce_strikethrough {background-position:-120px 0} +.o2k7Skin span.mce_undo {background-position:-160px 0} +.o2k7Skin span.mce_redo {background-position:-100px 0} +.o2k7Skin span.mce_cleanup {background-position:-40px 0} +.o2k7Skin span.mce_bullist {background-position:-20px 0} +.o2k7Skin span.mce_numlist {background-position:-80px 0} +.o2k7Skin span.mce_justifyleft {background-position:-460px 0} +.o2k7Skin span.mce_justifyright {background-position:-480px 0} +.o2k7Skin span.mce_justifycenter {background-position:-420px 0} +.o2k7Skin span.mce_justifyfull {background-position:-440px 0} +.o2k7Skin span.mce_anchor {background-position:-200px 0} +.o2k7Skin span.mce_indent {background-position:-400px 0} +.o2k7Skin span.mce_outdent {background-position:-540px 0} +.o2k7Skin span.mce_link {background-position:-500px 0} +.o2k7Skin span.mce_unlink {background-position:-640px 0} +.o2k7Skin span.mce_sub {background-position:-600px 0} +.o2k7Skin span.mce_sup {background-position:-620px 0} +.o2k7Skin span.mce_removeformat {background-position:-580px 0} +.o2k7Skin span.mce_newdocument {background-position:-520px 0} +.o2k7Skin span.mce_image {background-position:-380px 0} +.o2k7Skin span.mce_help {background-position:-340px 0} +.o2k7Skin span.mce_code {background-position:-260px 0} +.o2k7Skin span.mce_hr {background-position:-360px 0} +.o2k7Skin span.mce_visualaid {background-position:-660px 0} +.o2k7Skin span.mce_charmap {background-position:-240px 0} +.o2k7Skin span.mce_paste {background-position:-560px 0} +.o2k7Skin span.mce_copy {background-position:-700px 0} +.o2k7Skin span.mce_cut {background-position:-680px 0} +.o2k7Skin span.mce_blockquote {background-position:-220px 0} +.o2k7Skin .mce_forecolor span.mceAction {background-position:-720px 0} +.o2k7Skin .mce_backcolor span.mceAction {background-position:-760px 0} +.o2k7Skin span.mce_forecolorpicker {background-position:-720px 0} +.o2k7Skin span.mce_backcolorpicker {background-position:-760px 0} + +/* Plugins */ +.o2k7Skin span.mce_advhr {background-position:-0px -20px} +.o2k7Skin span.mce_ltr {background-position:-20px -20px} +.o2k7Skin span.mce_rtl {background-position:-40px -20px} +.o2k7Skin span.mce_emotions {background-position:-60px -20px} +.o2k7Skin span.mce_fullpage {background-position:-80px -20px} +.o2k7Skin span.mce_fullscreen {background-position:-100px -20px} +.o2k7Skin span.mce_iespell {background-position:-120px -20px} +.o2k7Skin span.mce_insertdate {background-position:-140px -20px} +.o2k7Skin span.mce_inserttime {background-position:-160px -20px} +.o2k7Skin span.mce_absolute {background-position:-180px -20px} +.o2k7Skin span.mce_backward {background-position:-200px -20px} +.o2k7Skin span.mce_forward {background-position:-220px -20px} +.o2k7Skin span.mce_insert_layer {background-position:-240px -20px} +.o2k7Skin span.mce_insertlayer {background-position:-260px -20px} +.o2k7Skin span.mce_movebackward {background-position:-280px -20px} +.o2k7Skin span.mce_moveforward {background-position:-300px -20px} +.o2k7Skin span.mce_media {background-position:-320px -20px} +.o2k7Skin span.mce_nonbreaking {background-position:-340px -20px} +.o2k7Skin span.mce_pastetext {background-position:-360px -20px} +.o2k7Skin span.mce_pasteword {background-position:-380px -20px} +.o2k7Skin span.mce_selectall {background-position:-400px -20px} +.o2k7Skin span.mce_preview {background-position:-420px -20px} +.o2k7Skin span.mce_print {background-position:-440px -20px} +.o2k7Skin span.mce_cancel {background-position:-460px -20px} +.o2k7Skin span.mce_save {background-position:-480px -20px} +.o2k7Skin span.mce_replace {background-position:-500px -20px} +.o2k7Skin span.mce_search {background-position:-520px -20px} +.o2k7Skin span.mce_styleprops {background-position:-560px -20px} +.o2k7Skin span.mce_table {background-position:-580px -20px} +.o2k7Skin span.mce_cell_props {background-position:-600px -20px} +.o2k7Skin span.mce_delete_table {background-position:-620px -20px} +.o2k7Skin span.mce_delete_col {background-position:-640px -20px} +.o2k7Skin span.mce_delete_row {background-position:-660px -20px} +.o2k7Skin span.mce_col_after {background-position:-680px -20px} +.o2k7Skin span.mce_col_before {background-position:-700px -20px} +.o2k7Skin span.mce_row_after {background-position:-720px -20px} +.o2k7Skin span.mce_row_before {background-position:-740px -20px} +.o2k7Skin span.mce_merge_cells {background-position:-760px -20px} +.o2k7Skin span.mce_table_props {background-position:-980px -20px} +.o2k7Skin span.mce_row_props {background-position:-780px -20px} +.o2k7Skin span.mce_split_cells {background-position:-800px -20px} +.o2k7Skin span.mce_template {background-position:-820px -20px} +.o2k7Skin span.mce_visualchars {background-position:-840px -20px} +.o2k7Skin span.mce_abbr {background-position:-860px -20px} +.o2k7Skin span.mce_acronym {background-position:-880px -20px} +.o2k7Skin span.mce_attribs {background-position:-900px -20px} +.o2k7Skin span.mce_cite {background-position:-920px -20px} +.o2k7Skin span.mce_del {background-position:-940px -20px} +.o2k7Skin span.mce_ins {background-position:-960px -20px} +.o2k7Skin span.mce_pagebreak {background-position:0 -40px} +.o2k7Skin span.mce_restoredraft {background-position:-20px -40px} +.o2k7Skin span.mce_spellchecker {background-position:-540px -20px} diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/ui_black.css b/tools/tiny_mce/themes/advanced/skins/o2k7/ui_black.css new file mode 100644 index 00000000..81dbfe41 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/o2k7/ui_black.css @@ -0,0 +1,8 @@ +/* Black */ +.o2k7SkinBlack .mceToolbar .mceToolbarStart span, .o2k7SkinBlack .mceToolbar .mceToolbarEnd span, .o2k7SkinBlack .mceButton, .o2k7SkinBlack .mceSplitButton, .o2k7SkinBlack .mceSeparator, .o2k7SkinBlack .mceSplitButton a.mceOpen, .o2k7SkinBlack .mceListBox a.mceOpen {background-image:url(img/button_bg_black.png)} +.o2k7SkinBlack table, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack .mceMenuItemTitle span.mceText, .o2k7SkinBlack .mceStatusbar div, .o2k7SkinBlack .mceStatusbar span, .o2k7SkinBlack .mceStatusbar a {background:#535353; color:#FFF} +.o2k7SkinBlack table.mceListBoxEnabled .mceText, o2k7SkinBlack .mceListBox .mceText {background:#FFF; border:1px solid #CBCFD4; border-bottom-color:#989FA9; border-right:0} +.o2k7SkinBlack table.mceListBoxEnabled:hover .mceText, .o2k7SkinBlack .mceListBoxHover .mceText, .o2k7SkinBlack .mceListBoxSelected .mceText {background:#FFF; border:1px solid #FFBD69; border-right:0} +.o2k7SkinBlack .mceExternalToolbar, .o2k7SkinBlack .mceListBox .mceText, .o2k7SkinBlack div.mceMenu, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceFirst td, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceLast td, .o2k7SkinBlack .mceIframeContainer {border-color: #535353;} +.o2k7SkinBlack table.mceSplitButtonEnabled:hover a.mceAction, .o2k7SkinBlack .mceSplitButtonHover a.mceAction, .o2k7SkinBlack .mceSplitButtonSelected {background-image:url(img/button_bg_black.png)} +.o2k7SkinBlack .mceMenu .mceMenuItemEnabled a:hover, .o2k7SkinBlack .mceMenu .mceMenuItemActive {background-color:#FFE7A1} \ No newline at end of file diff --git a/tools/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css b/tools/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css new file mode 100644 index 00000000..e8ae844f --- /dev/null +++ b/tools/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css @@ -0,0 +1,5 @@ +/* Silver */ +.o2k7SkinSilver .mceToolbar .mceToolbarStart span, .o2k7SkinSilver .mceButton, .o2k7SkinSilver .mceSplitButton, .o2k7SkinSilver .mceSeparator, .o2k7SkinSilver .mceSplitButton a.mceOpen, .o2k7SkinSilver .mceListBox a.mceOpen {background-image:url(img/button_bg_silver.png)} +.o2k7SkinSilver table, .o2k7SkinSilver .mceMenuItemTitle a {background:#eee} +.o2k7SkinSilver .mceListBox .mceText {background:#FFF} +.o2k7SkinSilver .mceExternalToolbar, .o2k7SkinSilver .mceListBox .mceText, .o2k7SkinSilver div.mceMenu, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceFirst td, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceLast td, .o2k7SkinSilver .mceIframeContainer {border-color: #bbb} diff --git a/tools/tiny_mce/themes/advanced/source_editor.htm b/tools/tiny_mce/themes/advanced/source_editor.htm new file mode 100644 index 00000000..d3f75d66 --- /dev/null +++ b/tools/tiny_mce/themes/advanced/source_editor.htm @@ -0,0 +1,25 @@ + + + {#advanced_dlg.code_title} + + + + +
    +
    + +
    + +
    + +
    + + + +
    + + +
    +
    + + diff --git a/tools/tiny_mce/themes/simple/editor_template.js b/tools/tiny_mce/themes/simple/editor_template.js new file mode 100644 index 00000000..ed89abc0 --- /dev/null +++ b/tools/tiny_mce/themes/simple/editor_template.js @@ -0,0 +1 @@ +(function(){var a=tinymce.DOM;tinymce.ThemeManager.requireLangPack("simple");tinymce.create("tinymce.themes.SimpleTheme",{init:function(c,d){var e=this,b=["Bold","Italic","Underline","Strikethrough","InsertUnorderedList","InsertOrderedList"],f=c.settings;e.editor=c;c.onInit.add(function(){c.onNodeChange.add(function(h,g){tinymce.each(b,function(i){g.get(i.toLowerCase()).setActive(h.queryCommandState(i))})});c.dom.loadCSS(d+"/skins/"+f.skin+"/content.css")});a.loadCSS((f.editor_css?c.documentBaseURI.toAbsolute(f.editor_css):"")||d+"/skins/"+f.skin+"/ui.css")},renderUI:function(h){var e=this,i=h.targetNode,b,c,d=e.editor,f=d.controlManager,g;i=a.insertAfter(a.create("span",{id:d.id+"_container","class":"mceEditor "+d.settings.skin+"SimpleSkin"}),i);i=g=a.add(i,"table",{cellPadding:0,cellSpacing:0,"class":"mceLayout"});i=c=a.add(i,"tbody");i=a.add(c,"tr");i=b=a.add(a.add(i,"td"),"div",{"class":"mceIframeContainer"});i=a.add(a.add(c,"tr",{"class":"last"}),"td",{"class":"mceToolbar mceLast",align:"center"});c=e.toolbar=f.createToolbar("tools1");c.add(f.createButton("bold",{title:"simple.bold_desc",cmd:"Bold"}));c.add(f.createButton("italic",{title:"simple.italic_desc",cmd:"Italic"}));c.add(f.createButton("underline",{title:"simple.underline_desc",cmd:"Underline"}));c.add(f.createButton("strikethrough",{title:"simple.striketrough_desc",cmd:"Strikethrough"}));c.add(f.createSeparator());c.add(f.createButton("undo",{title:"simple.undo_desc",cmd:"Undo"}));c.add(f.createButton("redo",{title:"simple.redo_desc",cmd:"Redo"}));c.add(f.createSeparator());c.add(f.createButton("cleanup",{title:"simple.cleanup_desc",cmd:"mceCleanup"}));c.add(f.createSeparator());c.add(f.createButton("insertunorderedlist",{title:"simple.bullist_desc",cmd:"InsertUnorderedList"}));c.add(f.createButton("insertorderedlist",{title:"simple.numlist_desc",cmd:"InsertOrderedList"}));c.renderTo(i);return{iframeContainer:b,editorContainer:d.id+"_container",sizeContainer:g,deltaHeight:-20}},getInfo:function(){return{longname:"Simple theme",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.ThemeManager.add("simple",tinymce.themes.SimpleTheme)})(); \ No newline at end of file diff --git a/tools/tiny_mce/themes/simple/editor_template_src.js b/tools/tiny_mce/themes/simple/editor_template_src.js new file mode 100644 index 00000000..ec9e9632 --- /dev/null +++ b/tools/tiny_mce/themes/simple/editor_template_src.js @@ -0,0 +1,85 @@ +/** + * editor_template_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(function() { + var DOM = tinymce.DOM; + + // Tell it to load theme specific language pack(s) + tinymce.ThemeManager.requireLangPack('simple'); + + tinymce.create('tinymce.themes.SimpleTheme', { + init : function(ed, url) { + var t = this, states = ['Bold', 'Italic', 'Underline', 'Strikethrough', 'InsertUnorderedList', 'InsertOrderedList'], s = ed.settings; + + t.editor = ed; + + ed.onInit.add(function() { + ed.onNodeChange.add(function(ed, cm) { + tinymce.each(states, function(c) { + cm.get(c.toLowerCase()).setActive(ed.queryCommandState(c)); + }); + }); + + ed.dom.loadCSS(url + "/skins/" + s.skin + "/content.css"); + }); + + DOM.loadCSS((s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : '') || url + "/skins/" + s.skin + "/ui.css"); + }, + + renderUI : function(o) { + var t = this, n = o.targetNode, ic, tb, ed = t.editor, cf = ed.controlManager, sc; + + n = DOM.insertAfter(DOM.create('span', {id : ed.id + '_container', 'class' : 'mceEditor ' + ed.settings.skin + 'SimpleSkin'}), n); + n = sc = DOM.add(n, 'table', {cellPadding : 0, cellSpacing : 0, 'class' : 'mceLayout'}); + n = tb = DOM.add(n, 'tbody'); + + // Create iframe container + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(DOM.add(n, 'td'), 'div', {'class' : 'mceIframeContainer'}); + + // Create toolbar container + n = DOM.add(DOM.add(tb, 'tr', {'class' : 'last'}), 'td', {'class' : 'mceToolbar mceLast', align : 'center'}); + + // Create toolbar + tb = t.toolbar = cf.createToolbar("tools1"); + tb.add(cf.createButton('bold', {title : 'simple.bold_desc', cmd : 'Bold'})); + tb.add(cf.createButton('italic', {title : 'simple.italic_desc', cmd : 'Italic'})); + tb.add(cf.createButton('underline', {title : 'simple.underline_desc', cmd : 'Underline'})); + tb.add(cf.createButton('strikethrough', {title : 'simple.striketrough_desc', cmd : 'Strikethrough'})); + tb.add(cf.createSeparator()); + tb.add(cf.createButton('undo', {title : 'simple.undo_desc', cmd : 'Undo'})); + tb.add(cf.createButton('redo', {title : 'simple.redo_desc', cmd : 'Redo'})); + tb.add(cf.createSeparator()); + tb.add(cf.createButton('cleanup', {title : 'simple.cleanup_desc', cmd : 'mceCleanup'})); + tb.add(cf.createSeparator()); + tb.add(cf.createButton('insertunorderedlist', {title : 'simple.bullist_desc', cmd : 'InsertUnorderedList'})); + tb.add(cf.createButton('insertorderedlist', {title : 'simple.numlist_desc', cmd : 'InsertOrderedList'})); + tb.renderTo(n); + + return { + iframeContainer : ic, + editorContainer : ed.id + '_container', + sizeContainer : sc, + deltaHeight : -20 + }; + }, + + getInfo : function() { + return { + longname : 'Simple theme', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + version : tinymce.majorVersion + "." + tinymce.minorVersion + } + } + }); + + tinymce.ThemeManager.add('simple', tinymce.themes.SimpleTheme); +})(); \ No newline at end of file diff --git a/tools/tiny_mce/themes/simple/img/icons.gif b/tools/tiny_mce/themes/simple/img/icons.gif new file mode 100644 index 00000000..16af141f Binary files /dev/null and b/tools/tiny_mce/themes/simple/img/icons.gif differ diff --git a/tools/tiny_mce/themes/simple/langs/en.js b/tools/tiny_mce/themes/simple/langs/en.js new file mode 100644 index 00000000..6f095311 --- /dev/null +++ b/tools/tiny_mce/themes/simple/langs/en.js @@ -0,0 +1,11 @@ +tinyMCE.addI18n('en.simple',{ +bold_desc:"Bold (Ctrl+B)", +italic_desc:"Italic (Ctrl+I)", +underline_desc:"Underline (Ctrl+U)", +striketrough_desc:"Strikethrough", +bullist_desc:"Unordered list", +numlist_desc:"Ordered list", +undo_desc:"Undo (Ctrl+Z)", +redo_desc:"Redo (Ctrl+Y)", +cleanup_desc:"Cleanup messy code" +}); \ No newline at end of file diff --git a/tools/tiny_mce/themes/simple/skins/default/content.css b/tools/tiny_mce/themes/simple/skins/default/content.css new file mode 100644 index 00000000..783b170f --- /dev/null +++ b/tools/tiny_mce/themes/simple/skins/default/content.css @@ -0,0 +1,25 @@ +body, td, pre { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; +} + +body { + background-color: #FFFFFF; +} + +.mceVisualAid { + border: 1px dashed #BBBBBB; +} + +/* MSIE specific */ + +* html body { + scrollbar-3dlight-color: #F0F0EE; + scrollbar-arrow-color: #676662; + scrollbar-base-color: #F0F0EE; + scrollbar-darkshadow-color: #DDDDDD; + scrollbar-face-color: #E0E0DD; + scrollbar-highlight-color: #F0F0EE; + scrollbar-shadow-color: #F0F0EE; + scrollbar-track-color: #F5F5F5; +} diff --git a/tools/tiny_mce/themes/simple/skins/default/ui.css b/tools/tiny_mce/themes/simple/skins/default/ui.css new file mode 100644 index 00000000..32feae62 --- /dev/null +++ b/tools/tiny_mce/themes/simple/skins/default/ui.css @@ -0,0 +1,32 @@ +/* Reset */ +.defaultSimpleSkin table, .defaultSimpleSkin tbody, .defaultSimpleSkin a, .defaultSimpleSkin img, .defaultSimpleSkin tr, .defaultSimpleSkin div, .defaultSimpleSkin td, .defaultSimpleSkin iframe, .defaultSimpleSkin span, .defaultSimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000} + +/* Containers */ +.defaultSimpleSkin {position:relative} +.defaultSimpleSkin table.mceLayout {background:#F0F0EE; border:1px solid #CCC;} +.defaultSimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #CCC;} +.defaultSimpleSkin .mceToolbar {height:24px;} + +/* Layout */ +.defaultSimpleSkin span.mceIcon, .defaultSimpleSkin img.mceIcon {display:block; width:20px; height:20px} +.defaultSimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} + +/* Button */ +.defaultSimpleSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px} +.defaultSimpleSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0} +.defaultSimpleSkin a.mceButtonActive {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSimpleSkin .mceButtonDisabled span {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} + +/* Separator */ +.defaultSimpleSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:0 2px 0 4px} + +/* Theme */ +.defaultSimpleSkin span.mce_bold {background-position:0 0} +.defaultSimpleSkin span.mce_italic {background-position:-60px 0} +.defaultSimpleSkin span.mce_underline {background-position:-140px 0} +.defaultSimpleSkin span.mce_strikethrough {background-position:-120px 0} +.defaultSimpleSkin span.mce_undo {background-position:-160px 0} +.defaultSimpleSkin span.mce_redo {background-position:-100px 0} +.defaultSimpleSkin span.mce_cleanup {background-position:-40px 0} +.defaultSimpleSkin span.mce_insertunorderedlist {background-position:-20px 0} +.defaultSimpleSkin span.mce_insertorderedlist {background-position:-80px 0} diff --git a/tools/tiny_mce/themes/simple/skins/o2k7/content.css b/tools/tiny_mce/themes/simple/skins/o2k7/content.css new file mode 100644 index 00000000..e10558f9 --- /dev/null +++ b/tools/tiny_mce/themes/simple/skins/o2k7/content.css @@ -0,0 +1,17 @@ +body, td, pre {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} + +body {background: #FFF;} +.mceVisualAid {border: 1px dashed #BBB;} + +/* IE */ + +* html body { +scrollbar-3dlight-color: #F0F0EE; +scrollbar-arrow-color: #676662; +scrollbar-base-color: #F0F0EE; +scrollbar-darkshadow-color: #DDDDDD; +scrollbar-face-color: #E0E0DD; +scrollbar-highlight-color: #F0F0EE; +scrollbar-shadow-color: #F0F0EE; +scrollbar-track-color: #F5F5F5; +} diff --git a/tools/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png b/tools/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png new file mode 100644 index 00000000..527e3495 Binary files /dev/null and b/tools/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png differ diff --git a/tools/tiny_mce/themes/simple/skins/o2k7/ui.css b/tools/tiny_mce/themes/simple/skins/o2k7/ui.css new file mode 100644 index 00000000..021d650f --- /dev/null +++ b/tools/tiny_mce/themes/simple/skins/o2k7/ui.css @@ -0,0 +1,35 @@ +/* Reset */ +.o2k7SimpleSkin table, .o2k7SimpleSkin tbody, .o2k7SimpleSkin a, .o2k7SimpleSkin img, .o2k7SimpleSkin tr, .o2k7SimpleSkin div, .o2k7SimpleSkin td, .o2k7SimpleSkin iframe, .o2k7SimpleSkin span, .o2k7SimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000} + +/* Containers */ +.o2k7SimpleSkin {position:relative} +.o2k7SimpleSkin table.mceLayout {background:#E5EFFD; border:1px solid #ABC6DD;} +.o2k7SimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #ABC6DD;} +.o2k7SimpleSkin .mceToolbar {height:26px;} + +/* Layout */ +.o2k7SimpleSkin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; } +.o2k7SimpleSkin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px} +.o2k7SimpleSkin span.mceIcon, .o2k7SimpleSkin img.mceIcon {display:block; width:20px; height:20px} +.o2k7SimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} + +/* Button */ +.o2k7SimpleSkin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px} +.o2k7SimpleSkin a.mceButton span, .o2k7SimpleSkin a.mceButton img {margin:1px 0 0 1px} +.o2k7SimpleSkin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px} +.o2k7SimpleSkin a.mceButtonActive {background-position:0 -44px} +.o2k7SimpleSkin .mceButtonDisabled span {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} + +/* Separator */ +.o2k7SimpleSkin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px} + +/* Theme */ +.o2k7SimpleSkin span.mce_bold {background-position:0 0} +.o2k7SimpleSkin span.mce_italic {background-position:-60px 0} +.o2k7SimpleSkin span.mce_underline {background-position:-140px 0} +.o2k7SimpleSkin span.mce_strikethrough {background-position:-120px 0} +.o2k7SimpleSkin span.mce_undo {background-position:-160px 0} +.o2k7SimpleSkin span.mce_redo {background-position:-100px 0} +.o2k7SimpleSkin span.mce_cleanup {background-position:-40px 0} +.o2k7SimpleSkin span.mce_insertunorderedlist {background-position:-20px 0} +.o2k7SimpleSkin span.mce_insertorderedlist {background-position:-80px 0} diff --git a/tools/tiny_mce/tiny_mce.js b/tools/tiny_mce/tiny_mce.js new file mode 100644 index 00000000..4cdd0dba --- /dev/null +++ b/tools/tiny_mce/tiny_mce.js @@ -0,0 +1 @@ +(function(d){var a=/^\s*|\s*$/g,e,c="B".replace(/A(.)|B/,"$1")==="$1";var b={majorVersion:"3",minorVersion:"3.9.4",releaseDate:"2011-04-13",_init:function(){var s=this,q=document,o=navigator,g=o.userAgent,m,f,l,k,j,r;s.isOpera=d.opera&&opera.buildNumber;s.isWebKit=/WebKit/.test(g);s.isIE=!s.isWebKit&&!s.isOpera&&(/MSIE/gi).test(g)&&(/Explorer/gi).test(o.appName);s.isIE6=s.isIE&&/MSIE [56]/.test(g);s.isIE9=s.isIE&&!/MSIE [5678]/.test(g);s.isGecko=!s.isWebKit&&/Gecko/.test(g);s.isMac=g.indexOf("Mac")!=-1;s.isAir=/adobeair/i.test(g);s.isIDevice=/(iPad|iPhone)/.test(g);if(d.tinyMCEPreInit){s.suffix=tinyMCEPreInit.suffix;s.baseURL=tinyMCEPreInit.base;s.query=tinyMCEPreInit.query;return}s.suffix="";f=q.getElementsByTagName("base");for(m=0;m=c.length){for(e=0,b=g.length;e=c.length||g[e]!=c[e]){f=e+1;break}}}if(g.length=g.length||g[e]!=c[e]){f=e+1;break}}}if(f==1){return h}for(e=0,b=g.length-(f-1);e=0;c--){if(f[c].length==0||f[c]=="."){continue}if(f[c]==".."){b++;continue}if(b>0){b--;continue}h.push(f[c])}c=e.length-b;if(c<=0){g=h.reverse().join("/")}else{g=e.slice(0,c).join("/")+"/"+h.reverse().join("/")}if(g.indexOf("/")!==0){g="/"+g}if(d&&g.lastIndexOf("/")!==g.length-1){g+=d}return g},getURI:function(d){var c,b=this;if(!b.source||d){c="";if(!d){if(b.protocol){c+=b.protocol+"://"}if(b.userInfo){c+=b.userInfo+"@"}if(b.host){c+=b.host}if(b.port){c+=":"+b.port}}if(b.path){c+=b.path}if(b.query){c+="?"+b.query}if(b.anchor){c+="#"+b.anchor}b.source=c}return b.source}})})();(function(){var a=tinymce.each;tinymce.create("static tinymce.util.Cookie",{getHash:function(d){var b=this.get(d),c;if(b){a(b.split("&"),function(e){e=e.split("=");c=c||{};c[unescape(e[0])]=unescape(e[1])})}return c},setHash:function(j,b,g,f,i,c){var h="";a(b,function(e,d){h+=(!h?"":"&")+escape(d)+"="+escape(e)});this.set(j,h,g,f,i,c)},get:function(i){var h=document.cookie,g,f=i+"=",d;if(!h){return}d=h.indexOf("; "+f);if(d==-1){d=h.indexOf(f);if(d!=0){return null}}else{d+=2}g=h.indexOf(";",d);if(g==-1){g=h.length}return unescape(h.substring(d+f.length,g))},set:function(i,b,g,f,h,c){document.cookie=i+"="+escape(b)+((g)?"; expires="+g.toGMTString():"")+((f)?"; path="+escape(f):"")+((h)?"; domain="+h:"")+((c)?"; secure":"")},remove:function(e,b){var c=new Date();c.setTime(c.getTime()-1000);this.set(e,"",c,b,c)}})})();tinymce.create("static tinymce.util.JSON",{serialize:function(e){var c,a,d=tinymce.util.JSON.serialize,b;if(e==null){return"null"}b=typeof e;if(b=="string"){a="\bb\tt\nn\ff\rr\"\"''\\\\";return'"'+e.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g,function(g,f){c=a.indexOf(f);if(c+1){return"\\"+a.charAt(c+1)}g=f.charCodeAt().toString(16);return"\\u"+"0000".substring(g.length)+g})+'"'}if(b=="object"){if(e.hasOwnProperty&&e instanceof Array){for(c=0,a="[";c0?",":"")+d(e[c])}return a+"]"}a="{";for(c in e){a+=typeof e[c]!="function"?(a.length>1?',"':'"')+c+'":'+d(e[c]):""}return a+"}"}return""+e},parse:function(s){try{return eval("("+s+")")}catch(ex){}}});tinymce.create("static tinymce.util.XHR",{send:function(g){var a,e,b=window,h=0;g.scope=g.scope||this;g.success_scope=g.success_scope||g.scope;g.error_scope=g.error_scope||g.scope;g.async=g.async===false?false:true;g.data=g.data||"";function d(i){a=0;try{a=new ActiveXObject(i)}catch(c){}return a}a=b.XMLHttpRequest?new XMLHttpRequest():d("Microsoft.XMLHTTP")||d("Msxml2.XMLHTTP");if(a){if(a.overrideMimeType){a.overrideMimeType(g.content_type)}a.open(g.type||(g.data?"POST":"GET"),g.url,g.async);if(g.content_type){a.setRequestHeader("Content-Type",g.content_type)}a.setRequestHeader("X-Requested-With","XMLHttpRequest");a.send(g.data);function f(){if(!g.async||a.readyState==4||h++>10000){if(g.success&&h<10000&&a.status==200){g.success.call(g.success_scope,""+a.responseText,a,g)}else{if(g.error){g.error.call(g.error_scope,h>10000?"TIMED_OUT":"GENERAL",a,g)}}a=null}else{b.setTimeout(f,10)}}if(!g.async){return f()}e=b.setTimeout(f,10)}}});(function(){var c=tinymce.extend,b=tinymce.util.JSON,a=tinymce.util.XHR;tinymce.create("tinymce.util.JSONRequest",{JSONRequest:function(d){this.settings=c({},d);this.count=0},send:function(f){var e=f.error,d=f.success;f=c(this.settings,f);f.success=function(h,g){h=b.parse(h);if(typeof(h)=="undefined"){h={error:"JSON Parse error."}}if(h.error){e.call(f.error_scope||f.scope,h.error,g)}else{d.call(f.success_scope||f.scope,h.result)}};f.error=function(h,g){e.call(f.error_scope||f.scope,h,g)};f.data=b.serialize({id:f.id||"c"+(this.count++),method:f.method,params:f.params});f.content_type="application/json";a.send(f)},"static":{sendRPC:function(d){return new tinymce.util.JSONRequest().send(d)}}})}());(function(m){var k=m.each,j=m.is,i=m.isWebKit,d=m.isIE,a=/^(H[1-6R]|P|DIV|ADDRESS|PRE|FORM|T(ABLE|BODY|HEAD|FOOT|H|R|D)|LI|OL|UL|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|MENU|ISINDEX|SAMP)$/,e=g("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),f=g("src,href,style,coords,shape"),c={"&":"&",'"':""","<":"<",">":">"},n=/[<>&\"]/g,b=/^([a-z0-9],?)+$/i,h=/<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)(\s*\/?)>/g,l=/(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;function g(q){var p={},o;q=q.split(",");for(o=q.length;o>=0;o--){p[q[o]]=1}return p}m.create("tinymce.dom.DOMUtils",{doc:null,root:null,files:null,pixelStyles:/^(top|left|bottom|right|width|height|borderWidth)$/,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},DOMUtils:function(u,q){var p=this,o;p.doc=u;p.win=window;p.files={};p.cssFlicker=false;p.counter=0;p.stdMode=u.documentMode>=8;p.boxModel=!m.isIE||u.compatMode=="CSS1Compat"||p.stdMode;p.settings=q=m.extend({keep_values:false,hex_colors:1,process_html:1},q);if(m.isIE6){try{u.execCommand("BackgroundImageCache",false,true)}catch(r){p.cssFlicker=true}}if(q.valid_styles){p._styles={};k(q.valid_styles,function(t,s){p._styles[s]=m.explode(t)})}m.addUnload(p.destroy,p)},getRoot:function(){var o=this,p=o.settings;return(p&&o.get(p.root_element))||o.doc.body},getViewPort:function(p){var q,o;p=!p?this.win:p;q=p.document;o=this.boxModel?q.documentElement:q.body;return{x:p.pageXOffset||o.scrollLeft,y:p.pageYOffset||o.scrollTop,w:p.innerWidth||o.clientWidth,h:p.innerHeight||o.clientHeight}},getRect:function(s){var r,o=this,q;s=o.get(s);r=o.getPos(s);q=o.getSize(s);return{x:r.x,y:r.y,w:q.w,h:q.h}},getSize:function(r){var p=this,o,q;r=p.get(r);o=p.getStyle(r,"width");q=p.getStyle(r,"height");if(o.indexOf("px")===-1){o=0}if(q.indexOf("px")===-1){q=0}return{w:parseInt(o)||r.offsetWidth||r.clientWidth,h:parseInt(q)||r.offsetHeight||r.clientHeight}},getParent:function(q,p,o){return this.getParents(q,p,o,false)},getParents:function(z,v,s,y){var q=this,p,u=q.settings,x=[];z=q.get(z);y=y===undefined;if(u.strict_root){s=s||q.getRoot()}if(j(v,"string")){p=v;if(v==="*"){v=function(o){return o.nodeType==1}}else{v=function(o){return q.is(o,p)}}}while(z){if(z==s||!z.nodeType||z.nodeType===9){break}if(!v||v(z)){if(y){x.push(z)}else{return z}}z=z.parentNode}return y?x:null},get:function(o){var p;if(o&&this.doc&&typeof(o)=="string"){p=o;o=this.doc.getElementById(o);if(o&&o.id!==p){return this.doc.getElementsByName(p)[1]}}return o},getNext:function(p,o){return this._findSib(p,o,"nextSibling")},getPrev:function(p,o){return this._findSib(p,o,"previousSibling")},add:function(s,v,o,r,u){var q=this;return this.run(s,function(y){var x,t;x=j(v,"string")?q.doc.createElement(v):v;q.setAttribs(x,o);if(r){if(r.nodeType){x.appendChild(r)}else{q.setHTML(x,r)}}return !u?y.appendChild(x):x})},create:function(q,o,p){return this.add(this.doc.createElement(q),q,o,p,1)},createHTML:function(v,p,s){var u="",r=this,q;u+="<"+v;for(q in p){if(p.hasOwnProperty(q)){u+=" "+q+'="'+r.encode(p[q])+'"'}}if(typeof(s)!="undefined"){return u+">"+s+""}return u+" />"},remove:function(o,p){return this.run(o,function(r){var q,s;q=r.parentNode;if(!q){return null}if(p){while(s=r.firstChild){if(!m.isIE||s.nodeType!==3||s.nodeValue){q.insertBefore(s,r)}else{r.removeChild(s)}}}return q.removeChild(r)})},setStyle:function(r,o,p){var q=this;return q.run(r,function(v){var u,t;u=v.style;o=o.replace(/-(\D)/g,function(x,s){return s.toUpperCase()});if(q.pixelStyles.test(o)&&(m.is(p,"number")||/^[\-0-9\.]+$/.test(p))){p+="px"}switch(o){case"opacity":if(d){u.filter=p===""?"":"alpha(opacity="+(p*100)+")";if(!r.currentStyle||!r.currentStyle.hasLayout){u.display="inline-block"}}u[o]=u["-moz-opacity"]=u["-khtml-opacity"]=p||"";break;case"float":d?u.styleFloat=p:u.cssFloat=p;break;default:u[o]=p||""}if(q.settings.update_styles){q.setAttrib(v,"_mce_style")}})},getStyle:function(r,o,q){r=this.get(r);if(!r){return false}if(this.doc.defaultView&&q){o=o.replace(/[A-Z]/g,function(s){return"-"+s});try{return this.doc.defaultView.getComputedStyle(r,null).getPropertyValue(o)}catch(p){return null}}o=o.replace(/-(\D)/g,function(t,s){return s.toUpperCase()});if(o=="float"){o=d?"styleFloat":"cssFloat"}if(r.currentStyle&&q){return r.currentStyle[o]}return r.style[o]},setStyles:function(u,v){var q=this,r=q.settings,p;p=r.update_styles;r.update_styles=0;k(v,function(o,s){q.setStyle(u,s,o)});r.update_styles=p;if(r.update_styles){q.setAttrib(u,r.cssText)}},removeAllAttribs:function(o){return this.run(o,function(r){var p=r.attributes;for(var q=p.length-1;q>=0;q--){r.removeAttributeNode(p.item(q))}})},setAttrib:function(q,r,o){var p=this;if(!q||!r){return}if(p.settings.strict){r=r.toLowerCase()}return this.run(q,function(u){var t=p.settings;switch(r){case"style":if(!j(o,"string")){k(o,function(s,x){p.setStyle(u,x,s)});return}if(t.keep_values){if(o&&!p._isRes(o)){u.setAttribute("_mce_style",o,2)}else{u.removeAttribute("_mce_style",2)}}u.style.cssText=o;break;case"class":u.className=o||"";break;case"src":case"href":if(t.keep_values){if(t.url_converter){o=t.url_converter.call(t.url_converter_scope||p,o,r,u)}p.setAttrib(u,"_mce_"+r,o,2)}break;case"shape":u.setAttribute("_mce_style",o);break}if(j(o)&&o!==null&&o.length!==0){u.setAttribute(r,""+o,2)}else{u.removeAttribute(r,2)}})},setAttribs:function(q,r){var p=this;return this.run(q,function(o){k(r,function(s,t){p.setAttrib(o,t,s)})})},getAttrib:function(r,s,q){var o,p=this;r=p.get(r);if(!r||r.nodeType!==1){return false}if(!j(q)){q=""}if(/^(src|href|style|coords|shape)$/.test(s)){o=r.getAttribute("_mce_"+s);if(o){return o}}if(d&&p.props[s]){o=r[p.props[s]];o=o&&o.nodeValue?o.nodeValue:o}if(!o){o=r.getAttribute(s,2)}if(/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(s)){if(r[p.props[s]]===true&&o===""){return s}return o?s:""}if(r.nodeName==="FORM"&&r.getAttributeNode(s)){return r.getAttributeNode(s).nodeValue}if(s==="style"){o=o||r.style.cssText;if(o){o=p.serializeStyle(p.parseStyle(o),r.nodeName);if(p.settings.keep_values&&!p._isRes(o)){r.setAttribute("_mce_style",o)}}}if(i&&s==="class"&&o){o=o.replace(/(apple|webkit)\-[a-z\-]+/gi,"")}if(d){switch(s){case"rowspan":case"colspan":if(o===1){o=""}break;case"size":if(o==="+0"||o===20||o===0){o=""}break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":if(o===0){o=""}break;case"hspace":if(o===-1){o=""}break;case"maxlength":case"tabindex":if(o===32768||o===2147483647||o==="32768"){o=""}break;case"multiple":case"compact":case"noshade":case"nowrap":if(o===65535){return s}return q;case"shape":o=o.toLowerCase();break;default:if(s.indexOf("on")===0&&o){o=m._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1",""+o)}}}return(o!==undefined&&o!==null&&o!=="")?""+o:q},getPos:function(A,s){var p=this,o=0,z=0,u,v=p.doc,q;A=p.get(A);s=s||v.body;if(A){if(d&&!p.stdMode){A=A.getBoundingClientRect();u=p.boxModel?v.documentElement:v.body;o=p.getStyle(p.select("html")[0],"borderWidth");o=(o=="medium"||p.boxModel&&!p.isIE6)&&2||o;return{x:A.left+u.scrollLeft-o,y:A.top+u.scrollTop-o}}q=A;while(q&&q!=s&&q.nodeType){o+=q.offsetLeft||0;z+=q.offsetTop||0;q=q.offsetParent}q=A.parentNode;while(q&&q!=s&&q.nodeType){o-=q.scrollLeft||0;z-=q.scrollTop||0;q=q.parentNode}}return{x:o,y:z}},parseStyle:function(r){var u=this,x=u.settings,y={};if(!r){return y}function p(E,B,D){var A,C,o,z;A=y[E+"-top"+B];if(!A){return}C=y[E+"-right"+B];if(A!=C){return}o=y[E+"-bottom"+B];if(C!=o){return}z=y[E+"-left"+B];if(o!=z){return}y[D]=z;delete y[E+"-top"+B];delete y[E+"-right"+B];delete y[E+"-bottom"+B];delete y[E+"-left"+B]}function v(s){var o,t=y[s];if(!t||t.indexOf(" ")<0){return}o=t.split(" ");if(k(o,function(z){return z===o[0]})){y[s]=o[0];return true}else{return false}}function q(z,s,o,B){var A;if(!v(s)){return}if(!v(o)){return}if(!v(B)){return}y[z]=y[s]+" "+y[o]+" "+y[B];delete y[s];delete y[o];delete y[B]}r=r.replace(/&(#?[a-z0-9]+);/g,"&$1_MCE_SEMI_");k(r.split(";"),function(s){var o,t=[];if(s){s=s.replace(/_MCE_SEMI_/g,";");s=s.replace(/url\([^\)]+\)/g,function(z){t.push(z);return"url("+t.length+")"});s=s.split(":");o=m.trim(s[1]);o=o.replace(/url\(([^\)]+)\)/g,function(A,z){return t[parseInt(z)-1]});o=o.replace(/rgb\([^\)]+\)/g,function(z){return u.toHex(z)});if(x.url_converter){o=o.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g,function(z,A){return"url("+x.url_converter.call(x.url_converter_scope||u,u.decode(A),"style",null)+")"})}y[m.trim(s[0]).toLowerCase()]=o}});p("border","","border");p("border","-width","border-width");p("border","-color","border-color");p("border","-style","border-style");p("padding","","padding");p("margin","","margin");q("border","border-width","border-style","border-color");if(d){if(y.border=="medium none"){y.border=""}}return y},serializeStyle:function(v,p){var q=this,r="";function u(s,o){if(o&&s){if(o.indexOf("-")===0){return}switch(o){case"font-weight":if(s==700){s="bold"}break;case"color":case"background-color":s=s.toLowerCase();break}r+=(r?" ":"")+o+": "+s+";"}}if(p&&q._styles){k(q._styles["*"],function(o){u(v[o],o)});k(q._styles[p.toLowerCase()],function(o){u(v[o],o)})}else{k(v,u)}return r},loadCSS:function(o){var q=this,r=q.doc,p;if(!o){o=""}p=q.select("head")[0];k(o.split(","),function(s){var t;if(q.files[s]){return}q.files[s]=true;t=q.create("link",{rel:"stylesheet",href:m._addVer(s)});if(d&&r.documentMode&&r.recalc){t.onload=function(){r.recalc();t.onload=null}}p.appendChild(t)})},addClass:function(o,p){return this.run(o,function(q){var r;if(!p){return 0}if(this.hasClass(q,p)){return q.className}r=this.removeClass(q,p);return q.className=(r!=""?(r+" "):"")+p})},removeClass:function(q,r){var o=this,p;return o.run(q,function(t){var s;if(o.hasClass(t,r)){if(!p){p=new RegExp("(^|\\s+)"+r+"(\\s+|$)","g")}s=t.className.replace(p," ");s=m.trim(s!=" "?s:"");t.className=s;if(!s){t.removeAttribute("class");t.removeAttribute("className")}return s}return t.className})},hasClass:function(p,o){p=this.get(p);if(!p||!o){return false}return(" "+p.className+" ").indexOf(" "+o+" ")!==-1},show:function(o){return this.setStyle(o,"display","block")},hide:function(o){return this.setStyle(o,"display","none")},isHidden:function(o){o=this.get(o);return !o||o.style.display=="none"||this.getStyle(o,"display")=="none"},uniqueId:function(o){return(!o?"mce_":o)+(this.counter++)},setHTML:function(q,p){var o=this;return this.run(q,function(v){var r,t,s,z,u,r;p=o.processHTML(p);if(d){function y(){while(v.firstChild){v.removeChild(v.firstChild)}try{v.innerHTML="
    "+p;v.removeChild(v.firstChild)}catch(x){r=o.create("div");r.innerHTML="
    "+p;k(r.childNodes,function(B,A){if(A){v.appendChild(B)}})}}if(o.settings.fix_ie_paragraphs){p=p.replace(/

    <\/p>|]+)><\/p>|/gi,' 

    ')}y();if(o.settings.fix_ie_paragraphs){s=v.getElementsByTagName("p");for(t=s.length-1,r=0;t>=0;t--){z=s[t];if(!z.hasChildNodes()){if(!z._mce_keep){r=1;break}z.removeAttribute("_mce_keep")}}}if(r){p=p.replace(/

    ]+)>|

    /ig,'

    ');p=p.replace(/<\/p>/gi,"
    ");y();if(o.settings.fix_ie_paragraphs){s=v.getElementsByTagName("DIV");for(t=s.length-1;t>=0;t--){z=s[t];if(z.hasAttribute("_mce_tmp")){u=o.doc.createElement("p");z.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi,function(A,x){var B;if(x!=="_mce_tmp"){B=z.getAttribute(x);if(!B&&x==="class"){B=z.className}u.setAttribute(x,B)}});for(r=0;r]+)\/>|/gi,"",r);if(q.keep_values){if(/)/g,"\n");t=t.replace(/^[\r\n]*|[\r\n]*$/g,"");t=t.replace(/^\s*(\/\/\s*|\]\]>|-->|\]\]-->)\s*$/g,"");return t}r=r.replace(/]+|)>([\s\S]*?)<\/script>/gi,function(s,x,t){if(!x){x=' type="text/javascript"'}x=x.replace(/src=\"([^\"]+)\"?/i,function(y,z){if(q.url_converter){z=p.encode(q.url_converter.call(q.url_converter_scope||p,p.decode(z),"src","script"))}return'_mce_src="'+z+'"'});if(m.trim(t)){v.push(o(t));t=""}return""+t+""});r=r.replace(/]+|)>([\s\S]*?)<\/style>/gi,function(s,x,t){if(t){v.push(o(t));t=""}return""+t+""});r=r.replace(/]+|)>([\s\S]*?)<\/noscript>/g,function(s,x,t){return""})}r=m._replace(//g,"",r);function u(s){return s.replace(h,function(y,z,x,t){return"<"+z+x.replace(l,function(B,A,E,D,C){var F;A=A.toLowerCase();E=E||D||C||"";if(e[A]){if(E==="false"||E==="0"){return}return A+'="'+A+'"'}if(f[A]&&x.indexOf("_mce_"+A)==-1){F=p.decode(E);if(q.url_converter&&(A=="src"||A=="href")){F=q.url_converter.call(q.url_converter_scope||p,F,A,z)}if(A=="style"){F=p.serializeStyle(p.parseStyle(F),A)}return A+'="'+E+'" _mce_'+A+'="'+p.encode(F)+'"'}return B})+t+">"})}r=u(r);r=r.replace(/MCE_SCRIPT:([0-9]+)/g,function(t,s){return v[s]})}return r},getOuterHTML:function(o){var p;o=this.get(o);if(!o){return null}if(o.outerHTML!==undefined){return o.outerHTML}p=(o.ownerDocument||this.doc).createElement("body");p.appendChild(o.cloneNode(true));return p.innerHTML},setOuterHTML:function(r,p,s){var o=this;function q(u,t,x){var y,v;v=x.createElement("body");v.innerHTML=t;y=v.lastChild;while(y){o.insertAfter(y.cloneNode(true),u);y=y.previousSibling}o.remove(u)}return this.run(r,function(u){u=o.get(u);if(u.nodeType==1){s=s||u.ownerDocument||o.doc;if(d){try{if(d&&u.nodeType==1){u.outerHTML=p}else{q(u,p,s)}}catch(t){q(u,p,s)}}else{q(u,p,s)}}})},decode:function(p){var q,r,o;if(/&[\w#]+;/.test(p)){q=this.doc.createElement("div");q.innerHTML=p;r=q.firstChild;o="";if(r){do{o+=r.nodeValue}while(r=r.nextSibling)}return o||p}return p},encode:function(o){return(""+o).replace(n,function(p){return c[p]})},insertAfter:function(o,p){p=this.get(p);return this.run(o,function(r){var q,s;q=p.parentNode;s=p.nextSibling;if(s){q.insertBefore(r,s)}else{q.appendChild(r)}return r})},isBlock:function(o){if(o.nodeType&&o.nodeType!==1){return false}o=o.nodeName||o;return a.test(o)},replace:function(s,r,p){var q=this;if(j(r,"array")){s=s.cloneNode(true)}return q.run(r,function(t){if(p){k(m.grep(t.childNodes),function(o){s.appendChild(o)})}return t.parentNode.replaceChild(s,t)})},rename:function(r,o){var q=this,p;if(r.nodeName!=o.toUpperCase()){p=q.create(o);k(q.getAttribs(r),function(s){q.setAttrib(p,s.nodeName,q.getAttrib(r,s.nodeName))});q.replace(p,r,1)}return p||r},findCommonAncestor:function(q,o){var r=q,p;while(r){p=o;while(p&&r!=p){p=p.parentNode}if(r==p){break}r=r.parentNode}if(!r&&q.ownerDocument){return q.ownerDocument.documentElement}return r},toHex:function(o){var q=/^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(o);function p(r){r=parseInt(r).toString(16);return r.length>1?r:"0"+r}if(q){o="#"+p(q[1])+p(q[2])+p(q[3]);return o}return o},getClasses:function(){var s=this,o=[],r,u={},v=s.settings.class_filter,q;if(s.classes){return s.classes}function x(t){k(t.imports,function(y){x(y)});k(t.cssRules||t.rules,function(y){switch(y.type||1){case 1:if(y.selectorText){k(y.selectorText.split(","),function(z){z=z.replace(/^\s*|\s*$|^\s\./g,"");if(/\.mce/.test(z)||!/\.[\w\-]+$/.test(z)){return}q=z;z=m._replace(/.*\.([a-z0-9_\-]+).*/i,"$1",z);if(v&&!(z=v(z,q))){return}if(!u[z]){o.push({"class":z});u[z]=1}})}break;case 3:x(y.styleSheet);break}})}try{k(s.doc.styleSheets,x)}catch(p){}if(o.length>0){s.classes=o}return o},run:function(u,r,q){var p=this,v;if(p.doc&&typeof(u)==="string"){u=p.get(u)}if(!u){return false}q=q||this;if(!u.nodeType&&(u.length||u.length===0)){v=[];k(u,function(s,o){if(s){if(typeof(s)=="string"){s=p.doc.getElementById(s)}v.push(r.call(q,s,o))}});return v}return r.call(q,u)},getAttribs:function(q){var p;q=this.get(q);if(!q){return[]}if(d){p=[];if(q.nodeName=="OBJECT"){return q.attributes}if(q.nodeName==="OPTION"&&this.getAttrib(q,"selected")){p.push({specified:1,nodeName:"selected"})}q.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi,"").replace(/[\w:\-]+/gi,function(o){p.push({specified:1,nodeName:o})});return p}return q.attributes},destroy:function(p){var o=this;if(o.events){o.events.destroy()}o.win=o.doc=o.root=o.events=null;if(!p){m.removeUnload(o.destroy)}},createRng:function(){var o=this.doc;return o.createRange?o.createRange():new m.dom.Range(this)},nodeIndex:function(t,u){var o=0,r,s,q,p;if(t){for(r=t.nodeType,t=t.previousSibling,s=t;t;t=t.previousSibling){q=t.nodeType;if(u&&q==3){p=false;try{p==t.nodeValue.length}catch(v){}if(q==r||!p){continue}}o++;r=q}}return o},split:function(u,s,y){var z=this,o=z.createRng(),v,q,x;function p(A){var t,r=A.childNodes;if(A.nodeType==1&&A.getAttribute("_mce_type")=="bookmark"){return}for(t=r.length-1;t>=0;t--){p(r[t])}if(A.nodeType!=9){if(A.nodeType==3&&A.nodeValue.length>0){if(!z.isBlock(A.parentNode)||m.trim(A.nodeValue).length>0){return}}if(A.nodeType==1){r=A.childNodes;if(r.length==1&&r[0]&&r[0].nodeType==1&&r[0].getAttribute("_mce_type")=="bookmark"){A.parentNode.insertBefore(r[0],A)}if(r.length||/^(br|hr|input|img)$/i.test(A.nodeName)){return}}z.remove(A)}return A}if(u&&s){o.setStart(u.parentNode,z.nodeIndex(u));o.setEnd(s.parentNode,z.nodeIndex(s));v=o.extractContents();o=z.createRng();o.setStart(s.parentNode,z.nodeIndex(s)+1);o.setEnd(u.parentNode,z.nodeIndex(u)+1);q=o.extractContents();x=u.parentNode;x.insertBefore(p(v),u);if(y){x.replaceChild(y,s)}else{x.insertBefore(s,u)}x.insertBefore(p(q),u);z.remove(u);return y||s}},bind:function(s,o,r,q){var p=this;if(!p.events){p.events=new m.dom.EventUtils()}return p.events.add(s,o,r,q||this)},unbind:function(r,o,q){var p=this;if(!p.events){p.events=new m.dom.EventUtils()}return p.events.remove(r,o,q)},_findSib:function(r,o,p){var q=this,s=o;if(r){if(j(s,"string")){s=function(t){return q.is(t,o)}}for(r=r[p];r;r=r[p]){if(s(r)){return r}}}return null},_isRes:function(o){return/^(top|left|bottom|right|width|height)/i.test(o)||/;\s*(top|left|bottom|right|width|height)/i.test(o)}});m.DOM=new m.dom.DOMUtils(document,{process_html:0})})(tinymce);(function(a){function b(c){var N=this,e=c.doc,S=0,E=1,j=2,D=true,R=false,U="startOffset",h="startContainer",P="endContainer",z="endOffset",k=tinymce.extend,n=c.nodeIndex;k(N,{startContainer:e,startOffset:0,endContainer:e,endOffset:0,collapsed:D,commonAncestorContainer:e,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:q,setEnd:s,setStartBefore:g,setStartAfter:I,setEndBefore:J,setEndAfter:u,collapse:A,selectNode:x,selectNodeContents:F,compareBoundaryPoints:v,deleteContents:p,extractContents:H,cloneContents:d,insertNode:C,surroundContents:M,cloneRange:K});function q(V,t){B(D,V,t)}function s(V,t){B(R,V,t)}function g(t){q(t.parentNode,n(t))}function I(t){q(t.parentNode,n(t)+1)}function J(t){s(t.parentNode,n(t))}function u(t){s(t.parentNode,n(t)+1)}function A(t){if(t){N[P]=N[h];N[z]=N[U]}else{N[h]=N[P];N[U]=N[z]}N.collapsed=D}function x(t){g(t);u(t)}function F(t){q(t,0);s(t,t.nodeType===1?t.childNodes.length:t.nodeValue.length)}function v(Y,t){var ab=N[h],W=N[U],aa=N[P],V=N[z],Z=t.startContainer,ad=t.startOffset,X=t.endContainer,ac=t.endOffset;if(Y===0){return G(ab,W,Z,ad)}if(Y===1){return G(aa,V,Z,ad)}if(Y===2){return G(aa,V,X,ac)}if(Y===3){return G(ab,W,X,ac)}}function p(){m(j)}function H(){return m(S)}function d(){return m(E)}function C(Y){var V=this[h],t=this[U],X,W;if((V.nodeType===3||V.nodeType===4)&&V.nodeValue){if(!t){V.parentNode.insertBefore(Y,V)}else{if(t>=V.nodeValue.length){c.insertAfter(Y,V)}else{X=V.splitText(t);V.parentNode.insertBefore(Y,X)}}}else{if(V.childNodes.length>0){W=V.childNodes[t]}if(W){V.insertBefore(Y,W)}else{V.appendChild(Y)}}}function M(V){var t=N.extractContents();N.insertNode(V);V.appendChild(t);N.selectNode(V)}function K(){return k(new b(c),{startContainer:N[h],startOffset:N[U],endContainer:N[P],endOffset:N[z],collapsed:N.collapsed,commonAncestorContainer:N.commonAncestorContainer})}function O(t,V){var W;if(t.nodeType==3){return t}if(V<0){return t}W=t.firstChild;while(W&&V>0){--V;W=W.nextSibling}if(W){return W}return t}function l(){return(N[h]==N[P]&&N[U]==N[z])}function G(X,Z,V,Y){var aa,W,t,ab,ad,ac;if(X==V){if(Z==Y){return 0}if(Z0){N.collapse(V)}}else{N.collapse(V)}N.collapsed=l();N.commonAncestorContainer=c.findCommonAncestor(N[h],N[P])}function m(ab){var aa,X=0,ad=0,V,Z,W,Y,t,ac;if(N[h]==N[P]){return f(ab)}for(aa=N[P],V=aa.parentNode;V;aa=V,V=V.parentNode){if(V==N[h]){return r(aa,ab)}++X}for(aa=N[h],V=aa.parentNode;V;aa=V,V=V.parentNode){if(V==N[P]){return T(aa,ab)}++ad}Z=ad-X;W=N[h];while(Z>0){W=W.parentNode;Z--}Y=N[P];while(Z<0){Y=Y.parentNode;Z++}for(t=W.parentNode,ac=Y.parentNode;t!=ac;t=t.parentNode,ac=ac.parentNode){W=t;Y=ac}return o(W,Y,ab)}function f(Z){var ab,Y,X,aa,t,W,V;if(Z!=j){ab=e.createDocumentFragment()}if(N[U]==N[z]){return ab}if(N[h].nodeType==3){Y=N[h].nodeValue;X=Y.substring(N[U],N[z]);if(Z!=E){N[h].deleteData(N[U],N[z]-N[U]);N.collapse(D)}if(Z==j){return}ab.appendChild(e.createTextNode(X));return ab}aa=O(N[h],N[U]);t=N[z]-N[U];while(t>0){W=aa.nextSibling;V=y(aa,Z);if(ab){ab.appendChild(V)}--t;aa=W}if(Z!=E){N.collapse(D)}return ab}function r(ab,Y){var aa,Z,V,t,X,W;if(Y!=j){aa=e.createDocumentFragment()}Z=i(ab,Y);if(aa){aa.appendChild(Z)}V=n(ab);t=V-N[U];if(t<=0){if(Y!=E){N.setEndBefore(ab);N.collapse(R)}return aa}Z=ab.previousSibling;while(t>0){X=Z.previousSibling;W=y(Z,Y);if(aa){aa.insertBefore(W,aa.firstChild)}--t;Z=X}if(Y!=E){N.setEndBefore(ab);N.collapse(R)}return aa}function T(Z,Y){var ab,V,aa,t,X,W;if(Y!=j){ab=e.createDocumentFragment()}aa=Q(Z,Y);if(ab){ab.appendChild(aa)}V=n(Z);++V;t=N[z]-V;aa=Z.nextSibling;while(t>0){X=aa.nextSibling;W=y(aa,Y);if(ab){ab.appendChild(W)}--t;aa=X}if(Y!=E){N.setStartAfter(Z);N.collapse(D)}return ab}function o(Z,t,ac){var W,ae,Y,aa,ab,V,ad,X;if(ac!=j){ae=e.createDocumentFragment()}W=Q(Z,ac);if(ae){ae.appendChild(W)}Y=Z.parentNode;aa=n(Z);ab=n(t);++aa;V=ab-aa;ad=Z.nextSibling;while(V>0){X=ad.nextSibling;W=y(ad,ac);if(ae){ae.appendChild(W)}ad=X;--V}W=i(t,ac);if(ae){ae.appendChild(W)}if(ac!=E){N.setStartAfter(Z);N.collapse(D)}return ae}function i(aa,ab){var W=O(N[P],N[z]-1),ac,Z,Y,t,V,X=W!=N[P];if(W==aa){return L(W,X,R,ab)}ac=W.parentNode;Z=L(ac,R,R,ab);while(ac){while(W){Y=W.previousSibling;t=L(W,X,R,ab);if(ab!=j){Z.insertBefore(t,Z.firstChild)}X=D;W=Y}if(ac==aa){return Z}W=ac.previousSibling;ac=ac.parentNode;V=L(ac,R,R,ab);if(ab!=j){V.appendChild(Z)}Z=V}}function Q(aa,ab){var X=O(N[h],N[U]),Y=X!=N[h],ac,Z,W,t,V;if(X==aa){return L(X,Y,D,ab)}ac=X.parentNode;Z=L(ac,R,D,ab);while(ac){while(X){W=X.nextSibling;t=L(X,Y,D,ab);if(ab!=j){Z.appendChild(t)}Y=D;X=W}if(ac==aa){return Z}X=ac.nextSibling;ac=ac.parentNode;V=L(ac,R,D,ab);if(ab!=j){V.appendChild(Z)}Z=V}}function L(t,Y,ab,ac){var X,W,Z,V,aa;if(Y){return y(t,ac)}if(t.nodeType==3){X=t.nodeValue;if(ab){V=N[U];W=X.substring(V);Z=X.substring(0,V)}else{V=N[z];W=X.substring(0,V);Z=X.substring(V)}if(ac!=E){t.nodeValue=Z}if(ac==j){return}aa=t.cloneNode(R);aa.nodeValue=W;return aa}if(ac==j){return}return t.cloneNode(R)}function y(V,t){if(t!=j){return t==E?V.cloneNode(D):V}V.parentNode.removeChild(V)}}a.Range=b})(tinymce.dom);(function(){function a(g){var i=this,j="\uFEFF",e,h,d=g.dom,c=true,f=false;function b(){var n=g.getRng(),k=d.createRng(),m,o;m=n.item?n.item(0):n.parentElement();if(m.ownerDocument!=d.doc){return k}if(n.item||!m.hasChildNodes()){k.setStart(m.parentNode,d.nodeIndex(m));k.setEnd(k.startContainer,k.startOffset+1);return k}o=g.isCollapsed();function l(s){var u,q,t,p,A=0,x,y,z,r,v;r=n.duplicate();r.collapse(s);u=d.create("a");z=r.parentElement();if(!z.hasChildNodes()){k[s?"setStart":"setEnd"](z,0);return}z.appendChild(u);r.moveToElementText(u);v=n.compareEndPoints(s?"StartToStart":"EndToEnd",r);if(v>0){k[s?"setStartAfter":"setEndAfter"](z);d.remove(u);return}p=tinymce.grep(z.childNodes);x=p.length-1;while(A<=x){y=Math.floor((A+x)/2);z.insertBefore(u,p[y]);r.moveToElementText(u);v=n.compareEndPoints(s?"StartToStart":"EndToEnd",r);if(v>0){A=y+1}else{if(v<0){x=y-1}else{found=true;break}}}q=v>0||y==0?u.nextSibling:u.previousSibling;if(q.nodeType==1){d.remove(u);t=d.nodeIndex(q);q=q.parentNode;if(!s||y>0){t++}}else{if(v>0||y==0){r.setEndPoint(s?"StartToStart":"EndToEnd",n);t=r.text.length}else{r.setEndPoint(s?"StartToStart":"EndToEnd",n);t=q.nodeValue.length-r.text.length}d.remove(u)}k[s?"setStart":"setEnd"](q,t)}l(true);if(!o){l()}return k}this.addRange=function(k){var p,n,m,r,u,s,t=g.dom.doc,o=t.body;function l(B){var x,A,v,z,y;v=d.create("a");x=B?m:u;A=B?r:s;z=p.duplicate();if(x==t){x=o;A=0}if(x.nodeType==3){x.parentNode.insertBefore(v,x);z.moveToElementText(v);z.moveStart("character",A);d.remove(v);p.setEndPoint(B?"StartToStart":"EndToEnd",z)}else{y=x.childNodes;if(y.length){if(A>=y.length){d.insertAfter(v,y[y.length-1])}else{x.insertBefore(v,y[A])}z.moveToElementText(v)}else{v=t.createTextNode(j);x.appendChild(v);z.moveToElementText(v.parentNode);z.collapse(c)}p.setEndPoint(B?"StartToStart":"EndToEnd",z);d.remove(v)}}this.destroy();m=k.startContainer;r=k.startOffset;u=k.endContainer;s=k.endOffset;p=o.createTextRange();if(m==u&&m.nodeType==1&&r==s-1){if(r==s-1){try{n=o.createControlRange();n.addElement(m.childNodes[r]);n.select();return}catch(q){}}}l(true);l();p.select()};this.getRangeAt=function(){if(!e||!tinymce.dom.RangeUtils.compareRanges(h,g.getRng())){e=b();h=g.getRng()}try{e.startContainer.nextSibling}catch(k){e=b();h=null}return e};this.destroy=function(){h=e=null}}tinymce.dom.TridentSelection=a})();(function(d){var f=d.each,c=d.DOM,b=d.isIE,e=d.isWebKit,a;d.create("tinymce.dom.EventUtils",{EventUtils:function(){this.inits=[];this.events=[]},add:function(m,p,l,j){var g,h=this,i=h.events,k;if(p instanceof Array){k=[];f(p,function(o){k.push(h.add(m,o,l,j))});return k}if(m&&m.hasOwnProperty&&m instanceof Array){k=[];f(m,function(n){n=c.get(n);k.push(h.add(n,p,l,j))});return k}m=c.get(m);if(!m){return}g=function(n){if(h.disabled){return}n=n||window.event;if(n&&b){if(!n.target){n.target=n.srcElement}d.extend(n,h._stoppers)}if(!j){return l(n)}return l.call(j,n)};if(p=="unload"){d.unloads.unshift({func:g});return g}if(p=="init"){if(h.domLoaded){g()}else{h.inits.push(g)}return g}i.push({obj:m,name:p,func:l,cfunc:g,scope:j});h._add(m,p,g);return l},remove:function(l,m,k){var h=this,g=h.events,i=false,j;if(l&&l.hasOwnProperty&&l instanceof Array){j=[];f(l,function(n){n=c.get(n);j.push(h.remove(n,m,k))});return j}l=c.get(l);f(g,function(o,n){if(o.obj==l&&o.name==m&&(!k||(o.func==k||o.cfunc==k))){g.splice(n,1);h._remove(l,m,o.cfunc);i=true;return false}});return i},clear:function(l){var j=this,g=j.events,h,k;if(l){l=c.get(l);for(h=g.length-1;h>=0;h--){k=g[h];if(k.obj===l){j._remove(k.obj,k.name,k.cfunc);k.obj=k.cfunc=null;g.splice(h,1)}}}},cancel:function(g){if(!g){return false}this.stop(g);return this.prevent(g)},stop:function(g){if(g.stopPropagation){g.stopPropagation()}else{g.cancelBubble=true}return false},prevent:function(g){if(g.preventDefault){g.preventDefault()}else{g.returnValue=false}return false},destroy:function(){var g=this;f(g.events,function(j,h){g._remove(j.obj,j.name,j.cfunc);j.obj=j.cfunc=null});g.events=[];g=null},_add:function(h,i,g){if(h.attachEvent){h.attachEvent("on"+i,g)}else{if(h.addEventListener){h.addEventListener(i,g,false)}else{h["on"+i]=g}}},_remove:function(i,j,h){if(i){try{if(i.detachEvent){i.detachEvent("on"+j,h)}else{if(i.removeEventListener){i.removeEventListener(j,h,false)}else{i["on"+j]=null}}}catch(g){}}},_pageInit:function(h){var g=this;if(g.domLoaded){return}g.domLoaded=true;f(g.inits,function(i){i()});g.inits=[]},_wait:function(i){var g=this,h=i.document;if(i.tinyMCE_GZ&&tinyMCE_GZ.loaded){g.domLoaded=1;return}if(h.attachEvent){h.attachEvent("onreadystatechange",function(){if(h.readyState==="complete"){h.detachEvent("onreadystatechange",arguments.callee);g._pageInit(i)}});if(h.documentElement.doScroll&&i==i.top){(function(){if(g.domLoaded){return}try{h.documentElement.doScroll("left")}catch(j){setTimeout(arguments.callee,0);return}g._pageInit(i)})()}}else{if(h.addEventListener){g._add(i,"DOMContentLoaded",function(){g._pageInit(i)})}}g._add(i,"load",function(){g._pageInit(i)})},_stoppers:{preventDefault:function(){this.returnValue=false},stopPropagation:function(){this.cancelBubble=true}}});a=d.dom.Event=new d.dom.EventUtils();a._wait(window);d.addUnload(function(){a.destroy()})})(tinymce);(function(a){a.dom.Element=function(f,d){var b=this,e,c;b.settings=d=d||{};b.id=f;b.dom=e=d.dom||a.DOM;if(!a.isIE){c=e.get(b.id)}a.each(("getPos,getRect,getParent,add,setStyle,getStyle,setStyles,setAttrib,setAttribs,getAttrib,addClass,removeClass,hasClass,getOuterHTML,setOuterHTML,remove,show,hide,isHidden,setHTML,get").split(/,/),function(g){b[g]=function(){var h=[f],j;for(j=0;j_';if(k.startContainer==l&&k.endContainer==l){l.body.innerHTML=j}else{k.deleteContents();if(l.body.childNodes.length==0){l.body.innerHTML=j}else{if(k.createContextualFragment){k.insertNode(k.createContextualFragment(j))}else{var m=l.createDocumentFragment(),f=l.createElement("div");m.appendChild(f);f.outerHTML=j;k.insertNode(m)}}}n=g.dom.get("__caret");k=l.createRange();k.setStartBefore(n);k.setEndBefore(n);g.setRng(k);g.dom.remove("__caret");g.setRng(k)}else{if(k.item){l.execCommand("Delete",false,null);k=g.getRng()}k.pasteHTML(j)}g.onSetContent.dispatch(g,i)},getStart:function(){var g=this.getRng(),h,f,j,i;if(g.duplicate||g.item){if(g.item){return g.item(0)}j=g.duplicate();j.collapse(1);h=j.parentElement();f=i=g.parentElement();while(i=i.parentNode){if(i==h){h=f;break}}return h}else{h=g.startContainer;if(h.nodeType==1&&h.hasChildNodes()){h=h.childNodes[Math.min(h.childNodes.length-1,g.startOffset)]}if(h&&h.nodeType==3){return h.parentNode}return h}},getEnd:function(){var g=this,h=g.getRng(),i,f;if(h.duplicate||h.item){if(h.item){return h.item(0)}h=h.duplicate();h.collapse(0);i=h.parentElement();if(i&&i.nodeName=="BODY"){return i.lastChild||i}return i}else{i=h.endContainer;f=h.endOffset;if(i.nodeType==1&&i.hasChildNodes()){i=i.childNodes[f>0?f-1:f]}if(i&&i.nodeType==3){return i.parentNode}return i}},getBookmark:function(q,r){var u=this,m=u.dom,g,j,i,n,h,o,p,l="\uFEFF",s;function f(v,x){var t=0;d(m.select(v),function(z,y){if(z==x){t=y}});return t}if(q==2){function k(){var v=u.getRng(true),t=m.getRoot(),x={};function y(B,G){var A=B[G?"startContainer":"endContainer"],F=B[G?"startOffset":"endOffset"],z=[],C,E,D=0;if(A.nodeType==3){if(r){for(C=A.previousSibling;C&&C.nodeType==3;C=C.previousSibling){F+=C.nodeValue.length}}z.push(F)}else{E=A.childNodes;if(F>=E.length&&E.length){D=1;F=Math.max(0,E.length-1)}z.push(u.dom.nodeIndex(E[F],r)+D)}for(;A&&A!=t;A=A.parentNode){z.push(u.dom.nodeIndex(A,r))}return z}x.start=y(v,true);if(!u.isCollapsed()){x.end=y(v)}return x}return k()}if(q){return{rng:u.getRng()}}g=u.getRng();i=m.uniqueId();n=tinyMCE.activeEditor.selection.isCollapsed();s="overflow:hidden;line-height:0px";if(g.duplicate||g.item){if(!g.item){j=g.duplicate();g.collapse();g.pasteHTML(''+l+"");if(!n){j.collapse(false);j.pasteHTML(''+l+"")}}else{o=g.item(0);h=o.nodeName;return{name:h,index:f(h,o)}}}else{o=u.getNode();h=o.nodeName;if(h=="IMG"){return{name:h,index:f(h,o)}}j=g.cloneRange();if(!n){j.collapse(false);j.insertNode(m.create("span",{_mce_type:"bookmark",id:i+"_end",style:s},l))}g.collapse(true);g.insertNode(m.create("span",{_mce_type:"bookmark",id:i+"_start",style:s},l))}u.moveToBookmark({id:i,keep:1});return{id:i}},moveToBookmark:function(n){var r=this,l=r.dom,i,h,f,q,j,s,o,p;if(r.tridentSel){r.tridentSel.destroy()}if(n){if(n.start){f=l.createRng();q=l.getRoot();function g(z){var t=n[z?"start":"end"],v,x,y,u;if(t){for(x=q,v=t.length-1;v>=1;v--){u=x.childNodes;if(u.length){x=u[t[v]]}}if(z){f.setStart(x,t[0])}else{f.setEnd(x,t[0])}}}g(true);g();r.setRng(f)}else{if(n.id){function k(A){var u=l.get(n.id+"_"+A),z,t,x,y,v=n.keep;if(u){z=u.parentNode;if(A=="start"){if(!v){t=l.nodeIndex(u)}else{z=u.firstChild;t=1}j=s=z;o=p=t}else{if(!v){t=l.nodeIndex(u)}else{z=u.firstChild;t=1}s=z;p=t}if(!v){y=u.previousSibling;x=u.nextSibling;d(c.grep(u.childNodes),function(B){if(B.nodeType==3){B.nodeValue=B.nodeValue.replace(/\uFEFF/g,"")}});while(u=l.get(n.id+"_"+A)){l.remove(u,1)}if(y&&x&&y.nodeType==x.nodeType&&y.nodeType==3&&!c.isOpera){t=y.nodeValue.length;y.appendData(x.nodeValue);l.remove(x);if(A=="start"){j=s=y;o=p=t}else{s=y;p=t}}}}}function m(t){if(!a&&l.isBlock(t)&&!t.innerHTML){t.innerHTML='
    '}return t}k("start");k("end");if(j){f=l.createRng();f.setStart(m(j),o);f.setEnd(m(s),p);r.setRng(f)}}else{if(n.name){r.select(l.select(n.name)[n.index])}else{if(n.rng){r.setRng(n.rng)}}}}}},moveAfterNode:function(g){var f=this.dom.createRng();f.setStartAfter(g);f.setEndAfter(g);this.setRng(f)},select:function(k,j){var i=this,l=i.dom,g=l.createRng(),f;f=l.nodeIndex(k);g.setStart(k.parentNode,f);g.setEnd(k.parentNode,f+1);if(j){function h(m,o){var n=new c.dom.TreeWalker(m,m);do{if(m.nodeType==3&&c.trim(m.nodeValue).length!=0){if(o){g.setStart(m,0)}else{g.setEnd(m,m.nodeValue.length)}return}if(m.nodeName=="BR"){if(o){g.setStartBefore(m)}else{g.setEndBefore(m)}return}}while(m=(o?n.next():n.prev()))}h(k,1);h(k)}i.setRng(g);return k},isCollapsed:function(){var f=this,h=f.getRng(),g=f.getSel();if(!h||h.item){return false}if(h.compareEndPoints){return h.compareEndPoints("StartToEnd",h)===0}return !g||h.collapsed},collapse:function(f){var g=this,h=g.getRng(),i;if(h.item){i=h.item(0);h=this.win.document.body.createTextRange();h.moveToElementText(i)}h.collapse(!!f);g.setRng(h)},getSel:function(){var g=this,f=this.win;return f.getSelection?f.getSelection():f.document.selection},getRng:function(l){var g=this,h,i,k,j=g.win.document;if(l&&g.tridentSel){return g.tridentSel.getRangeAt(0)}try{if(h=g.getSel()){i=h.rangeCount>0?h.getRangeAt(0):(h.createRange?h.createRange():j.createRange())}}catch(f){}if(c.isIE&&i.setStart&&j.selection.createRange().item){k=j.selection.createRange().item(0);i=j.createRange();i.setStartBefore(k);i.setEndAfter(k)}if(!i){i=j.createRange?j.createRange():j.body.createTextRange()}if(g.selectedRange&&g.explicitRange){if(i.compareBoundaryPoints(i.START_TO_START,g.selectedRange)===0&&i.compareBoundaryPoints(i.END_TO_END,g.selectedRange)===0){i=g.explicitRange}else{g.selectedRange=null;g.explicitRange=null}}return i},setRng:function(i){var h,g=this;if(!g.tridentSel){h=g.getSel();if(h){g.explicitRange=i;h.removeAllRanges();h.addRange(i);g.selectedRange=h.getRangeAt(0)}}else{if(i.cloneRange){g.tridentSel.addRange(i);return}try{i.select()}catch(f){}}},setNode:function(g){var f=this;f.setContent(f.dom.getOuterHTML(g));return g},getNode:function(){var h=this,g=h.getRng(),i=h.getSel(),l,k=g.startContainer,f=g.endContainer;if(g.setStart){if(!g){return h.dom.getRoot()}l=g.commonAncestorContainer;if(!g.collapsed){if(g.startContainer==g.endContainer){if(g.startOffset-g.endOffset<2){if(g.startContainer.hasChildNodes()){l=g.startContainer.childNodes[g.startOffset]}}}if(c.isWebKit&&i.anchorNode&&i.anchorNode.nodeType==1){return i.anchorNode.childNodes[i.anchorOffset]}if(k.nodeType===3&&f.nodeType===3){function j(p,m){var o=p;while(p&&p.nodeType===3&&p.length===0){p=m?p.nextSibling:p.previousSibling}return p||o}if(k.length===g.startOffset){k=j(k.nextSibling,true)}else{k=k.parentNode}if(g.endOffset===0){f=j(f.previousSibling,false)}else{f=f.parentNode}if(k&&k===f){return k}}}if(l&&l.nodeType==3){return l.parentNode}return l}return g.item?g.item(0):g.parentElement()},getSelectedBlocks:function(g,f){var i=this,j=i.dom,m,h,l,k=[];m=j.getParent(g||i.getStart(),j.isBlock);h=j.getParent(f||i.getEnd(),j.isBlock);if(m){k.push(m)}if(m&&h&&m!=h){l=m;while((l=l.nextSibling)&&l!=h){if(j.isBlock(l)){k.push(l)}}}if(h&&m!=h){k.push(h)}return k},destroy:function(g){var f=this;f.win=null;if(f.tridentSel){f.tridentSel.destroy()}if(!g){c.removeUnload(f.destroy)}},_fixIESelection:function(){var m=this.dom,l=m.doc,g=l.body,i,j;l.documentElement.unselectable=true;function k(n,q){var o=g.createTextRange();try{o.moveToPoint(n,q)}catch(p){o=null}return o}function h(o){var n;if(o.button){n=k(o.x,o.y);if(n){if(n.compareEndPoints("StartToStart",j)>0){n.setEndPoint("StartToStart",j)}else{n.setEndPoint("EndToEnd",j)}n.select()}}else{f()}}function f(){m.unbind(l,"mouseup",f);m.unbind(l,"mousemove",h);i=0}m.bind(l,"mousedown",function(n){if(n.target.nodeName==="HTML"){if(i){f()}i=1;j=k(n.x,n.y);if(j){m.bind(l,"mouseup",f);m.bind(l,"mousemove",h);m.win.focus();j.select()}}})}})})(tinymce);(function(a){a.create("tinymce.dom.XMLWriter",{node:null,XMLWriter:function(c){function b(){var e=document.implementation;if(!e||!e.createDocument){try{return new ActiveXObject("MSXML2.DOMDocument")}catch(d){}try{return new ActiveXObject("Microsoft.XmlDom")}catch(d){}}else{return e.createDocument("","",null)}}this.doc=b();this.valid=a.isOpera||a.isWebKit;this.reset()},reset:function(){var b=this,c=b.doc;if(c.firstChild){c.removeChild(c.firstChild)}b.node=c.appendChild(c.createElement("html"))},writeStartElement:function(c){var b=this;b.node=b.node.appendChild(b.doc.createElement(c))},writeAttribute:function(c,b){if(this.valid){b=b.replace(/>/g,"%MCGT%")}this.node.setAttribute(c,b)},writeEndElement:function(){this.node=this.node.parentNode},writeFullEndElement:function(){var b=this,c=b.node;c.appendChild(b.doc.createTextNode(""));b.node=c.parentNode},writeText:function(b){if(this.valid){b=b.replace(/>/g,"%MCGT%")}this.node.appendChild(this.doc.createTextNode(b))},writeCDATA:function(b){this.node.appendChild(this.doc.createCDATASection(b))},writeComment:function(b){if(a.isIE){b=b.replace(/^\-|\-$/g," ")}this.node.appendChild(this.doc.createComment(b.replace(/\-\-/g," ")))},getContent:function(){var b;b=this.doc.xml||new XMLSerializer().serializeToString(this.doc);b=b.replace(/<\?[^?]+\?>|]*>|<\/html>||]+>/g,"");b=b.replace(/ ?\/>/g," />");if(this.valid){b=b.replace(/\%MCGT%/g,">")}return b}})})(tinymce);(function(c){var d=/[&\"<>]/g,b=/[<>&]/g,a={"&":"&",'"':""","<":"<",">":">"};c.create("tinymce.dom.StringWriter",{str:null,tags:null,count:0,settings:null,indent:null,StringWriter:function(e){this.settings=c.extend({indent_char:" ",indentation:0},e);this.reset()},reset:function(){this.indent="";this.str="";this.tags=[];this.count=0},writeStartElement:function(e){this._writeAttributesEnd();this.writeRaw("<"+e);this.tags.push(e);this.inAttr=true;this.count++;this.elementCount=this.count;this.attrs={}},writeAttribute:function(g,e){var f=this;if(!f.attrs[g]){f.writeRaw(" "+f.encode(g,true)+'="'+f.encode(e,true)+'"');f.attrs[g]=e}},writeEndElement:function(){var e;if(this.tags.length>0){e=this.tags.pop();if(this._writeAttributesEnd(1)){this.writeRaw("")}if(this.settings.indentation>0){this.writeRaw("\n")}}},writeFullEndElement:function(){if(this.tags.length>0){this._writeAttributesEnd();this.writeRaw("");if(this.settings.indentation>0){this.writeRaw("\n")}}},writeText:function(e){this._writeAttributesEnd();this.writeRaw(this.encode(e));this.count++},writeCDATA:function(e){this._writeAttributesEnd();this.writeRaw("");this.count++},writeComment:function(e){this._writeAttributesEnd();this.writeRaw("");this.count++},writeRaw:function(e){this.str+=e},encode:function(f,e){return f.replace(e?d:b,function(g){return a[g]})},getContent:function(){return this.str},_writeAttributesEnd:function(e){if(!this.inAttr){return}this.inAttr=false;if(e&&this.elementCount==this.count){this.writeRaw(" />");return false}this.writeRaw(">");return true}})})(tinymce);(function(e){var g=e.extend,f=e.each,b=e.util.Dispatcher,d=e.isIE,a=e.isGecko;function c(h){return h.replace(/([?+*])/g,".$1")}e.create("tinymce.dom.Serializer",{Serializer:function(j){var i=this;i.key=0;i.onPreProcess=new b(i);i.onPostProcess=new b(i);try{i.writer=new e.dom.XMLWriter()}catch(h){i.writer=new e.dom.StringWriter()}if(e.isIE&&document.documentMode>8){i.writer=new e.dom.StringWriter()}i.settings=j=g({dom:e.DOM,valid_nodes:0,node_filter:0,attr_filter:0,invalid_attrs:/^(_mce_|_moz_|sizset|sizcache)/,closed:/^(br|hr|input|meta|img|link|param|area)$/,entity_encoding:"named",entities:"160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro",valid_elements:"*[*]",extended_valid_elements:0,invalid_elements:0,fix_table_elements:1,fix_list_elements:true,fix_content_duplication:true,convert_fonts_to_spans:false,font_size_classes:0,apply_source_formatting:0,indent_mode:"simple",indent_char:"\t",indent_levels:1,remove_linebreaks:1,remove_redundant_brs:1,element_format:"xhtml"},j);i.dom=j.dom;i.schema=j.schema;if(j.entity_encoding=="named"&&!j.entities){j.entity_encoding="raw"}if(j.remove_redundant_brs){i.onPostProcess.add(function(k,l){l.content=l.content.replace(/(
    \s*)+<\/(p|h[1-6]|div|li)>/gi,function(n,m,o){if(/^
    \s*<\//.test(n)){return""}return n})})}if(j.element_format=="html"){i.onPostProcess.add(function(k,l){l.content=l.content.replace(/<([^>]+) \/>/g,"<$1>")})}if(j.fix_list_elements){i.onPreProcess.add(function(v,s){var l,z,y=["ol","ul"],u,t,q,k=/^(OL|UL)$/,A;function m(r,x){var o=x.split(","),p;while((r=r.previousSibling)!=null){for(p=0;p1){f(q[1].split("|"),function(u){var p={},t;k=k||[];u=u.replace(/::/g,"~");u=/^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/.exec(u);u[2]=u[2].replace(/~/g,":");if(u[1]=="!"){r=r||[];r.push(u[2])}if(u[1]=="-"){for(t=0;t]*>)(.*?)(<\/script>)/g},{pattern:/(]*>)(.*?)(<\/noscript>)/g},{pattern:/(]*>)(.*?)(<\/style>)/g},{pattern:/(]*>)(.*?)(<\/pre>)/g,encode:1},{pattern:/()/g}]});j=l.content;if(k.entity_encoding!=="raw"){j=i._encode(j)}if(!n.set){j=e._replace(/

    \s+<\/p>|]+)>\s+<\/p>/g,k.entity_encoding=="numeric"?" 

    ":" 

    ",j);if(k.remove_linebreaks){j=j.replace(/\r?\n|\r/g," ");j=e._replace(/(<[^>]+>)\s+/g,"$1 ",j);j=e._replace(/\s+(<\/[^>]+>)/g," $1",j);j=e._replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g,"<$1 $2>",j);j=e._replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g,"<$1>",j);j=e._replace(/\s+<\/(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g,"",j)}if(k.apply_source_formatting&&k.indent_mode=="simple"){j=e._replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g,"\n<$1$2$3>\n",j);j=e._replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g,"\n<$1$2>",j);j=e._replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g,"\n",j);j=j.replace(/\n\n/g,"\n")}}j=i._unprotect(j,l);j=e._replace(//g,"",j);if(k.entity_encoding=="raw"){j=e._replace(/

     <\/p>|]+)> <\/p>/g,"\u00a0

    ",j)}j=j.replace(/]+|)>([\s\S]*?)<\/noscript>/g,function(h,p,o){return""+i.dom.decode(o.replace(//g,""))+""})}n.content=j},_serializeNode:function(E,J){var A=this,B=A.settings,y=A.writer,q,j,u,G,F,I,C,h,z,k,r,D,p,m,H,o,x;if(!B.node_filter||B.node_filter(E)){switch(E.nodeType){case 1:if(E.hasAttribute?E.hasAttribute("_mce_bogus"):E.getAttribute("_mce_bogus")){return}p=H=false;q=E.hasChildNodes();k=E.getAttribute("_mce_name")||E.nodeName.toLowerCase();o=E.getAttribute("_mce_type");if(o){if(!A._info.cleanup){p=true;return}else{H=1}}if(d){x=E.scopeName;if(x&&x!=="HTML"&&x!=="html"&&k.indexOf(x+":")!==0){k=x+":"+k}}if(k.indexOf("mce:")===0){k=k.substring(4)}if(!H){if(!A.validElementsRE||!A.validElementsRE.test(k)||(A.invalidElementsRE&&A.invalidElementsRE.test(k))||J){p=true;break}}if(d){if(B.fix_content_duplication){if(E._mce_serialized==A.key){return}E._mce_serialized=A.key}if(k.charAt(0)=="/"){k=k.substring(1)}}else{if(a){if(E.nodeName==="BR"&&E.getAttribute("type")=="_moz"){return}}}if(B.validate_children){if(A.elementName&&!A.schema.isValid(A.elementName,k)){p=true;break}A.elementName=k}r=A.findRule(k);if(!r){p=true;break}k=r.name||k;m=B.closed.test(k);if((!q&&r.noEmpty)||(d&&!k)){p=true;break}if(r.requiredAttribs){I=r.requiredAttribs;for(G=I.length-1;G>=0;G--){if(this.dom.getAttrib(E,I[G])!==""){break}}if(G==-1){p=true;break}}y.writeStartElement(k);if(r.attribs){for(G=0,C=r.attribs,F=C.length;G-1;G--){h=C[G];if(h.specified){I=h.nodeName.toLowerCase();if(B.invalid_attrs.test(I)||!r.validAttribsRE.test(I)){continue}D=A.findAttribRule(r,I);z=A._getAttrib(E,D,I);if(z!==null){y.writeAttribute(I,z)}}}}if(o&&H){y.writeAttribute("_mce_type",o)}if(k==="script"&&e.trim(E.innerHTML)){y.writeText("// ");y.writeCDATA(E.innerHTML.replace(/|<\[CDATA\[|\]\]>/g,""));q=false;break}if(r.padd){if(q&&(u=E.firstChild)&&u.nodeType===1&&E.childNodes.length===1){if(u.hasAttribute?u.hasAttribute("_mce_bogus"):u.getAttribute("_mce_bogus")){y.writeText("\u00a0")}}else{if(!q){y.writeText("\u00a0")}}}break;case 3:if(B.validate_children&&A.elementName&&!A.schema.isValid(A.elementName,"#text")){return}return y.writeText(E.nodeValue);case 4:return y.writeCDATA(E.nodeValue);case 8:return y.writeComment(E.nodeValue)}}else{if(E.nodeType==1){q=E.hasChildNodes()}}if(q&&!m){u=E.firstChild;while(u){A._serializeNode(u);A.elementName=k;u=u.nextSibling}}if(!p){if(!m){y.writeFullEndElement()}else{y.writeEndElement()}}},_protect:function(j){var i=this;j.items=j.items||[];function h(l){return l.replace(/[\r\n\\]/g,function(m){if(m==="\n"){return"\\n"}else{if(m==="\\"){return"\\\\"}}return"\\r"})}function k(l){return l.replace(/\\[\\rn]/g,function(m){if(m==="\\n"){return"\n"}else{if(m==="\\\\"){return"\\"}}return"\r"})}f(j.patterns,function(l){j.content=k(h(j.content).replace(l.pattern,function(n,o,m,p){m=k(m);if(l.encode){m=i._encode(m)}j.items.push(m);return o+""+p}))});return j},_unprotect:function(i,j){i=i.replace(/\"))}if(d&&k.ListBox){if(d.Button||d.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarEnd"},c.createHTML("span",null,""))}}if(c.stdMode){f+=''+k.renderHTML()+""}else{f+=""+k.renderHTML()+""}if(g&&k.ListBox){if(g.Button||g.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarStart"},c.createHTML("span",null,""))}}}j="mceToolbarEnd";if(k.Button){j+=" mceToolbarEndButton"}else{if(k.SplitButton){j+=" mceToolbarEndSplitButton"}else{if(k.ListBox){j+=" mceToolbarEndListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,""));return c.createHTML("table",{id:m.id,"class":"mceToolbar"+(n["class"]?" "+n["class"]:""),cellpadding:"0",cellspacing:"0",align:m.settings.align||"",role:"presentation",tabindex:"-1"},""+f+"")}})})(tinymce);(function(b){var a=b.util.Dispatcher,c=b.each;b.create("tinymce.AddOnManager",{AddOnManager:function(){var d=this;d.items=[];d.urls={};d.lookup={};d.onAdd=new a(d)},get:function(d){return this.lookup[d]},requireLangPack:function(e){var d=b.settings;if(d&&d.language){b.ScriptLoader.add(this.urls[e]+"/langs/"+d.language+".js")}},add:function(e,d){this.items.push(d);this.lookup[e]=d;this.onAdd.dispatch(this,e,d);return d},load:function(h,e,d,g){var f=this;if(f.urls[h]){return}if(e.indexOf("/")!=0&&e.indexOf("://")==-1){e=b.baseURL+"/"+e}f.urls[h]=e.substring(0,e.lastIndexOf("/"));if(!f.lookup[h]){b.ScriptLoader.add(e,d,g)}}});b.PluginManager=new b.AddOnManager();b.ThemeManager=new b.AddOnManager()}(tinymce));(function(j){var g=j.each,d=j.extend,k=j.DOM,i=j.dom.Event,f=j.ThemeManager,b=j.PluginManager,e=j.explode,h=j.util.Dispatcher,a,c=0;j.documentBaseURL=window.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,"");if(!/[\/\\]$/.test(j.documentBaseURL)){j.documentBaseURL+="/"}j.baseURL=new j.util.URI(j.documentBaseURL).toAbsolute(j.baseURL);j.baseURI=new j.util.URI(j.baseURL);j.onBeforeUnload=new h(j);i.add(window,"beforeunload",function(l){j.onBeforeUnload.dispatch(j,l)});j.onAddEditor=new h(j);j.onRemoveEditor=new h(j);j.EditorManager=d(j,{editors:[],i18n:{},activeEditor:null,init:function(q){var n=this,p,l=j.ScriptLoader,u,o=[],m;function r(x,y,t){var v=x[y];if(!v){return}if(j.is(v,"string")){t=v.replace(/\.\w+$/,"");t=t?j.resolve(t):0;v=j.resolve(v)}return v.apply(t||this,Array.prototype.slice.call(arguments,2))}q=d({theme:"simple",language:"en"},q);n.settings=q;i.add(document,"init",function(){var s,v;r(q,"onpageload");switch(q.mode){case"exact":s=q.elements||"";if(s.length>0){g(e(s),function(x){if(k.get(x)){m=new j.Editor(x,q);o.push(m);m.render(1)}else{g(document.forms,function(y){g(y.elements,function(z){if(z.name===x){x="mce_editor_"+c++;k.setAttrib(z,"id",x);m=new j.Editor(x,q);o.push(m);m.render(1)}})})}})}break;case"textareas":case"specific_textareas":function t(y,x){return x.constructor===RegExp?x.test(y.className):k.hasClass(y,x)}g(k.select("textarea"),function(x){if(q.editor_deselector&&t(x,q.editor_deselector)){return}if(!q.editor_selector||t(x,q.editor_selector)){u=k.get(x.name);if(!x.id&&!u){x.id=x.name}if(!x.id||n.get(x.id)){x.id=k.uniqueId()}m=new j.Editor(x.id,q);o.push(m);m.render(1)}});break}if(q.oninit){s=v=0;g(o,function(x){v++;if(!x.initialized){x.onInit.add(function(){s++;if(s==v){r(q,"oninit")}})}else{s++}if(s==v){r(q,"oninit")}})}})},get:function(l){if(l===a){return this.editors}return this.editors[l]},getInstanceById:function(l){return this.get(l)},add:function(m){var l=this,n=l.editors;n[m.id]=m;n.push(m);l._setActive(m);l.onAddEditor.dispatch(l,m);if(j.adapter){j.adapter.patchEditor(m)}return m},remove:function(n){var m=this,l,o=m.editors;if(!o[n.id]){return null}delete o[n.id];for(l=0;l':"",visual_table_class:"mceItemTable",visual:1,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",apply_source_formatting:1,directionality:"ltr",forced_root_block:"p",valid_elements:"@[id|class|style|title|dir';if(F.document_base_url!=m.documentBaseURL){E.iframeHTML+=''}E.iframeHTML+='';if(m.relaxedDomain){E.iframeHTML+=''; + + bi = s.body_id || 'tinymce'; + if (bi.indexOf('=') != -1) { + bi = t.getParam('body_id', '', 'hash'); + bi = bi[t.id] || bi; + } + + bc = s.body_class || ''; + if (bc.indexOf('=') != -1) { + bc = t.getParam('body_class', '', 'hash'); + bc = bc[t.id] || ''; + } + + t.iframeHTML += ''; + + // Domain relaxing enabled, then set document domain + if (tinymce.relaxedDomain) { + // We need to write the contents here in IE since multiple writes messes up refresh button and back button + if (isIE || (tinymce.isOpera && parseFloat(opera.version()) >= 9.5)) + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + t.id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()'; + else if (tinymce.isOpera) + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()'; + } + + // Create iframe + //TODO: ACC add the appropriate description on this. + n = DOM.add(o.iframeContainer, 'iframe', { + id : t.id + "_ifr", + src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7 + frameBorder : '0', + title : s.aria_label, + + style : { + width : '100%', + height : h + } + }); + + t.contentAreaContainer = o.iframeContainer; + DOM.get(o.editorContainer).style.display = t.orgDisplay; + DOM.get(t.id).style.display = 'none'; + DOM.setAttrib(t.id, 'aria-hidden', true); + + if (!isIE || !tinymce.relaxedDomain) + t.setupIframe(); + + e = n = o = null; // Cleanup + }, + + setupIframe : function() { + var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b; + + // Setup iframe body + if (!isIE || !tinymce.relaxedDomain) { + d.open(); + d.write(t.iframeHTML); + d.close(); + } + + // Design mode needs to be added here Ctrl+A will fail otherwise + if (!isIE) { + try { + if (!s.readonly) + d.designMode = 'On'; + } catch (ex) { + // Will fail on Gecko if the editor is placed in an hidden container element + // The design mode will be set ones the editor is focused + } + } + + // IE needs to use contentEditable or it will display non secure items for HTTPS + if (isIE) { + // It will not steal focus if we hide it while setting contentEditable + b = t.getBody(); + DOM.hide(b); + + if (!s.readonly) + b.contentEditable = true; + + DOM.show(b); + } + + t.dom = new tinymce.dom.DOMUtils(t.getDoc(), { + keep_values : true, + url_converter : t.convertURL, + url_converter_scope : t, + hex_colors : s.force_hex_style_colors, + class_filter : s.class_filter, + update_styles : 1, + fix_ie_paragraphs : 1, + valid_styles : s.valid_styles + }); + + t.schema = new tinymce.dom.Schema(); + + t.serializer = new tinymce.dom.Serializer(extend(s, { + valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements, + dom : t.dom, + schema : t.schema + })); + + t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer); + + t.formatter = new tinymce.Formatter(this); + + // Register default formats + t.formatter.register({ + alignleft : [ + {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}}, + {selector : 'img,table', styles : {'float' : 'left'}} + ], + + aligncenter : [ + {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}}, + {selector : 'img', styles : {display : 'block', marginLeft : 'auto', marginRight : 'auto'}}, + {selector : 'table', styles : {marginLeft : 'auto', marginRight : 'auto'}} + ], + + alignright : [ + {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}}, + {selector : 'img,table', styles : {'float' : 'right'}} + ], + + alignfull : [ + {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'justify'}} + ], + + bold : [ + {inline : 'strong'}, + {inline : 'span', styles : {fontWeight : 'bold'}}, + {inline : 'b'} + ], + + italic : [ + {inline : 'em'}, + {inline : 'span', styles : {fontStyle : 'italic'}}, + {inline : 'i'} + ], + + underline : [ + {inline : 'span', styles : {textDecoration : 'underline'}, exact : true}, + {inline : 'u'} + ], + + strikethrough : [ + {inline : 'span', styles : {textDecoration : 'line-through'}, exact : true}, + {inline : 'u'} + ], + + forecolor : {inline : 'span', styles : {color : '%value'}, wrap_links : false}, + hilitecolor : {inline : 'span', styles : {backgroundColor : '%value'}, wrap_links : false}, + fontname : {inline : 'span', styles : {fontFamily : '%value'}}, + fontsize : {inline : 'span', styles : {fontSize : '%value'}}, + fontsize_class : {inline : 'span', attributes : {'class' : '%value'}}, + blockquote : {block : 'blockquote', wrapper : 1, remove : 'all'}, + + removeformat : [ + {selector : 'b,strong,em,i,font,u,strike', remove : 'all', split : true, expand : false, block_expand : true, deep : true}, + {selector : 'span', attributes : ['style', 'class'], remove : 'empty', split : true, expand : false, deep : true}, + {selector : '*', attributes : ['style', 'class'], split : false, expand : false, deep : true} + ] + }); + + // Register default block formats + each('p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp'.split(/\s/), function(name) { + t.formatter.register(name, {block : name, remove : 'all'}); + }); + + // Register user defined formats + t.formatter.register(t.settings.formats); + + t.undoManager = new tinymce.UndoManager(t); + + // Pass through + t.undoManager.onAdd.add(function(um, l) { + if (!l.initial) + return t.onChange.dispatch(t, l, um); + }); + + t.undoManager.onUndo.add(function(um, l) { + return t.onUndo.dispatch(t, l, um); + }); + + t.undoManager.onRedo.add(function(um, l) { + return t.onRedo.dispatch(t, l, um); + }); + + t.forceBlocks = new tinymce.ForceBlocks(t, { + forced_root_block : s.forced_root_block + }); + + t.editorCommands = new tinymce.EditorCommands(t); + + // Pass through + t.serializer.onPreProcess.add(function(se, o) { + return t.onPreProcess.dispatch(t, o, se); + }); + + t.serializer.onPostProcess.add(function(se, o) { + return t.onPostProcess.dispatch(t, o, se); + }); + + t.onPreInit.dispatch(t); + + if (!s.gecko_spellcheck) + t.getBody().spellcheck = 0; + + if (!s.readonly) + t._addEvents(); + + t.controlManager.onPostRender.dispatch(t, t.controlManager); + t.onPostRender.dispatch(t); + + if (s.directionality) + t.getBody().dir = s.directionality; + + if (s.nowrap) + t.getBody().style.whiteSpace = "nowrap"; + + if (s.custom_elements) { + function handleCustom(ed, o) { + each(explode(s.custom_elements), function(v) { + var n; + + if (v.indexOf('~') === 0) { + v = v.substring(1); + n = 'span'; + } else + n = 'div'; + + o.content = o.content.replace(new RegExp('<(' + v + ')([^>]*)>', 'g'), '<' + n + ' _mce_name="$1"$2>'); + o.content = o.content.replace(new RegExp('', 'g'), ''); + }); + }; + + t.onBeforeSetContent.add(handleCustom); + t.onPostProcess.add(function(ed, o) { + if (o.set) + handleCustom(ed, o); + }); + } + + if (s.handle_node_change_callback) { + t.onNodeChange.add(function(ed, cm, n) { + t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed()); + }); + } + + if (s.save_callback) { + t.onSaveContent.add(function(ed, o) { + var h = t.execCallback('save_callback', t.id, o.content, t.getBody()); + + if (h) + o.content = h; + }); + } + + if (s.onchange_callback) { + t.onChange.add(function(ed, l) { + t.execCallback('onchange_callback', t, l); + }); + } + + if (s.convert_newlines_to_brs) { + t.onBeforeSetContent.add(function(ed, o) { + if (o.initial) + o.content = o.content.replace(/\r?\n/g, '
    '); + }); + } + + if (s.fix_nesting && isIE) { + t.onBeforeSetContent.add(function(ed, o) { + o.content = t._fixNesting(o.content); + }); + } + + if (s.preformatted) { + t.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/^\s*/, ''); + o.content = o.content.replace(/<\/pre>\s*$/, ''); + + if (o.set) + o.content = '
    ' + o.content + '
    '; + }); + } + + if (s.verify_css_classes) { + t.serializer.attribValueFilter = function(n, v) { + var s, cl; + + if (n == 'class') { + // Build regexp for classes + if (!t.classesRE) { + cl = t.dom.getClasses(); + + if (cl.length > 0) { + s = ''; + + each (cl, function(o) { + s += (s ? '|' : '') + o['class']; + }); + + t.classesRE = new RegExp('(' + s + ')', 'gi'); + } + } + + return !t.classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v) || t.classesRE.test(v) ? v : ''; + } + + return v; + }; + } + + if (s.cleanup_callback) { + t.onBeforeSetContent.add(function(ed, o) { + o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o); + }); + + t.onPreProcess.add(function(ed, o) { + if (o.set) + t.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o); + + if (o.get) + t.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o); + }); + + t.onPostProcess.add(function(ed, o) { + if (o.set) + o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o); + + if (o.get) + o.content = t.execCallback('cleanup_callback', 'get_from_editor', o.content, o); + }); + } + + if (s.save_callback) { + t.onGetContent.add(function(ed, o) { + if (o.save) + o.content = t.execCallback('save_callback', t.id, o.content, t.getBody()); + }); + } + + if (s.handle_event_callback) { + t.onEvent.add(function(ed, e, o) { + if (t.execCallback('handle_event_callback', e, ed, o) === false) + Event.cancel(e); + }); + } + + // Add visual aids when new contents is added + t.onSetContent.add(function() { + t.addVisual(t.getBody()); + }); + + // Remove empty contents + if (s.padd_empty_editor) { + t.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/^(]*>( | |\s|\u00a0|)<\/p>[\r\n]*|
    [\r\n]*)$/, ''); + }); + } + + if (isGecko) { + // Fix gecko link bug, when a link is placed at the end of block elements there is + // no way to move the caret behind the link. This fix adds a bogus br element after the link + function fixLinks(ed, o) { + each(ed.dom.select('a'), function(n) { + var pn = n.parentNode; + + if (ed.dom.isBlock(pn) && pn.lastChild === n) + ed.dom.add(pn, 'br', {'_mce_bogus' : 1}); + }); + }; + + t.onExecCommand.add(function(ed, cmd) { + if (cmd === 'CreateLink') + fixLinks(ed); + }); + + t.onSetContent.add(t.selection.onSetContent.add(fixLinks)); + + if (!s.readonly) { + try { + // Design mode must be set here once again to fix a bug where + // Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again + d.designMode = 'Off'; + d.designMode = 'On'; + } catch (ex) { + // Will fail on Gecko if the editor is placed in an hidden container element + // The design mode will be set ones the editor is focused + } + } + } + + // A small timeout was needed since firefox will remove. Bug: #1838304 + setTimeout(function () { + if (t.removed) + return; + + t.load({initial : true, format : (s.cleanup_on_startup ? 'html' : 'raw')}); + t.startContent = t.getContent({format : 'raw'}); + t.initialized = true; + + t.onInit.dispatch(t); + t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc()); + t.execCallback('init_instance_callback', t); + t.focus(true); + t.nodeChanged({initial : 1}); + + // Load specified content CSS last + if (s.content_css) { + tinymce.each(explode(s.content_css), function(u) { + t.dom.loadCSS(t.documentBaseURI.toAbsolute(u)); + }); + } + + // Handle auto focus + if (s.auto_focus) { + setTimeout(function () { + var ed = tinymce.get(s.auto_focus); + + ed.selection.select(ed.getBody(), 1); + ed.selection.collapse(1); + ed.getWin().focus(); + }, 100); + } + }, 1); + + e = null; + }, + + + focus : function(sf) { + var oed, t = this, ce = t.settings.content_editable, ieRng, controlElm, doc = t.getDoc(); + + if (!sf) { + // Get selected control element + ieRng = t.selection.getRng(); + if (ieRng.item) { + controlElm = ieRng.item(0); + } + + // Is not content editable + if (!ce) { + if (t.getWin().frameElement) t.getWin().frameElement.focus(); + t.getWin().focus(); + } + + // Restore selected control element + // This is needed when for example an image is selected within a + // layer a call to focus will then remove the control selection + if (controlElm && controlElm.ownerDocument == doc) { + ieRng = doc.body.createControlRange(); + ieRng.addElement(controlElm); + ieRng.select(); + } + + } + + if (tinymce.activeEditor != t) { + if ((oed = tinymce.activeEditor) != null) + oed.onDeactivate.dispatch(oed, t); + + t.onActivate.dispatch(t, oed); + } + + tinymce._setActive(t); + }, + + execCallback : function(n) { + var t = this, f = t.settings[n], s; + + if (!f) + return; + + // Look through lookup + if (t.callbackLookup && (s = t.callbackLookup[n])) { + f = s.func; + s = s.scope; + } + + if (is(f, 'string')) { + s = f.replace(/\.\w+$/, ''); + s = s ? tinymce.resolve(s) : 0; + f = tinymce.resolve(f); + t.callbackLookup = t.callbackLookup || {}; + t.callbackLookup[n] = {func : f, scope : s}; + } + + return f.apply(s || t, Array.prototype.slice.call(arguments, 1)); + }, + + translate : function(s) { + var c = this.settings.language || 'en', i18n = tinymce.i18n; + + if (!s) + return ''; + + return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) { + return i18n[c + '.' + b] || '{#' + b + '}'; + }); + }, + + getLang : function(n, dv) { + return tinymce.i18n[(this.settings.language || 'en') + '.' + n] || (is(dv) ? dv : '{#' + n + '}'); + }, + + getParam : function(n, dv, ty) { + var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o; + + if (ty === 'hash') { + o = {}; + + if (is(v, 'string')) { + each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) { + v = v.split('='); + + if (v.length > 1) + o[tr(v[0])] = tr(v[1]); + else + o[tr(v[0])] = tr(v); + }); + } else + o = v; + + return o; + } + + return v; + }, + + nodeChanged : function(o) { + var t = this, s = t.selection, n = (isIE ? s.getNode() : s.getStart()) || t.getBody(); + + // Fix for bug #1896577 it seems that this can not be fired while the editor is loading + if (t.initialized) { + o = o || {}; + n = isIE && n.ownerDocument != t.getDoc() ? t.getBody() : n; // Fix for IE initial state + + // Get parents and add them to object + o.parents = []; + t.dom.getParent(n, function(node) { + if (node.nodeName == 'BODY') + return true; + + o.parents.push(node); + }); + + t.onNodeChange.dispatch( + t, + o ? o.controlManager || t.controlManager : t.controlManager, + n, + s.isCollapsed(), + o + ); + } + }, + + addButton : function(n, s) { + var t = this; + + t.buttons = t.buttons || {}; + t.buttons[n] = s; + }, + + addCommand : function(n, f, s) { + this.execCommands[n] = {func : f, scope : s || this}; + }, + + addQueryStateHandler : function(n, f, s) { + this.queryStateCommands[n] = {func : f, scope : s || this}; + }, + + addQueryValueHandler : function(n, f, s) { + this.queryValueCommands[n] = {func : f, scope : s || this}; + }, + + addShortcut : function(pa, desc, cmd_func, sc) { + var t = this, c; + + if (!t.settings.custom_shortcuts) + return false; + + t.shortcuts = t.shortcuts || {}; + + if (is(cmd_func, 'string')) { + c = cmd_func; + + cmd_func = function() { + t.execCommand(c, false, null); + }; + } + + if (is(cmd_func, 'object')) { + c = cmd_func; + + cmd_func = function() { + t.execCommand(c[0], c[1], c[2]); + }; + } + + each(explode(pa), function(pa) { + var o = { + func : cmd_func, + scope : sc || this, + desc : desc, + alt : false, + ctrl : false, + shift : false + }; + + each(explode(pa, '+'), function(v) { + switch (v) { + case 'alt': + case 'ctrl': + case 'shift': + o[v] = true; + break; + + default: + o.charCode = v.charCodeAt(0); + o.keyCode = v.toUpperCase().charCodeAt(0); + } + }); + + t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o; + }); + + return true; + }, + + execCommand : function(cmd, ui, val, a) { + var t = this, s = 0, o, st; + + if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus)) + t.focus(); + + o = {}; + t.onBeforeExecCommand.dispatch(t, cmd, ui, val, o); + if (o.terminate) + return false; + + // Command callback + if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Registred commands + if (o = t.execCommands[cmd]) { + st = o.func.call(o.scope, ui, val); + + // Fall through on true + if (st !== true) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return st; + } + } + + // Plugin commands + each(t.plugins, function(p) { + if (p.execCommand && p.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + s = 1; + return false; + } + }); + + if (s) + return true; + + // Theme commands + if (t.theme && t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Execute global commands + if (tinymce.GlobalCommands.execCommand(t, cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Editor commands + if (t.editorCommands.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Browser commands + t.getDoc().execCommand(cmd, ui, val); + t.onExecCommand.dispatch(t, cmd, ui, val, a); + }, + + queryCommandState : function(cmd) { + var t = this, o, s; + + // Is hidden then return undefined + if (t._isHidden()) + return; + + // Registred commands + if (o = t.queryStateCommands[cmd]) { + s = o.func.call(o.scope); + + // Fall though on true + if (s !== true) + return s; + } + + // Registred commands + o = t.editorCommands.queryCommandState(cmd); + if (o !== -1) + return o; + + // Browser commands + try { + return this.getDoc().queryCommandState(cmd); + } catch (ex) { + // Fails sometimes see bug: 1896577 + } + }, + + queryCommandValue : function(c) { + var t = this, o, s; + + // Is hidden then return undefined + if (t._isHidden()) + return; + + // Registred commands + if (o = t.queryValueCommands[c]) { + s = o.func.call(o.scope); + + // Fall though on true + if (s !== true) + return s; + } + + // Registred commands + o = t.editorCommands.queryCommandValue(c); + if (is(o)) + return o; + + // Browser commands + try { + return this.getDoc().queryCommandValue(c); + } catch (ex) { + // Fails sometimes see bug: 1896577 + } + }, + + show : function() { + var t = this; + + DOM.show(t.getContainer()); + DOM.hide(t.id); + t.load(); + }, + + hide : function() { + var t = this, d = t.getDoc(); + + // Fixed bug where IE has a blinking cursor left from the editor + if (isIE && d) + d.execCommand('SelectAll'); + + // We must save before we hide so Safari doesn't crash + t.save(); + DOM.hide(t.getContainer()); + DOM.setStyle(t.id, 'display', t.orgDisplay); + }, + + isHidden : function() { + return !DOM.isHidden(this.id); + }, + + setProgressState : function(b, ti, o) { + this.onSetProgressState.dispatch(this, b, ti, o); + + return b; + }, + + load : function(o) { + var t = this, e = t.getElement(), h; + + if (e) { + o = o || {}; + o.load = true; + + // Double encode existing entities in the value + h = t.setContent(is(e.value) ? e.value : e.innerHTML, o); + o.element = e; + + if (!o.no_events) + t.onLoadContent.dispatch(t, o); + + o.element = e = null; + + return h; + } + }, + + save : function(o) { + var t = this, e = t.getElement(), h, f; + + if (!e || !t.initialized) + return; + + o = o || {}; + o.save = true; + + // Add undo level will trigger onchange event + if (!o.no_events) { + t.undoManager.typing = 0; + t.undoManager.add(); + } + + o.element = e; + h = o.content = t.getContent(o); + + if (!o.no_events) + t.onSaveContent.dispatch(t, o); + + h = o.content; + + if (!/TEXTAREA|INPUT/i.test(e.nodeName)) { + e.innerHTML = h; + + // Update hidden form element + if (f = DOM.getParent(t.id, 'form')) { + each(f.elements, function(e) { + if (e.name == t.id) { + e.value = h; + return false; + } + }); + } + } else + e.value = h; + + o.element = e = null; + + return h; + }, + + setContent : function(h, o) { + var t = this; + + o = o || {}; + o.format = o.format || 'html'; + o.set = true; + o.content = h; + + if (!o.no_events) + t.onBeforeSetContent.dispatch(t, o); + + // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content + // It will also be impossible to place the caret in the editor unless there is a BR element present + if (!tinymce.isIE && (h.length === 0 || /^\s+$/.test(h))) { + o.content = t.dom.setHTML(t.getBody(), '
    '); + o.format = 'raw'; + } + + o.content = t.dom.setHTML(t.getBody(), tinymce.trim(o.content)); + + if (o.format != 'raw' && t.settings.cleanup) { + o.getInner = true; + o.content = t.dom.setHTML(t.getBody(), t.serializer.serialize(t.getBody(), o)); + } + + if (!o.no_events) + t.onSetContent.dispatch(t, o); + + return o.content; + }, + + getContent : function(o) { + var t = this, h; + + o = o || {}; + o.format = o.format || 'html'; + o.get = true; + + if (!o.no_events) + t.onBeforeGetContent.dispatch(t, o); + + if (o.format != 'raw' && t.settings.cleanup) { + o.getInner = true; + h = t.serializer.serialize(t.getBody(), o); + } else + h = t.getBody().innerHTML; + + h = h.replace(/^\s*|\s*$/g, ''); + o.content = h; + + if (!o.no_events) + t.onGetContent.dispatch(t, o); + + return o.content; + }, + + isDirty : function() { + var t = this; + + return tinymce.trim(t.startContent) != tinymce.trim(t.getContent({format : 'raw', no_events : 1})) && !t.isNotDirty; + }, + + getContainer : function() { + var t = this; + + if (!t.container) + t.container = DOM.get(t.editorContainer || t.id + '_parent'); + + return t.container; + }, + + getContentAreaContainer : function() { + return this.contentAreaContainer; + }, + + getElement : function() { + return DOM.get(this.settings.content_element || this.id); + }, + + getWin : function() { + var t = this, e; + + if (!t.contentWindow) { + e = DOM.get(t.id + "_ifr"); + + if (e) + t.contentWindow = e.contentWindow; + } + + return t.contentWindow; + }, + + getDoc : function() { + var t = this, w; + + if (!t.contentDocument) { + w = t.getWin(); + + if (w) + t.contentDocument = w.document; + } + + return t.contentDocument; + }, + + getBody : function() { + return this.bodyElement || this.getDoc().body; + }, + + convertURL : function(u, n, e) { + var t = this, s = t.settings; + + // Use callback instead + if (s.urlconverter_callback) + return t.execCallback('urlconverter_callback', u, e, true, n); + + // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs + if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0) + return u; + + // Convert to relative + if (s.relative_urls) + return t.documentBaseURI.toRelative(u); + + // Convert to absolute + u = t.documentBaseURI.toAbsolute(u, s.remove_script_host); + + return u; + }, + + addVisual : function(e) { + var t = this, s = t.settings; + + e = e || t.getBody(); + + if (!is(t.hasVisual)) + t.hasVisual = s.visual; + + each(t.dom.select('table,a', e), function(e) { + var v; + + switch (e.nodeName) { + case 'TABLE': + v = t.dom.getAttrib(e, 'border'); + + if (!v || v == '0') { + if (t.hasVisual) + t.dom.addClass(e, s.visual_table_class); + else + t.dom.removeClass(e, s.visual_table_class); + } + + return; + + case 'A': + v = t.dom.getAttrib(e, 'name'); + + if (v) { + if (t.hasVisual) + t.dom.addClass(e, 'mceItemAnchor'); + else + t.dom.removeClass(e, 'mceItemAnchor'); + } + + return; + } + }); + + t.onVisualAid.dispatch(t, e, t.hasVisual); + }, + + remove : function() { + var t = this, e = t.getContainer(); + + t.removed = 1; // Cancels post remove event execution + t.hide(); + + t.execCallback('remove_instance_callback', t); + t.onRemove.dispatch(t); + + // Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command + t.onExecCommand.listeners = []; + + tinymce.remove(t); + DOM.remove(e); + }, + + destroy : function(s) { + var t = this; + + // One time is enough + if (t.destroyed) + return; + + if (!s) { + tinymce.removeUnload(t.destroy); + tinyMCE.onBeforeUnload.remove(t._beforeUnload); + + // Manual destroy + if (t.theme && t.theme.destroy) + t.theme.destroy(); + + // Destroy controls, selection and dom + t.controlManager.destroy(); + t.selection.destroy(); + t.dom.destroy(); + + // Remove all events + + // Don't clear the window or document if content editable + // is enabled since other instances might still be present + if (!t.settings.content_editable) { + Event.clear(t.getWin()); + Event.clear(t.getDoc()); + } + + Event.clear(t.getBody()); + Event.clear(t.formElement); + } + + if (t.formElement) { + t.formElement.submit = t.formElement._mceOldSubmit; + t.formElement._mceOldSubmit = null; + } + + t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null; + + if (t.selection) + t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null; + + t.destroyed = 1; + }, + + // Internal functions + + _addEvents : function() { + // 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset + var t = this, i, s = t.settings, dom = t.dom, lo = { + mouseup : 'onMouseUp', + mousedown : 'onMouseDown', + click : 'onClick', + keyup : 'onKeyUp', + keydown : 'onKeyDown', + keypress : 'onKeyPress', + submit : 'onSubmit', + reset : 'onReset', + contextmenu : 'onContextMenu', + dblclick : 'onDblClick', + paste : 'onPaste' // Doesn't work in all browsers yet + }; + + function eventHandler(e, o) { + var ty = e.type; + + // Don't fire events when it's removed + if (t.removed) + return; + + // Generic event handler + if (t.onEvent.dispatch(t, e, o) !== false) { + // Specific event handler + t[lo[e.fakeType || e.type]].dispatch(t, e, o); + } + }; + + // Add DOM events + each(lo, function(v, k) { + switch (k) { + case 'contextmenu': + if (tinymce.isOpera) { + // Fake contextmenu on Opera + dom.bind(t.getBody(), 'mousedown', function(e) { + if (e.ctrlKey) { + e.fakeType = 'contextmenu'; + eventHandler(e); + } + }); + } else + dom.bind(isGecko ? t.getDoc() : t.getBody(), k, eventHandler); + break; + + case 'paste': + dom.bind(t.getBody(), k, function(e) { + eventHandler(e); + }); + break; + + case 'submit': + case 'reset': + dom.bind(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler); + break; + + default: + dom.bind(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler); + } + }); + + dom.bind(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) { + t.focus(true); + }); + + + // Fixes bug where a specified document_base_uri could result in broken images + // This will also fix drag drop of images in Gecko + if (tinymce.isGecko) { + dom.bind(t.getDoc(), 'DOMNodeInserted', function(e) { + var v; + + e = e.target; + + if (e.nodeType === 1 && e.nodeName === 'IMG' && (v = e.getAttribute('_mce_src'))) + e.src = t.documentBaseURI.toAbsolute(v); + }); + } + + // Set various midas options in Gecko + if (isGecko) { + function setOpts() { + var t = this, d = t.getDoc(), s = t.settings; + + if (isGecko && !s.readonly) { + if (t._isHidden()) { + try { + if (!s.content_editable) + d.designMode = 'On'; + } catch (ex) { + // Fails if it's hidden + } + } + + try { + // Try new Gecko method + d.execCommand("styleWithCSS", 0, false); + } catch (ex) { + // Use old method + if (!t._isHidden()) + try {d.execCommand("useCSS", 0, true);} catch (ex) {} + } + + if (!s.table_inline_editing) + try {d.execCommand('enableInlineTableEditing', false, false);} catch (ex) {} + + if (!s.object_resizing) + try {d.execCommand('enableObjectResizing', false, false);} catch (ex) {} + } + }; + + t.onBeforeExecCommand.add(setOpts); + t.onMouseDown.add(setOpts); + } + + // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250 + // WebKit can't even do simple things like selecting an image + // This also fixes so it's possible to select mceItemAnchors + if (tinymce.isWebKit) { + t.onClick.add(function(ed, e) { + e = e.target; + + // Needs tobe the setBaseAndExtend or it will fail to select floated images + if (e.nodeName == 'IMG' || (e.nodeName == 'A' && dom.hasClass(e, 'mceItemAnchor'))) { + t.selection.getSel().setBaseAndExtent(e, 0, e, 1); + t.nodeChanged(); + } + }); + } + + // Add node change handlers + t.onMouseUp.add(t.nodeChanged); + //t.onClick.add(t.nodeChanged); + t.onKeyUp.add(function(ed, e) { + var c = e.keyCode; + + if ((c >= 33 && c <= 36) || (c >= 37 && c <= 40) || c == 13 || c == 45 || c == 46 || c == 8 || (tinymce.isMac && (c == 91 || c == 93)) || e.ctrlKey) + t.nodeChanged(); + }); + + // Add reset handler + t.onReset.add(function() { + t.setContent(t.startContent, {format : 'raw'}); + }); + + // Add shortcuts + if (s.custom_shortcuts) { + if (s.custom_undo_redo_keyboard_shortcuts) { + t.addShortcut('ctrl+z', t.getLang('undo_desc'), 'Undo'); + t.addShortcut('ctrl+y', t.getLang('redo_desc'), 'Redo'); + } + + // Add default shortcuts for gecko + t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold'); + t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic'); + t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline'); + + // BlockFormat shortcuts keys + for (i=1; i<=6; i++) + t.addShortcut('ctrl+' + i, '', ['FormatBlock', false, 'h' + i]); + + t.addShortcut('ctrl+7', '', ['FormatBlock', false, '

    ']); + t.addShortcut('ctrl+8', '', ['FormatBlock', false, '

    ']); + t.addShortcut('ctrl+9', '', ['FormatBlock', false, '
    ']); + + function find(e) { + var v = null; + + if (!e.altKey && !e.ctrlKey && !e.metaKey) + return v; + + each(t.shortcuts, function(o) { + if (tinymce.isMac && o.ctrl != e.metaKey) + return; + else if (!tinymce.isMac && o.ctrl != e.ctrlKey) + return; + + if (o.alt != e.altKey) + return; + + if (o.shift != e.shiftKey) + return; + + if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) { + v = o; + return false; + } + }); + + return v; + }; + + t.onKeyUp.add(function(ed, e) { + var o = find(e); + + if (o) + return Event.cancel(e); + }); + + t.onKeyPress.add(function(ed, e) { + var o = find(e); + + if (o) + return Event.cancel(e); + }); + + t.onKeyDown.add(function(ed, e) { + var o = find(e); + + if (o) { + o.func.call(o.scope); + return Event.cancel(e); + } + }); + } + + if (tinymce.isIE) { + // Fix so resize will only update the width and height attributes not the styles of an image + // It will also block mceItemNoResize items + dom.bind(t.getDoc(), 'controlselect', function(e) { + var re = t.resizeInfo, cb; + + e = e.target; + + // Don't do this action for non image elements + if (e.nodeName !== 'IMG') + return; + + if (re) + dom.unbind(re.node, re.ev, re.cb); + + if (!dom.hasClass(e, 'mceItemNoResize')) { + ev = 'resizeend'; + cb = dom.bind(e, ev, function(e) { + var v; + + e = e.target; + + if (v = dom.getStyle(e, 'width')) { + dom.setAttrib(e, 'width', v.replace(/[^0-9%]+/g, '')); + dom.setStyle(e, 'width', ''); + } + + if (v = dom.getStyle(e, 'height')) { + dom.setAttrib(e, 'height', v.replace(/[^0-9%]+/g, '')); + dom.setStyle(e, 'height', ''); + } + }); + } else { + ev = 'resizestart'; + cb = dom.bind(e, 'resizestart', Event.cancel, Event); + } + + re = t.resizeInfo = { + node : e, + ev : ev, + cb : cb + }; + }); + + t.onKeyDown.add(function(ed, e) { + var sel; + + switch (e.keyCode) { + case 8: + sel = t.getDoc().selection; + + // Fix IE control + backspace browser bug + if (sel.createRange && sel.createRange().item) { + ed.dom.remove(sel.createRange().item(0)); + return Event.cancel(e); + } + } + }); + } + + if (tinymce.isOpera) { + t.onClick.add(function(ed, e) { + Event.prevent(e); + }); + } + + // Add custom undo/redo handlers + if (s.custom_undo_redo) { + function addUndo() { + t.undoManager.typing = 0; + t.undoManager.add(); + }; + + dom.bind(t.getDoc(), 'focusout', function(e) { + if (!t.removed && t.undoManager.typing) + addUndo(); + }); + + t.dom.bind(t.dom.getRoot(), 'dragend', function(e) { + addUndo(); + }); + + t.onKeyUp.add(function(ed, e) { + var rng, parent, bookmark; + if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey) + addUndo(); + + // Fix for bug #3168, to remove odd ".." nodes from the DOM we need to get/set the HTML of the parent node. + if (isIE && e.keyCode == 8) { + rng = t.selection.getRng(); + if (rng.parentElement) { + parent = rng.parentElement(); + bookmark = t.selection.getBookmark(); + parent.innerHTML = parent.innerHTML; + t.selection.moveToBookmark(bookmark); + } + } + + }); + + t.onKeyDown.add(function(ed, e) { + var rng, parent, bookmark; + + // IE has a really odd bug where the DOM might include an node that doesn't have + // a proper structure. If you try to access nodeValue it would throw an illegal value exception. + // This seems to only happen when you delete contents and it seems to be avoidable if you refresh the element + // after you delete contents from it. See: #3008923 + if (isIE && e.keyCode == 46) { + rng = t.selection.getRng(); + + if (rng.parentElement) { + addUndo(); + parent = rng.parentElement(); + + // Select next word when ctrl key is used in combo with delete + if (e.ctrlKey) { + rng.moveEnd('word', 1); + rng.select(); + } + + // Delete contents + t.selection.getSel().clear(); + + // Check if we are within the same parent + if (rng.parentElement() == parent) { + bookmark = t.selection.getBookmark(); + + try { + // Update the HTML and hopefully it will remove the artifacts + parent.innerHTML = parent.innerHTML; + } catch (ex) { + // And since it's IE it can sometimes produce an unknown runtime error + } + + // Restore the caret position + t.selection.moveToBookmark(bookmark); + } + + addUndo(); + + // Block the default delete behavior since it might be broken + e.preventDefault(); + return; + } + } + + // Special handling for enter to ensure typing is still set to true + if (e.keyCode == 13 && t.undoManager.typing) { + addUndo(); + t.undoManager.typing = 1; + } + + // Is caracter positon keys + if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 45) { + if (t.undoManager.typing) + addUndo(); + + return; + } + + if (!t.undoManager.typing) { + t.undoManager.add(); + t.undoManager.typing = 1; + } + }); + + t.onMouseDown.add(function() { + if (t.undoManager.typing) + addUndo(); + }); + } + + // Bug fix for FireFox keeping styles from end of selection instead of start. + if (tinymce.isGecko) { + function getAttributeApplyFunction() { + t.undoManager.typing = 0; + t.undoManager.add(); + var template = t.dom.getAttribs(t.selection.getStart().cloneNode(false)); + return function() { + var target = t.selection.getStart(); + t.dom.removeAllAttribs(target); + each(template, function(attr) { + target.setAttributeNode(attr.cloneNode(true)); + }); + //t.dom.setAttribs(target, template); + t.undoManager.typing = 0; + t.undoManager.add(); + }; + } + + function isSelectionAcrossElements() { + var s = t.selection; + return !s.isCollapsed() && s.getStart() != s.getEnd(); + } + + t.onKeyPress.add(function(ed, e) { + if ((e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) { + var applyAttributes = getAttributeApplyFunction(); + t.getDoc().execCommand('delete', false, null); + applyAttributes(); + return Event.cancel(e); + } + }); + + t.dom.bind(t.getDoc(), 'cut', function(e) { + if (isSelectionAcrossElements()) { + var applyAttributes = getAttributeApplyFunction(); + t.onKeyUp.addToTop(Event.cancel, Event); + setTimeout(function() { + applyAttributes(); + t.onKeyUp.remove(Event.cancel, Event); + }, 0); + } + }); + } + }, + + _isHidden : function() { + var s; + + if (!isGecko) + return 0; + + // Weird, wheres that cursor selection? + s = this.selection.getSel(); + return (!s || !s.rangeCount || s.rangeCount == 0); + }, + + // Fix for bug #1867292 + _fixNesting : function(s) { + var d = [], i; + + s = s.replace(/<(\/)?([^\s>]+)[^>]*?>/g, function(a, b, c) { + var e; + + // Handle end element + if (b === '/') { + if (!d.length) + return ''; + + if (c !== d[d.length - 1].tag) { + for (i=d.length - 1; i>=0; i--) { + if (d[i].tag === c) { + d[i].close = 1; + break; + } + } + + return ''; + } else { + d.pop(); + + if (d.length && d[d.length - 1].close) { + a = a + ''; + d.pop(); + } + } + } else { + // Ignore these + if (/^(br|hr|input|meta|img|link|param)$/i.test(c)) + return a; + + // Ignore closed ones + if (/\/>$/.test(a)) + return a; + + d.push({tag : c}); // Push start element + } + + return a; + }); + + // End all open tags + for (i=d.length - 1; i>=0; i--) + s += ''; + + return s; + } + }); +})(tinymce); + +(function(tinymce) { + // Added for compression purposes + var each = tinymce.each, undefined, TRUE = true, FALSE = false; + + tinymce.EditorCommands = function(editor) { + var dom = editor.dom, + selection = editor.selection, + commands = {state: {}, exec : {}, value : {}}, + settings = editor.settings, + bookmark; + + function execCommand(command, ui, value) { + var func; + + command = command.toLowerCase(); + if (func = commands.exec[command]) { + func(command, ui, value); + return TRUE; + } + + return FALSE; + }; + + function queryCommandState(command) { + var func; + + command = command.toLowerCase(); + if (func = commands.state[command]) + return func(command); + + return -1; + }; + + function queryCommandValue(command) { + var func; + + command = command.toLowerCase(); + if (func = commands.value[command]) + return func(command); + + return FALSE; + }; + + function addCommands(command_list, type) { + type = type || 'exec'; + + each(command_list, function(callback, command) { + each(command.toLowerCase().split(','), function(command) { + commands[type][command] = callback; + }); + }); + }; + + // Expose public methods + tinymce.extend(this, { + execCommand : execCommand, + queryCommandState : queryCommandState, + queryCommandValue : queryCommandValue, + addCommands : addCommands + }); + + // Private methods + + function execNativeCommand(command, ui, value) { + if (ui === undefined) + ui = FALSE; + + if (value === undefined) + value = null; + + return editor.getDoc().execCommand(command, ui, value); + }; + + function isFormatMatch(name) { + return editor.formatter.match(name); + }; + + function toggleFormat(name, value) { + editor.formatter.toggle(name, value ? {value : value} : undefined); + }; + + function storeSelection(type) { + bookmark = selection.getBookmark(type); + }; + + function restoreSelection() { + selection.moveToBookmark(bookmark); + }; + + // Add execCommand overrides + addCommands({ + // Ignore these, added for compatibility + 'mceResetDesignMode,mceBeginUndoLevel' : function() {}, + + // Add undo manager logic + 'mceEndUndoLevel,mceAddUndoLevel' : function() { + editor.undoManager.add(); + }, + + 'Cut,Copy,Paste' : function(command) { + var doc = editor.getDoc(), failed; + + // Try executing the native command + try { + execNativeCommand(command); + } catch (ex) { + // Command failed + failed = TRUE; + } + + // Present alert message about clipboard access not being available + if (failed || !doc.queryCommandSupported(command)) { + if (tinymce.isGecko) { + editor.windowManager.confirm(editor.getLang('clipboard_msg'), function(state) { + if (state) + open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', '_blank'); + }); + } else + editor.windowManager.alert(editor.getLang('clipboard_no_support')); + } + }, + + // Override unlink command + unlink : function(command) { + if (selection.isCollapsed()) + selection.select(selection.getNode()); + + execNativeCommand(command); + selection.collapse(FALSE); + }, + + // Override justify commands to use the text formatter engine + 'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) { + var align = command.substring(7); + + // Remove all other alignments first + each('left,center,right,full'.split(','), function(name) { + if (align != name) + editor.formatter.remove('align' + name); + }); + + toggleFormat('align' + align); + execCommand('mceRepaint'); + }, + + // Override list commands to fix WebKit bug + 'InsertUnorderedList,InsertOrderedList' : function(command) { + var listElm, listParent; + + execNativeCommand(command); + + // WebKit produces lists within block elements so we need to split them + // we will replace the native list creation logic to custom logic later on + // TODO: Remove this when the list creation logic is removed + listElm = dom.getParent(selection.getNode(), 'ol,ul'); + if (listElm) { + listParent = listElm.parentNode; + + // If list is within a text block then split that block + if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) { + storeSelection(); + dom.split(listParent, listElm); + restoreSelection(); + } + } + }, + + // Override commands to use the text formatter engine + 'Bold,Italic,Underline,Strikethrough' : function(command) { + toggleFormat(command); + }, + + // Override commands to use the text formatter engine + 'ForeColor,HiliteColor,FontName' : function(command, ui, value) { + toggleFormat(command, value); + }, + + FontSize : function(command, ui, value) { + var fontClasses, fontSizes; + + // Convert font size 1-7 to styles + if (value >= 1 && value <= 7) { + fontSizes = tinymce.explode(settings.font_size_style_values); + fontClasses = tinymce.explode(settings.font_size_classes); + + if (fontClasses) + value = fontClasses[value - 1] || value; + else + value = fontSizes[value - 1] || value; + } + + toggleFormat(command, value); + }, + + RemoveFormat : function(command) { + editor.formatter.remove(command); + }, + + mceBlockQuote : function(command) { + toggleFormat('blockquote'); + }, + + FormatBlock : function(command, ui, value) { + return toggleFormat(value || 'p'); + }, + + mceCleanup : function() { + var bookmark = selection.getBookmark(); + + editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE}); + + selection.moveToBookmark(bookmark); + }, + + mceRemoveNode : function(command, ui, value) { + var node = value || selection.getNode(); + + // Make sure that the body node isn't removed + if (node != editor.getBody()) { + storeSelection(); + editor.dom.remove(node, TRUE); + restoreSelection(); + } + }, + + mceSelectNodeDepth : function(command, ui, value) { + var counter = 0; + + dom.getParent(selection.getNode(), function(node) { + if (node.nodeType == 1 && counter++ == value) { + selection.select(node); + return FALSE; + } + }, editor.getBody()); + }, + + mceSelectNode : function(command, ui, value) { + selection.select(value); + }, + + mceInsertContent : function(command, ui, value) { + selection.setContent(value); + }, + + mceInsertRawHTML : function(command, ui, value) { + selection.setContent('tiny_mce_marker'); + editor.setContent(editor.getContent().replace(/tiny_mce_marker/g, function() { return value })); + }, + + mceSetContent : function(command, ui, value) { + editor.setContent(value); + }, + + 'Indent,Outdent' : function(command) { + var intentValue, indentUnit, value; + + // Setup indent level + intentValue = settings.indentation; + indentUnit = /[a-z%]+$/i.exec(intentValue); + intentValue = parseInt(intentValue); + + if (!queryCommandState('InsertUnorderedList') && !queryCommandState('InsertOrderedList')) { + each(selection.getSelectedBlocks(), function(element) { + if (command == 'outdent') { + value = Math.max(0, parseInt(element.style.paddingLeft || 0) - intentValue); + dom.setStyle(element, 'paddingLeft', value ? value + indentUnit : ''); + } else + dom.setStyle(element, 'paddingLeft', (parseInt(element.style.paddingLeft || 0) + intentValue) + indentUnit); + }); + } else + execNativeCommand(command); + }, + + mceRepaint : function() { + var bookmark; + + if (tinymce.isGecko) { + try { + storeSelection(TRUE); + + if (selection.getSel()) + selection.getSel().selectAllChildren(editor.getBody()); + + selection.collapse(TRUE); + restoreSelection(); + } catch (ex) { + // Ignore + } + } + }, + + mceToggleFormat : function(command, ui, value) { + editor.formatter.toggle(value); + }, + + InsertHorizontalRule : function() { + var hrElm, hrParent, rng; + selection.setContent('
    '); + + hrElm = dom.get('_mce_inserted_hr'); + hrParent = hrElm.parentNode; + // If HR is within a text block then split that block + if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(hrParent.nodeName)) { + dom.split(hrParent, hrElm); + } + dom.removeAllAttribs(hrElm); + if (hrElm.nextSibling) { + rng = dom.createRng(); + rng.setStart(hrElm.nextSibling, 0); + rng.setEnd(hrElm.nextSibling, 0); + selection.setRng(rng); + } else { + selection.moveAfterNode(hrElm); + } + }, + + mceToggleVisualAid : function() { + editor.hasVisual = !editor.hasVisual; + editor.addVisual(); + }, + + mceReplaceContent : function(command, ui, value) { + selection.setContent(value.replace(/\{\$selection\}/g, selection.getContent({format : 'text'}))); + }, + + mceInsertLink : function(command, ui, value) { + var link = dom.getParent(selection.getNode(), 'a'); + + if (tinymce.is(value, 'string')) + value = {href : value}; + + // Spaces are never valid in URLs and it's a very common mistake for people to make so we fix it here. + value.href = value.href.replace(' ', '%20'); + + if (!link) { + execNativeCommand('CreateLink', FALSE, 'javascript:mctmp(0);'); + each(dom.select('a[href=javascript:mctmp(0);]'), function(link) { + dom.setAttribs(link, value); + }); + } else { + if (value.href) + dom.setAttribs(link, value); + else + editor.dom.remove(link, TRUE); + } + }, + + selectAll : function() { + var root = dom.getRoot(), rng = dom.createRng(); + + rng.setStart(root, 0); + rng.setEnd(root, root.childNodes.length); + + editor.selection.setRng(rng); + } + }); + + // Add queryCommandState overrides + addCommands({ + // Override justify commands + 'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) { + return isFormatMatch('align' + command.substring(7)); + }, + + 'Bold,Italic,Underline,Strikethrough' : function(command) { + return isFormatMatch(command); + }, + + mceBlockQuote : function() { + return isFormatMatch('blockquote'); + }, + + Outdent : function() { + var node; + + if (settings.inline_styles) { + if ((node = dom.getParent(selection.getStart(), dom.isBlock)) && parseInt(node.style.paddingLeft) > 0) + return TRUE; + + if ((node = dom.getParent(selection.getEnd(), dom.isBlock)) && parseInt(node.style.paddingLeft) > 0) + return TRUE; + } + + return queryCommandState('InsertUnorderedList') || queryCommandState('InsertOrderedList') || (!settings.inline_styles && !!dom.getParent(selection.getNode(), 'BLOCKQUOTE')); + }, + + 'InsertUnorderedList,InsertOrderedList' : function(command) { + return dom.getParent(selection.getNode(), command == 'insertunorderedlist' ? 'UL' : 'OL'); + } + }, 'state'); + + // Add queryCommandValue overrides + addCommands({ + 'FontSize,FontName' : function(command) { + var value = 0, parent; + + if (parent = dom.getParent(selection.getNode(), 'span')) { + if (command == 'fontsize') + value = parent.style.fontSize; + else + value = parent.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase(); + } + + return value; + } + }, 'value'); + + // Add undo manager logic + if (settings.custom_undo_redo) { + addCommands({ + Undo : function() { + editor.undoManager.undo(); + }, + + Redo : function() { + editor.undoManager.redo(); + } + }); + } + }; +})(tinymce); +(function(tinymce) { + var Dispatcher = tinymce.util.Dispatcher; + + tinymce.UndoManager = function(editor) { + var self, index = 0, data = []; + + function getContent() { + return tinymce.trim(editor.getContent({format : 'raw', no_events : 1})); + }; + + return self = { + typing : 0, + + onAdd : new Dispatcher(self), + onUndo : new Dispatcher(self), + onRedo : new Dispatcher(self), + + add : function(level) { + var i, settings = editor.settings, lastLevel; + + level = level || {}; + level.content = getContent(); + + // Add undo level if needed + lastLevel = data[index]; + if (lastLevel && lastLevel.content == level.content) { + if (index > 0 || data.length == 1) + return null; + } + + // Time to compress + if (settings.custom_undo_redo_levels) { + if (data.length > settings.custom_undo_redo_levels) { + for (i = 0; i < data.length - 1; i++) + data[i] = data[i + 1]; + + data.length--; + index = data.length; + } + } + + // Get a non intrusive normalized bookmark + level.bookmark = editor.selection.getBookmark(2, true); + + // Crop array if needed + if (index < data.length - 1) { + // Treat first level as initial + if (index == 0) + data = []; + else + data.length = index + 1; + } + + data.push(level); + index = data.length - 1; + + self.onAdd.dispatch(self, level); + editor.isNotDirty = 0; + + return level; + }, + + undo : function() { + var level, i; + + if (self.typing) { + self.add(); + self.typing = 0; + } + + if (index > 0) { + level = data[--index]; + + editor.setContent(level.content, {format : 'raw'}); + editor.selection.moveToBookmark(level.bookmark); + + self.onUndo.dispatch(self, level); + } + + return level; + }, + + redo : function() { + var level; + + if (index < data.length - 1) { + level = data[++index]; + + editor.setContent(level.content, {format : 'raw'}); + editor.selection.moveToBookmark(level.bookmark); + + self.onRedo.dispatch(self, level); + } + + return level; + }, + + clear : function() { + data = []; + index = self.typing = 0; + }, + + hasUndo : function() { + return index > 0 || self.typing; + }, + + hasRedo : function() { + return index < data.length - 1; + } + }; + }; +})(tinymce); + +(function(tinymce) { + // Shorten names + var Event = tinymce.dom.Event, + isIE = tinymce.isIE, + isGecko = tinymce.isGecko, + isOpera = tinymce.isOpera, + each = tinymce.each, + extend = tinymce.extend, + TRUE = true, + FALSE = false; + + function cloneFormats(node) { + var clone, temp, inner; + + do { + if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) { + if (clone) { + temp = node.cloneNode(false); + temp.appendChild(clone); + clone = temp; + } else { + clone = inner = node.cloneNode(false); + } + + clone.removeAttribute('id'); + } + } while (node = node.parentNode); + + if (clone) + return {wrapper : clone, inner : inner}; + }; + + // Checks if the selection/caret is at the end of the specified block element + function isAtEnd(rng, par) { + var rng2 = par.ownerDocument.createRange(); + + rng2.setStart(rng.endContainer, rng.endOffset); + rng2.setEndAfter(par); + + // Get number of characters to the right of the cursor if it's zero then we are at the end and need to merge the next block element + return rng2.cloneContents().textContent.length == 0; + }; + + function isEmpty(n) { + n = n.innerHTML; + + n = n.replace(/<(img|hr|table|input|select|textarea)[ \>]/gi, '-'); // Keep these convert them to - chars + n = n.replace(/<[^>]+>/g, ''); // Remove all tags + + return n.replace(/[ \u00a0\t\r\n]+/g, '') == ''; + }; + + function splitList(selection, dom, li) { + var listBlock, block; + + if (isEmpty(li)) { + listBlock = dom.getParent(li, 'ul,ol'); + + if (!dom.getParent(listBlock.parentNode, 'ul,ol')) { + dom.split(listBlock, li); + block = dom.create('p', 0, '
    '); + dom.replace(block, li); + selection.select(block, 1); + } + + return FALSE; + } + + return TRUE; + }; + + tinymce.create('tinymce.ForceBlocks', { + ForceBlocks : function(ed) { + var t = this, s = ed.settings, elm; + + t.editor = ed; + t.dom = ed.dom; + elm = (s.forced_root_block || 'p').toLowerCase(); + s.element = elm.toUpperCase(); + + ed.onPreInit.add(t.setup, t); + + t.reOpera = new RegExp('(\\u00a0| | )<\/' + elm + '>', 'gi'); + t.rePadd = new RegExp(']+)><\\\/p>|]+)\\\/>|]+)>\\s+<\\\/p>|

    <\\\/p>||

    \\s+<\\\/p>'.replace(/p/g, elm), 'gi'); + t.reNbsp2BR1 = new RegExp(']+)>[\\s\\u00a0]+<\\\/p>|

    [\\s\\u00a0]+<\\\/p>'.replace(/p/g, elm), 'gi'); + t.reNbsp2BR2 = new RegExp('<%p()([^>]+)>( | )<\\\/%p>|<%p>( | )<\\\/%p>'.replace(/%p/g, elm), 'gi'); + t.reBR2Nbsp = new RegExp(']+)>\\s*
    \\s*<\\\/p>|

    \\s*
    \\s*<\\\/p>'.replace(/p/g, elm), 'gi'); + + function padd(ed, o) { + if (isOpera) + o.content = o.content.replace(t.reOpera, ''); + + o.content = tinymce._replace(t.rePadd, '<' + elm + '$1$2$3$4$5$6>\u00a0', o.content); + + if (!isIE && !isOpera && o.set) { + // Use   instead of BR in padded paragraphs + o.content = o.content.replace(t.reNbsp2BR1, '<' + elm + '$1$2>
    '); + o.content = o.content.replace(t.reNbsp2BR2, '<' + elm + '$1$2>
    '); + } else + o.content = tinymce._replace(t.reBR2Nbsp, '<' + elm + '$1$2>\u00a0', o.content); + }; + + ed.onBeforeSetContent.add(padd); + ed.onPostProcess.add(padd); + + if (s.forced_root_block) { + ed.onInit.add(t.forceRoots, t); + ed.onSetContent.add(t.forceRoots, t); + ed.onBeforeGetContent.add(t.forceRoots, t); + } + }, + + setup : function() { + var t = this, ed = t.editor, s = ed.settings, dom = ed.dom, selection = ed.selection; + + // Force root blocks when typing and when getting output + if (s.forced_root_block) { + ed.onBeforeExecCommand.add(t.forceRoots, t); + ed.onKeyUp.add(t.forceRoots, t); + ed.onPreProcess.add(t.forceRoots, t); + } + + if (s.force_br_newlines) { + // Force IE to produce BRs on enter + if (isIE) { + ed.onKeyPress.add(function(ed, e) { + var n; + + if (e.keyCode == 13 && selection.getNode().nodeName != 'LI') { + selection.setContent('
    ', {format : 'raw'}); + n = dom.get('__'); + n.removeAttribute('id'); + selection.select(n); + selection.collapse(); + return Event.cancel(e); + } + }); + } + } + + if (s.force_p_newlines) { + if (!isIE) { + ed.onKeyPress.add(function(ed, e) { + if (e.keyCode == 13 && !e.shiftKey && !t.insertPara(e)) + Event.cancel(e); + }); + } else { + // Ungly hack to for IE to preserve the formatting when you press + // enter at the end of a block element with formatted contents + // This logic overrides the browsers default logic with + // custom logic that enables us to control the output + tinymce.addUnload(function() { + t._previousFormats = 0; // Fix IE leak + }); + + ed.onKeyPress.add(function(ed, e) { + t._previousFormats = 0; + + // Clone the current formats, this will later be applied to the new block contents + if (e.keyCode == 13 && !e.shiftKey && ed.selection.isCollapsed() && s.keep_styles) + t._previousFormats = cloneFormats(ed.selection.getStart()); + }); + + ed.onKeyUp.add(function(ed, e) { + // Let IE break the element and the wrap the new caret location in the previous formats + if (e.keyCode == 13 && !e.shiftKey) { + var parent = ed.selection.getStart(), fmt = t._previousFormats; + + // Parent is an empty block + if (!parent.hasChildNodes() && fmt) { + parent = dom.getParent(parent, dom.isBlock); + + if (parent && parent.nodeName != 'LI') { + parent.innerHTML = ''; + + if (t._previousFormats) { + parent.appendChild(fmt.wrapper); + fmt.inner.innerHTML = '\uFEFF'; + } else + parent.innerHTML = '\uFEFF'; + + selection.select(parent, 1); + ed.getDoc().execCommand('Delete', false, null); + t._previousFormats = 0; + } + } + } + }); + } + + if (isGecko) { + ed.onKeyDown.add(function(ed, e) { + if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) + t.backspaceDelete(e, e.keyCode == 8); + }); + } + } + + // Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973 + if (tinymce.isWebKit) { + function insertBr(ed) { + var rng = selection.getRng(), br, div = dom.create('div', null, ' '), divYPos, vpHeight = dom.getViewPort(ed.getWin()).h; + + // Insert BR element + rng.insertNode(br = dom.create('br')); + + // Place caret after BR + rng.setStartAfter(br); + rng.setEndAfter(br); + selection.setRng(rng); + + // Could not place caret after BR then insert an nbsp entity and move the caret + if (selection.getSel().focusNode == br.previousSibling) { + selection.select(dom.insertAfter(dom.doc.createTextNode('\u00a0'), br)); + selection.collapse(TRUE); + } + + // Create a temporary DIV after the BR and get the position as it + // seems like getPos() returns 0 for text nodes and BR elements. + dom.insertAfter(div, br); + divYPos = dom.getPos(div).y; + dom.remove(div); + + // Scroll to new position, scrollIntoView can't be used due to bug: http://bugs.webkit.org/show_bug.cgi?id=16117 + if (divYPos > vpHeight) // It is not necessary to scroll if the DIV is inside the view port. + ed.getWin().scrollTo(0, divYPos); + }; + + ed.onKeyPress.add(function(ed, e) { + if (e.keyCode == 13 && (e.shiftKey || (s.force_br_newlines && !dom.getParent(selection.getNode(), 'h1,h2,h3,h4,h5,h6,ol,ul')))) { + insertBr(ed); + Event.cancel(e); + } + }); + } + + // Padd empty inline elements within block elements + // For example:

    becomes

     

    + ed.onPreProcess.add(function(ed, o) { + each(dom.select('p,h1,h2,h3,h4,h5,h6,div', o.node), function(p) { + if (isEmpty(p)) { + each(dom.select('span,em,strong,b,i', o.node), function(n) { + if (!n.hasChildNodes()) { + n.appendChild(ed.getDoc().createTextNode('\u00a0')); + return FALSE; // Break the loop one padding is enough + } + }); + } + }); + }); + + // IE specific fixes + if (isIE) { + // Replaces IE:s auto generated paragraphs with the specified element name + if (s.element != 'P') { + ed.onKeyPress.add(function(ed, e) { + t.lastElm = selection.getNode().nodeName; + }); + + ed.onKeyUp.add(function(ed, e) { + var bl, n = selection.getNode(), b = ed.getBody(); + + if (b.childNodes.length === 1 && n.nodeName == 'P') { + n = dom.rename(n, s.element); + selection.select(n); + selection.collapse(); + ed.nodeChanged(); + } else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') { + bl = dom.getParent(n, 'p'); + + if (bl) { + dom.rename(bl, s.element); + ed.nodeChanged(); + } + } + }); + } + } + }, + + find : function(n, t, s) { + var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, FALSE), c = -1; + + while (n = w.nextNode()) { + c++; + + // Index by node + if (t == 0 && n == s) + return c; + + // Node by index + if (t == 1 && c == s) + return n; + } + + return -1; + }, + + forceRoots : function(ed, e) { + var t = this, ed = t.editor, b = ed.getBody(), d = ed.getDoc(), se = ed.selection, s = se.getSel(), r = se.getRng(), si = -2, ei, so, eo, tr, c = -0xFFFFFF; + var nx, bl, bp, sp, le, nl = b.childNodes, i, n, eid; + + // Fix for bug #1863847 + //if (e && e.keyCode == 13) + // return TRUE; + + // Wrap non blocks into blocks + for (i = nl.length - 1; i >= 0; i--) { + nx = nl[i]; + + // Ignore internal elements + if (nx.nodeType === 1 && nx.getAttribute('_mce_type')) { + bl = null; + continue; + } + + // Is text or non block element + if (nx.nodeType === 3 || (!t.dom.isBlock(nx) && nx.nodeType !== 8 && !/^(script|mce:script|style|mce:style)$/i.test(nx.nodeName))) { + if (!bl) { + // Create new block but ignore whitespace + if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) { + // Store selection + if (si == -2 && r) { + if (!isIE || r.setStart) { + // If selection is element then mark it + if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) { + // Save the id of the selected element + eid = n.getAttribute("id"); + n.setAttribute("id", "__mce"); + } else { + // If element is inside body, might not be the case in contentEdiable mode + if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) { + so = r.startOffset; + eo = r.endOffset; + si = t.find(b, 0, r.startContainer); + ei = t.find(b, 0, r.endContainer); + } + } + } else { + // Force control range into text range + if (r.item) { + tr = d.body.createTextRange(); + tr.moveToElementText(r.item(0)); + r = tr; + } + + tr = d.body.createTextRange(); + tr.moveToElementText(b); + tr.collapse(1); + bp = tr.move('character', c) * -1; + + tr = r.duplicate(); + tr.collapse(1); + sp = tr.move('character', c) * -1; + + tr = r.duplicate(); + tr.collapse(0); + le = (tr.move('character', c) * -1) - sp; + + si = sp - bp; + ei = le; + } + } + + // Uses replaceChild instead of cloneNode since it removes selected attribute from option elements on IE + // See: http://support.microsoft.com/kb/829907 + bl = ed.dom.create(ed.settings.forced_root_block); + nx.parentNode.replaceChild(bl, nx); + bl.appendChild(nx); + } + } else { + if (bl.hasChildNodes()) + bl.insertBefore(nx, bl.firstChild); + else + bl.appendChild(nx); + } + } else + bl = null; // Time to create new block + } + + // Restore selection + if (si != -2) { + if (!isIE || r.setStart) { + bl = b.getElementsByTagName(ed.settings.element)[0]; + r = d.createRange(); + + // Select last location or generated block + if (si != -1) + r.setStart(t.find(b, 1, si), so); + else + r.setStart(bl, 0); + + // Select last location or generated block + if (ei != -1) + r.setEnd(t.find(b, 1, ei), eo); + else + r.setEnd(bl, 0); + + if (s) { + s.removeAllRanges(); + s.addRange(r); + } + } else { + try { + r = s.createRange(); + r.moveToElementText(b); + r.collapse(1); + r.moveStart('character', si); + r.moveEnd('character', ei); + r.select(); + } catch (ex) { + // Ignore + } + } + } else if ((!isIE || r.setStart) && (n = ed.dom.get('__mce'))) { + // Restore the id of the selected element + if (eid) + n.setAttribute('id', eid); + else + n.removeAttribute('id'); + + // Move caret before selected element + r = d.createRange(); + r.setStartBefore(n); + r.setEndBefore(n); + se.setRng(r); + } + }, + + getParentBlock : function(n) { + var d = this.dom; + + return d.getParent(n, d.isBlock); + }, + + insertPara : function(e) { + var t = this, ed = t.editor, dom = ed.dom, d = ed.getDoc(), se = ed.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body; + var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = dom.getViewPort(ed.getWin()), y, ch, car; + + // If root blocks are forced then use Operas default behavior since it's really good +// Removed due to bug: #1853816 +// if (se.forced_root_block && isOpera) +// return TRUE; + + // Setup before range + rb = d.createRange(); + + // If is before the first block element and in body, then move it into first block element + rb.setStart(s.anchorNode, s.anchorOffset); + rb.collapse(TRUE); + + // Setup after range + ra = d.createRange(); + + // If is before the first block element and in body, then move it into first block element + ra.setStart(s.focusNode, s.focusOffset); + ra.collapse(TRUE); + + // Setup start/end points + dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0; + sn = dir ? s.anchorNode : s.focusNode; + so = dir ? s.anchorOffset : s.focusOffset; + en = dir ? s.focusNode : s.anchorNode; + eo = dir ? s.focusOffset : s.anchorOffset; + + // If selection is in empty table cell + if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) { + if (sn.firstChild.nodeName == 'BR') + dom.remove(sn.firstChild); // Remove BR + + // Create two new block elements + if (sn.childNodes.length == 0) { + ed.dom.add(sn, se.element, null, '
    '); + aft = ed.dom.add(sn, se.element, null, '
    '); + } else { + n = sn.innerHTML; + sn.innerHTML = ''; + ed.dom.add(sn, se.element, null, n); + aft = ed.dom.add(sn, se.element, null, '
    '); + } + + // Move caret into the last one + r = d.createRange(); + r.selectNodeContents(aft); + r.collapse(1); + ed.selection.setRng(r); + + return FALSE; + } + + // If the caret is in an invalid location in FF we need to move it into the first block + if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) { + sn = en = sn.firstChild; + so = eo = 0; + rb = d.createRange(); + rb.setStart(sn, 0); + ra = d.createRange(); + ra.setStart(en, 0); + } + + // Never use body as start or end node + sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes + sn = sn.nodeName == "BODY" ? sn.firstChild : sn; + en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes + en = en.nodeName == "BODY" ? en.firstChild : en; + + // Get start and end blocks + sb = t.getParentBlock(sn); + eb = t.getParentBlock(en); + bn = sb ? sb.nodeName : se.element; // Get block name to create + + // Return inside list use default browser behavior + if (n = t.dom.getParent(sb, 'li,pre')) { + if (n.nodeName == 'LI') + return splitList(ed.selection, t.dom, n); + + return TRUE; + } + + // If caption or absolute layers then always generate new blocks within + if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) { + bn = se.element; + sb = null; + } + + // If caption or absolute layers then always generate new blocks within + if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|fixed/gi.test(dom.getStyle(sb, 'position', 1)))) { + bn = se.element; + eb = null; + } + + // Use P instead + if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(dom.getStyle(sb, 'float', 1)))) { + bn = se.element; + sb = eb = null; + } + + // Setup new before and after blocks + bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn); + aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn); + + // Remove id from after clone + aft.removeAttribute('id'); + + // Is header and cursor is at the end, then force paragraph under + if (/^(H[1-6])$/.test(bn) && isAtEnd(r, sb)) + aft = ed.dom.create(se.element); + + // Find start chop node + n = sc = sn; + do { + if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName)) + break; + + sc = n; + } while ((n = n.previousSibling ? n.previousSibling : n.parentNode)); + + // Find end chop node + n = ec = en; + do { + if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName)) + break; + + ec = n; + } while ((n = n.nextSibling ? n.nextSibling : n.parentNode)); + + // Place first chop part into before block element + if (sc.nodeName == bn) + rb.setStart(sc, 0); + else + rb.setStartBefore(sc); + + rb.setEnd(sn, so); + bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari + + // Place secnd chop part within new block element + try { + ra.setEndAfter(ec); + } catch(ex) { + //console.debug(s.focusNode, s.focusOffset); + } + + ra.setStart(en, eo); + aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari + + // Create range around everything + r = d.createRange(); + if (!sc.previousSibling && sc.parentNode.nodeName == bn) { + r.setStartBefore(sc.parentNode); + } else { + if (rb.startContainer.nodeName == bn && rb.startOffset == 0) + r.setStartBefore(rb.startContainer); + else + r.setStart(rb.startContainer, rb.startOffset); + } + + if (!ec.nextSibling && ec.parentNode.nodeName == bn) + r.setEndAfter(ec.parentNode); + else + r.setEnd(ra.endContainer, ra.endOffset); + + // Delete and replace it with new block elements + r.deleteContents(); + + if (isOpera) + ed.getWin().scrollTo(0, vp.y); + + // Never wrap blocks in blocks + if (bef.firstChild && bef.firstChild.nodeName == bn) + bef.innerHTML = bef.firstChild.innerHTML; + + if (aft.firstChild && aft.firstChild.nodeName == bn) + aft.innerHTML = aft.firstChild.innerHTML; + + // Padd empty blocks + if (isEmpty(bef)) + bef.innerHTML = '
    '; + + function appendStyles(e, en) { + var nl = [], nn, n, i; + + e.innerHTML = ''; + + // Make clones of style elements + if (se.keep_styles) { + n = en; + do { + // We only want style specific elements + if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)) { + nn = n.cloneNode(FALSE); + dom.setAttrib(nn, 'id', ''); // Remove ID since it needs to be unique + nl.push(nn); + } + } while (n = n.parentNode); + } + + // Append style elements to aft + if (nl.length > 0) { + for (i = nl.length - 1, nn = e; i >= 0; i--) + nn = nn.appendChild(nl[i]); + + // Padd most inner style element + nl[0].innerHTML = isOpera ? ' ' : '
    '; // Extra space for Opera so that the caret can move there + return nl[0]; // Move caret to most inner element + } else + e.innerHTML = isOpera ? ' ' : '
    '; // Extra space for Opera so that the caret can move there + }; + + // Fill empty afterblook with current style + if (isEmpty(aft)) + car = appendStyles(aft, en); + + // Opera needs this one backwards for older versions + if (isOpera && parseFloat(opera.version()) < 9.5) { + r.insertNode(bef); + r.insertNode(aft); + } else { + r.insertNode(aft); + r.insertNode(bef); + } + + // Normalize + aft.normalize(); + bef.normalize(); + + function first(n) { + return d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, FALSE).nextNode() || n; + }; + + // Move cursor and scroll into view + r = d.createRange(); + r.selectNodeContents(isGecko ? first(car || aft) : car || aft); + r.collapse(1); + s.removeAllRanges(); + s.addRange(r); + + // scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs + y = ed.dom.getPos(aft).y; + ch = aft.clientHeight; + + // Is element within viewport + if (y < vp.y || y + ch > vp.y + vp.h) { + ed.getWin().scrollTo(0, y < vp.y ? y : y - vp.h + 25); // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks + //console.debug('SCROLL!', 'vp.y: ' + vp.y, 'y' + y, 'vp.h' + vp.h, 'clientHeight' + aft.clientHeight, 'yyy: ' + (y < vp.y ? y : y - vp.h + aft.clientHeight)); + } + + return FALSE; + }, + + backspaceDelete : function(e, bs) { + var t = this, ed = t.editor, b = ed.getBody(), dom = ed.dom, n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn, walker; + + // Delete when caret is behind a element doesn't work correctly on Gecko see #3011651 + if (!bs && r.collapsed && sc.nodeType == 1 && r.startOffset == sc.childNodes.length) { + walker = new tinymce.dom.TreeWalker(sc.lastChild, sc); + + // Walk the dom backwards until we find a text node + for (n = sc.lastChild; n; n = walker.prev()) { + if (n.nodeType == 3) { + r.setStart(n, n.nodeValue.length); + r.collapse(true); + se.setRng(r); + return; + } + } + } + + // The caret sometimes gets stuck in Gecko if you delete empty paragraphs + // This workaround removes the element by hand and moves the caret to the previous element + if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) { + if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) { + // Find previous block element + n = sc; + while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ; + + if (n) { + if (sc != b.firstChild) { + // Find last text node + w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, FALSE); + while (tn = w.nextNode()) + n = tn; + + // Place caret at the end of last text node + r = ed.getDoc().createRange(); + r.setStart(n, n.nodeValue ? n.nodeValue.length : 0); + r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0); + se.setRng(r); + + // Remove the target container + ed.dom.remove(sc); + } + + return Event.cancel(e); + } + } + } + } + }); +})(tinymce); + +(function(tinymce) { + // Shorten names + var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend; + + tinymce.create('tinymce.ControlManager', { + ControlManager : function(ed, s) { + var t = this, i; + + s = s || {}; + t.editor = ed; + t.controls = {}; + t.onAdd = new tinymce.util.Dispatcher(t); + t.onPostRender = new tinymce.util.Dispatcher(t); + t.prefix = s.prefix || ed.id + '_'; + t._cls = {}; + + t.onPostRender.add(function() { + each(t.controls, function(c) { + c.postRender(); + }); + }); + }, + + get : function(id) { + return this.controls[this.prefix + id] || this.controls[id]; + }, + + setActive : function(id, s) { + var c = null; + + if (c = this.get(id)) + c.setActive(s); + + return c; + }, + + setDisabled : function(id, s) { + var c = null; + + if (c = this.get(id)) + c.setDisabled(s); + + return c; + }, + + add : function(c) { + var t = this; + + if (c) { + t.controls[c.id] = c; + t.onAdd.dispatch(c, t); + } + + return c; + }, + + createControl : function(n) { + var c, t = this, ed = t.editor; + + each(ed.plugins, function(p) { + if (p.createControl) { + c = p.createControl(n, t); + + if (c) + return false; + } + }); + + switch (n) { + case "|": + case "separator": + return t.createSeparator(); + } + + if (!c && ed.buttons && (c = ed.buttons[n])) + return t.createButton(n, c); + + return t.add(c); + }, + + createDropMenu : function(id, s, cc) { + var t = this, ed = t.editor, c, bm, v, cls; + + s = extend({ + 'class' : 'mceDropDown', + constrain : ed.settings.constrain_menus + }, s); + + s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin'; + if (v = ed.getParam('skin_variant')) + s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1); + + id = t.prefix + id; + cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu; + c = t.controls[id] = new cls(id, s); + c.onAddItem.add(function(c, o) { + var s = o.settings; + + s.title = ed.getLang(s.title, s.title); + + if (!s.onclick) { + s.onclick = function(v) { + if (s.cmd) + ed.execCommand(s.cmd, s.ui || false, s.value); + }; + } + }); + + ed.onRemove.add(function() { + c.destroy(); + }); + + // Fix for bug #1897785, #1898007 + if (tinymce.isIE) { + c.onShowMenu.add(function() { + // IE 8 needs focus in order to store away a range with the current collapsed caret location + ed.focus(); + + bm = ed.selection.getBookmark(1); + }); + + c.onHideMenu.add(function() { + if (bm) { + ed.selection.moveToBookmark(bm); + bm = 0; + } + }); + } + + return t.add(c); + }, + + createListBox : function(id, s, cc) { + var t = this, ed = t.editor, cmd, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.scope = s.scope || ed; + + if (!s.onselect) { + s.onselect = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + scope : s.scope, + control_manager : t + }, s); + + id = t.prefix + id; + + if (ed.settings.use_native_selects) + c = new tinymce.ui.NativeListBox(id, s); + else { + cls = cc || t._cls.listbox || tinymce.ui.ListBox; + c = new cls(id, s, ed); + } + + t.controls[id] = c; + + // Fix focus problem in Safari + if (tinymce.isWebKit) { + c.onPostRender.add(function(c, n) { + // Store bookmark on mousedown + Event.add(n, 'mousedown', function() { + ed.bookmark = ed.selection.getBookmark(1); + }); + + // Restore on focus, since it might be lost + Event.add(n, 'focus', function() { + ed.selection.moveToBookmark(ed.bookmark); + ed.bookmark = null; + }); + }); + } + + if (c.hideMenu) + ed.onMouseDown.add(c.hideMenu, c); + + return t.add(c); + }, + + createButton : function(id, s, cc) { + var t = this, ed = t.editor, o, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.label = ed.translate(s.label); + s.scope = s.scope || ed; + + if (!s.onclick && !s.menu_button) { + s.onclick = function() { + ed.execCommand(s.cmd, s.ui || false, s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + unavailable_prefix : ed.getLang('unavailable', ''), + scope : s.scope, + control_manager : t + }, s); + + id = t.prefix + id; + + if (s.menu_button) { + cls = cc || t._cls.menubutton || tinymce.ui.MenuButton; + c = new cls(id, s, ed); + ed.onMouseDown.add(c.hideMenu, c); + } else { + cls = t._cls.button || tinymce.ui.Button; + c = new cls(id, s); + } + + return t.add(c); + }, + + createMenuButton : function(id, s, cc) { + s = s || {}; + s.menu_button = 1; + + return this.createButton(id, s, cc); + }, + + createSplitButton : function(id, s, cc) { + var t = this, ed = t.editor, cmd, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.scope = s.scope || ed; + + if (!s.onclick) { + s.onclick = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + if (!s.onselect) { + s.onselect = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + scope : s.scope, + control_manager : t + }, s); + + id = t.prefix + id; + cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton; + c = t.add(new cls(id, s, ed)); + ed.onMouseDown.add(c.hideMenu, c); + + return c; + }, + + createColorSplitButton : function(id, s, cc) { + var t = this, ed = t.editor, cmd, c, cls, bm; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.scope = s.scope || ed; + + if (!s.onclick) { + s.onclick = function(v) { + if (tinymce.isIE) + bm = ed.selection.getBookmark(1); + + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + if (!s.onselect) { + s.onselect = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + 'menu_class' : ed.getParam('skin') + 'Skin', + scope : s.scope, + more_colors_title : ed.getLang('more_colors') + }, s); + + id = t.prefix + id; + cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton; + c = new cls(id, s, ed); + ed.onMouseDown.add(c.hideMenu, c); + + // Remove the menu element when the editor is removed + ed.onRemove.add(function() { + c.destroy(); + }); + + // Fix for bug #1897785, #1898007 + if (tinymce.isIE) { + c.onShowMenu.add(function() { + // IE 8 needs focus in order to store away a range with the current collapsed caret location + ed.focus(); + bm = ed.selection.getBookmark(1); + }); + + c.onHideMenu.add(function() { + if (bm) { + ed.selection.moveToBookmark(bm); + bm = 0; + } + }); + } + + return t.add(c); + }, + + createToolbar : function(id, s, cc) { + var c, t = this, cls; + + id = t.prefix + id; + cls = cc || t._cls.toolbar || tinymce.ui.Toolbar; + c = new cls(id, s, t.editor); + + if (t.get(id)) + return null; + + return t.add(c); + }, + + createToolbarGroup : function(id, s, cc) { + var c, t = this, cls; + id = t.prefix + id; + cls = cc || this._cls.toolbarGroup || tinymce.ui.ToolbarGroup; + c = new cls(id, s, t.editor); + + if (t.get(id)) + return null; + + return t.add(c); + }, + + createSeparator : function(cc) { + var cls = cc || this._cls.separator || tinymce.ui.Separator; + + return new cls(); + }, + + setControlType : function(n, c) { + return this._cls[n.toLowerCase()] = c; + }, + + destroy : function() { + each(this.controls, function(c) { + c.destroy(); + }); + + this.controls = null; + } + }); +})(tinymce); + +(function(tinymce) { + var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera; + + tinymce.create('tinymce.WindowManager', { + WindowManager : function(ed) { + var t = this; + + t.editor = ed; + t.onOpen = new Dispatcher(t); + t.onClose = new Dispatcher(t); + t.params = {}; + t.features = {}; + }, + + open : function(s, p) { + var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u; + + // Default some options + s = s || {}; + p = p || {}; + sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window + sh = isOpera ? vp.h : screen.height; + s.name = s.name || 'mc_' + new Date().getTime(); + s.width = parseInt(s.width || 320); + s.height = parseInt(s.height || 240); + s.resizable = true; + s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0); + s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0); + p.inline = false; + p.mce_width = s.width; + p.mce_height = s.height; + p.mce_auto_focus = s.auto_focus; + + if (mo) { + if (isIE) { + s.center = true; + s.help = false; + s.dialogWidth = s.width + 'px'; + s.dialogHeight = s.height + 'px'; + s.scroll = s.scrollbars || false; + } + } + + // Build features string + each(s, function(v, k) { + if (tinymce.is(v, 'boolean')) + v = v ? 'yes' : 'no'; + + if (!/^(name|url)$/.test(k)) { + if (isIE && mo) + f += (f ? ';' : '') + k + ':' + v; + else + f += (f ? ',' : '') + k + '=' + v; + } + }); + + t.features = s; + t.params = p; + t.onOpen.dispatch(t, s, p); + + u = s.url || s.file; + u = tinymce._addVer(u); + + try { + if (isIE && mo) { + w = 1; + window.showModalDialog(u, window, f); + } else + w = window.open(u, s.name, f); + } catch (ex) { + // Ignore + } + + if (!w) + alert(t.editor.getLang('popup_blocked')); + }, + + close : function(w) { + w.close(); + this.onClose.dispatch(this); + }, + + createInstance : function(cl, a, b, c, d, e) { + var f = tinymce.resolve(cl); + + return new f(a, b, c, d, e); + }, + + confirm : function(t, cb, s, w) { + w = w || window; + + cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t)))); + }, + + alert : function(tx, cb, s, w) { + var t = this; + + w = w || window; + w.alert(t._decode(t.editor.getLang(tx, tx))); + + if (cb) + cb.call(s || t); + }, + + resizeBy : function(dw, dh, win) { + win.resizeBy(dw, dh); + }, + + // Internal functions + + _decode : function(s) { + return tinymce.DOM.decode(s).replace(/\\n/g, '\n'); + } + }); +}(tinymce)); +(function(tinymce) { + function CommandManager() { + var execCommands = {}, queryStateCommands = {}, queryValueCommands = {}; + + function add(collection, cmd, func, scope) { + if (typeof(cmd) == 'string') + cmd = [cmd]; + + tinymce.each(cmd, function(cmd) { + collection[cmd.toLowerCase()] = {func : func, scope : scope}; + }); + }; + + tinymce.extend(this, { + add : function(cmd, func, scope) { + add(execCommands, cmd, func, scope); + }, + + addQueryStateHandler : function(cmd, func, scope) { + add(queryStateCommands, cmd, func, scope); + }, + + addQueryValueHandler : function(cmd, func, scope) { + add(queryValueCommands, cmd, func, scope); + }, + + execCommand : function(scope, cmd, ui, value, args) { + if (cmd = execCommands[cmd.toLowerCase()]) { + if (cmd.func.call(scope || cmd.scope, ui, value, args) !== false) + return true; + } + }, + + queryCommandValue : function() { + if (cmd = queryValueCommands[cmd.toLowerCase()]) + return cmd.func.call(scope || cmd.scope, ui, value, args); + }, + + queryCommandState : function() { + if (cmd = queryStateCommands[cmd.toLowerCase()]) + return cmd.func.call(scope || cmd.scope, ui, value, args); + } + }); + }; + + tinymce.GlobalCommands = new CommandManager(); +})(tinymce); +(function(tinymce) { + tinymce.Formatter = function(ed) { + var formats = {}, + each = tinymce.each, + dom = ed.dom, + selection = ed.selection, + TreeWalker = tinymce.dom.TreeWalker, + rangeUtils = new tinymce.dom.RangeUtils(dom), + isValid = ed.schema.isValid, + isBlock = dom.isBlock, + forcedRootBlock = ed.settings.forced_root_block, + nodeIndex = dom.nodeIndex, + INVISIBLE_CHAR = '\uFEFF', + MCE_ATTR_RE = /^(src|href|style)$/, + FALSE = false, + TRUE = true, + undefined, + pendingFormats = {apply : [], remove : []}; + + function isArray(obj) { + return obj instanceof Array; + }; + + function getParents(node, selector) { + return dom.getParents(node, selector, dom.getRoot()); + }; + + function isCaretNode(node) { + return node.nodeType === 1 && (node.face === 'mceinline' || node.style.fontFamily === 'mceinline'); + }; + + // Public functions + + function get(name) { + return name ? formats[name] : formats; + }; + + function register(name, format) { + if (name) { + if (typeof(name) !== 'string') { + each(name, function(format, name) { + register(name, format); + }); + } else { + // Force format into array and add it to internal collection + format = format.length ? format : [format]; + + each(format, function(format) { + // Set deep to false by default on selector formats this to avoid removing + // alignment on images inside paragraphs when alignment is changed on paragraphs + if (format.deep === undefined) + format.deep = !format.selector; + + // Default to true + if (format.split === undefined) + format.split = !format.selector || format.inline; + + // Default to true + if (format.remove === undefined && format.selector && !format.inline) + format.remove = 'none'; + + // Mark format as a mixed format inline + block level + if (format.selector && format.inline) { + format.mixed = true; + format.block_expand = true; + } + + // Split classes if needed + if (typeof(format.classes) === 'string') + format.classes = format.classes.split(/\s+/); + }); + + formats[name] = format; + } + } + }; + + var getTextDecoration = function(node) { + var decoration; + + ed.dom.getParent(node, function(n) { + decoration = ed.dom.getStyle(n, 'text-decoration'); + return decoration && decoration !== 'none'; + }); + + return decoration; + }; + + var processUnderlineAndColor = function(node) { + var textDecoration; + if (node.nodeType === 1 && node.parentNode && node.parentNode.nodeType === 1) { + textDecoration = getTextDecoration(node.parentNode); + if (ed.dom.getStyle(node, 'color') && textDecoration) { + ed.dom.setStyle(node, 'text-decoration', textDecoration); + } else if (ed.dom.getStyle(node, 'textdecoration') === textDecoration) { + ed.dom.setStyle(node, 'text-decoration', null); + } + } + }; + + function apply(name, vars, node) { + var formatList = get(name), format = formatList[0], bookmark, rng, i; + + function moveStart(rng) { + var container = rng.startContainer, + offset = rng.startOffset, + walker, node; + + // Move startContainer/startOffset in to a suitable node + if (container.nodeType == 1 || container.nodeValue === "") { + container = container.nodeType == 1 ? container.childNodes[offset] : container; + + // Might fail if the offset is behind the last element in it's container + if (container) { + walker = new TreeWalker(container, container.parentNode); + for (node = walker.current(); node; node = walker.next()) { + if (node.nodeType == 3 && !isWhiteSpaceNode(node)) { + rng.setStart(node, 0); + break; + } + } + } + } + + return rng; + }; + + function setElementFormat(elm, fmt) { + fmt = fmt || format; + + if (elm) { + each(fmt.styles, function(value, name) { + dom.setStyle(elm, name, replaceVars(value, vars)); + }); + + each(fmt.attributes, function(value, name) { + dom.setAttrib(elm, name, replaceVars(value, vars)); + }); + + each(fmt.classes, function(value) { + value = replaceVars(value, vars); + + if (!dom.hasClass(elm, value)) + dom.addClass(elm, value); + }); + } + }; + + function applyRngStyle(rng) { + var newWrappers = [], wrapName, wrapElm; + + // Setup wrapper element + wrapName = format.inline || format.block; + wrapElm = dom.create(wrapName); + setElementFormat(wrapElm); + + rangeUtils.walk(rng, function(nodes) { + var currentWrapElm; + + function process(node) { + var nodeName = node.nodeName.toLowerCase(), parentName = node.parentNode.nodeName.toLowerCase(), found; + + // Stop wrapping on br elements + if (isEq(nodeName, 'br')) { + currentWrapElm = 0; + + // Remove any br elements when we wrap things + if (format.block) + dom.remove(node); + + return; + } + + // If node is wrapper type + if (format.wrapper && matchNode(node, name, vars)) { + currentWrapElm = 0; + return; + } + + // Can we rename the block + if (format.block && !format.wrapper && isTextBlock(nodeName)) { + node = dom.rename(node, wrapName); + setElementFormat(node); + newWrappers.push(node); + currentWrapElm = 0; + return; + } + + // Handle selector patterns + if (format.selector) { + // Look for matching formats + each(formatList, function(format) { + if (dom.is(node, format.selector) && !isCaretNode(node)) { + setElementFormat(node, format); + found = true; + } + }); + + // Continue processing if a selector match wasn't found and a inline element is defined + if (!format.inline || found) { + currentWrapElm = 0; + return; + } + } + + // Is it valid to wrap this item + if ((format.wrap_links !== false || nodeName != 'a') && isValid(wrapName, nodeName) && isValid(parentName, wrapName)) { + // Start wrapping + if (!currentWrapElm) { + // Wrap the node + currentWrapElm = wrapElm.cloneNode(FALSE); + node.parentNode.insertBefore(currentWrapElm, node); + newWrappers.push(currentWrapElm); + } + + currentWrapElm.appendChild(node); + } else { + // Start a new wrapper for possible children + currentWrapElm = 0; + + each(tinymce.grep(node.childNodes), process); + + // End the last wrapper + currentWrapElm = 0; + } + }; + + // Process siblings from range + each(nodes, process); + }); + + // Cleanup + each(newWrappers, function(node) { + var childCount; + + function getChildCount(node) { + var count = 0; + + each(node.childNodes, function(node) { + if (!isWhiteSpaceNode(node) && !isBookmarkNode(node)) + count++; + }); + + return count; + }; + + function mergeStyles(node) { + var child, clone; + + each(node.childNodes, function(node) { + if (node.nodeType == 1 && !isBookmarkNode(node) && !isCaretNode(node)) { + child = node; + return FALSE; // break loop + } + }); + + // If child was found and of the same type as the current node + if (child && matchName(child, format)) { + clone = child.cloneNode(FALSE); + setElementFormat(clone); + + dom.replace(clone, node, TRUE); + dom.remove(child, 1); + } + + return clone || node; + }; + + childCount = getChildCount(node); + + // Remove empty nodes + if (childCount === 0) { + dom.remove(node, 1); + return; + } + + if (format.inline || format.wrapper) { + // Merges the current node with it's children of similar type to reduce the number of elements + if (!format.exact && childCount === 1) + node = mergeStyles(node); + + // Remove/merge children + each(formatList, function(format) { + // Merge all children of similar type will move styles from child to parent + // this: text + // will become: text + each(dom.select(format.inline, node), function(child) { + removeFormat(format, vars, child, format.exact ? child : null); + }); + }); + + // Remove child if direct parent is of same type + if (matchNode(node.parentNode, name, vars)) { + dom.remove(node, 1); + node = 0; + return TRUE; + } + + // Look for parent with similar style format + if (format.merge_with_parents) { + dom.getParent(node.parentNode, function(parent) { + if (matchNode(parent, name, vars)) { + dom.remove(node, 1); + node = 0; + return TRUE; + } + }); + } + + // Merge next and previous siblings if they are similar texttext becomes texttext + if (node) { + node = mergeSiblings(getNonWhiteSpaceSibling(node), node); + node = mergeSiblings(node, getNonWhiteSpaceSibling(node, TRUE)); + } + } + }); + }; + + if (format) { + if (node) { + rng = dom.createRng(); + + rng.setStartBefore(node); + rng.setEndAfter(node); + + applyRngStyle(expandRng(rng, formatList)); + } else { + if (!selection.isCollapsed() || !format.inline) { + // Obtain selection node before selection is unselected by applyRngStyle() + var curSelNode = ed.selection.getNode(); + + // Apply formatting to selection + bookmark = selection.getBookmark(); + applyRngStyle(expandRng(selection.getRng(TRUE), formatList)); + + // Colored nodes should be underlined so that the color of the underline matches the text color. + if (format.styles && (format.styles.color || format.styles.textDecoration)) { + tinymce.walk(curSelNode, processUnderlineAndColor, 'childNodes'); + processUnderlineAndColor(curSelNode); + } + + selection.moveToBookmark(bookmark); + selection.setRng(moveStart(selection.getRng(TRUE))); + ed.nodeChanged(); + } else + performCaretAction('apply', name, vars); + } + } + }; + + function remove(name, vars, node) { + var formatList = get(name), format = formatList[0], bookmark, i, rng; + + function moveStart(rng) { + var container = rng.startContainer, + offset = rng.startOffset, + walker, node, nodes, tmpNode; + + // Convert text node into index if possible + if (container.nodeType == 3 && offset >= container.nodeValue.length - 1) { + container = container.parentNode; + offset = nodeIndex(container) + 1; + } + + // Move startContainer/startOffset in to a suitable node + if (container.nodeType == 1) { + nodes = container.childNodes; + container = nodes[Math.min(offset, nodes.length - 1)]; + walker = new TreeWalker(container); + + // If offset is at end of the parent node walk to the next one + if (offset > nodes.length - 1) + walker.next(); + + for (node = walker.current(); node; node = walker.next()) { + if (node.nodeType == 3 && !isWhiteSpaceNode(node)) { + // IE has a "neat" feature where it moves the start node into the closest element + // we can avoid this by inserting an element before it and then remove it after we set the selection + tmpNode = dom.create('a', null, INVISIBLE_CHAR); + node.parentNode.insertBefore(tmpNode, node); + + // Set selection and remove tmpNode + rng.setStart(node, 0); + selection.setRng(rng); + dom.remove(tmpNode); + + return; + } + } + } + }; + + // Merges the styles for each node + function process(node) { + var children, i, l; + + // Grab the children first since the nodelist might be changed + children = tinymce.grep(node.childNodes); + + // Process current node + for (i = 0, l = formatList.length; i < l; i++) { + if (removeFormat(formatList[i], vars, node, node)) + break; + } + + // Process the children + if (format.deep) { + for (i = 0, l = children.length; i < l; i++) + process(children[i]); + } + }; + + function findFormatRoot(container) { + var formatRoot; + + // Find format root + each(getParents(container.parentNode).reverse(), function(parent) { + var format; + + // Find format root element + if (!formatRoot && parent.id != '_start' && parent.id != '_end') { + // Is the node matching the format we are looking for + format = matchNode(parent, name, vars); + if (format && format.split !== false) + formatRoot = parent; + } + }); + + return formatRoot; + }; + + function wrapAndSplit(format_root, container, target, split) { + var parent, clone, lastClone, firstClone, i, formatRootParent; + + // Format root found then clone formats and split it + if (format_root) { + formatRootParent = format_root.parentNode; + + for (parent = container.parentNode; parent && parent != formatRootParent; parent = parent.parentNode) { + clone = parent.cloneNode(FALSE); + + for (i = 0; i < formatList.length; i++) { + if (removeFormat(formatList[i], vars, clone, clone)) { + clone = 0; + break; + } + } + + // Build wrapper node + if (clone) { + if (lastClone) + clone.appendChild(lastClone); + + if (!firstClone) + firstClone = clone; + + lastClone = clone; + } + } + + // Never split block elements if the format is mixed + if (split && (!format.mixed || !isBlock(format_root))) + container = dom.split(format_root, container); + + // Wrap container in cloned formats + if (lastClone) { + target.parentNode.insertBefore(lastClone, target); + firstClone.appendChild(target); + } + } + + return container; + }; + + function splitToFormatRoot(container) { + return wrapAndSplit(findFormatRoot(container), container, container, true); + }; + + function unwrap(start) { + var node = dom.get(start ? '_start' : '_end'), + out = node[start ? 'firstChild' : 'lastChild']; + + // If the end is placed within the start the result will be removed + // So this checks if the out node is a bookmark node if it is it + // checks for another more suitable node + if (isBookmarkNode(out)) + out = out[start ? 'firstChild' : 'lastChild']; + + dom.remove(node, true); + + return out; + }; + + function removeRngStyle(rng) { + var startContainer, endContainer; + + rng = expandRng(rng, formatList, TRUE); + + if (format.split) { + startContainer = getContainer(rng, TRUE); + endContainer = getContainer(rng); + + if (startContainer != endContainer) { + // Wrap start/end nodes in span element since these might be cloned/moved + startContainer = wrap(startContainer, 'span', {id : '_start', _mce_type : 'bookmark'}); + endContainer = wrap(endContainer, 'span', {id : '_end', _mce_type : 'bookmark'}); + + // Split start/end + splitToFormatRoot(startContainer); + splitToFormatRoot(endContainer); + + // Unwrap start/end to get real elements again + startContainer = unwrap(TRUE); + endContainer = unwrap(); + } else + startContainer = endContainer = splitToFormatRoot(startContainer); + + // Update range positions since they might have changed after the split operations + rng.startContainer = startContainer.parentNode; + rng.startOffset = nodeIndex(startContainer); + rng.endContainer = endContainer.parentNode; + rng.endOffset = nodeIndex(endContainer) + 1; + } + + // Remove items between start/end + rangeUtils.walk(rng, function(nodes) { + each(nodes, function(node) { + process(node); + + // Remove parent span if it only contains text-decoration: underline, yet a parent node is also underlined. + if (node.nodeType === 1 && ed.dom.getStyle(node, 'text-decoration') === 'underline' && node.parentNode && getTextDecoration(node.parentNode) === 'underline') { + removeFormat({'deep': false, 'exact': true, 'inline': 'span', 'styles': {'textDecoration' : 'underline'}}, null, node); + } + }); + }); + }; + + // Handle node + if (node) { + rng = dom.createRng(); + rng.setStartBefore(node); + rng.setEndAfter(node); + removeRngStyle(rng); + return; + } + + if (!selection.isCollapsed() || !format.inline) { + bookmark = selection.getBookmark(); + removeRngStyle(selection.getRng(TRUE)); + selection.moveToBookmark(bookmark); + + // Check if start element still has formatting then we are at: "text|text" and need to move the start into the next text node + if (match(name, vars, selection.getStart())) { + moveStart(selection.getRng(true)); + } + + ed.nodeChanged(); + } else + performCaretAction('remove', name, vars); + }; + + function toggle(name, vars, node) { + var fmt = get(name); + if (match(name, vars, node) && (!('toggle' in fmt[0]) || fmt[0]['toggle'])) + remove(name, vars, node); + else + apply(name, vars, node); + }; + + function matchNode(node, name, vars, similar) { + var formatList = get(name), format, i, classes; + + function matchItems(node, format, item_name) { + var key, value, items = format[item_name], i; + + // Check all items + if (items) { + // Non indexed object + if (items.length === undefined) { + for (key in items) { + if (items.hasOwnProperty(key)) { + if (item_name === 'attributes') + value = dom.getAttrib(node, key); + else + value = getStyle(node, key); + + if (similar && !value && !format.exact) + return; + + if ((!similar || format.exact) && !isEq(value, replaceVars(items[key], vars))) + return; + } + } + } else { + // Only one match needed for indexed arrays + for (i = 0; i < items.length; i++) { + if (item_name === 'attributes' ? dom.getAttrib(node, items[i]) : getStyle(node, items[i])) + return format; + } + } + } + + return format; + }; + + if (formatList && node) { + // Check each format in list + for (i = 0; i < formatList.length; i++) { + format = formatList[i]; + + // Name name, attributes, styles and classes + if (matchName(node, format) && matchItems(node, format, 'attributes') && matchItems(node, format, 'styles')) { + // Match classes + if (classes = format.classes) { + for (i = 0; i < classes.length; i++) { + if (!dom.hasClass(node, classes[i])) + return; + } + } + + return format; + } + } + } + }; + + function match(name, vars, node) { + var startNode, i; + + function matchParents(node) { + // Find first node with similar format settings + node = dom.getParent(node, function(node) { + return !!matchNode(node, name, vars, true); + }); + + // Do an exact check on the similar format element + return matchNode(node, name, vars); + }; + + // Check specified node + if (node) + return matchParents(node); + + // Check pending formats + if (selection.isCollapsed()) { + for (i = pendingFormats.apply.length - 1; i >= 0; i--) { + if (pendingFormats.apply[i].name == name) + return true; + } + + for (i = pendingFormats.remove.length - 1; i >= 0; i--) { + if (pendingFormats.remove[i].name == name) + return false; + } + + return matchParents(selection.getNode()); + } + + // Check selected node + node = selection.getNode(); + if (matchParents(node)) + return TRUE; + + // Check start node if it's different + startNode = selection.getStart(); + if (startNode != node) { + if (matchParents(startNode)) + return TRUE; + } + + return FALSE; + }; + + function matchAll(names, vars) { + var startElement, matchedFormatNames = [], checkedMap = {}, i, ni, name; + + // If the selection is collapsed then check pending formats + if (selection.isCollapsed()) { + for (ni = 0; ni < names.length; ni++) { + // If the name is to be removed, then stop it from being added + for (i = pendingFormats.remove.length - 1; i >= 0; i--) { + name = names[ni]; + + if (pendingFormats.remove[i].name == name) { + checkedMap[name] = true; + break; + } + } + } + + // If the format is to be applied + for (i = pendingFormats.apply.length - 1; i >= 0; i--) { + for (ni = 0; ni < names.length; ni++) { + name = names[ni]; + + if (!checkedMap[name] && pendingFormats.apply[i].name == name) { + checkedMap[name] = true; + matchedFormatNames.push(name); + } + } + } + } + + // Check start of selection for formats + startElement = selection.getStart(); + dom.getParent(startElement, function(node) { + var i, name; + + for (i = 0; i < names.length; i++) { + name = names[i]; + + if (!checkedMap[name] && matchNode(node, name, vars)) { + checkedMap[name] = true; + matchedFormatNames.push(name); + } + } + }); + + return matchedFormatNames; + }; + + function canApply(name) { + var formatList = get(name), startNode, parents, i, x, selector; + + if (formatList) { + startNode = selection.getStart(); + parents = getParents(startNode); + + for (x = formatList.length - 1; x >= 0; x--) { + selector = formatList[x].selector; + + // Format is not selector based, then always return TRUE + if (!selector) + return TRUE; + + for (i = parents.length - 1; i >= 0; i--) { + if (dom.is(parents[i], selector)) + return TRUE; + } + } + } + + return FALSE; + }; + + // Expose to public + tinymce.extend(this, { + get : get, + register : register, + apply : apply, + remove : remove, + toggle : toggle, + match : match, + matchAll : matchAll, + matchNode : matchNode, + canApply : canApply + }); + + // Private functions + + function matchName(node, format) { + // Check for inline match + if (isEq(node, format.inline)) + return TRUE; + + // Check for block match + if (isEq(node, format.block)) + return TRUE; + + // Check for selector match + if (format.selector) + return dom.is(node, format.selector); + }; + + function isEq(str1, str2) { + str1 = str1 || ''; + str2 = str2 || ''; + + str1 = '' + (str1.nodeName || str1); + str2 = '' + (str2.nodeName || str2); + + return str1.toLowerCase() == str2.toLowerCase(); + }; + + function getStyle(node, name) { + var styleVal = dom.getStyle(node, name); + + // Force the format to hex + if (name == 'color' || name == 'backgroundColor') + styleVal = dom.toHex(styleVal); + + // Opera will return bold as 700 + if (name == 'fontWeight' && styleVal == 700) + styleVal = 'bold'; + + return '' + styleVal; + }; + + function replaceVars(value, vars) { + if (typeof(value) != "string") + value = value(vars); + else if (vars) { + value = value.replace(/%(\w+)/g, function(str, name) { + return vars[name] || str; + }); + } + + return value; + }; + + function isWhiteSpaceNode(node) { + return node && node.nodeType === 3 && /^([\s\r\n]+|)$/.test(node.nodeValue); + }; + + function wrap(node, name, attrs) { + var wrapper = dom.create(name, attrs); + + node.parentNode.insertBefore(wrapper, node); + wrapper.appendChild(node); + + return wrapper; + }; + + function expandRng(rng, format, remove) { + var startContainer = rng.startContainer, + startOffset = rng.startOffset, + endContainer = rng.endContainer, + endOffset = rng.endOffset, sibling, lastIdx, leaf; + + // This function walks up the tree if there is no siblings before/after the node + function findParentContainer(container, child_name, sibling_name, root) { + var parent, child; + + root = root || dom.getRoot(); + + for (;;) { + // Check if we can move up are we at root level or body level + parent = container.parentNode; + + // Stop expanding on block elements or root depending on format + if (parent == root || (!format[0].block_expand && isBlock(parent))) + return container; + + for (sibling = parent[child_name]; sibling && sibling != container; sibling = sibling[sibling_name]) { + if (sibling.nodeType == 1 && !isBookmarkNode(sibling)) + return container; + + if (sibling.nodeType == 3 && !isWhiteSpaceNode(sibling)) + return container; + } + + container = container.parentNode; + } + + return container; + }; + + // This function walks down the tree to find the leaf at the selection. + // The offset is also returned as if node initially a leaf, the offset may be in the middle of the text node. + function findLeaf(node, offset) { + if (offset === undefined) + offset = node.nodeType === 3 ? node.length : node.childNodes.length; + while (node && node.hasChildNodes()) { + node = node.childNodes[offset]; + if (node) + offset = node.nodeType === 3 ? node.length : node.childNodes.length; + } + return { node: node, offset: offset }; + } + + // If index based start position then resolve it + if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) { + lastIdx = startContainer.childNodes.length - 1; + startContainer = startContainer.childNodes[startOffset > lastIdx ? lastIdx : startOffset]; + + if (startContainer.nodeType == 3) + startOffset = 0; + } + + // If index based end position then resolve it + if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) { + lastIdx = endContainer.childNodes.length - 1; + endContainer = endContainer.childNodes[endOffset > lastIdx ? lastIdx : endOffset - 1]; + + if (endContainer.nodeType == 3) + endOffset = endContainer.nodeValue.length; + } + + // Exclude bookmark nodes if possible + if (isBookmarkNode(startContainer.parentNode)) + startContainer = startContainer.parentNode; + + if (isBookmarkNode(startContainer)) + startContainer = startContainer.nextSibling || startContainer; + + if (isBookmarkNode(endContainer.parentNode)) { + endOffset = dom.nodeIndex(endContainer); + endContainer = endContainer.parentNode; + } + + if (isBookmarkNode(endContainer) && endContainer.previousSibling) { + endContainer = endContainer.previousSibling; + endOffset = endContainer.length; + } + + if (format[0].inline) { + // Avoid applying formatting to a trailing space. + leaf = findLeaf(endContainer, endOffset); + if (leaf.node) { + while (leaf.node && leaf.offset === 0 && leaf.node.previousSibling) + leaf = findLeaf(leaf.node.previousSibling); + + if (leaf.node && leaf.offset > 0 && leaf.node.nodeType === 3 && + leaf.node.nodeValue.charAt(leaf.offset - 1) === ' ') { + + if (leaf.offset > 1) { + endContainer = leaf.node; + endContainer.splitText(leaf.offset - 1); + } else if (leaf.node.previousSibling) { + endContainer = leaf.node.previousSibling; + } + } + } + } + + // Move start/end point up the tree if the leaves are sharp and if we are in different containers + // Example * becomes !: !

    *texttext*

    ! + // This will reduce the number of wrapper elements that needs to be created + // Move start point up the tree + if (format[0].inline || format[0].block_expand) { + startContainer = findParentContainer(startContainer, 'firstChild', 'nextSibling'); + endContainer = findParentContainer(endContainer, 'lastChild', 'previousSibling'); + } + + // Expand start/end container to matching selector + if (format[0].selector && format[0].expand !== FALSE && !format[0].inline) { + function findSelectorEndPoint(container, sibling_name) { + var parents, i, y; + + if (container.nodeType == 3 && container.nodeValue.length == 0 && container[sibling_name]) + container = container[sibling_name]; + + parents = getParents(container); + for (i = 0; i < parents.length; i++) { + for (y = 0; y < format.length; y++) { + if (dom.is(parents[i], format[y].selector)) + return parents[i]; + } + } + + return container; + }; + + // Find new startContainer/endContainer if there is better one + startContainer = findSelectorEndPoint(startContainer, 'previousSibling'); + endContainer = findSelectorEndPoint(endContainer, 'nextSibling'); + } + + // Expand start/end container to matching block element or text node + if (format[0].block || format[0].selector) { + function findBlockEndPoint(container, sibling_name, sibling_name2) { + var node; + + // Expand to block of similar type + if (!format[0].wrapper) + node = dom.getParent(container, format[0].block); + + // Expand to first wrappable block element or any block element + if (!node) + node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isBlock); + + // Exclude inner lists from wrapping + if (node && format[0].wrapper) + node = getParents(node, 'ul,ol').reverse()[0] || node; + + // Didn't find a block element look for first/last wrappable element + if (!node) { + node = container; + + while (node[sibling_name] && !isBlock(node[sibling_name])) { + node = node[sibling_name]; + + // Break on BR but include it will be removed later on + // we can't remove it now since we need to check if it can be wrapped + if (isEq(node, 'br')) + break; + } + } + + return node || container; + }; + + // Find new startContainer/endContainer if there is better one + startContainer = findBlockEndPoint(startContainer, 'previousSibling'); + endContainer = findBlockEndPoint(endContainer, 'nextSibling'); + + // Non block element then try to expand up the leaf + if (format[0].block) { + if (!isBlock(startContainer)) + startContainer = findParentContainer(startContainer, 'firstChild', 'nextSibling'); + + if (!isBlock(endContainer)) + endContainer = findParentContainer(endContainer, 'lastChild', 'previousSibling'); + } + } + + // Setup index for startContainer + if (startContainer.nodeType == 1) { + startOffset = nodeIndex(startContainer); + startContainer = startContainer.parentNode; + } + + // Setup index for endContainer + if (endContainer.nodeType == 1) { + endOffset = nodeIndex(endContainer) + 1; + endContainer = endContainer.parentNode; + } + + // Return new range like object + return { + startContainer : startContainer, + startOffset : startOffset, + endContainer : endContainer, + endOffset : endOffset + }; + } + + function removeFormat(format, vars, node, compare_node) { + var i, attrs, stylesModified; + + // Check if node matches format + if (!matchName(node, format)) + return FALSE; + + // Should we compare with format attribs and styles + if (format.remove != 'all') { + // Remove styles + each(format.styles, function(value, name) { + value = replaceVars(value, vars); + + // Indexed array + if (typeof(name) === 'number') { + name = value; + compare_node = 0; + } + + if (!compare_node || isEq(getStyle(compare_node, name), value)) + dom.setStyle(node, name, ''); + + stylesModified = 1; + }); + + // Remove style attribute if it's empty + if (stylesModified && dom.getAttrib(node, 'style') == '') { + node.removeAttribute('style'); + node.removeAttribute('_mce_style'); + } + + // Remove attributes + each(format.attributes, function(value, name) { + var valueOut; + + value = replaceVars(value, vars); + + // Indexed array + if (typeof(name) === 'number') { + name = value; + compare_node = 0; + } + + if (!compare_node || isEq(dom.getAttrib(compare_node, name), value)) { + // Keep internal classes + if (name == 'class') { + value = dom.getAttrib(node, name); + if (value) { + // Build new class value where everything is removed except the internal prefixed classes + valueOut = ''; + each(value.split(/\s+/), function(cls) { + if (/mce\w+/.test(cls)) + valueOut += (valueOut ? ' ' : '') + cls; + }); + + // We got some internal classes left + if (valueOut) { + dom.setAttrib(node, name, valueOut); + return; + } + } + } + + // IE6 has a bug where the attribute doesn't get removed correctly + if (name == "class") + node.removeAttribute('className'); + + // Remove mce prefixed attributes + if (MCE_ATTR_RE.test(name)) + node.removeAttribute('_mce_' + name); + + node.removeAttribute(name); + } + }); + + // Remove classes + each(format.classes, function(value) { + value = replaceVars(value, vars); + + if (!compare_node || dom.hasClass(compare_node, value)) + dom.removeClass(node, value); + }); + + // Check for non internal attributes + attrs = dom.getAttribs(node); + for (i = 0; i < attrs.length; i++) { + if (attrs[i].nodeName.indexOf('_') !== 0) + return FALSE; + } + } + + // Remove the inline child if it's empty for example or + if (format.remove != 'none') { + removeNode(node, format); + return TRUE; + } + }; + + function removeNode(node, format) { + var parentNode = node.parentNode, rootBlockElm; + + if (format.block) { + if (!forcedRootBlock) { + function find(node, next, inc) { + node = getNonWhiteSpaceSibling(node, next, inc); + + return !node || (node.nodeName == 'BR' || isBlock(node)); + }; + + // Append BR elements if needed before we remove the block + if (isBlock(node) && !isBlock(parentNode)) { + if (!find(node, FALSE) && !find(node.firstChild, TRUE, 1)) + node.insertBefore(dom.create('br'), node.firstChild); + + if (!find(node, TRUE) && !find(node.lastChild, FALSE, 1)) + node.appendChild(dom.create('br')); + } + } else { + // Wrap the block in a forcedRootBlock if we are at the root of document + if (parentNode == dom.getRoot()) { + if (!format.list_block || !isEq(node, format.list_block)) { + each(tinymce.grep(node.childNodes), function(node) { + if (isValid(forcedRootBlock, node.nodeName.toLowerCase())) { + if (!rootBlockElm) + rootBlockElm = wrap(node, forcedRootBlock); + else + rootBlockElm.appendChild(node); + } else + rootBlockElm = 0; + }); + } + } + } + } + + // Never remove nodes that isn't the specified inline element if a selector is specified too + if (format.selector && format.inline && !isEq(format.inline, node)) + return; + + dom.remove(node, 1); + }; + + function getNonWhiteSpaceSibling(node, next, inc) { + if (node) { + next = next ? 'nextSibling' : 'previousSibling'; + + for (node = inc ? node : node[next]; node; node = node[next]) { + if (node.nodeType == 1 || !isWhiteSpaceNode(node)) + return node; + } + } + }; + + function isBookmarkNode(node) { + return node && node.nodeType == 1 && node.getAttribute('_mce_type') == 'bookmark'; + }; + + function mergeSiblings(prev, next) { + var marker, sibling, tmpSibling; + + function compareElements(node1, node2) { + // Not the same name + if (node1.nodeName != node2.nodeName) + return FALSE; + + function getAttribs(node) { + var attribs = {}; + + each(dom.getAttribs(node), function(attr) { + var name = attr.nodeName.toLowerCase(); + + // Don't compare internal attributes or style + if (name.indexOf('_') !== 0 && name !== 'style') + attribs[name] = dom.getAttrib(node, name); + }); + + return attribs; + }; + + function compareObjects(obj1, obj2) { + var value, name; + + for (name in obj1) { + // Obj1 has item obj2 doesn't have + if (obj1.hasOwnProperty(name)) { + value = obj2[name]; + + // Obj2 doesn't have obj1 item + if (value === undefined) + return FALSE; + + // Obj2 item has a different value + if (obj1[name] != value) + return FALSE; + + // Delete similar value + delete obj2[name]; + } + } + + // Check if obj 2 has something obj 1 doesn't have + for (name in obj2) { + // Obj2 has item obj1 doesn't have + if (obj2.hasOwnProperty(name)) + return FALSE; + } + + return TRUE; + }; + + // Attribs are not the same + if (!compareObjects(getAttribs(node1), getAttribs(node2))) + return FALSE; + + // Styles are not the same + if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) + return FALSE; + + return TRUE; + }; + + // Check if next/prev exists and that they are elements + if (prev && next) { + function findElementSibling(node, sibling_name) { + for (sibling = node; sibling; sibling = sibling[sibling_name]) { + if (sibling.nodeType == 3 && !isWhiteSpaceNode(sibling)) + return node; + + if (sibling.nodeType == 1 && !isBookmarkNode(sibling)) + return sibling; + } + + return node; + }; + + // If previous sibling is empty then jump over it + prev = findElementSibling(prev, 'previousSibling'); + next = findElementSibling(next, 'nextSibling'); + + // Compare next and previous nodes + if (compareElements(prev, next)) { + // Append nodes between + for (sibling = prev.nextSibling; sibling && sibling != next;) { + tmpSibling = sibling; + sibling = sibling.nextSibling; + prev.appendChild(tmpSibling); + } + + // Remove next node + dom.remove(next); + + // Move children into prev node + each(tinymce.grep(next.childNodes), function(node) { + prev.appendChild(node); + }); + + return prev; + } + } + + return next; + }; + + function isTextBlock(name) { + return /^(h[1-6]|p|div|pre|address|dl|dt|dd)$/.test(name); + }; + + function getContainer(rng, start) { + var container, offset, lastIdx; + + container = rng[start ? 'startContainer' : 'endContainer']; + offset = rng[start ? 'startOffset' : 'endOffset']; + + if (container.nodeType == 1) { + lastIdx = container.childNodes.length - 1; + + if (!start && offset) + offset--; + + container = container.childNodes[offset > lastIdx ? lastIdx : offset]; + } + + return container; + }; + + function performCaretAction(type, name, vars) { + var i, currentPendingFormats = pendingFormats[type], + otherPendingFormats = pendingFormats[type == 'apply' ? 'remove' : 'apply']; + + function hasPending() { + return pendingFormats.apply.length || pendingFormats.remove.length; + }; + + function resetPending() { + pendingFormats.apply = []; + pendingFormats.remove = []; + }; + + function perform(caret_node) { + // Apply pending formats + each(pendingFormats.apply.reverse(), function(item) { + apply(item.name, item.vars, caret_node); + + // Colored nodes should be underlined so that the color of the underline matches the text color. + if (item.name === 'forecolor' && item.vars.value) + processUnderlineAndColor(caret_node.parentNode); + }); + + // Remove pending formats + each(pendingFormats.remove.reverse(), function(item) { + remove(item.name, item.vars, caret_node); + }); + + dom.remove(caret_node, 1); + resetPending(); + }; + + // Check if it already exists then ignore it + for (i = currentPendingFormats.length - 1; i >= 0; i--) { + if (currentPendingFormats[i].name == name) + return; + } + + currentPendingFormats.push({name : name, vars : vars}); + + // Check if it's in the other type, then remove it + for (i = otherPendingFormats.length - 1; i >= 0; i--) { + if (otherPendingFormats[i].name == name) + otherPendingFormats.splice(i, 1); + } + + // Pending apply or remove formats + if (hasPending()) { + ed.getDoc().execCommand('FontName', false, 'mceinline'); + pendingFormats.lastRng = selection.getRng(); + + // IE will convert the current word + each(dom.select('font,span'), function(node) { + var bookmark; + + if (isCaretNode(node)) { + bookmark = selection.getBookmark(); + perform(node); + selection.moveToBookmark(bookmark); + ed.nodeChanged(); + } + }); + + // Only register listeners once if we need to + if (!pendingFormats.isListening && hasPending()) { + pendingFormats.isListening = true; + + each('onKeyDown,onKeyUp,onKeyPress,onMouseUp'.split(','), function(event) { + ed[event].addToTop(function(ed, e) { + // Do we have pending formats and is the selection moved has moved + if (hasPending() && !tinymce.dom.RangeUtils.compareRanges(pendingFormats.lastRng, selection.getRng())) { + each(dom.select('font,span'), function(node) { + var textNode, rng; + + // Look for marker + if (isCaretNode(node)) { + textNode = node.firstChild; + + if (textNode) { + perform(node); + + rng = dom.createRng(); + rng.setStart(textNode, textNode.nodeValue.length); + rng.setEnd(textNode, textNode.nodeValue.length); + selection.setRng(rng); + ed.nodeChanged(); + } else + dom.remove(node); + } + }); + + // Always unbind and clear pending styles on keyup + if (e.type == 'keyup' || e.type == 'mouseup') + resetPending(); + } + }); + }); + } + } + }; + }; +})(tinymce); + +tinymce.onAddEditor.add(function(tinymce, ed) { + var filters, fontSizes, dom, settings = ed.settings; + + if (settings.inline_styles) { + fontSizes = tinymce.explode(settings.font_size_style_values); + + function replaceWithSpan(node, styles) { + tinymce.each(styles, function(value, name) { + if (value) + dom.setStyle(node, name, value); + }); + + dom.rename(node, 'span'); + }; + + filters = { + font : function(dom, node) { + replaceWithSpan(node, { + backgroundColor : node.style.backgroundColor, + color : node.color, + fontFamily : node.face, + fontSize : fontSizes[parseInt(node.size) - 1] + }); + }, + + u : function(dom, node) { + replaceWithSpan(node, { + textDecoration : 'underline' + }); + }, + + strike : function(dom, node) { + replaceWithSpan(node, { + textDecoration : 'line-through' + }); + } + }; + + function convert(editor, params) { + dom = editor.dom; + + if (settings.convert_fonts_to_spans) { + tinymce.each(dom.select('font,u,strike', params.node), function(node) { + filters[node.nodeName.toLowerCase()](ed.dom, node); + }); + } + }; + + ed.onPreProcess.add(convert); + + ed.onInit.add(function() { + ed.selection.onSetContent.add(convert); + }); + } +}); + diff --git a/tools/tiny_mce/utils/editable_selects.js b/tools/tiny_mce/utils/editable_selects.js new file mode 100644 index 00000000..6cf1b166 --- /dev/null +++ b/tools/tiny_mce/utils/editable_selects.js @@ -0,0 +1,70 @@ +/** + * editable_selects.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +var TinyMCE_EditableSelects = { + editSelectElm : null, + + init : function() { + var nl = document.getElementsByTagName("select"), i, d = document, o; + + for (i=0; i'; + h += ' '; + + return h; +} + +function updateColor(img_id, form_element_id) { + document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value; +} + +function setBrowserDisabled(id, state) { + var img = document.getElementById(id); + var lnk = document.getElementById(id + "_link"); + + if (lnk) { + if (state) { + lnk.setAttribute("realhref", lnk.getAttribute("href")); + lnk.removeAttribute("href"); + tinyMCEPopup.dom.addClass(img, 'disabled'); + } else { + if (lnk.getAttribute("realhref")) + lnk.setAttribute("href", lnk.getAttribute("realhref")); + + tinyMCEPopup.dom.removeClass(img, 'disabled'); + } + } +} + +function getBrowserHTML(id, target_form_element, type, prefix) { + var option = prefix + "_" + type + "_browser_callback", cb, html; + + cb = tinyMCEPopup.getParam(option, tinyMCEPopup.getParam("file_browser_callback")); + + if (!cb) + return ""; + + html = ""; + html += ''; + html += ' '; + + return html; +} + +function openBrowser(img_id, target_form_element, type, option) { + var img = document.getElementById(img_id); + + if (img.className != "mceButtonDisabled") + tinyMCEPopup.openBrowser(target_form_element, type, option); +} + +function selectByValue(form_obj, field_name, value, add_custom, ignore_case) { + if (!form_obj || !form_obj.elements[field_name]) + return; + if (!value) + value = ""; + + var sel = form_obj.elements[field_name]; + + var found = false; + for (var i=0; i parseInt(v)) + st = this.mark(f, n); + } + } + + return st; + }, + + hasClass : function(n, c, d) { + return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className); + }, + + getNum : function(n, c) { + c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0]; + c = c.replace(/[^0-9]/g, ''); + + return c; + }, + + addClass : function(n, c, b) { + var o = this.removeClass(n, c); + n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c; + }, + + removeClass : function(n, c) { + c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' '); + return n.className = c != ' ' ? c : ''; + }, + + tags : function(f, s) { + return f.getElementsByTagName(s); + }, + + mark : function(f, n) { + var s = this.settings; + + this.addClass(n, s.invalid_cls); + n.setAttribute('aria-invalid', 'true'); + this.markLabels(f, n, s.invalid_cls); + + return false; + }, + + markLabels : function(f, n, ic) { + var nl, i; + + nl = this.tags(f, "label"); + for (i=0; i + * @copyright 2016 WodzAAC + * @version 0.0.1 + * @link http://myaac.info + */ + +// we need some functions +require('../common.php'); +require(LIBS . 'validator.php'); +require(SYSTEM . 'functions.php'); +require(SYSTEM . 'init.php'); + +echo ''; +if(isset($_GET['account'])) +{ + $account = trim($_GET['account']); + $tmp = strtoupper($account); + + $error = ''; + if(!check_account_name($tmp, $error)) + error_($error); + + $_account = new OTS_Account(); + $_account->find($tmp); + if($_account->isLoaded()) + error_('Account with this name already exist.'); + + success_('Good account name ( ' . $account . ' ).'); +} +else if(isset($_GET['email'])) +{ + $email = trim($_GET['email']); + if(strlen($email) >= 255) + error_('E-mail is too long (max. 255 chars).'); + + if(!Validator::email($email)) + error_('Invalid e-mail format.'); + + if($config['account_mail_unique']) + { + $account = new OTS_Account(); + $account->findByEMail($email); + if($account->isLoaded()) + error_('Account with this e-mail already exist.'); + } + + success_('Good e-mail.'); +} +else if(isset($_GET['name'])) +{ + $name = strtolower(stripslashes(trim($_GET['name']))); + $error = ''; + if(!check_name($name, $error)) + error_($error); + + // check if this name wasn't namelocked + if(tableExist('player_namelocks') && fieldExist('name', 'player_namelocks')) { + $query = $db->query('SELECT `player_id` FROM `player_namelocks` WHERE name = ' . $db->quote($name)); + if($query->rowCount() > 0) + error_('Character with this name has been namelocked.'); + } + + $player = new OTS_Player(); + $player->find($name); + if($player->isLoaded()) + error_('Player with this name already exist.'); + + success_('Good. Your name will be:
    ' . ucwords($name) . ''); +} +else + error_('Error: no input specified.'); + +/** + * Output message & exit. + * + * @param string $desc Description + */ +function success_($desc) { + echo '' . $desc . ''; + exit(); +} +function error_($desc) { + echo '' . $desc . ''; + exit(); +} + +?> \ No newline at end of file