aboutsummaryrefslogtreecommitdiffstats
path: root/apps/tal
diff options
context:
space:
mode:
Diffstat (limited to 'apps/tal')
-rw-r--r--apps/tal/.gitignore51
-rw-r--r--apps/tal/COPYING-AGPL661
-rw-r--r--apps/tal/COPYING-README10
-rw-r--r--apps/tal/README.md26
-rw-r--r--apps/tal/TODO2
-rw-r--r--apps/tal/ajax/loadpage.php23
-rw-r--r--apps/tal/appinfo/app.php11
-rw-r--r--apps/tal/appinfo/info.xml11
-rw-r--r--apps/tal/css/tal.css25
-rw-r--r--apps/tal/index.php30
-rw-r--r--apps/tal/js/modernizr.js1265
-rw-r--r--apps/tal/js/tal.js32
-rw-r--r--apps/tal/lib/paths.php13
-rw-r--r--apps/tal/lib/tall10n.php105
-rw-r--r--apps/tal/lib/taltemplate.php372
-rw-r--r--apps/tal/settings.php16
-rw-r--r--apps/tal/templates/layout.guest.pt43
-rw-r--r--apps/tal/templates/layout.user.pt78
-rw-r--r--apps/tal/templates/macros.util.pt56
-rw-r--r--apps/tal/templates/manual.pt23
-rw-r--r--apps/tal/templates/sections.pt142
-rw-r--r--apps/tal/templates/settings.pt10
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 &shy; so use xml friendly encoded version. See issue #277
+ style = ['&#173;','<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> &ndash; 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>
+&lt;img class="svg" src="&lt;?php echo image_path('', 'logo-wide.svg'); ?&gt;" alt="ownCloud" /&gt;
+&lt;img class="svg" src="&lt;?php echo image_path('app', 'someimage.png'); ?&gt;" alt="ownCloud" /&gt;</pre>
+ <strong>After:</strong>
+ <pre>
+&lt;img class="svg" tal:attributes="src image:string:logo-wide.svg" alt="ownCloud" /&gt;
+&lt;img class="svg" tal:attributes="src image:string:app/someimage.png" alt="ownCloud" /&gt;</pre>
+ <h2>Constructing a link</h2>
+ <strong>Before:</strong>
+ <pre>
+&lt;a href="&lt;?php echo link_to('', 'index.php'); ?&gt;"&gt;Home&lt;/a&gt;
+&lt;a href="&lt;?php echo link_to('app', 'index.php'); ?&gt;"&gt;Some app&lt;/a&gt;</pre>
+ <strong>After:</strong>
+ <pre>
+&lt;a tal:attributes="href linkto:string:index.php"&gt;Home&lt;/a&gt;
+&lt;a tal:attributes="href linkto:string:app/index.php"&gt;Some app&lt;/a&gt;</pre>
+ <h2>Link to remote service</h2>
+ <strong>Before:</strong>
+ <pre>
+&lt;link rel="stylesheet" href="&lt;?php echo OC_Helper::linkToRemote('core.css') ?&gt;" type="text/css" media="screen" /&gt;
+&lt;a href="&lt;?php echo OC_Helper::linkToRemote('webdav') ?&gt;"&gt;WebDAV&lt;/a&gt;</pre>
+ <strong>After:</strong>
+ <pre>
+&lt;link rel="stylesheet" type="text/css" media="screen" tal:attributes="href remote:string:core.css" /&gt;
+&lt;a tal:attributes="href remote:string:webdav"&gt;WebDAV&lt;/a&gt;</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: &lt;?php echo OCP\Config::getSystemValue('version'); ?&gt;
+Default quota: &lt;?php echo OCP\Config::getAppValue('files', 'default_quota'); ?&gt;
+Calendar time zone: &lt;?php echo OCP\Config::getUserValue(OCP\User::getUser(), 'calendar', 'timezone'); ?&gt;</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>&lt;p&gt;&lt;?php echo $l-&gt;t('This will be translated.'); ?&gt;&lt;p&gt;</pre>
+ <strong>After:</strong>
+ <pre>&lt;p i18n:translate=""&gt;This will be translated.&lt;p&gt;</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>
+&lt;tal:block i18n:name="username" tal:content="user" /&gt;
+&lt;p i18n:translate=""&gt;Your user name is &#36;{username}.&lt;/p&gt;</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>
+&lt;p i18n:translate=""&gt;
+Welcome back &lt;span i18n:name="username" tal:replace="user"/&gt;.
+&lt;/p&gt;</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>&lt;img alt="&lt;?php echo $l->t('Log out');?&gt;" title="&lt;?php echo $l-&gt;t('Log out');?&gt;" src="&lt;?php echo image_path('', 'actions/logout.svg'); ?&gt;" /&gt;</pre>
+ <strong>After:</strong>
+ <pre>&lt;img tal:attributes="src image:string:/actions/logout.svg" i18n:attributes="alt;title" alt="Log out" title="Log out" /&gt;</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>
+&lt;select size="4"&gt;
+&lt;?php foreach($$arr as $key=&gt;$value) { ?&gt;
+&lt;option value="&lt;php echo $key; &gt;" &gt;&lt;php echo $value; &gt;&lt;/option&gt;
+&lt;/select&gt;
+&lt;?php } ?&gt;</pre>
+ <strong>After:</strong>
+ <pre>
+&lt;select size="4"&gt;
+&lt;option tal:repeat="item arr" tal:attributes="value repeat/item/key" tal:content="item"&gt;&lt;/option&gt;
+&lt;/select&gt;</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 &amp; 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>