diff options
Diffstat (limited to 'apps/tal')
-rw-r--r-- | apps/tal/.gitignore | 51 | ||||
-rw-r--r-- | apps/tal/COPYING-AGPL | 661 | ||||
-rw-r--r-- | apps/tal/COPYING-README | 10 | ||||
-rw-r--r-- | apps/tal/README.md | 26 | ||||
-rw-r--r-- | apps/tal/TODO | 2 | ||||
-rw-r--r-- | apps/tal/ajax/loadpage.php | 23 | ||||
-rw-r--r-- | apps/tal/appinfo/app.php | 11 | ||||
-rw-r--r-- | apps/tal/appinfo/info.xml | 11 | ||||
-rw-r--r-- | apps/tal/css/tal.css | 25 | ||||
-rw-r--r-- | apps/tal/index.php | 30 | ||||
-rw-r--r-- | apps/tal/js/modernizr.js | 1265 | ||||
-rw-r--r-- | apps/tal/js/tal.js | 32 | ||||
-rw-r--r-- | apps/tal/lib/paths.php | 13 | ||||
-rw-r--r-- | apps/tal/lib/tall10n.php | 105 | ||||
-rw-r--r-- | apps/tal/lib/taltemplate.php | 372 | ||||
-rw-r--r-- | apps/tal/settings.php | 16 | ||||
-rw-r--r-- | apps/tal/templates/layout.guest.pt | 43 | ||||
-rw-r--r-- | apps/tal/templates/layout.user.pt | 78 | ||||
-rw-r--r-- | apps/tal/templates/macros.util.pt | 56 | ||||
-rw-r--r-- | apps/tal/templates/manual.pt | 23 | ||||
-rw-r--r-- | apps/tal/templates/sections.pt | 142 | ||||
-rw-r--r-- | apps/tal/templates/settings.pt | 10 |
22 files changed, 3005 insertions, 0 deletions
diff --git a/apps/tal/.gitignore b/apps/tal/.gitignore new file mode 100644 index 00000000000..e2ff07d14d8 --- /dev/null +++ b/apps/tal/.gitignore @@ -0,0 +1,51 @@ +# the default generated dir + db file +data +owncloud +config/config.php +config/mount.php +apps/inc.php + +# just sane ignores +.*.sw[po] +*.bak +*.BAK +*~ +*.orig +*.class +.cvsignore +Thumbs.db +*.py[co] +_darcs/* +CVS/* +.svn/* +RCS/* + +# kdevelop +.kdev +*.kdev4 + +# Lokalize +*lokalize* + +# eclipse +.project +.settings + +# netbeans +nbproject + +# geany +*.geany + +# Cloud9IDE +.settings.xml + +# vim ex mode +.vimrc + +# Mac OS +.DS_Store + +# WebFinger +.well-known +/.buildpath diff --git a/apps/tal/COPYING-AGPL b/apps/tal/COPYING-AGPL new file mode 100644 index 00000000000..dba13ed2ddf --- /dev/null +++ b/apps/tal/COPYING-AGPL @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<http://www.gnu.org/licenses/>. diff --git a/apps/tal/COPYING-README b/apps/tal/COPYING-README new file mode 100644 index 00000000000..18f06caa3ec --- /dev/null +++ b/apps/tal/COPYING-README @@ -0,0 +1,10 @@ +Files in TAL Templating System for ownCloud are licensed under the Affero General Public License version 3, +the text of which can be found in COPYING-AGPL, or any later version of the AGPL, +unless otherwise noted. + +Licensing of components: +* PHPTAL - http://phptal.org/ : LGPL + +All unmodified files from these and other sources retain their original copyright +and license notices: see the relevant individual files. + diff --git a/apps/tal/README.md b/apps/tal/README.md new file mode 100644 index 00000000000..756221c07a6 --- /dev/null +++ b/apps/tal/README.md @@ -0,0 +1,26 @@ +# TAL Page Templates for ownCloud + +Develop using the Template Attribute Language instead of having clumsy +`<?php echo $var; ?>` tags in your markup. + +Read more at the [PHPTAL site](http://phptal.org/introduction.html) + +## Install from git + +1. Go to your ownCloud apps dir and clone the repo there: + <pre> + cd owncloud/apps + git clone git://github.com/tanghus/tal.git + </pre> + +2. Go to the `lib`directory of the newly created `tal` folder and clone the [PHPTAL repo](https://github.com/pornel/PHPTAL): + + <pre> + cd tal/lib + git clone git://github.com/pornel/PHPTAL.git + </pre> + +3. From your browser go to the ownCloud apps page (`/settings/apps.php`) and enable the "TAL Page Templates for ownCloud" app. + +4. Go to the Personal page (`/settings/personal.php`) and check if the installation has succeeded. You will find a section with a link to the manual. + diff --git a/apps/tal/TODO b/apps/tal/TODO new file mode 100644 index 00000000000..ef1e495249d --- /dev/null +++ b/apps/tal/TODO @@ -0,0 +1,2 @@ +TODO +- Create script to extract translatable strings. diff --git a/apps/tal/ajax/loadpage.php b/apps/tal/ajax/loadpage.php new file mode 100644 index 00000000000..f6a1499f454 --- /dev/null +++ b/apps/tal/ajax/loadpage.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright (c) 2011 Thomas Tanghus <thomas@tanghus.net> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OCP\JSON::checkLoggedIn(); +OCP\JSON::checkAppEnabled('tal'); + +$id = isset($_GET['id'])?trim(strip_tags($_GET['id'])):''; + +if($id) { + $tmpl = new OC_TALTemplate('tal', 'sections'); + $tmpl->assign('id',$id); + $page = $tmpl->fetchPage(); + OCP\JSON::success(array('data' => array('id'=>$id, 'page'=>$page))); + exit(); +} else { + $l10n = new OC_L10N('tal'); + OCP\JSON::error(array('data' => array('message' => $l10n->t('Page name missing from request.')))); +}
\ No newline at end of file diff --git a/apps/tal/appinfo/app.php b/apps/tal/appinfo/app.php new file mode 100644 index 00000000000..65c1c4b5bd5 --- /dev/null +++ b/apps/tal/appinfo/app.php @@ -0,0 +1,11 @@ +<?php +OC::$CLASSPATH['OC_TALTemplate'] = 'tal/lib/taltemplate.php'; +OC::$CLASSPATH['OC_TALL10N'] = 'tal/lib/tall10n.php'; +OC::$CLASSPATH['PHPTAL'] = 'tal/lib/PHPTAL/classes/PHPTAL.php'; +OC::$CLASSPATH['PHPTAL_TranslationService'] = 'tal/lib/PHPTAL/classes/PHPTAL/TranslationService.php'; + +OCP\App::register( array( + 'id' => 'tal', + 'name' => 'TAL Page Templates' )); + +OCP\App::registerPersonal('tal','settings');
\ No newline at end of file diff --git a/apps/tal/appinfo/info.xml b/apps/tal/appinfo/info.xml new file mode 100644 index 00000000000..40224f29ff3 --- /dev/null +++ b/apps/tal/appinfo/info.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<info> + <id>tal</id> + <name>TAL Page Templates for ownCloud</name> + <description>This is an alternative to OC_Template and OC_L10N - the templating and internationalization classes used in ownCloud. + </description> + <version>0.1</version> + <licence>AGPL</licence> + <author>Thomas Tanghus</author> + <require>5</require> +</info> diff --git a/apps/tal/css/tal.css b/apps/tal/css/tal.css new file mode 100644 index 00000000000..ed51bc5038d --- /dev/null +++ b/apps/tal/css/tal.css @@ -0,0 +1,25 @@ +#manual { + float: left; + position: absolute; left: 0; top: 0; right: 0; bottom: 0; + margin: 0.5em; + padding: 1em; + overflow: auto; + background-color :#f8f8f8; + color: #555; + border: 1px solid #ddd; + border-radius: 0.5em 0.5em 0.5em 0.5em; + -webkit-transition:background-color 200ms; -moz-transition:background-color 200ms; -o-transition:background-color 200ms; transition:background-color 200ms; +} +#manual nav { position: fixed; top: 5em; width: 15%; font-weight: bold; font-size: 1.2em; } +#manual ol { list-style: decimal; padding-left: 3em; } +#manual section { float:right; width: 80%; height: 95%; padding: 1em; font-size: 1.2em; } +#manual a { color: #555; } +#manual a:hover { color: #333; } +#manual li:hover { color: #333; background-color:#eee; } +code, pre { font-family: "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", monospace; } +code { margin: 0; padding: 0; } +pre { overflow:auto; display:block; margin: 1em; padding: 1em; background-color:#f5f5f5; border:1px solid rgba(0, 0, 0, 0.15); border-radius:4px;white-space:pre;} +h1 { font-size: 1.6em; font-weight: bold; padding: 0.2em 0.2em 0.8em 0.2em; } +h2 { font-size: 1.2em; font-weight: bold; padding: 1em 0.2em 0.8em 0em; } +h3 { font-size: 1em; font-weight: bold; } +.readmore { font-weight: bold; } diff --git a/apps/tal/index.php b/apps/tal/index.php new file mode 100644 index 00000000000..d847195dc9f --- /dev/null +++ b/apps/tal/index.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +// Check if we are a user +OCP\User::checkLoggedIn(); +OCP\App::checkAppEnabled('tal'); + +OCP\Util::addscript('tal','tal'); +OCP\Util::addscript('tal','modernizr'); +OCP\Util::addStyle('tal','tal'); + +$sections = array( + array('id' => 'intro', 'title' => 'Introduction'), + array('id' => 'example-1', 'title' => 'A simple example'), + array('id' => 'gotchas', 'title' => 'Caveats & Gotchas'), + array('id' => 'ref', 'title' => 'References'), + ); +$page = isset($_GET['page'])?trim(strip_tags($_GET['page'])):$sections[0]['id']; + +$tmpl = new OC_TALTemplate('tal', 'manual', 'user'); +$tmpl->assign('application', 'TAL'); +$tmpl->assign('page', $page); +$tmpl->assign('sections', $sections); +$tmpl->printPage(); +?> diff --git a/apps/tal/js/modernizr.js b/apps/tal/js/modernizr.js new file mode 100644 index 00000000000..c1a6a9a51d0 --- /dev/null +++ b/apps/tal/js/modernizr.js @@ -0,0 +1,1265 @@ +/*! + * Modernizr v2.5.3 + * www.modernizr.com + * + * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton + * Available under the BSD and MIT licenses: www.modernizr.com/license/ + */ + +/* + * Modernizr tests which native CSS3 and HTML5 features are available in + * the current UA and makes the results available to you in two ways: + * as properties on a global Modernizr object, and as classes on the + * <html> element. This information allows you to progressively enhance + * your pages with a granular level of control over the experience. + * + * Modernizr has an optional (not included) conditional resource loader + * called Modernizr.load(), based on Yepnope.js (yepnopejs.com). + * To get a build that includes Modernizr.load(), as well as choosing + * which tests to include, go to www.modernizr.com/download/ + * + * Authors Faruk Ates, Paul Irish, Alex Sexton + * Contributors Ryan Seddon, Ben Alman + */ + +window.Modernizr = (function( window, document, undefined ) { + + var version = '2.5.3', + + Modernizr = {}, + + // option for enabling the HTML classes to be added + enableClasses = true, + + docElement = document.documentElement, + + /** + * Create our "modernizr" element that we do most feature tests on. + */ + mod = 'modernizr', + modElem = document.createElement(mod), + mStyle = modElem.style, + + /** + * Create the input element for various Web Forms feature tests. + */ + inputElem = document.createElement('input'), + + smile = ':)', + + toString = {}.toString, + + // List of property values to set for css tests. See ticket #21 + prefixes = ' -webkit- -moz- -o- -ms- '.split(' '), + + // Following spec is to expose vendor-specific style properties as: + // elem.style.WebkitBorderRadius + // and the following would be incorrect: + // elem.style.webkitBorderRadius + + // Webkit ghosts their properties in lowercase but Opera & Moz do not. + // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ + // erik.eae.net/archives/2008/03/10/21.48.10/ + + // More here: github.com/Modernizr/Modernizr/issues/issue/21 + omPrefixes = 'Webkit Moz O ms', + + cssomPrefixes = omPrefixes.split(' '), + + domPrefixes = omPrefixes.toLowerCase().split(' '), + + ns = {'svg': 'http://www.w3.org/2000/svg'}, + + tests = {}, + inputs = {}, + attrs = {}, + + classes = [], + + slice = classes.slice, + + featureName, // used in testing loop + + + // Inject element with style element and some CSS rules + injectElementWithStyles = function( rule, callback, nodes, testnames ) { + + var style, ret, node, + div = document.createElement('div'), + // After page load injecting a fake body doesn't work so check if body exists + body = document.body, + // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it. + fakeBody = body ? body : document.createElement('body'); + + if ( parseInt(nodes, 10) ) { + // In order not to give false positives we create a node for each test + // This also allows the method to scale for unspecified uses + while ( nodes-- ) { + node = document.createElement('div'); + node.id = testnames ? testnames[nodes] : mod + (nodes + 1); + div.appendChild(node); + } + } + + // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed + // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element + // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements. + // msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx + // Documents served as xml will throw if using ­ so use xml friendly encoded version. See issue #277 + style = ['­','<style>', rule, '</style>'].join(''); + div.id = mod; + // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody. + // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 + fakeBody.innerHTML += style; + fakeBody.appendChild(div); + if(!body){ + //avoid crashing IE8, if background image is used + fakeBody.style.background = ""; + docElement.appendChild(fakeBody); + } + + ret = callback(div, rule); + // If this is done after page load we don't want to remove the body so check if body exists + !body ? fakeBody.parentNode.removeChild(fakeBody) : div.parentNode.removeChild(div); + + return !!ret; + + }, + + + // adapted from matchMedia polyfill + // by Scott Jehl and Paul Irish + // gist.github.com/786768 + testMediaQuery = function( mq ) { + + var matchMedia = window.matchMedia || window.msMatchMedia; + if ( matchMedia ) { + return matchMedia(mq).matches; + } + + var bool; + + injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) { + bool = (window.getComputedStyle ? + getComputedStyle(node, null) : + node.currentStyle)['position'] == 'absolute'; + }); + + return bool; + + }, + + + /** + * isEventSupported determines if a given element supports the given event + * function from yura.thinkweb2.com/isEventSupported/ + */ + isEventSupported = (function() { + + var TAGNAMES = { + 'select': 'input', 'change': 'input', + 'submit': 'form', 'reset': 'form', + 'error': 'img', 'load': 'img', 'abort': 'img' + }; + + function isEventSupported( eventName, element ) { + + element = element || document.createElement(TAGNAMES[eventName] || 'div'); + eventName = 'on' + eventName; + + // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those + var isSupported = eventName in element; + + if ( !isSupported ) { + // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element + if ( !element.setAttribute ) { + element = document.createElement('div'); + } + if ( element.setAttribute && element.removeAttribute ) { + element.setAttribute(eventName, ''); + isSupported = is(element[eventName], 'function'); + + // If property was created, "remove it" (by setting value to `undefined`) + if ( !is(element[eventName], 'undefined') ) { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + } + + element = null; + return isSupported; + } + return isEventSupported; + })(); + + // hasOwnProperty shim by kangax needed for Safari 2.0 support + var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty; + if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) { + hasOwnProperty = function (object, property) { + return _hasOwnProperty.call(object, property); + }; + } + else { + hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ + return ((property in object) && is(object.constructor.prototype[property], 'undefined')); + }; + } + + // Taken from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js + // ES-5 15.3.4.5 + // http://es5.github.com/#x15.3.4.5 + + if (!Function.prototype.bind) { + + Function.prototype.bind = function bind(that) { + + var target = this; + + if (typeof target != "function") { + throw new TypeError(); + } + + var args = slice.call(arguments, 1), + bound = function () { + + if (this instanceof bound) { + + var F = function(){}; + F.prototype = target.prototype; + var self = new F; + + var result = target.apply( + self, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return self; + + } else { + + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + + return bound; + }; + } + + /** + * setCss applies given styles to the Modernizr DOM node. + */ + function setCss( str ) { + mStyle.cssText = str; + } + + /** + * setCssAll extrapolates all vendor-specific css strings. + */ + function setCssAll( str1, str2 ) { + return setCss(prefixes.join(str1 + ';') + ( str2 || '' )); + } + + /** + * is returns a boolean for if typeof obj is exactly type. + */ + function is( obj, type ) { + return typeof obj === type; + } + + /** + * contains returns a boolean for if substr is found within str. + */ + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + /** + * testProps is a generic CSS / DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + * A supported CSS property returns empty string when its not yet set. + */ + function testProps( props, prefixed ) { + for ( var i in props ) { + if ( mStyle[ props[i] ] !== undefined ) { + return prefixed == 'pfx' ? props[i] : true; + } + } + return false; + } + + /** + * testDOMProps is a generic DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + */ + function testDOMProps( props, obj, elem ) { + for ( var i in props ) { + var item = obj[props[i]]; + if ( item !== undefined) { + + // return the property name as a string + if (elem === false) return props[i]; + + // let's bind a function + if (is(item, 'function')){ + // default to autobind unless override + return item.bind(elem || obj); + } + + // return the unbound function or obj or value + return item; + } + } + return false; + } + + /** + * testPropsAll tests a list of DOM properties we want to check against. + * We specify literally ALL possible (known and/or likely) properties on + * the element including the non-vendor prefixed one, for forward- + * compatibility. + */ + function testPropsAll( prop, prefixed, elem ) { + + var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1), + props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); + + // did they call .prefixed('boxSizing') or are we just testing a prop? + if(is(prefixed, "string") || is(prefixed, "undefined")) { + return testProps(props, prefixed); + + // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) + } else { + props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); + return testDOMProps(props, prefixed, elem); + } + } + + /** + * testBundle tests a list of CSS features that require element and style injection. + * By bundling them together we can reduce the need to touch the DOM multiple times. + */ + /*>>testBundle*/ + var testBundle = (function( styles, tests ) { + var style = styles.join(''), + len = tests.length; + + injectElementWithStyles(style, function( node, rule ) { + var style = document.styleSheets[document.styleSheets.length - 1], + // IE8 will bork if you create a custom build that excludes both fontface and generatedcontent tests. + // So we check for cssRules and that there is a rule available + // More here: github.com/Modernizr/Modernizr/issues/288 & github.com/Modernizr/Modernizr/issues/293 + cssText = style ? (style.cssRules && style.cssRules[0] ? style.cssRules[0].cssText : style.cssText || '') : '', + children = node.childNodes, hash = {}; + + while ( len-- ) { + hash[children[len].id] = children[len]; + } + + /*>>touch*/ Modernizr['touch'] = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch || (hash['touch'] && hash['touch'].offsetTop) === 9; /*>>touch*/ + /*>>csstransforms3d*/ Modernizr['csstransforms3d'] = (hash['csstransforms3d'] && hash['csstransforms3d'].offsetLeft) === 9 && hash['csstransforms3d'].offsetHeight === 3; /*>>csstransforms3d*/ + /*>>generatedcontent*/Modernizr['generatedcontent'] = (hash['generatedcontent'] && hash['generatedcontent'].offsetHeight) >= 1; /*>>generatedcontent*/ + /*>>fontface*/ Modernizr['fontface'] = /src/i.test(cssText) && + cssText.indexOf(rule.split(' ')[0]) === 0; /*>>fontface*/ + }, len, tests); + + })([ + // Pass in styles to be injected into document + /*>>fontface*/ '@font-face {font-family:"font";src:url("https://")}' /*>>fontface*/ + + /*>>touch*/ ,['@media (',prefixes.join('touch-enabled),('),mod,')', + '{#touch{top:9px;position:absolute}}'].join('') /*>>touch*/ + + /*>>csstransforms3d*/ ,['@media (',prefixes.join('transform-3d),('),mod,')', + '{#csstransforms3d{left:9px;position:absolute;height:3px;}}'].join('')/*>>csstransforms3d*/ + + /*>>generatedcontent*/,['#generatedcontent:after{content:"',smile,'";visibility:hidden}'].join('') /*>>generatedcontent*/ + ], + [ + /*>>fontface*/ 'fontface' /*>>fontface*/ + /*>>touch*/ ,'touch' /*>>touch*/ + /*>>csstransforms3d*/ ,'csstransforms3d' /*>>csstransforms3d*/ + /*>>generatedcontent*/,'generatedcontent' /*>>generatedcontent*/ + + ]);/*>>testBundle*/ + + + /** + * Tests + * ----- + */ + + // The *new* flexbox + // dev.w3.org/csswg/css3-flexbox + + tests['flexbox'] = function() { + return testPropsAll('flexOrder'); + }; + + // The *old* flexbox + // www.w3.org/TR/2009/WD-css3-flexbox-20090723/ + + tests['flexbox-legacy'] = function() { + return testPropsAll('boxDirection'); + }; + + // On the S60 and BB Storm, getContext exists, but always returns undefined + // so we actually have to call getContext() to verify + // github.com/Modernizr/Modernizr/issues/issue/97/ + + tests['canvas'] = function() { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); + }; + + tests['canvastext'] = function() { + return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function')); + }; + + // this test initiates a new webgl context. + // webk.it/70117 is tracking a legit feature detect proposal + + tests['webgl'] = function() { + try { + var canvas = document.createElement('canvas'), + ret; + ret = !!(window.WebGLRenderingContext && (canvas.getContext('experimental-webgl') || canvas.getContext('webgl'))); + canvas = undefined; + } catch (e){ + ret = false; + } + return ret; + }; + + /* + * The Modernizr.touch test only indicates if the browser supports + * touch events, which does not necessarily reflect a touchscreen + * device, as evidenced by tablets running Windows 7 or, alas, + * the Palm Pre / WebOS (touch) phones. + * + * Additionally, Chrome (desktop) used to lie about its support on this, + * but that has since been rectified: crbug.com/36415 + * + * We also test for Firefox 4 Multitouch Support. + * + * For more info, see: modernizr.github.com/Modernizr/touch.html + */ + + tests['touch'] = function() { + return Modernizr['touch']; + }; + + /** + * geolocation tests for the new Geolocation API specification. + * This test is a standards compliant-only test; for more complete + * testing, including a Google Gears fallback, please see: + * code.google.com/p/geo-location-javascript/ + * or view a fallback solution using google's geo API: + * gist.github.com/366184 + */ + tests['geolocation'] = function() { + return !!navigator.geolocation; + }; + + // Per 1.6: + // This used to be Modernizr.crosswindowmessaging but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['postmessage'] = function() { + return !!window.postMessage; + }; + + + // Chrome incognito mode used to throw an exception when using openDatabase + // It doesn't anymore. + tests['websqldatabase'] = function() { + return !!window.openDatabase; + }; + + // Vendors had inconsistent prefixing with the experimental Indexed DB: + // - Webkit's implementation is accessible through webkitIndexedDB + // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB + // For speed, we don't test the legacy (and beta-only) indexedDB + tests['indexedDB'] = function() { + return !!testPropsAll("indexedDB",window); + }; + + // documentMode logic from YUI to filter out IE8 Compat Mode + // which false positives. + tests['hashchange'] = function() { + return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7); + }; + + // Per 1.6: + // This used to be Modernizr.historymanagement but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['history'] = function() { + return !!(window.history && history.pushState); + }; + + tests['draganddrop'] = function() { + var div = document.createElement('div'); + return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div); + }; + + // FIXME: Once FF10 is sunsetted, we can drop prefixed MozWebSocket + // bugzil.la/695635 + tests['websockets'] = function() { + for ( var i = -1, len = cssomPrefixes.length; ++i < len; ){ + if ( window[cssomPrefixes[i] + 'WebSocket'] ){ + return true; + } + } + return 'WebSocket' in window; + }; + + + // css-tricks.com/rgba-browser-support/ + tests['rgba'] = function() { + // Set an rgba() color and check the returned value + + setCss('background-color:rgba(150,255,150,.5)'); + + return contains(mStyle.backgroundColor, 'rgba'); + }; + + tests['hsla'] = function() { + // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, + // except IE9 who retains it as hsla + + setCss('background-color:hsla(120,40%,100%,.5)'); + + return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla'); + }; + + tests['multiplebgs'] = function() { + // Setting multiple images AND a color on the background shorthand property + // and then querying the style.background property value for the number of + // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! + + setCss('background:url(https://),url(https://),red url(https://)'); + + // If the UA supports multiple backgrounds, there should be three occurrences + // of the string "url(" in the return value for elemStyle.background + + return /(url\s*\(.*?){3}/.test(mStyle.background); + }; + + + // In testing support for a given CSS property, it's legit to test: + // `elem.style[styleName] !== undefined` + // If the property is supported it will return an empty string, + // if unsupported it will return undefined. + + // We'll take advantage of this quick test and skip setting a style + // on our modernizr element, but instead just testing undefined vs + // empty string. + + + tests['backgroundsize'] = function() { + return testPropsAll('backgroundSize'); + }; + + tests['borderimage'] = function() { + return testPropsAll('borderImage'); + }; + + + // Super comprehensive table about all the unique implementations of + // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance + + tests['borderradius'] = function() { + return testPropsAll('borderRadius'); + }; + + // WebOS unfortunately false positives on this test. + tests['boxshadow'] = function() { + return testPropsAll('boxShadow'); + }; + + // FF3.0 will false positive on this test + tests['textshadow'] = function() { + return document.createElement('div').style.textShadow === ''; + }; + + + tests['opacity'] = function() { + // Browsers that actually have CSS Opacity implemented have done so + // according to spec, which means their return values are within the + // range of [0.0,1.0] - including the leading zero. + + setCssAll('opacity:.55'); + + // The non-literal . in this regex is intentional: + // German Chrome returns this value as 0,55 + // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 + return /^0.55$/.test(mStyle.opacity); + }; + + + // Note, Android < 4 will pass this test, but can only animate + // a single property at a time + // daneden.me/2011/12/putting-up-with-androids-bullshit/ + tests['cssanimations'] = function() { + return testPropsAll('animationName'); + }; + + + tests['csscolumns'] = function() { + return testPropsAll('columnCount'); + }; + + + tests['cssgradients'] = function() { + /** + * For CSS Gradients syntax, please see: + * webkit.org/blog/175/introducing-css-gradients/ + * developer.mozilla.org/en/CSS/-moz-linear-gradient + * developer.mozilla.org/en/CSS/-moz-radial-gradient + * dev.w3.org/csswg/css3-images/#gradients- + */ + + var str1 = 'background-image:', + str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', + str3 = 'linear-gradient(left top,#9f9, white);'; + + setCss( + // legacy webkit syntax (FIXME: remove when syntax not in use anymore) + (str1 + '-webkit- '.split(' ').join(str2 + str1) + // standard syntax // trailing 'background-image:' + + prefixes.join(str3 + str1)).slice(0, -str1.length) + ); + + return contains(mStyle.backgroundImage, 'gradient'); + }; + + + tests['cssreflections'] = function() { + return testPropsAll('boxReflect'); + }; + + + tests['csstransforms'] = function() { + return !!testPropsAll('transform'); + }; + + + tests['csstransforms3d'] = function() { + + var ret = !!testPropsAll('perspective'); + + // Webkit's 3D transforms are passed off to the browser's own graphics renderer. + // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in + // some conditions. As a result, Webkit typically recognizes the syntax but + // will sometimes throw a false positive, thus we must do a more thorough check: + if ( ret && 'webkitPerspective' in docElement.style ) { + + // Webkit allows this media query to succeed only if the feature is enabled. + // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }` + ret = Modernizr['csstransforms3d']; + } + return ret; + }; + + + tests['csstransitions'] = function() { + return testPropsAll('transition'); + }; + + + /*>>fontface*/ + // @font-face detection routine by Diego Perini + // javascript.nwbox.com/CSSSupport/ + + // false positives in WebOS: github.com/Modernizr/Modernizr/issues/342 + tests['fontface'] = function() { + return Modernizr['fontface']; + }; + /*>>fontface*/ + + // CSS generated content detection + tests['generatedcontent'] = function() { + return Modernizr['generatedcontent']; + }; + + + + // These tests evaluate support of the video/audio elements, as well as + // testing what types of content they support. + // + // We're using the Boolean constructor here, so that we can extend the value + // e.g. Modernizr.video // true + // Modernizr.video.ogg // 'probably' + // + // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 + // thx to NielsLeenheer and zcorpan + + // Note: in some older browsers, "no" was a return value instead of empty string. + // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2 + // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5 + + tests['video'] = function() { + var elem = document.createElement('video'), + bool = false; + + // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224 + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,''); + + bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,''); + + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,''); + } + + } catch(e) { } + + return bool; + }; + + tests['audio'] = function() { + var elem = document.createElement('audio'), + bool = false; + + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,''); + bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,''); + + // Mimetypes accepted: + // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements + // bit.ly/iphoneoscodecs + bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,''); + bool.m4a = ( elem.canPlayType('audio/x-m4a;') || + elem.canPlayType('audio/aac;')) .replace(/^no$/,''); + } + } catch(e) { } + + return bool; + }; + + + // In FF4, if disabled, window.localStorage should === null. + + // Normally, we could not test that directly and need to do a + // `('localStorage' in window) && ` test first because otherwise Firefox will + // throw bugzil.la/365772 if cookies are disabled + + // Also in iOS5 Private Browsing mode, attepting to use localStorage.setItem + // will throw the exception: + // QUOTA_EXCEEDED_ERRROR DOM Exception 22. + // Peculiarly, getItem and removeItem calls do not throw. + + // Because we are forced to try/catch this, we'll go aggressive. + + // Just FWIW: IE8 Compat mode supports these features completely: + // www.quirksmode.org/dom/html5.html + // But IE8 doesn't support either with local files + + tests['localstorage'] = function() { + try { + localStorage.setItem(mod, mod); + localStorage.removeItem(mod); + return true; + } catch(e) { + return false; + } + }; + + tests['sessionstorage'] = function() { + try { + sessionStorage.setItem(mod, mod); + sessionStorage.removeItem(mod); + return true; + } catch(e) { + return false; + } + }; + + + tests['webworkers'] = function() { + return !!window.Worker; + }; + + + tests['applicationcache'] = function() { + return !!window.applicationCache; + }; + + + // Thanks to Erik Dahlstrom + tests['svg'] = function() { + return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; + }; + + // specifically for SVG inline in HTML, not within XHTML + // test page: paulirish.com/demo/inline-svg + tests['inlinesvg'] = function() { + var div = document.createElement('div'); + div.innerHTML = '<svg/>'; + return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; + }; + + // SVG SMIL animation + tests['smil'] = function() { + return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); + }; + + // This test is only for clip paths in SVG proper, not clip paths on HTML content + // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg + + // However read the comments to dig into applying SVG clippaths to HTML content here: + // github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491 + tests['svgclippaths'] = function() { + return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); + }; + + // input features and input types go directly onto the ret object, bypassing the tests loop. + // Hold this guy to execute in a moment. + function webforms() { + // Run through HTML5's new input attributes to see if the UA understands any. + // We're using f which is the <input> element created early on + // Mike Taylr has created a comprehensive resource for testing these attributes + // when applied to all input types: + // miketaylr.com/code/input-type-attr.html + // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + + // Only input placeholder is tested while textarea's placeholder is not. + // Currently Safari 4 and Opera 11 have support only for the input placeholder + // Both tests are available in feature-detects/forms-placeholder.js + Modernizr['input'] = (function( props ) { + for ( var i = 0, len = props.length; i < len; i++ ) { + attrs[ props[i] ] = !!(props[i] in inputElem); + } + if (attrs.list){ + // safari false positive's on datalist: webk.it/74252 + // see also github.com/Modernizr/Modernizr/issues/146 + attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement); + } + return attrs; + })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); + + // Run through HTML5's new input types to see if the UA understands any. + // This is put behind the tests runloop because it doesn't return a + // true/false like all the other tests; instead, it returns an object + // containing each input type with its corresponding true/false value + + // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/ + Modernizr['inputtypes'] = (function(props) { + + for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { + + inputElem.setAttribute('type', inputElemType = props[i]); + bool = inputElem.type !== 'text'; + + // We first check to see if the type we give it sticks.. + // If the type does, we feed it a textual value, which shouldn't be valid. + // If the value doesn't stick, we know there's input sanitization which infers a custom UI + if ( bool ) { + + inputElem.value = smile; + inputElem.style.cssText = 'position:absolute;visibility:hidden;'; + + if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) { + + docElement.appendChild(inputElem); + defaultView = document.defaultView; + + // Safari 2-4 allows the smiley as a value, despite making a slider + bool = defaultView.getComputedStyle && + defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && + // Mobile android web browser has false positive, so must + // check the height to see if the widget is actually there. + (inputElem.offsetHeight !== 0); + + docElement.removeChild(inputElem); + + } else if ( /^(search|tel)$/.test(inputElemType) ){ + // Spec doesnt define any special parsing or detectable UI + // behaviors so we pass these through as true + + // Interestingly, opera fails the earlier test, so it doesn't + // even make it here. + + } else if ( /^(url|email)$/.test(inputElemType) ) { + // Real url and email support comes with prebaked validation. + bool = inputElem.checkValidity && inputElem.checkValidity() === false; + + } else if ( /^color$/.test(inputElemType) ) { + // chuck into DOM and force reflow for Opera bug in 11.00 + // github.com/Modernizr/Modernizr/issues#issue/159 + docElement.appendChild(inputElem); + docElement.offsetWidth; + bool = inputElem.value != smile; + docElement.removeChild(inputElem); + + } else { + // If the upgraded input compontent rejects the :) text, we got a winner + bool = inputElem.value != smile; + } + } + + inputs[ props[i] ] = !!bool; + } + return inputs; + })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); + } + + + // End of test definitions + // ----------------------- + + + + // Run through all tests and detect their support in the current UA. + // todo: hypothetically we could be doing an array of tests and use a basic loop here. + for ( var feature in tests ) { + if ( hasOwnProperty(tests, feature) ) { + // run the test, throw the return value into the Modernizr, + // then based on that boolean, define an appropriate className + // and push it into an array of classes we'll join later. + featureName = feature.toLowerCase(); + Modernizr[featureName] = tests[feature](); + + classes.push((Modernizr[featureName] ? '' : 'no-') + featureName); + } + } + + // input tests need to run. + Modernizr.input || webforms(); + + + /** + * addTest allows the user to define their own feature tests + * the result will be added onto the Modernizr object, + * as well as an appropriate className set on the html element + * + * @param feature - String naming the feature + * @param test - Function returning true if feature is supported, false if not + */ + Modernizr.addTest = function ( feature, test ) { + if ( typeof feature == 'object' ) { + for ( var key in feature ) { + if ( hasOwnProperty( feature, key ) ) { + Modernizr.addTest( key, feature[ key ] ); + } + } + } else { + + feature = feature.toLowerCase(); + + if ( Modernizr[feature] !== undefined ) { + // we're going to quit if you're trying to overwrite an existing test + // if we were to allow it, we'd do this: + // var re = new RegExp("\\b(no-)?" + feature + "\\b"); + // docElement.className = docElement.className.replace( re, '' ); + // but, no rly, stuff 'em. + return Modernizr; + } + + test = typeof test == 'function' ? test() : test; + + docElement.className += ' ' + (test ? '' : 'no-') + feature; + Modernizr[feature] = test; + + } + + return Modernizr; // allow chaining. + }; + + + // Reset modElem.cssText to nothing to reduce memory footprint. + setCss(''); + modElem = inputElem = null; + + //>>BEGIN IEPP + // Enable HTML 5 elements for styling in IE & add HTML5 css + /*! HTML5 Shiv v3.4 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */ + ;(function(window, document) { + + /** Preset options */ + var options = window.html5 || {}; + + /** Used to skip problem elements */ + var reSkip = /^<|^(?:button|form|map|select|textarea)$/i; + + /** Detect whether the browser supports default html5 styles */ + var supportsHtml5Styles; + + /** Detect whether the browser supports unknown elements */ + var supportsUnknownElements; + + (function() { + var a = document.createElement('a'); + + a.innerHTML = '<xyz></xyz>'; + + //if the hidden property is implemented we can assume, that the browser supports HTML5 Styles + supportsHtml5Styles = ('hidden' in a); + supportsUnknownElements = a.childNodes.length == 1 || (function() { + // assign a false positive if unable to shiv + try { + (document.createElement)('a'); + } catch(e) { + return true; + } + var frag = document.createDocumentFragment(); + return ( + typeof frag.cloneNode == 'undefined' || + typeof frag.createDocumentFragment == 'undefined' || + typeof frag.createElement == 'undefined' + ); + }()); + + }()); + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a style sheet with the given CSS text and adds it to the document. + * @private + * @param {Document} ownerDocument The document. + * @param {String} cssText The CSS text. + * @returns {StyleSheet} The style element. + */ + function addStyleSheet(ownerDocument, cssText) { + var p = ownerDocument.createElement('p'), + parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; + + p.innerHTML = 'x<style>' + cssText + '</style>'; + return parent.insertBefore(p.lastChild, parent.firstChild); + } + + /** + * Returns the value of `html5.elements` as an array. + * @private + * @returns {Array} An array of shived element node names. + */ + function getElements() { + var elements = html5.elements; + return typeof elements == 'string' ? elements.split(' ') : elements; + } + + /** + * Shivs the `createElement` and `createDocumentFragment` methods of the document. + * @private + * @param {Document|DocumentFragment} ownerDocument The document. + */ + function shivMethods(ownerDocument) { + var cache = {}, + docCreateElement = ownerDocument.createElement, + docCreateFragment = ownerDocument.createDocumentFragment, + frag = docCreateFragment(); + + ownerDocument.createElement = function(nodeName) { + // Avoid adding some elements to fragments in IE < 9 because + // * Attributes like `name` or `type` cannot be set/changed once an element + // is inserted into a document/fragment + // * Link elements with `src` attributes that are inaccessible, as with + // a 403 response, will cause the tab/window to crash + // * Script elements appended to fragments will execute when their `src` + // or `text` property is set + var node = (cache[nodeName] || (cache[nodeName] = docCreateElement(nodeName))).cloneNode(); + return html5.shivMethods && node.canHaveChildren && !reSkip.test(nodeName) ? frag.appendChild(node) : node; + }; + + ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' + + 'var n=f.cloneNode(),c=n.createElement;' + + 'h.shivMethods&&(' + + // unroll the `createElement` calls + getElements().join().replace(/\w+/g, function(nodeName) { + cache[nodeName] = docCreateElement(nodeName); + frag.createElement(nodeName); + return 'c("' + nodeName + '")'; + }) + + ');return n}' + )(html5, frag); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Shivs the given document. + * @memberOf html5 + * @param {Document} ownerDocument The document to shiv. + * @returns {Document} The shived document. + */ + function shivDocument(ownerDocument) { + var shived; + if (ownerDocument.documentShived) { + return ownerDocument; + } + if (html5.shivCSS && !supportsHtml5Styles) { + shived = !!addStyleSheet(ownerDocument, + // corrects block display not defined in IE6/7/8/9 + 'article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}' + + // corrects audio display not defined in IE6/7/8/9 + 'audio{display:none}' + + // corrects canvas and video display not defined in IE6/7/8/9 + 'canvas,video{display:inline-block;*display:inline;*zoom:1}' + + // corrects 'hidden' attribute and audio[controls] display not present in IE7/8/9 + '[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}' + + // adds styling not present in IE6/7/8/9 + 'mark{background:#FF0;color:#000}' + ); + } + if (!supportsUnknownElements) { + shived = !shivMethods(ownerDocument); + } + if (shived) { + ownerDocument.documentShived = shived; + } + return ownerDocument; + } + + /*--------------------------------------------------------------------------*/ + + /** + * The `html5` object is exposed so that more elements can be shived and + * existing shiving can be detected on iframes. + * @type Object + * @example + * + * // options can be changed before the script is included + * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false }; + */ + var html5 = { + + /** + * An array or space separated string of node names of the elements to shiv. + * @memberOf html5 + * @type Array|String + */ + 'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video', + + /** + * A flag to indicate that the HTML5 style sheet should be inserted. + * @memberOf html5 + * @type Boolean + */ + 'shivCSS': !(options.shivCSS === false), + + /** + * A flag to indicate that the document's `createElement` and `createDocumentFragment` + * methods should be overwritten. + * @memberOf html5 + * @type Boolean + */ + 'shivMethods': !(options.shivMethods === false), + + /** + * A string to describe the type of `html5` object ("default" or "default print"). + * @memberOf html5 + * @type String + */ + 'type': 'default', + + // shivs the document according to the specified `html5` object options + 'shivDocument': shivDocument + }; + + /*--------------------------------------------------------------------------*/ + + // expose html5 + window.html5 = html5; + + // shiv the document + shivDocument(document); + + }(this, document)); + + //>>END IEPP + + // Assign private properties to the return object with prefix + Modernizr._version = version; + + // expose these for the plugin API. Look in the source for how to join() them against your input + Modernizr._prefixes = prefixes; + Modernizr._domPrefixes = domPrefixes; + Modernizr._cssomPrefixes = cssomPrefixes; + + // Modernizr.mq tests a given media query, live against the current state of the window + // A few important notes: + // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false + // * A max-width or orientation query will be evaluated against the current state, which may change later. + // * You must specify values. Eg. If you are testing support for the min-width media query use: + // Modernizr.mq('(min-width:0)') + // usage: + // Modernizr.mq('only screen and (max-width:768)') + Modernizr.mq = testMediaQuery; + + // Modernizr.hasEvent() detects support for a given event, with an optional element to test on + // Modernizr.hasEvent('gesturestart', elem) + Modernizr.hasEvent = isEventSupported; + + // Modernizr.testProp() investigates whether a given style property is recognized + // Note that the property names must be provided in the camelCase variant. + // Modernizr.testProp('pointerEvents') + Modernizr.testProp = function(prop){ + return testProps([prop]); + }; + + // Modernizr.testAllProps() investigates whether a given style property, + // or any of its vendor-prefixed variants, is recognized + // Note that the property names must be provided in the camelCase variant. + // Modernizr.testAllProps('boxSizing') + Modernizr.testAllProps = testPropsAll; + + + + // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards + // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... }) + Modernizr.testStyles = injectElementWithStyles; + + + // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input + // Modernizr.prefixed('boxSizing') // 'MozBoxSizing' + + // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style. + // Return values will also be the camelCase variant, if you need to translate that to hypenated style use: + // + // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-'); + + // If you're trying to ascertain which transition end event to bind to, you might do something like... + // + // var transEndEventNames = { + // 'WebkitTransition' : 'webkitTransitionEnd', + // 'MozTransition' : 'transitionend', + // 'OTransition' : 'oTransitionEnd', + // 'msTransition' : 'MsTransitionEnd', + // 'transition' : 'transitionend' + // }, + // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ]; + + Modernizr.prefixed = function(prop, obj, elem){ + if(!obj) { + return testPropsAll(prop, 'pfx'); + } else { + // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame' + return testPropsAll(prop, obj, elem); + } + }; + + + + // Remove "no-js" class from <html> element, if it exists: + docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') + + + // Add the new classes to the <html> element. + (enableClasses ? ' js ' + classes.join(' ') : ''); + + return Modernizr; + +})(this, this.document); diff --git a/apps/tal/js/tal.js b/apps/tal/js/tal.js new file mode 100644 index 00000000000..c4c64694404 --- /dev/null +++ b/apps/tal/js/tal.js @@ -0,0 +1,32 @@ + +$(document).ready(function(){ + $('#manual nav').keydown(function(event) { + if(event.which == 13) { + $('#manual ol').click(); + } + }); + $('#manual nav').click(function(event){ + var $tgt = $(event.target); + if ($tgt.is('li') || $tgt.is('a')) { + var item = $tgt.is('li')?$($tgt):($tgt).parent(); + var section = $('#manual section'); + var id = item.data('id'); + item.addClass('active'); + var oldpage = section.data('id'); + if(oldpage){ + $('#manual li[data-id="'+oldpage+'"]').removeClass('active'); + } + $.getJSON(OC.filePath('tal', 'ajax', 'loadpage.php'),{'id':id},function(jsondata){ + if(jsondata.status == 'success'){ + $('#manual li[data-id="'+id+'"]').addClass('active'); + section.replaceWith(jsondata.data.page); + section.data('id', id); + } + else{ + OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + } + }); + } + return false; + }); +});
\ No newline at end of file diff --git a/apps/tal/lib/paths.php b/apps/tal/lib/paths.php new file mode 100644 index 00000000000..b61d52c0f47 --- /dev/null +++ b/apps/tal/lib/paths.php @@ -0,0 +1,13 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * This class provides TAL templates for owncloud. + */ +class OC_TALTemplate extends OC_Template { +}
\ No newline at end of file diff --git a/apps/tal/lib/tall10n.php b/apps/tal/lib/tall10n.php new file mode 100644 index 00000000000..81ebfe49041 --- /dev/null +++ b/apps/tal/lib/tall10n.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +//require_once 'PHPTAL/TranslationService.php'; + + +class OC_TALL10N extends OC_L10N implements PHPTAL_TranslationService { + private $encoding = 'UTF-8'; + private $vars = array(); + //private $lang = ''; + //private $app = ''; + + /** + * @brief The constructor + * @param $app the app requesting l10n + * @param $lang default: null Language + * @returns OC_L10N-Object + * + * If language is not set, the constructor tries to find the right + * language. + */ + public function __construct($app, $lang = null){ + //$this->app = $app; + //$this->lang = $lang; + parent::__construct($app, $lang); + } + + /** + * Set the target language for translations. + * @return string - chosen language + */ + function setLanguage(/*...*/) { + $langs = func_get_args(); + $this->language = $langs[0]; + } + + /** + * PHPTAL will inform translation service what encoding page uses. + * Output of translate() must be in this encoding. + * NOTE: Currently not used (and probably won't be as we use utf-8 all over?). + */ + function setEncoding($encoding) { + $this->encoding = $encoding; + } + + /** + * Set the domain to use for translations (if different parts of application are translated in different files. This is not for language selection). + */ + function useDomain($domain) { + if(!$domain) { + return; + } + error_log('useDomain: '.$domain); + $this->app = $domain; + $this->init(); + } + + /** + * Set value of a variable used in translation key. + * + * You should use it to replace all {key}s with values in translated strings. + * + * @param string $key - name of the variable + * @param string $value + */ + public function setVar($key, $value) { + error_log('setVar: '.$key.'=>'.$value); + $this->vars[$key] = $value; + } + + /** + * Translate a gettext key and interpolate variables. + * + * @param string $key - translation key, e.g. "hello {username}!" + * @param string $htmlescape - if true, you should HTML-escape translated string. You should never HTML-escape interpolated variables. + */ + function translate($key, $escape=true) { + $translations = $this->getTranslations(); + if (array_key_exists($key, $translations)) { + $v = $translations[$key]; + } else { + $v = $key; + } + + if ($escape) { + $v = htmlspecialchars($v); + } + + //while (preg_match('/\{(.*?)\}/sm', $v, $m)) { + while (preg_match('/\$\{(.*?)\}/sm', $v, $m)) { + list($src, $var) = $m; + if (!isset($this->vars[$var])) { + $v = str_replace($src, 'undefined', $v); + } else { + $v = str_replace($src, $this->vars[$var], $v); + } + } + return $v; + } +}
\ No newline at end of file diff --git a/apps/tal/lib/taltemplate.php b/apps/tal/lib/taltemplate.php new file mode 100644 index 00000000000..523e857e6f2 --- /dev/null +++ b/apps/tal/lib/taltemplate.php @@ -0,0 +1,372 @@ +<?php +/** + * kate: replace-tabs off; indent-mode Normal; keep-extra-spaces: off; tab-indents: on; + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +function phptal_tales_remote($exp, $nothrow) { + //$exp = trim($exp, ' \t\r\n/'); + error_log(phptal_tales($exp, $nothrow)); + return "OCP\Util::linkToRemote(".phptal_tales($exp, $nothrow).")"; +} + +function phptal_tales_url($src, $nothrow) { + //$exp = trim($exp, ' \t\r\n/'); + error_log(phptal_tales($src, $nothrow)); + return "OC_TALTemplate::linkToAbsolute(".phptal_tales($src, $nothrow).")"; +} + +function phptal_tales_linkto($src, $nothrow) { + return "OC_TALTemplate::linkTo(".phptal_tales($src, $nothrow).")"; +} + +function phptal_tales_image($src, $nothrow) { + return "OC_TALTemplate::imagePath(".phptal_tales($src, $nothrow).")"; +} + +function phptal_tales_config($src, $nothrow) { + return "OC_TALTemplate::config(".phptal_tales($src, $nothrow).")"; +} + +/** + * This class provides TAL templates for owncloud. + */ +class OC_TALTemplate extends OC_Template { + /** + */ + protected $_engine = null; + protected $scripts = Array(); + protected $styles = Array(); + protected $_headers = Array(); + protected $renderas; + protected static $app = ''; + + public function __construct($app, $name, $renderas = "") { + //if(defined('DEBUG') && DEBUG) { + ini_set('display_errors', true); + //} + $this->renderas = $renderas; + $this->i18n = new OC_TALL10N($app); + $this->setEngine(new PHPTAL()); + parent::__construct($app, $name, $renderas); + //$this->fetchHeadVars(); + self::$app = $app; + //$this->assign('application', $this->app); + $this->assign('i18n', $this->i18n); + $this->assign('user', OCP\User::getUser()); + $this->assign('appinfo', OCP\App::getAppInfo($app)); + $this->assign('appajaxpath', OC::$SERVERROOT.OC_App::getAppPath($app).'/ajax'); + $this->assign('appjspath', OC::$SERVERROOT.OC_App::getAppPath($app).'/js'); + $this->assign('apptemplatepath', OC::$SERVERROOT.OC_App::getAppPath($app).'/templates'); + if($renderas) { + $this->assign('maintemplate', OC_App::getAppPath('tal').'/templates/layout.'.$renderas.'.pt'); + if($renderas == 'user') { + $this->assign('requesttoken', OC_Util::callRegister()); + } + } + //$this->assign('styles', $this->styles); + $this->assign('core_styles', !empty(OC_Util::$core_styles)?'core.css':null); + $this->assign('core_scripts', !empty(OC_Util::$core_scripts)?'core.js':null); + $request = isset($_REQUEST)?$_REQUEST:array(); + $request['post'] = isset($_POST)?$_POST:array(); + $request['get'] = isset($_GET)?$_GET:array(); + $this->assign('request', $request); + $this->assign('server', $_SERVER); + $this->assign('webroot', OC::$WEBROOT); + $this->assign('theme', OC_Config::getValue('theme')); + + $apps_paths = array(); + foreach(OC_App::getEnabledApps() as $app){ + $apps_paths[$app] = OC_App::getAppWebPath($app); + } + $this->assign( 'apps_paths', str_replace('\\/', '/',json_encode($apps_paths)),false ); // Ugly unescape slashes waiting for better solution + + // Add the js files + $jsfiles = OC_TemplateLayout::findJavascriptFiles(OC_Util::$scripts); + + foreach($jsfiles as $info) { + $root = $info[0]; + $web = $info[1]; + $file = $info[2]; + $this->scripts[] = $web.'/'.$file; + } + $this->assign('scripts',$this->scripts); + + // Add the css files + $cssfiles = OC_TemplateLayout::findStylesheetFiles(OC_Util::$styles); + + foreach($cssfiles as $info) { + $root = $info[0]; + $web = $info[1]; + $file = $info[2]; + $paths = explode('/', $file); + + $in_root = false; + foreach(OC::$APPSROOTS as $app_root) { + if($root == $app_root['path']) { + $in_root = true; + break; + } + } + + if($in_root ) { + $app = $paths[0]; + unset($paths[0]); + $path = implode('/', $paths); + $this->styles[] = OC_Helper::linkTo($app, $path); + } + else { + $this->styles[] = $web.'/'.$file; + } + } + $this->assign('styles', $this->styles); + + } + + /** + * Plug in PHPTAL object into View + * + * @name setEngine + * @access public + * @param object PHPTAL $engine + */ + public function setEngine(PHPTAL $engine) { + $view = new OC_FilesystemView('/'.OC_User::getUser()); + if(!$view->file_exists('phptal')) { + $view->mkdir('phptal'); + } + $this->_engine = $engine; + $this->_engine->setPhpCodeDestination($view->getLocalFile('/phptal/')); + $this->_engine->setTemplateRepository($_SERVER['DOCUMENT_ROOT'].OCP\Util::linkTo(self::$app, 'templates')); + $this->_engine->set('this', $this); + $this->_engine->setOutputMode(PHPTAL::HTML5); + $this->_engine->setTranslator($this->i18n); + return $this; + } + + /** + * Forces reparsing of all templates all the time. It should be used only for testing and debugging. + * It's useful if you're testing pre filters or changing code of PHPTAL itself. + * WARNING: This slows down PHPTAL very much. Never enable this on production servers! + */ + public function setForceReparse() { + OCP\Util::writeLog('tal','ForceReparse is enabled!', OCP\Util::WARN); + $this->_engine->setForceReparse(); + } + + /** + * Get PHPTAL object from View + * + * @name getEngine + * @access public + */ + public function getEngine() { + return $this->_engine; + } + + /** + * Clone PHPTAL object + * + * @access public + */ + public function __clone() { + $this->_engine = clone $this->_engine; + } + + /** + * Display template + * + * @access protected + */ + protected function _run() { + $this->_engine->setTemplate(func_get_arg(0)); + try { + echo $this->_engine->execute(); + } catch (Exception $e) { + throw new Exception($e); + } + } + + /** + * @brief check Path For Template with and without $fext + * @param $path to check + * @param $name of the template file (without suffix) + * @param $fext formfactor extension + * @return bool true when found + * + * Will set $this->template and $this->path if there is a template at + * the specified $path + */ + protected function checkPathForTemplate($path, $name, $fext) { + if ($name =='') return false; + $template = null; + if( is_file( $path.$name.$fext.'.pt' )){ + $template = $path.$name.$fext.'.pt'; + }elseif( is_file( $path.$name.'.pt' )){ + $template = $path.$name.'.pt'; + } + //error_log('Template: '.$template); + if ($template) { + $this->template = $template; + $this->path = $path; + $this->_engine->template = $this->template; + $this->_engine->setTemplate($this->template); + return true; + } + return false; + } + + /** + * @brief Assign variables + * @param $key key + * @param $value value + * @param $sanitizeHTML Ignored, as values are always sanitized unless explicitly specified not to. + * @returns true + * + * This function assigns a variable. It can be accessed via TALES expressions or ${$key} in + * the template. + * + * If the key existed before, it will be overwritten + */ + public function assign( $key, $value, $sanitizeHTML=false ){ + $this->_engine->set($key, $value); + return true; + } + + /** + * @brief Add a custom element to the header + * @param string tag tag name of the element + * @param array $attributes array of attributes for the element + * @param string $text the text content for the element + */ + public function addHeader( $tag, $attributes, $text=''){ + $this->_headers[]=array('tag'=>$tag,'attributes'=>$attributes,'text'=>$text); + } + + /** + * @brief Prints the proceeded template + * @returns true/false + * + * This function proceeds the template and prints its output. + */ + public function printPage(){ + echo $this->fetchPage(); + } + + /** + * @brief Proceeds the template + * @returns content + * + * This function proceeds the template. If $this->renderas is set, it + * will produce a full page. + */ + public function fetchPage(){ + error_log('renderas: '.$this->renderas); + if($this->renderas) { + // Add custom headers + $this->assign('headers',array_merge($this->_headers, OC_Util::$headers)); + // Add navigation entry + $navigation = OC_App::getNavigation(); + $this->assign( "navigation", $navigation); + $this->assign( "settingsnavigation", OC_App::getSettingsNavigation()); + if(array_search(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false){ + $this->assign('bodyid','body-settings'); + }else{ + $this->assign('bodyid','body-user'); + } + foreach($navigation as $entry) { + if ($entry['active']) { + $this->assign( 'application', $entry['name'] ); + break; + } + } + } + //error_log('utilheaders'.print_r(array_merge($this->_headers, OC_Util::$headers), true)); + return $this->_engine->execute(); + } + + static function linkTo($src) { + //error_log('linkTo '.$src); + $parts = is_array($src)?$src:explode('/', rtrim($src, ' \t\r\n/')); + if($parts[0] == '') { + array_shift($parts); + return OCP\Util::linkTo('', implode('/', $parts)); + } elseif(count($parts) == 1) { + return OCP\Util::linkTo('', implode('/', $parts)); + } elseif(trim($parts[0] == 'core')) { + array_shift($parts); + return OCP\Util::linkTo('', implode('/', $parts)); + } else { // This should be an app. + return OCP\Util::linkTo(array_shift($parts), implode('/', $parts)); + } + } + + static function linkToAbsolute($src) { + //error_log('linkTo '.$src); + $parts = is_array($src)?$src:explode('/', rtrim($src, ' \t\r\n/')); + if($parts[0] == '') { + array_shift($parts); + return OCP\Util::linkToAbsolute('', implode('/', $parts)); + } elseif(count($parts) == 1) { + return OCP\Util::linkToAbsolute('', implode('/', $parts)); + } elseif(trim($parts[0] == 'core')) { + array_shift($parts); + return OCP\Util::linkToAbsolute('', implode('/', $parts)); + } else { // This should be an app. + return OCP\Util::linkToAbsolute(array_shift($parts), implode('/', $parts)); + } + } + + static function imagePath($src) { + //error_log('imagePath '.$src); + $parts = is_array($src)?$src:explode('/', rtrim($src, ' \t\r\n/')); + if($parts[0] == '') { + array_shift($parts); + return OCP\Util::imagePath('', implode('/', $parts)); + } elseif(count($parts) == 1) { + return OCP\Util::imagePath('', implode('/', $parts)); + } elseif(trim($parts[0] == 'core')) { + array_shift($parts); + return OCP\Util::imagePath('', implode('/', $parts)); + } else { // This should be an app. + return OCP\Util::imagePath(array_shift($parts), implode('/', $parts)); + } + } + + static function config($src) { + error_log('pref '.$src); + $parts = is_array($src)?$src:explode('/', rtrim($src, ' \t\r\n/')); + if(count($parts) < 2) { + throw new PHPTAL_Exception('Wrong argument count: config: takes no less than 2 arguments.'); + } else { + switch ($parts[0]) { + case 'sys': + return OCP\Config::getSystemValue($parts[1]); + break; + case 'app': + if(count($parts) == 2) { + return OCP\Config::getAppValue(self::app, $parts[1]); + } elseif(count($parts) == 3) { + return OCP\Config::getAppValue($parts[1], $parts[2]); + } else { + throw new PHPTAL_Exception('Wrong argument count: config:$app takes no more than 3 arguments.'); + } + break; + case 'user': + if(count($parts) == 2) { + return OCP\Config::getUserValue(OCP\User::getUser(), self::app, $parts[1]); + } elseif(count($parts) == 3) { + return OCP\Config::getUserValue(OCP\User::getUser(), $parts[1], $parts[2]); + } elseif(count($parts) == 4) { + return OCP\Config::getUserValue($parts[1], $parts[2], $parts[3]); + } else { + throw new PHPTAL_Exception('Wrong argument count: config: takes no more than 4 arguments.'); + } + break; + } + } + } +}
\ No newline at end of file diff --git a/apps/tal/settings.php b/apps/tal/settings.php new file mode 100644 index 00000000000..a4eeb333446 --- /dev/null +++ b/apps/tal/settings.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +OCP\JSON::checkLoggedIn(); +OCP\JSON::checkAppEnabled('tal'); + +$tmpl = new OC_TALTemplate('tal', 'settings'); +return $tmpl->fetchPage(); + +?> diff --git a/apps/tal/templates/layout.guest.pt b/apps/tal/templates/layout.guest.pt new file mode 100644 index 00000000000..884b44a582e --- /dev/null +++ b/apps/tal/templates/layout.guest.pt @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html metal:define-macro="page"> +<head> + <title>ownCloud</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="shortcut icon" href="/owncloud/core/img/favicon.png" tal:attributes="href string:${webroot}/core/img/favicon.png" /> + <link rel="apple-touch-icon-precomposed" href="/owncloud/core/img/favicon-touch.png" tal:attributes="href string:${webroot}/core/img/favicon-touch.png" /> + + <link rel="stylesheet" href="core.css" type="text/css" media="screen" tal:condition="php:OC_Util::$core_styles" tal:attributes="href php:OC_Helper::linkToRemote('core.css', false)" /> + + <tal:block tal:repeat="style styles"> + <link rel="stylesheet" href="/owncloud/core/css/styles.css" type="text/css" media="screen" tal:attributes="href style" /> + </tal:block> + <script type="text/javascript"> + var oc_webroot = '${webroot}'; + var oc_appswebroot = '${appswebroot}'; + </script> + + <script type="text/javascript" src="<?php echo OC_Helper::linkToRemote('core.js', false) ?>" tal:condition="php:OC_Util::$core_scripts" tal:attributes="src php:OC_Helper::linkToRemote('core.js', false)"></script> + + <tal:block tal:repeat="script scripts"> + <script type="text/javascript" tal:attributes="src script"></script> + </tal:block> + + <tal:block tal:repeat="header headers"> + <tal:block tal:replace='structure string:<${header/tag}' /> <tal:block tal:repeat="attribute header/attributes"><tal:block tal:replace='structure string:${repeat/attribute/key}="${attribute}"' /></tal:block> /> + </tal:block> +</head> + +<body id="body-login"> + <div id="login"> + <header> + <div id="header"> + <img src="/owncloud/core/img/logo.png" alt="ownCloud" tal:attributes="href string:${webroot}/core/img/logo.png" /> + </div> + </header> + <div id="content" metal:define-slot="content"> + This is the content. + </div> + </div> + <footer><p class="info"><a href="http://owncloud.org/" i18n:translate="">ownCloud</a> – web services under your control</p></footer> +</body> +</html> diff --git a/apps/tal/templates/layout.user.pt b/apps/tal/templates/layout.user.pt new file mode 100644 index 00000000000..a945e1af7a2 --- /dev/null +++ b/apps/tal/templates/layout.user.pt @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html metal:define-macro="page"> +<head> + <title tal:define="pretitle php:(!empty(application)) ? application . ' | ' : null" tal:content="string:${pretitle} ownCloud (${user}@${server/SERVER_NAME})"> + Scripts and Styles + </title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <link rel="shortcut icon" href="/owncloud/core/img/favicon.png" tal:attributes="href string:${webroot}/core/img/favicon.png" /> + <link rel="apple-touch-icon-precomposed" href="favicon-touch.png" tal:attributes="href string:${webroot}/core/img/favicon-touch.png" /> + + <link rel="stylesheet" href="core.css" type="text/css" media="screen" tal:condition="core_styles" tal:attributes="href remote:core_styles" /> + <tal:block tal:repeat="style styles"> + <link rel="stylesheet" href="/owncloud/core/css/styles.css" type="text/css" media="screen" tal:attributes="href style" /> + </tal:block> + + <script type="text/javascript"> + var oc_webroot = '${webroot}'; + var oc_appswebroots = ${structure apps_paths}; + var oc_current_user = '${user}'; + </script> + + <script type="text/javascript" src="core.js" tal:condition="core_scripts" tal:attributes="src remote:core_scripts"></script> + <tal:block tal:repeat="script scripts"> + <script type="text/javascript" tal:attributes="src script"></script> + </tal:block> + + <script type="text/javascript"> + $(function() { + requesttoken = '${requesttoken}'; + $(document).bind('ajaxSend', function(elm, xhr, s){ + if(requesttoken) { + xhr.setRequestHeader('requesttoken', requesttoken); + } + }); + }); + </script> + + <tal:block tal:repeat="header headers"> + <tal:block tal:replace='structure string:${header/tag}' /> <tal:block tal:repeat="attribute header/attributes"><tal:block tal:replace='structure string:${repeat/attribute/key}="${attribute}"' /></tal:block> /> + </tal:block> +</head> +<body tal:attributes="id bodyid"> +<header> + <div id="header" tal:define="index linkto:string:/index.php"> + <a id="owncloud" tal:attributes="href index"><img class="svg" tal:attributes="src image:string:logo-wide.svg" src="logo-wide.svg" alt="ownCloud" /></a> + <a class="header-right header-action" id="logout" tal:attributes="href string:${index}?logout=true"><img class="svg" tal:attributes="src image:string:/actions/logout.svg" i18n:attributes="alt;title" alt="Log out" title="Log out" src="actions/logout.svg" /></a> + <form class="searchbox header-right" action="#" method="post"> + <input id="searchbox" class="svg" type="search" name="query" tal:attributes="value request/post/query|nothing" value="" autocomplete="off" /> + </form> + </div> +</header> + +<nav i18n:domain="core"> + <div id="navigation"> + <ul id="apps" class="svg"> + <li tal:repeat="entry navigation"> + <a tal:attributes="style structure string:background-image:url(${entry/icon});href entry/href;class php:entry['active']?'active':null" tal:content="entry/name">Name</a> + </li> + </ul> + + <ul id="settings" class="svg"> + <img role="button" tabindex="0" id="expand" class="svg" + i18n:attributes="alt Settings" alt="Settings" tal:attributes="src image:string:/actions/settings.svg" src="actions/settings.svg" /> + <span i18n:translate="">Settings</span> + <div id="expanddiv" + tal:attributes="class structure php:bodyid EQ 'body-user' ? 'hidden' : nothing"> + <li tal:repeat="entry settingsnavigation"> +<a tal:attributes="style structure string:background-image:url(${entry/icon});href entry/href;class entry/active|nothing" tal:content="entry/name">Name</a></li> + </div> + </ul> + </div> +</nav> + +<div id="content" metal:define-slot="content"> + This is the content. +</div> +</body> +</html>
\ No newline at end of file diff --git a/apps/tal/templates/macros.util.pt b/apps/tal/templates/macros.util.pt new file mode 100644 index 00000000000..0e8c590e0e6 --- /dev/null +++ b/apps/tal/templates/macros.util.pt @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html> +<head> + <title> + Utility macros + </title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +</head> +<body tal:attributes="id bodyid"> +<header> + <div id="header" tal:define="index php:OCP\Util::linkTo('', 'index.php')"> + <a id="owncloud" tal:attributes="href index"><img class="svg" tal:attributes="src php:OCP\Util::imagePath('', 'logo-wide.svg')" src="logo-wide.svg" alt="ownCloud" /></a> + <form class="searchbox" action="#" method="post"> + <input id="searchbox" class="svg" type="search" name="query" tal:attributes="value request/post/query|nothing" value="" autocomplete="off" /> + </form> + <a id="logout" tal:attributes="href string:${index}?logout=true"><img class="svg" tal:attributes="src php:OCP\Util::imagePath('', 'actions/logout.svg')" i18n:attributes="alt Log out;title Log out" alt="Log out" title="Log out" src="actions/logout.svg" /></a> + </div> +</header> +<body> +<tal:block metal:define-macro="html_select_options"> + <tal:block condition="options"> + <tal:block tal:define="options php:isset('combine') AND array_combine(options, options) OR options" repeat="option options"> + <option tal:content="option" tal:attributes></option> + </tal:block> + </tal:block> +</tal:block> +function html_select_options($options, $selected, $params=array()) { + if (!is_array($selected)){ + $selected=array($selected); + } + if (isset($params['combine']) && $params['combine']){ + $options = array_combine($options, $options); + } + $value_name = $label_name = false; + if (isset($params['value'])){ + $value_name = $params['value']; + } + if (isset($params['label'])){ + $label_name = $params['label']; + } + $html = ''; + foreach($options as $value => $label){ + if ($value_name && is_array($label)){ + $value = $label[$value_name]; + } + if ($label_name && is_array($label)){ + $label = $label[$label_name]; + } + $select = in_array($value, $selected) ? ' selected="selected"' : ''; + $html .= '<option value="' . $value . '"' . $select . '>' . $label . '</option>'."\n"; + } + return $html; +} + +</body> +</html>
\ No newline at end of file diff --git a/apps/tal/templates/manual.pt b/apps/tal/templates/manual.pt new file mode 100644 index 00000000000..9ad03db30be --- /dev/null +++ b/apps/tal/templates/manual.pt @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html metal:use-macro="${maintemplate}/page"> +<head> + <title>TAL Page Templates</title> +</head> +<body> +<div id="content" metal:fill-slot="content"> + <article id="manual" i18n:domain="tal" tal:define="page page|string:intro"> + <nav> + <ol> + <li tal:repeat="section sections" tal:attributes="data-id section/id" data-page="intro"> + <a tal:content="section/title">Introduction</a> + </li> + </ol> + </nav> + <section metal:use-macro="sections.pt/${page}"> + <h1>Manual</h1> + rest of the content + </section> + </article> +</div> +</body> +</html>
\ No newline at end of file diff --git a/apps/tal/templates/sections.pt b/apps/tal/templates/sections.pt new file mode 100644 index 00000000000..9dcda6ebf45 --- /dev/null +++ b/apps/tal/templates/sections.pt @@ -0,0 +1,142 @@ +<span metal:use-macro="${id}"> +TRUT +</span> +<section data-id="intro" metal:define-macro="intro"> + <h1>Introduction</h1> + <h2>Initializing a template</h2> + <strong>Before:</strong> + <pre>$output = new OCP\Template('app', 'template', 'user');</pre> + <strong>After:</strong> + <pre>$tmpl = new OC_TALTemplate('app', 'template', 'user');</pre> + <h2>Assigning a variable</h2> + <strong>Before:</strong> + <pre>$tmpl->assign('myvar', $myvar);</pre> + <strong>After:</strong> + <pre>$tmpl->assign('myvar', $myvar);</pre> + The sharp minds may have noticed that there is no difference ;-) + <h2>Linking to an image</h2> + <strong>Before:</strong> + <pre> +<img class="svg" src="<?php echo image_path('', 'logo-wide.svg'); ?>" alt="ownCloud" /> +<img class="svg" src="<?php echo image_path('app', 'someimage.png'); ?>" alt="ownCloud" /></pre> + <strong>After:</strong> + <pre> +<img class="svg" tal:attributes="src image:string:logo-wide.svg" alt="ownCloud" /> +<img class="svg" tal:attributes="src image:string:app/someimage.png" alt="ownCloud" /></pre> + <h2>Constructing a link</h2> + <strong>Before:</strong> + <pre> +<a href="<?php echo link_to('', 'index.php'); ?>">Home</a> +<a href="<?php echo link_to('app', 'index.php'); ?>">Some app</a></pre> + <strong>After:</strong> + <pre> +<a tal:attributes="href linkto:string:index.php">Home</a> +<a tal:attributes="href linkto:string:app/index.php">Some app</a></pre> + <h2>Link to remote service</h2> + <strong>Before:</strong> + <pre> +<link rel="stylesheet" href="<?php echo OC_Helper::linkToRemote('core.css') ?>" type="text/css" media="screen" /> +<a href="<?php echo OC_Helper::linkToRemote('webdav') ?>">WebDAV</a></pre> + <strong>After:</strong> + <pre> +<link rel="stylesheet" type="text/css" media="screen" tal:attributes="href remote:string:core.css" /> +<a tal:attributes="href remote:string:webdav">WebDAV</a></pre> + <p>The latter produces a link to the WebDAV service on the current instance: + <a tal:attributes="href remote:string:webdav">WebDAV</a></p> + <h2>Accessing configuration</h2> + <strong>Before:</strong> + <pre> +ownCloud version: <?php echo OCP\Config::getSystemValue('version'); ?> +Default quota: <?php echo OCP\Config::getAppValue('files', 'default_quota'); ?> +Calendar time zone: <?php echo OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone'); ?></pre> + <strong>After:</strong> + <pre> +ownCloud version: $${config:string:sys/version} +Default quota: $${config:string:app/files/default_quota} +Calendar time zone: $${config:string:user/calendar/timezone}</pre> + ownCloud version: ${config:string:sys/version}<br /> + Default quota: ${config:string:app/files/default_quota}<br /> + Calendar time zone: ${config:string:user/calendar/timezone}<br /> + <h2>Translating content</h2> + <strong>Before:</strong> + <pre><p><?php echo $l->t('This will be translated.'); ?><p></pre> + <strong>After:</strong> + <pre><p i18n:translate="">This will be translated.<p></pre> + <a class="readmore" href="http://phptal.org/manual/en/split/i18n-content.html" target="_blank">Read more...</a> + <h2>Translating content with variables</h2> + <strong>Before:</strong> + <p>There is no standardized way to do this currently. I have seen both translation keys using printf formatting + and custom interpolation using e.g. curly brackets.</p> + <strong>After:</strong> + <pre> +<tal:block i18n:name="username" tal:content="user" /> +<p i18n:translate="">Your user name is ${username}.</p></pre> + <tal:block i18n:name="username" tal:content="user" /> + <p i18n:translate="">Your user name is ${username}.</p> + <p>Or you can wrap it in some markup:</p> + <pre> +<p i18n:translate=""> +Welcome back <span i18n:name="username" tal:replace="user"/>. +</p></pre> + <p i18n:translate=""> + Welcome back <span i18n:name="username" tal:replace="user"/>. + </p> + <a class="readmore" href="http://phptal.org/manual/en/split/i18n-name.html" target="_blank">Read more...</a> + <h2>Translating attributes.</h2> + <strong>Before:</strong> + <pre><img alt="<?php echo $l->t('Log out');?>" title="<?php echo $l->t('Log out');?>" src="<?php echo image_path('', 'actions/logout.svg'); ?>" /></pre> + <strong>After:</strong> + <pre><img tal:attributes="src image:string:/actions/logout.svg" i18n:attributes="alt;title" alt="Log out" title="Log out" /></pre> + <a href="http://phptal.org/manual/en/split/i18n-attributes.html" target="_blank">See more...</a> + <h2>Iterating</h2> + <pre> +$$arr = array('color' => 'red', + 'taste' => 'sweet', + 'shape' => 'round', + 'name' => 'apple'); + </pre> + <strong>Before:</strong> + <pre> +<select size="4"> +<?php foreach($$arr as $key=>$value) { ?> +<option value="<php echo $key; >" ><php echo $value; ></option> +</select> +<?php } ?></pre> + <strong>After:</strong> + <pre> +<select size="4"> +<option tal:repeat="item arr" tal:attributes="value repeat/item/key" tal:content="item"></option> +</select></pre> + <form> + <select size="4" tal:define="arr php:array('color' => 'red', 'taste' => 'sweet', 'shape' => 'round', 'name' => 'apple')"> + <option tal:repeat="item arr" tal:attributes="value repeat/item/key" tal:content="item"></option> + </select> + </form> + <a class="readmore" href="http://phptal.org/manual/en/split/tal-repeat.html" target="_blank">Read more...</a> + <h2>Initializing a template</h2> + <strong>Before:</strong> + <pre></pre> + <strong>After:</strong> + <pre></pre> +</section> +<section data-id="example-1" metal:define-macro="example-1"> + <h1>A simple example</h1> + This is actually the main template for this manual. + <pre tal:define="dut php:file_get_contents(apptemplatepath . '/manual.pt')" tal:content="dut"> + </pre> +</section> +<section data-id="gotchas" metal:define-macro="gotchas"> + <h1>Caveats & Gotchas</h1> + I know +</section> +<section data-id="ref" metal:define-macro="ref"> + <h1>References</h1> + <dl> + <dt><a href="http://phptal.org/" target="_blank">PHPTAL</a></dt><dd>The PHP TAL implementation</dd> + <dt><a href="http://phptal.org/manual/en/split/tal-namespace.html" target="_blank">TAL</a></dt><dd>Template Attribute Language</dd> + <dt><a href="http://phptal.org/manual/en/split/phptales.html" target="_blank">TALES</a></dt><dd>TAL Expression Syntax</dd> + <dt><a href="http://phptal.org/manual/en/split/metal.html" target="_blank">METAL</a></dt><dd>Macro Expansion Template Attribute Language</dd> + <dt><a href="http://phptal.org/manual/en/split/i18n.html" target="_blank">i18n namespace</a></dt><dd>Internationalization in TAL</dd> + <dt><a href="http://phptal.org/wiki/doku.php/zopepagetemplates" target="_blank">Zope Page Templates</a></dt><dd>Links and specifications from the original TAL implementation</dd> + </dl> +</section> diff --git a/apps/tal/templates/settings.pt b/apps/tal/templates/settings.pt new file mode 100644 index 00000000000..1ae6eea9e7f --- /dev/null +++ b/apps/tal/templates/settings.pt @@ -0,0 +1,10 @@ +<form id="tal"> + <fieldset class="personalblock"> + <legend i18n:translate="">TAL Page Templates for ownCloud</legend> + <p i18n:translate="">You can now create templates using TAL. As a matter of fact this section is using the internationalization namespace defined in TAL.<br /> + Read more about it from the links below</p> + <ul> + <li><a href="" tal:attributes="href php:OCP\Util::linkTo('tal', 'index.php')" i18n:translate="">HOWTO use it in ownCloud</a></li> + </ul> + </fieldset> +</form> |