version 0.2
|
|
@ -0,0 +1,3 @@
|
|||
RewriteEngine on
|
||||
RewriteCond $1 !^(index\.php|phpdoc|skin|asset|plugin|favicon\.ico|robots\.txt)
|
||||
RewriteRule ^(.*)$ /index.php/$1 [L]
|
||||
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 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 General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 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.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser 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
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
TaskFreak! Time Tracking
|
||||
------------------------
|
||||
version 0.2
|
||||
released on 2010-05-21
|
||||
------------------------
|
||||
|
||||
This is the first official release
|
||||
status : beta
|
||||
|
||||
Requirements
|
||||
------------
|
||||
- apache with mod_rewrite
|
||||
- PHP 5.3.x
|
||||
- mySQL 4.1 or later
|
||||
- a virtual host
|
||||
|
||||
v0.2 can not run under yourdomain.com/taskfreak, it has to be yourdomain.com
|
||||
|
||||
Setup
|
||||
-----
|
||||
1) Set up your virtual host
|
||||
2) create a mySQL database
|
||||
3) create tables and data with taskfreak_time.sql
|
||||
4) open app/config/db.php and change database settings
|
||||
|
||||
You can stop here and have a look.
|
||||
login is "admin" with no password
|
||||
|
||||
If you don't want multi user support, open app/config/core.php
|
||||
Search for APP_SETUP_USER_MODEL and set it up to false :
|
||||
[code]
|
||||
define('APP_SETUP_USER_MODEL',false);
|
||||
[/code]
|
||||
|
||||
If you feel like playing so more, open app/config/app.php and look into it
|
||||
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
-- phpMyAdmin SQL Dump
|
||||
-- version 3.3.1
|
||||
-- http://www.phpmyadmin.net
|
||||
--
|
||||
-- Host: localhost
|
||||
-- Generation Time: May 21, 2010 at 02:12 AM
|
||||
-- Server version: 5.0.67
|
||||
-- PHP Version: 5.3.0
|
||||
|
||||
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
|
||||
--
|
||||
-- Database: `taskfreak_timer`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `acl`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `acl`;
|
||||
CREATE TABLE `acl` (
|
||||
`id` mediumint(8) unsigned NOT NULL auto_increment,
|
||||
`name` varchar(127) NOT NULL,
|
||||
`section` varchar(63) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `acl`
|
||||
--
|
||||
|
||||
INSERT INTO `acl` VALUES(1, 'task_see_all', 'general');
|
||||
INSERT INTO `acl` VALUES(2, 'admin_user', 'general');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `acl_user`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `acl_user`;
|
||||
CREATE TABLE `acl_user` (
|
||||
`user_id` mediumint(8) unsigned NOT NULL,
|
||||
`acl_id` mediumint(8) unsigned NOT NULL,
|
||||
PRIMARY KEY (`user_id`,`acl_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `acl_user`
|
||||
--
|
||||
|
||||
INSERT INTO `acl_user` VALUES(1, 1);
|
||||
INSERT INTO `acl_user` VALUES(1, 2);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `member`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `member`;
|
||||
CREATE TABLE `member` (
|
||||
`id` int(10) unsigned NOT NULL auto_increment,
|
||||
`nickname` varchar(30) NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password` varchar(40) NOT NULL,
|
||||
`salt` varchar(40) NOT NULL,
|
||||
`auto_login` tinyint(1) unsigned NOT NULL,
|
||||
`time_zone` varchar(63) NOT NULL,
|
||||
`date_format_us` tinyint(1) NOT NULL default '0',
|
||||
`creation_date` datetime NOT NULL,
|
||||
`expiration_date` date NOT NULL,
|
||||
`last_login_date` datetime NOT NULL,
|
||||
`last_login_address` varchar(60) NOT NULL,
|
||||
`last_change_date` datetime NOT NULL,
|
||||
`visits` int(10) unsigned NOT NULL,
|
||||
`bad_access` smallint(5) unsigned NOT NULL,
|
||||
`activation` varchar(16) NOT NULL,
|
||||
`enabled` tinyint(1) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `member`
|
||||
--
|
||||
|
||||
INSERT INTO `member` VALUES(1, 'Administrator', '', 'admin', '', '12345678', 0, 'Asia/Bangkok', 0, '2010-05-21 01:43:21', '0000-00-00', '0000-00-00 00:00:00', '127.0.0.1', '0000-00-00 00:00:00', 0, 0, '', 1);
|
||||
INSERT INTO `member` VALUES(2, 'Emilie', '', 'emilie', '', '12345678', 0, 'Europe/Paris', 0, '2010-05-21 01:44:17', '0000-00-00', '0000-00-00 00:00:00', '127.0.0.1', '0000-00-00 00:00:00', 0, 0, '', 1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `task`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `task`;
|
||||
CREATE TABLE `task` (
|
||||
`id` int(10) unsigned NOT NULL auto_increment,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`note` text NOT NULL,
|
||||
`priority` tinyint(3) unsigned NOT NULL default '5',
|
||||
`begin` date NOT NULL,
|
||||
`deadline` date NOT NULL,
|
||||
`status` tinyint(3) unsigned NOT NULL,
|
||||
`archived` tinyint(3) unsigned NOT NULL,
|
||||
`member_id` mediumint(8) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `member_id` (`member_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `task`
|
||||
--
|
||||
|
||||
INSERT INTO `task` VALUES(1, 'taskfreak : README first about this beta version', 'Please keep in mind that this is an early beta version. There are quite a few known bugs, a handful of unknown bugs.\r\n\r\nHere''s what you can do so far :\r\n- create, edit and archive tasks\r\n- start and stop task timers\r\n- report time spent on a task\r\n- edit your own profile\r\n- see other''s tasks (task manager only)\r\n- create and edit users (user admin only)', 5, '9999-00-00', '2010-05-22', 0, 0, 1);
|
||||
INSERT INTO `task` VALUES(2, 'taskfreak : another quick notes about v0.2', 'There''s still some work to be done before TaskFreak Time Tracking goes stable.\r\n\r\nThis includes :\r\n- fix found bugs (obviously)\r\n- finish table prefix testing\r\n- add multi language support\r\n- Internet Explorer support (only tested on FireFox, Safari & Chrome)', 4, '9999-00-00', '9999-00-00', 0, 0, 1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `timer`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `timer`;
|
||||
CREATE TABLE `timer` (
|
||||
`task_id` int(10) unsigned NOT NULL,
|
||||
`start` datetime NOT NULL,
|
||||
`stop` datetime NOT NULL,
|
||||
`spent` int(10) unsigned NOT NULL,
|
||||
`manual` tinyint(3) unsigned NOT NULL,
|
||||
KEY `task_id` (`task_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Dumping data for table `timer`
|
||||
--
|
||||
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
// ---- LOG and DEBUGGING -----------------------------------------------------
|
||||
|
||||
$GLOBALS['config']['log_front'] = 0;
|
||||
$GLOBALS['config']['log_debug'] = 0;
|
||||
$GLOBALS['config']['log_message'] = 0;
|
||||
$GLOBALS['config']['log_warn'] = 0;
|
||||
$GLOBALS['config']['log_error'] = 1;
|
||||
$GLOBALS['config']['log_core'] = 0;
|
||||
|
||||
$GLOBALS['config']['log_signature'] = '[TF]';
|
||||
|
||||
// --- APPLICATION CONTOLLER, ACTION and PAGES---------------------------------
|
||||
|
||||
$GLOBALS['config']['app'] = array(
|
||||
'default_controller' => 'task',
|
||||
// default controller to call (home page)
|
||||
'default_action' => 'main'
|
||||
// default action to call (home page)
|
||||
);
|
||||
|
||||
$GLOBALS['config']['pages'] = array(
|
||||
'Todo' => 'task/main',
|
||||
'Report' => 'task/report',
|
||||
'Archives' => 'task/archives'
|
||||
);
|
||||
|
||||
// ---- LANGUAGE DEFAULTS -----------------------------------------------------
|
||||
|
||||
$GLOBALS['config']['lang'] = array(
|
||||
'default' => 'en',
|
||||
'user' => 'en',
|
||||
'specialchars' => 2
|
||||
);
|
||||
|
||||
// ---- DATE / TIME FORMATS ---------------------------------------------------
|
||||
|
||||
// date/time timezone and formats defaults
|
||||
$GLOBALS['config']['datetime'] = array(
|
||||
'timezone_server' => new DateTimeZone(APP_TIMEZONE_SERVER),
|
||||
'timezone_user' => new DateTimeZone(APP_TIMEZONE_SERVER),
|
||||
'us_format' => false,
|
||||
);
|
||||
$GLOBALS['config']['datetime']['now'] = new DateTime('now', $GLOBALS['config']['datetime']['timezone_server']);
|
||||
|
||||
// --- Specific DATE FORMATS -------------------------------------------------
|
||||
|
||||
define("APP_DATE","%d/%m");
|
||||
define("APP_DATETIME","%d/%m <small>%H:%M</small>");
|
||||
|
||||
// --- TASKFREAK DEFAULTS ---------------------------------------------------------
|
||||
|
||||
$GLOBALS['config']['task'] = array(
|
||||
'date' => APP_SQL_TODAY, // default date is today
|
||||
'validate' => true // add validation button
|
||||
);
|
||||
|
||||
$GLOBALS['config']['task']['priority'] = array(
|
||||
'options' => array(
|
||||
1 => '1) urgent',
|
||||
2 => '2) important',
|
||||
3 => '3) quickly',
|
||||
4 => '4) pretty soon',
|
||||
5 => '5) normal',
|
||||
6 => '6) after',
|
||||
7 => '7) later',
|
||||
8 => '8) anytime',
|
||||
9 => '9) whatever'
|
||||
),
|
||||
'default' => 5
|
||||
);
|
||||
|
||||
// ---- DEFAULT Javascript ----------------------------------------------------
|
||||
|
||||
$GLOBALS['config']['header']['js'] = array(
|
||||
'jquery-1.4.2.min.js',
|
||||
// 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js',
|
||||
);
|
||||
|
||||
|
||||
// ---- SKINS and Templates ---------------------------------------------------
|
||||
|
||||
$GLOBALS['config']['skin'] = 'default';
|
||||
|
||||
// ---- LANGUAGE --------------------------------------------------------------
|
||||
|
||||
$GLOBALS['config']['lang']['default'] = 'en';
|
||||
$GLOBALS['config']['lang']['user'] = 'en';
|
||||
$GLOBALS['config']['lang']['specialchars'] = 2;
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// --- APPLICATION SETUP ------------------------------------------------------
|
||||
|
||||
$GLOBALS['config'] = array();
|
||||
|
||||
// connect to database (see /app/config/db.php for settings)
|
||||
define('APP_SETUP_DATABASE', true);
|
||||
|
||||
// load global settings on startup (requires database)
|
||||
define('APP_SETUP_GLOBAL_SETTINGS', true);
|
||||
|
||||
// load user settings on startup (requires database and auth)
|
||||
define('APP_SETUP_USER_SETTINGS', false);
|
||||
|
||||
// use translation helper
|
||||
define('APP_SETUP_TRANSLATOR', false);
|
||||
|
||||
// use (trans-sessions) messaging helper
|
||||
define('APP_SETUP_MESSAGING', true);
|
||||
|
||||
// use navi helper
|
||||
define('APP_SETUP_NAVI', true);
|
||||
|
||||
// --- USER AUTHENTICATION SETUP ----------------------------------------------
|
||||
|
||||
// model class used for app users
|
||||
// (will load logged in user if not false)
|
||||
// see APP_AUTH_* below for other settings
|
||||
define('APP_SETUP_USER_MODEL','member');
|
||||
|
||||
// field used for authentication (usually username or email)
|
||||
define('APP_AUTH_FIELD', 'username');
|
||||
|
||||
// password encryption
|
||||
// 1: php crypt, 2:mySQL ENCRYPT, 3: mysql ENCODE, 4: MD5, 5: MD5 with challenge
|
||||
define('APP_AUTH_PASSWORD_MODE', 4);
|
||||
|
||||
// USER AUTHENTICATION DEFAULTS
|
||||
// following settings can be modified by global settings
|
||||
|
||||
$GLOBALS['config']['auth'] = array(
|
||||
'remember' => true,
|
||||
// allow auto login (true or false)
|
||||
'password_recover' => true,
|
||||
// allow password recovery (true or false)
|
||||
'register' => 2
|
||||
// register mode
|
||||
// 0: no registration, 1: account created directly (no validation)
|
||||
// 2: user validation (from email), 3: admin validate account
|
||||
);
|
||||
|
||||
// ---- FILE PATHs ------------------------------------------------------------
|
||||
|
||||
define('APP_ROOT_PATH',substr(dirname(__FILE__),0,-10));
|
||||
|
||||
define('APP_WWW_PATH',APP_ROOT_PATH);
|
||||
|
||||
define('APP_CORE_PATH',APP_ROOT_PATH.'app/');
|
||||
define('APP_CONFIG_PATH',APP_CORE_PATH.'config/');
|
||||
define('APP_MODEL_PATH',APP_CORE_PATH.'model/');
|
||||
define('APP_CONTROLLER_PATH',APP_CORE_PATH.'controller/');
|
||||
define('APP_VIEW_PATH',APP_CORE_PATH.'view/');
|
||||
|
||||
define('APP_INCLUDE_PATH', APP_ROOT_PATH);
|
||||
define('APP_CACHE_PATH',APP_INCLUDE_PATH.'cache/');
|
||||
define('APP_LIB_PATH',APP_INCLUDE_PATH.'lib/');
|
||||
define('APP_CLASS_PATH',APP_LIB_PATH.'class/');
|
||||
define('APP_HELPER_PATH',APP_LIB_PATH.'helper/');
|
||||
|
||||
define('APP_ASSET_PATH',APP_ROOT_PATH.'asset/');
|
||||
define('APP_LANGUAGE_PATH',APP_ASSET_PATH.'lang/');
|
||||
define('APP_PLUGIN_PATH',APP_ROOT_PATH.'plugin/');
|
||||
define('APP_SKIN_PATH',APP_ROOT_PATH.'skin/');
|
||||
|
||||
// ---- APPLICATION URLs ------------------------------------------------------
|
||||
|
||||
define('APP_WWW_URI', '/');
|
||||
|
||||
if (!defined('APP_WWW_URI')) {
|
||||
define('APP_WWW_URI',preg_replace('/^\/admin/','',dirname($_SERVER['PHP_SELF']))
|
||||
.(preg_match('/\/$/',dirname($_SERVER['PHP_SELF']))?'':'/'));
|
||||
}
|
||||
define('APP_WWW_URL','http://'.$_SERVER['SERVER_NAME'].APP_WWW_URI);
|
||||
|
||||
// ---- USER and PASSWORD SETTINGS --------------------------------------------
|
||||
|
||||
define('APP_USER_ID_LENGTH',8); // length of user ID
|
||||
define('APP_USER_SANITIZE','/^[a-z0-9_-]+$/i');
|
||||
define('APP_USER_NAME_MIN',4); // minimum length for username
|
||||
define('APP_USER_NAME_MAX',15); // maximum length for username
|
||||
define('APP_USER_PASS_MIN',4); // minimum length for password
|
||||
define('APP_USER_PASS_MAX',16); // maximum length for password
|
||||
define('APP_PASSWORD_SANITIZE','/^[a-z0-9%!@#&*+:;,<>\.\?\|\{\}\(\)\[\]\$_-]+$/i');
|
||||
|
||||
// ---- FILE UPLOAD Settings --------------------------------------------------
|
||||
|
||||
define('APP_FILE_SLASH','/');
|
||||
define('APP_FILE_RANDOM',false);
|
||||
define('APP_FILE_FOLDER_SIZE',300); // number of files per folder
|
||||
define('APP_FILE_GD_VERSION',2);
|
||||
define('APP_FILE_GD_QUALITY',80);
|
||||
|
||||
// ---- Default DATE/TIME FORMATs ---------------------------------------------
|
||||
|
||||
define("APP_DATE_SQL","%Y-%m-%d");
|
||||
define('APP_DATE_EUR', '%d/%m/%y');
|
||||
define('APP_DATE_USA', '%m/%d/%y');
|
||||
define("APP_DATE_SHT","%d %b %y"); // -TODO- %e bug
|
||||
define("APP_DATE_SHX","%a %e %b %y");
|
||||
define("APP_DATE_LNG","%d %B %Y");
|
||||
define("APP_DATE_LNX","%A %d %B %Y");
|
||||
define("APP_DATETIME_SQL","%Y-%m-%d %H:%M:%S");
|
||||
define("APP_DATETIME_EUR","%d/%m/%y %H:%M");
|
||||
define("APP_DATETIME_USA","%m/%d/%y %I:%M%p");
|
||||
define("APP_DATETIME_SHT","%d %b %y, %H:%M");
|
||||
define("APP_DATETIME_SHX","%a %d %b %y, %H:%M");
|
||||
define("APP_DATETIME_LNG","%d %B %Y, %H:%M");
|
||||
define("APP_DATETIME_LNX","%A %d %B %Y, %H:%M");
|
||||
define("APP_DATETIME_HRS","%H:%M");
|
||||
|
||||
// date_default_timezone_set('Europe/Paris');
|
||||
define('APP_TIMEZONE_SERVER',date_default_timezone_get());
|
||||
define('APP_TZSERVER',intval(date('Z')));
|
||||
// define('APP_TZSERVER',timezone_offset_get(new DateTimeZone(APP_TIMEZONE_SERVER), new DateTime()));
|
||||
|
||||
define('APP_SQL_NOW', gmdate('Y-m-d H:i:s'));
|
||||
define('APP_SQL_TODAY',substr(APP_SQL_NOW,0,10));
|
||||
define('APP_NOW',strtotime(APP_SQL_NOW));
|
||||
define('APP_TODAY',strtotime(APP_SQL_TODAY));
|
||||
define('APP_YEAR',substr(APP_SQL_TODAY,0,4));
|
||||
|
||||
// ---- MISC MODEL PROPERTIES Settings ----------------------------------------
|
||||
|
||||
define('APP_KEY_LENGTH',8);
|
||||
define('APP_KEY_STRING','ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
|
||||
|
||||
define('APP_SANITIZE_SIMPLE','/^[a-z0-9_-]+$/i');
|
||||
|
||||
|
||||
// ----- PHP SESSION Settings -------------------------------------------------
|
||||
|
||||
define('TZN_TRANS_ID',0);
|
||||
define('TZN_TRANS_STATUS',1);
|
||||
if (@constant('APP_TRANS_ID')) {
|
||||
ini_set("session.use_trans_sid",1);
|
||||
} else {
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
define('APP_DB_HOST','localhost');
|
||||
define('APP_DB_USER','root'); // edit here
|
||||
define('APP_DB_PASS',''); // edit here
|
||||
define('APP_DB_BASE','taskfreak_timer'); // edit here
|
||||
define('APP_DB_PREFIX','');
|
||||
define('APP_DB_PERMANENT', true);
|
||||
define('APP_DB_CONNECTOR','mysql');
|
||||
|
||||
define('APP_DB_CRITICAL', true); // exit on DB error
|
||||
|
||||
// DEBUG level :
|
||||
// 0 : nothing at all
|
||||
// 1 : use FC::log_error (on error only)
|
||||
// 2 : show error code in browser, the rest using FC::log_error (on error only)
|
||||
// 3 : show error and SQL query in browser (on error only) - useful in development
|
||||
// 4 : verbose : use FC::log_message (everything) - for debugging only
|
||||
// 5 : verbose : sends to browser (everything) - for heavy debugging only
|
||||
|
||||
define('APP_DB_DEBUG', 2);
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
// === PHP CLASS and SCRIPTS paths ============================================
|
||||
|
||||
$autoPath['class'] = array(
|
||||
APP_CLASS_PATH
|
||||
);
|
||||
$autoPath['helper'] = array(
|
||||
APP_HELPER_PATH
|
||||
);
|
||||
$autoPath['model'] = array(
|
||||
APP_CORE_PATH.'model/',
|
||||
APP_LIB_PATH.'model/'
|
||||
);
|
||||
$autoPath['controller'] = array(
|
||||
APP_CORE_PATH.'controller/',
|
||||
APP_CLASS_PATH
|
||||
);
|
||||
$autoPath['view'] = array(
|
||||
APP_CORE_PATH.'view/'
|
||||
);
|
||||
|
||||
// -TODO-
|
||||
// browse plugin directory to add other classes into the searched path
|
||||
|
||||
// === JS and CSS paths =======================================================
|
||||
|
||||
$GLOBALS['config']['path']['css'] = array(
|
||||
'skin/'.$GLOBALS['config']['skin'].'/css/',
|
||||
'asset/css/'
|
||||
);
|
||||
|
||||
$GLOBALS['config']['path']['js'] = array(
|
||||
$GLOBALS['config']['skin'].'/js/',
|
||||
'asset/js/'
|
||||
);
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Admin
|
||||
*
|
||||
* Administration pages
|
||||
* @since 0.2
|
||||
*/
|
||||
class Admin extends AppController {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(true);
|
||||
|
||||
$this->fc->setSessionDefault('userlimit',10);
|
||||
|
||||
if ($this->fc->getReqVar('ajax')) {
|
||||
$this->page->clean('css');
|
||||
$this->page->clean('js');
|
||||
} else {
|
||||
$this->page->add('css',array('form.css','freak.css','list.css','tracker.css','colorbox.css'));
|
||||
// $this->page->add('js',array('jquery.form.min.js','jquery.colorbox-min.js'));
|
||||
$this->page->add('js','freak.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function mainAction() {
|
||||
|
||||
// check access rights
|
||||
if (!$this->fc->user->checkAcl('admin_user')) {
|
||||
$this->fc->redirect(APP_WWW_URI,'access_denied');
|
||||
}
|
||||
|
||||
$this->filter = $this->fc->sessionVariable('userfilter');
|
||||
$this->limit = $this->fc->sessionVariable('userlimit');
|
||||
$this->search = $this->fc->sessionVariable('search');
|
||||
|
||||
$title = 'All users';
|
||||
$filter = '';
|
||||
|
||||
switch ($this->filter) {
|
||||
case '1':
|
||||
$title = 'Task managers';
|
||||
$filter = "actags LIKE '%task_see_all%'";
|
||||
$this->limit = 0;
|
||||
break;
|
||||
case '2':
|
||||
$title = 'User managers';
|
||||
$filter = "actags LIKE '%admin_user%'";
|
||||
$this->limit = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$this->data = new MemberModel();
|
||||
$this->data->enableAuthentication();
|
||||
$this->data->connectDb();
|
||||
$this->data->orderBy('nickname ASC');
|
||||
if ($fs = DbQueryHelper::parseSearch($this->search)) {
|
||||
$this->data->where("nickname LIKE '$fs'");
|
||||
}
|
||||
if ($filter) {
|
||||
$this->data->having($filter);
|
||||
}
|
||||
if ($this->limit) {
|
||||
$this->data->limit(0, $this->limit);
|
||||
}
|
||||
$this->data->loadList();
|
||||
|
||||
$this->page->set('title',$title.' | TaskFreak! Time Tracker Administration');
|
||||
|
||||
$this->setView('admin/user-list');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
public function editAction() {
|
||||
|
||||
$this->_loadUser();
|
||||
$this->data->addHelper('html_form');
|
||||
|
||||
$this->setView('admin/user-edit');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
public function editReaction() {
|
||||
|
||||
$this->_loadUser();
|
||||
|
||||
$this->data->fields('nickname,username,time_zone,email');
|
||||
$this->data->set($this->fc->request);
|
||||
|
||||
if ($this->fc->chkReqVar('pass1') && $this->fc->chkReqVar('pass2')) {
|
||||
if ($this->data->setPassword($this->fc->getReqVar('pass1'), $this->fc->getReqVar('pass2'))) {
|
||||
// save it all
|
||||
$this->data->ignore();
|
||||
} else {
|
||||
// do not save password
|
||||
$this->data->ignore('password,salt');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->data->check()) {
|
||||
$this->data->set('enabled',1); // always enable for now
|
||||
$myself = ($this->data->getUid() == $this->fc->user->getUid());
|
||||
if ($this->data->save(!$myself)) {
|
||||
if ($myself) {
|
||||
// editing own profile need to relogin
|
||||
$this->data->updateSessionVariables();
|
||||
}
|
||||
$this->fc->autoRedirect('user saved');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteAction() {
|
||||
|
||||
$this->_loadUser();
|
||||
|
||||
if ($this->canDeleteThisUser) {
|
||||
if ($this->data->delete()) {
|
||||
$db = DbConnector::getConnection();
|
||||
// delete this user's rights
|
||||
$db->query('DELETE FROM '.$this->data->dbTable('acl_user').' WHERE user_id='.$this->data->getUid());
|
||||
// delete this user's tasks
|
||||
$db->query('DELETE FROM '.$this->data->dbTable('task').' WHERE member_id='.$this->data->getUid());
|
||||
$this->fc->redirect(APP_WWW_URI.'admin','user deleted');
|
||||
}
|
||||
}
|
||||
|
||||
$this->fc->redirect(APP_WWW_URI.'admin','user deleted');
|
||||
|
||||
}
|
||||
|
||||
public function switchAction() {
|
||||
|
||||
if (!$this->fc->user->checkAcl('task_see_all')) {
|
||||
$this->fc->redirect(APP_WWW_URI,'access_denied');
|
||||
}
|
||||
|
||||
if ($id = $this->fc->getReqVar('id')) {
|
||||
// switch has been requested
|
||||
$obj = new MemberModel();
|
||||
$obj->connectDb();
|
||||
$obj->setUid($id);
|
||||
if ($obj->load()) {
|
||||
$this->fc->setSessionVariable('switch_id', $id);
|
||||
$this->fc->setSessionVariable('switch_name', $obj->get('nickname'));
|
||||
}
|
||||
$this->fc->redirect(APP_WWW_URI,'switched to '.$obj->get('nickname'));
|
||||
}
|
||||
|
||||
$this->switch_id = $this->fc->getSessionVariable('switch_id');
|
||||
|
||||
$this->data = new MemberModel();
|
||||
$this->data->connectDb();
|
||||
$this->data->orderBy('nickname ASC');
|
||||
$this->data->loadList();
|
||||
|
||||
$this->setView('admin/switch');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
protected function _loadUser() {
|
||||
if (isset($this->data)) {
|
||||
// already loaded
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->canDeleteThisUser = false;
|
||||
|
||||
$this->data = new MemberModel();
|
||||
$this->data->enableAuthentication();
|
||||
$this->data->connectDb();
|
||||
|
||||
// check access rights
|
||||
if ($this->fc->user->checkAcl('admin_user')) {
|
||||
if ($id = $this->fc->getReqVar('id')) {
|
||||
$this->data->setUid($id);
|
||||
$this->data->load();
|
||||
if ($id != $this->fc->user->getUid()) {
|
||||
$this->canDeleteThisUser = true;
|
||||
}
|
||||
} else {
|
||||
// create a ne user : set defaults
|
||||
$this->data->set('time_zone', $GLOBALS['config']['datetime']['timezone_server']->getName());
|
||||
}
|
||||
} else {
|
||||
// not an admin : can only load itself
|
||||
$this->data = $this->fc->user;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
* List of current tasks
|
||||
* @since 0.2
|
||||
*/
|
||||
class Login extends AppController {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login form
|
||||
*/
|
||||
public function mainAction() {
|
||||
$this->fc->user->addHelper('html_form');
|
||||
$this->page->set('title','TaskFreak! Login');
|
||||
$this->page->add('css',array('form.css','freak.css','login.css'));
|
||||
$this->page->add('js','form.js');
|
||||
$this->setView('login/login');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs user in
|
||||
* @todo redirect to requested page
|
||||
*/
|
||||
public function mainReaction() {
|
||||
$this->fc->user->fields('username,password');
|
||||
$this->fc->user->set($this->fc->request);
|
||||
if ($this->fc->user->login($this->fc->user->get('username'), $this->fc->user->get('password'))) {
|
||||
NaviHelper::redirect(APP_WWW_URI);
|
||||
}
|
||||
return true; // show action again
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs user out
|
||||
* @todo show logout summary page
|
||||
*/
|
||||
public function outAction() {
|
||||
$this->fc->user->logout();
|
||||
NaviHelper::redirect(APP_WWW_URI);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* List of current tasks
|
||||
* @since 0.1
|
||||
*/
|
||||
class Task extends AppController {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(true);
|
||||
|
||||
$this->fc->setSessionDefault('limit',10);
|
||||
if (APP_SETUP_USER_MODEL) {
|
||||
$this->fc->setSessionDefault('switch_id',$this->fc->user->getUid());
|
||||
$this->fc->setSessionDefault('switch_name',$this->fc->user->get('nickname'));
|
||||
$this->switch_id = $this->fc->getSessionVariable('switch_id');
|
||||
$this->user_id = $this->fc->user->getUid();
|
||||
} else {
|
||||
$this->switch_id = $this->user_id = 0;
|
||||
}
|
||||
|
||||
$this->fc->loadModel('TaskModel');
|
||||
$this->current = TaskSummary::loadCurrent();
|
||||
if ($this->fc->getReqVar('ajax')) {
|
||||
$this->page->clean('css');
|
||||
$this->page->clean('js');
|
||||
} else {
|
||||
$this->page->add('css',array('form.css','freak.css','list.css','tracker.css','colorbox.css'));
|
||||
// $this->page->add('js',array('jquery.form.min.js','jquery.colorbox-min.js'));
|
||||
$this->page->add('js','freak.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function mainAction() {
|
||||
$this->filter = $this->fc->sessionVariable('filter');
|
||||
$title = 'Todo';
|
||||
$filter = 'status=0 AND archived=0';
|
||||
$this->actions = array();
|
||||
switch ($this->filter) {
|
||||
case '1':
|
||||
$title = 'Completed';
|
||||
$filter = 'status=1 AND archived=0';
|
||||
$this->actions['open'] = 'Re-open';
|
||||
$this->actions['valid'] = 'Validate';
|
||||
$this->actions['archive'] = 'Archive';
|
||||
break;
|
||||
case '2':
|
||||
$title = 'Valid'; // -TODO- check english term
|
||||
$filter = 'status=2 AND archived=0';
|
||||
$this->actions['open'] = 'Re-open';
|
||||
$this->actions['archive'] = 'Archive';
|
||||
break;
|
||||
case '3':
|
||||
$title = 'Archives';
|
||||
$filter = 'archived=1';
|
||||
$this->actions['unarchive'] = 'Unarchive';
|
||||
break;
|
||||
default:
|
||||
$this->actions['report'] = 'Report 1 day';
|
||||
$this->actions['close'] = 'Mark as done';
|
||||
$this->actions['valid'] = 'Validate';
|
||||
$this->actions['archive'] = 'Archive';
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_taskList($filter);
|
||||
|
||||
$this->page->set('title',$title.' | TaskFreak! Time Tracker');
|
||||
|
||||
if ($this->fc->getReqVar('ajax')) {
|
||||
$this->setView('include/list-'.($this->expand?'expand':'compact'));
|
||||
} else {
|
||||
$this->setView('main');
|
||||
}
|
||||
$this->view();
|
||||
|
||||
}
|
||||
|
||||
public function mainReaction() {
|
||||
// drop if no checkbox have been checked
|
||||
if (!isset($_POST['chk'])) {
|
||||
// -TODO- show error
|
||||
$this->fc->redirect(APP_WWW_URI.'task/main/','please check at least one task');
|
||||
}
|
||||
// check action request
|
||||
$action = $this->fc->chkReqVar('report,open,close,valid,archive,unarchive');
|
||||
// do it then
|
||||
TaskModel::updateManyAtOnce($action, $_POST['chk']);
|
||||
// reload entire page
|
||||
$this->fc->redirect(APP_WWW_URI.'task/main/');
|
||||
}
|
||||
|
||||
/**
|
||||
* called to start a task (from the task list)
|
||||
* will only update the timer panel and change the task in the list
|
||||
* (method called by ajax request only)
|
||||
*/
|
||||
public function timerAction() {
|
||||
if ($id = $this->fc->getReqVar('id')) {
|
||||
$obj = new TaskSummary();
|
||||
$obj->connectDb();
|
||||
$obj->setUid($id);
|
||||
$obj->load();
|
||||
if ($obj->getUid()) {
|
||||
// -TODO- check rights
|
||||
// first stop any running task (TODO for current user only)
|
||||
if ($this->current) {
|
||||
$cid = $this->current->getUid();
|
||||
TimerModel::stop($cid);
|
||||
$this->jsCode = "clockreport('$cid');";
|
||||
}
|
||||
// now start selected task
|
||||
TimerModel::start($id);
|
||||
$this->current = TaskSummary::loadCurrent();
|
||||
$this->jsCode .= "clockstart('$id')";
|
||||
}
|
||||
$this->setView('include/timer');
|
||||
$this->view();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* change a task status (start, stop, close) or save a new one
|
||||
* will only update the timer panel and reload the task list
|
||||
* (method called by ajax request only)
|
||||
*/
|
||||
public function timerReaction() {
|
||||
$this->jsCode = '';
|
||||
if ($id = $this->fc->getReqVar('id')) {
|
||||
// start / stop timer
|
||||
$obj = new TaskSummary();
|
||||
$obj->connectDb();
|
||||
$obj->setUid($id);
|
||||
$obj->load();
|
||||
|
||||
// what action then ?
|
||||
$action = $this->fc->chkReqVar('pause,resume,start,stop,close');
|
||||
|
||||
FC::log_debug('loaded task ID='.$obj->getUid());
|
||||
switch($action) {
|
||||
case 'pause':
|
||||
// try to pause
|
||||
if ($this->current && $this->current->getUid() == $id) {
|
||||
// ok, task is actually running
|
||||
TimerModel::stop($id);
|
||||
$this->current->set('stop',APP_SQL_NOW);
|
||||
$this->jsCode .= "clockreport('$cid');clockstatus('paused');";
|
||||
} else {
|
||||
// nope, requested task is not running, show error
|
||||
$this->jsCode = "alert('error trying to pause')";
|
||||
FC::log_debug('error trying to pause non running task');
|
||||
}
|
||||
break;
|
||||
case 'resume':
|
||||
case 'start':
|
||||
TimerModel::start($id);
|
||||
$this->current = TaskSummary::loadCurrent();
|
||||
$this->jsCode = "clockstart();";
|
||||
break;
|
||||
case 'stop':
|
||||
if (TimerModel::stop($id)) {
|
||||
$this->jsCode = "clockstatus();";
|
||||
} else {
|
||||
$this->jsCode = "alert('task already stopped');";
|
||||
}
|
||||
$this->current = false;
|
||||
break;
|
||||
case 'close':
|
||||
if (TimerModel::stop($id)) {
|
||||
$this->jsCode = "clockstatus();";
|
||||
$this->current->updateStatus(1); // mark as done
|
||||
$this->current = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if ($title = $this->fc->getReqVar('title')) {
|
||||
// creating a new task ?
|
||||
$obj = TaskModel::parse($title, $def, $dte);
|
||||
$obj->connectDb();
|
||||
if ($this->fc->getReqVar('start')) {
|
||||
$obj->set('deadline', APP_SQL_TODAY);
|
||||
}
|
||||
if ($obj->check($this->switch_id)) {
|
||||
$obj->insert();
|
||||
}
|
||||
if ($this->fc->chkReqVar('start')) {
|
||||
TimerModel::start($obj->getUid());
|
||||
$this->current = TaskSummary::loadCurrent();
|
||||
$this->jsCode = "clockstart();";
|
||||
} else {
|
||||
$this->current = false;
|
||||
$this->jsCode = "clockstatus();";
|
||||
}
|
||||
}
|
||||
$this->jsCode .= 'reloadList();';
|
||||
$this->setView('include/timer');
|
||||
$this->view();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function _taskList($filter) {
|
||||
|
||||
$this->expand = $this->fc->sessionVariable('expand');
|
||||
$this->search = $this->fc->sessionVariable('search');
|
||||
$this->limit = $this->fc->sessionVariable('limit');
|
||||
|
||||
$this->data = new TaskSummary();
|
||||
$this->data->connectDb();
|
||||
$this->data->where($filter);
|
||||
if ($this->search) {
|
||||
$this->data->where("title LIKE '%".$this->search."%'");
|
||||
}
|
||||
if ($this->switch_id) {
|
||||
// user login enabled, filter by users
|
||||
$this->data->where('member_id='.$this->switch_id);
|
||||
}
|
||||
$this->data->orderBy('deadline ASC, priority ASC, title ASC, start ASC');
|
||||
if ($this->expand) {
|
||||
$this->limit = 0;
|
||||
$this->data->loadExpandList();
|
||||
} else {
|
||||
$this->data->limit(0,$this->limit);
|
||||
$this->data->loadCompactList();
|
||||
}
|
||||
}
|
||||
|
||||
public function viewAction() {
|
||||
$this->data = new TaskSummary();
|
||||
$this->data->connectDb();
|
||||
|
||||
$ok = false;
|
||||
if ($id = $this->fc->getReqVar('id')) {
|
||||
$this->data->where('id='.$id);
|
||||
$this->data->orderBy('start ASC');
|
||||
if ($this->data->loadExpandList()) {
|
||||
$ok = $this->data->next();
|
||||
}
|
||||
}
|
||||
if (!$ok) {
|
||||
echo 'Todo not found';
|
||||
exit;
|
||||
}
|
||||
$this->data->chkDeadline();
|
||||
|
||||
$this->timer = new TimerModel();
|
||||
$this->timer->addHelper('html_form');
|
||||
|
||||
$this->page->set('title','Todo details | TaskFreak! Time Tracker');
|
||||
// $this->page->add('js',array('jquery.dateentry.pack.js','jquery.timeentry.pack.js'));
|
||||
$this->setView('view');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
public function createAction() {
|
||||
$this->_loadTask();
|
||||
$this->data->addHelper('html_form');
|
||||
$this->page->set('title','Create Multiple Todos | TaskFreak! Time Tracker');
|
||||
$this->setView('create');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
public function createReaction() {
|
||||
$this->result = array();
|
||||
$data = explode("\n",$this->fc->getReqVar('data'));
|
||||
ArrayHelper::arrayTrim($data);
|
||||
$t = count($data); // total to parse
|
||||
$i = 0; // successfully parsed counter
|
||||
$defDate = ''; // date of previous created task
|
||||
$defValue = ''; // default value for multiple tasks creation (set by *)
|
||||
foreach ($data as $val) {
|
||||
if ($objTask = TaskModel::parse($val, $defValue, $defDate)) {
|
||||
// really creating a task
|
||||
$objTask->connectDb();
|
||||
if ($objTask->check($this->switch_id)) {
|
||||
$objTask->insert();
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->fc->redirect('/task/main',$i.' task(s) created !');
|
||||
}
|
||||
|
||||
public function editAction() {
|
||||
$this->_loadTask();
|
||||
$this->data->addHelper('html_form');
|
||||
|
||||
$this->page->set('title',($this->data->getUid()?'Edit':'Create').' Todo | TaskFreak! Time Tracker');
|
||||
$this->setView('edit');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
public function editReaction() {
|
||||
$this->_loadTask();
|
||||
$this->data->ignore('creation_date'); // do not submit or change creation date
|
||||
$this->data->set($this->fc->request);
|
||||
if ($this->data->check($this->switch_id)) {
|
||||
$this->data->save();
|
||||
$this->fc->redirect(APP_WWW_URI,'task_created');
|
||||
}
|
||||
return true; // show action again
|
||||
}
|
||||
|
||||
protected function _loadTask() {
|
||||
if (empty($this->data)) {
|
||||
$this->data = new TaskModel();
|
||||
$this->data->connectDb();
|
||||
|
||||
$uid = $this->data->dbUid();
|
||||
if ($id = $this->fc->getReqVar($uid)) {
|
||||
$this->data->setUid($id);
|
||||
$this->data->load();
|
||||
}
|
||||
}
|
||||
return $this->data->getUid();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* List of current tasks
|
||||
* @since 0.1
|
||||
*/
|
||||
class Timer extends AppController {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(true);
|
||||
|
||||
$this->fc->loadModel('TaskModel');
|
||||
|
||||
$this->page->clean('css');
|
||||
$this->page->clean('js');
|
||||
}
|
||||
|
||||
/**
|
||||
* show timer creation form
|
||||
*/
|
||||
public function mainAction() {
|
||||
$this->setView('include/timer-form.php');
|
||||
$this->view();
|
||||
}
|
||||
|
||||
/**
|
||||
* create timer
|
||||
*/
|
||||
public function mainReaction() {
|
||||
$date = VarDte::sanitize($_POST['date'],$err);
|
||||
$start = VarTim::sanitize($_POST['start_time'],$err);
|
||||
$stop = VarTim::sanitize($_POST['stop_time'],$err);
|
||||
$spent = VarDur::sanitize($_POST['spent'],$err);
|
||||
$this->data = new TimerModel();
|
||||
$this->data->set('task_id', $_POST['id']);
|
||||
if ($start) {
|
||||
$this->data->set('start',$_POST['date'].' '.$_POST['start_time']);
|
||||
}
|
||||
if ($stop) {
|
||||
$this->data->set('stop',$_POST['date'].' '.$_POST['stop_time']);
|
||||
}
|
||||
if ($spent) {
|
||||
$this->data->set('spent', $_POST['spent']);
|
||||
}
|
||||
|
||||
/*
|
||||
echo '<pre>';
|
||||
print_r($_POST);
|
||||
echo "\n\n";
|
||||
echo "date : $date\n";
|
||||
echo "start : $start : ".$this->data->get('start')."\n";
|
||||
echo "stop : $stop : ".$this->data->get('stop')."\n";
|
||||
echo "spent: $spent\n";
|
||||
echo '</pre>';
|
||||
*/
|
||||
|
||||
$this->data->setCheck();
|
||||
if ($this->data->check()) {
|
||||
$this->data->connectDb();
|
||||
$this->data->set('manual',1);
|
||||
$this->data->insert();
|
||||
}
|
||||
|
||||
/*
|
||||
echo $this->data;
|
||||
exit;
|
||||
*/
|
||||
|
||||
echo '<script type="text/javascript">';
|
||||
echo "reloadList(); window.setTimeout('$.fn.colorbox.close()',1000);";
|
||||
echo '</script>';
|
||||
echo '<p class="empty">time added</p>';
|
||||
return false;
|
||||
}
|
||||
|
||||
public function deleteAction() {
|
||||
// check stuff
|
||||
$id = $this->fc->getReqVar('id');
|
||||
$start = $this->fc->getReqVar('start');
|
||||
|
||||
if (empty($id) || empty($start)) {
|
||||
$this->fc->redirect(CMS_WWW_URI,'ERROR:missing parameters');
|
||||
}
|
||||
|
||||
// delete timer
|
||||
$this->data = new TimerModel();
|
||||
$this->data->connectDb();
|
||||
if ($this->data->delete('task_id='.$id." AND start='".$start."'"))
|
||||
{
|
||||
// successfully deleted
|
||||
if ($this->fc->getReqVar('ajax')) {
|
||||
$this->data = new TaskSummary();
|
||||
$this->data->connectDb();
|
||||
|
||||
$ok = false;
|
||||
if ($id = $this->fc->getReqVar('id')) {
|
||||
$this->data->where('id='.$id);
|
||||
if ($this->data->loadExpandList()) {
|
||||
$ok = $this->data->next();
|
||||
}
|
||||
}
|
||||
$this->setView('include/timer-list');
|
||||
$this->view();
|
||||
echo '<script type="text/javascript">';
|
||||
echo "reloadList();";
|
||||
echo '</script>';
|
||||
} else {
|
||||
$this->fc->redirect(CMS_WWW_URI,'Timer deleted');
|
||||
}
|
||||
} else {
|
||||
// error deleting
|
||||
if ($this->fc->getReqVar('ajax')) {
|
||||
echo '<script type="text/javascript">';
|
||||
echo 'alert("can not delete timer");';
|
||||
echo '</script>';
|
||||
} else {
|
||||
$this->fc->redirect(CMS_WWW_URI,'Timer NOT deleted');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* MemberModel
|
||||
* @since 0.2
|
||||
*/
|
||||
class MemberModel extends UserAclModel {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('member');
|
||||
$this->addProperties(array(
|
||||
'nickname' => 'STR',
|
||||
'email' => 'EML'
|
||||
));
|
||||
}
|
||||
|
||||
public function htmlRights() {
|
||||
if ($this->isEmpty('actags')) {
|
||||
return '';
|
||||
}
|
||||
$arr = explode(',', $this->get('actags'));
|
||||
$arrTrans = array();
|
||||
if (in_array('task_see_all', $arr)) {
|
||||
$arrTrans[] = 'task manager';
|
||||
}
|
||||
if (in_array('admin_user', $arr)) {
|
||||
$arrTrans[] = 'user admin';
|
||||
}
|
||||
return implode(', ',$arrTrans);
|
||||
}
|
||||
|
||||
public function check() {
|
||||
return parent::check('nickname,username');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* Class representing a task
|
||||
* @since 0.1
|
||||
*/
|
||||
class TaskModel extends Model {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('task');
|
||||
$this->addProperties(array(
|
||||
'id' => 'UID',
|
||||
'title' => 'STR',
|
||||
'note' => 'BBS',
|
||||
'priority' => 'NUM,'.json_encode($GLOBALS['config']['task']['priority']),
|
||||
'begin' => 'DTE',
|
||||
'deadline' => 'DTE',
|
||||
'status' => 'NUM,{"options":["todo","done","valid"],"default":0}',
|
||||
'archived' => 'BOL',
|
||||
'member_id' => 'NUM'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* check submitted data before saving task
|
||||
*/
|
||||
public function check($usrId) {
|
||||
if ($this->isEmpty('begin')) {
|
||||
$this->set('begin','9999-00-00');
|
||||
}
|
||||
if ($this->isEmpty('deadline')) {
|
||||
$this->set('deadline','9999-00-00');
|
||||
}
|
||||
if ($this->isEmpty('member_id') && APP_SETUP_USER_MODEL) {
|
||||
$this->set('member_id', $usrId);
|
||||
}
|
||||
return parent::check('title');
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a single line string for task params
|
||||
* @return a task object
|
||||
*/
|
||||
public static function parse($str, &$def, &$dte) {
|
||||
if (!preg_match('/^(\* |\*{2,3})?([+|-][0-9]{0,2}|[0-9]{2}\/[0-9]{2})?( ?[0-9]+\))?(.+)?$/',$str, $arr)) {
|
||||
return false;
|
||||
}
|
||||
ArrayHelper::arrayTrim($arr);
|
||||
$obj = new TaskModel();
|
||||
$tst = substr($arr[1],0,1);
|
||||
switch ($tst) {
|
||||
case '*': // multiple
|
||||
if ($arr[1] == '**') {
|
||||
// reset default date (**)
|
||||
$dte = '';
|
||||
} else if ($arr[1] == '***') {
|
||||
// reset default title (***)
|
||||
$def = '';
|
||||
} else {
|
||||
if ($arr[2]) {
|
||||
// remember date
|
||||
if ($tst == '+') {
|
||||
if ($n = substr($arr[2], 1)) {
|
||||
// number of days later
|
||||
$obj->set('deadline',$arr[2].' days');
|
||||
} else {
|
||||
// no number, means today
|
||||
$obj->set('deadline', APP_SQL_TODAY);
|
||||
}
|
||||
} else {
|
||||
$dte = $arr[2];
|
||||
}
|
||||
}
|
||||
if ($arr[4]) {
|
||||
// remember title
|
||||
$def = $arr[4];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case '-': // no deadline
|
||||
$obj->set('deadline','9999-00-00');
|
||||
break;
|
||||
case '+': // specify deadline
|
||||
if ($n = substr($arr[2], 1)) {
|
||||
// number of days later
|
||||
$obj->set('deadline',$arr[2].' days');
|
||||
} else {
|
||||
// no number, means today
|
||||
$obj->set('deadline', APP_SQL_TODAY);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ($arr[2]) {
|
||||
// specific date set
|
||||
$obj->set('deadline', $arr[2]);
|
||||
$dte = $obj->get('deadline');
|
||||
} else if (!empty($dte)) {
|
||||
// use default date (from batch)
|
||||
$obj->set('deadline', $dte);
|
||||
} else if ($GLOBALS['config']['task']['date']) {
|
||||
// use default date (config)
|
||||
$obj->set('deadline', $GLOBALS['config']['task']['date']);
|
||||
// $dte = $obj->get('deadline');
|
||||
} else {
|
||||
// no date by default (config)
|
||||
$dte = '';
|
||||
}
|
||||
}
|
||||
$prio = $GLOBALS['config']['task']['priority']['default']; // default priority
|
||||
if ($arr[3]) {
|
||||
// priority ?
|
||||
$prio = intval(substr($arr[3],0,-1));
|
||||
}
|
||||
$obj->set('priority',$prio);
|
||||
$title = $arr[4];
|
||||
if ($def) {
|
||||
$title = $def.' : '.$title;
|
||||
}
|
||||
$obj->set('title',$title);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* set archive status for multiple tasks
|
||||
*/
|
||||
public static function updateManyAtOnce($action, $arr) {
|
||||
if (!count($arr)) {
|
||||
return false;
|
||||
}
|
||||
$sta = '';
|
||||
switch ($action) {
|
||||
case 'report':
|
||||
$sta = 'deadline = DATE_ADD(deadline, INTERVAL 1 DAY)';
|
||||
break;
|
||||
case 'open':
|
||||
$sta = 'status=0';
|
||||
break;
|
||||
case 'close':
|
||||
$sta = 'status=1';
|
||||
break;
|
||||
case 'valid':
|
||||
$sta = 'status=2';
|
||||
break;
|
||||
case 'archive':
|
||||
$sta = 'archived=1';
|
||||
break;
|
||||
case 'unarchive':
|
||||
$sta = 'archived=0';
|
||||
break;
|
||||
}
|
||||
if ($sta) {
|
||||
$filter = 'id IN ('.implode(',',$arr).')';
|
||||
DbConnector::query('UPDATE task SET '.$sta.' WHERE '.$filter);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class TaskSummary extends TaskModel {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->addProperties(array(
|
||||
'start' => 'DTM',
|
||||
'stop' => 'DTM',
|
||||
'spent' => 'NUM',
|
||||
'timers' => 'NUM'
|
||||
));
|
||||
}
|
||||
|
||||
public function htmlPriority() {
|
||||
$arr = $this->getPropertyOptions('priority');
|
||||
$st = $this->get('priority');
|
||||
return $arr['options'][$st];
|
||||
}
|
||||
|
||||
public function htmlStatus() {
|
||||
$arr = $this->getPropertyOptions('status');
|
||||
$str = $this->get('status');
|
||||
$str = $arr['options'][$str]; // -TODO- TRANSLATE
|
||||
if ($this->get('archived')) {
|
||||
$str .= ' (archived)';
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function htmlBegin() {
|
||||
if ($this->isEmpty('start')) {
|
||||
if ($this->isEmpty('begin')) {
|
||||
return '-';
|
||||
} else {
|
||||
// -TODO- show in grey
|
||||
return $this->html('begin',APP_DATE);
|
||||
}
|
||||
} else {
|
||||
return $this->html('start',APP_DATETIME);
|
||||
}
|
||||
}
|
||||
|
||||
public function getEnd() {
|
||||
if ($this->isEmpty('stop')) {
|
||||
if ($this->isEmpty('deadline')) {
|
||||
return '';
|
||||
} else {
|
||||
return $this->get('deadline');
|
||||
}
|
||||
} else {
|
||||
return $this->get('stop');
|
||||
}
|
||||
}
|
||||
|
||||
public function htmlEnd($expanded=false) {
|
||||
if ($this->isEmpty('stop')) {
|
||||
return '-';
|
||||
} else {
|
||||
return $this->html('stop',APP_DATETIME);
|
||||
}
|
||||
}
|
||||
|
||||
public function htmlDeadline() {
|
||||
if ($this->isEmpty('deadline')) {
|
||||
return '-';
|
||||
} else {
|
||||
switch ($this->_diff) {
|
||||
case 9999:
|
||||
return '-';
|
||||
case -1:
|
||||
return 'yesterday';
|
||||
case 0:
|
||||
return 'today';
|
||||
case 1:
|
||||
return 'tomorrow';
|
||||
default:
|
||||
return $this->html('deadline',APP_DATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTimeSpent() {
|
||||
return $this->htmlTime($this->get('spent'), $this->isEmpty('start'));
|
||||
}
|
||||
|
||||
public function getRealSpentSecs() {
|
||||
return APP_NOW - strtotime($this->get('start'));
|
||||
}
|
||||
|
||||
public function getRealSpent() {
|
||||
$spent = $this->getRealSpentSecs();
|
||||
$h = floor($spent / 3600);
|
||||
$m = floor($spent / 60) - ($h*60);
|
||||
$s = $spent - ($h*3600 + $m*60);
|
||||
return str_pad($h, 2, '0',STR_PAD_LEFT)
|
||||
.':'.str_pad($m, 2, '0',STR_PAD_LEFT)
|
||||
.':'.str_pad($s, 2, '0',STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
public function chkDeadline() {
|
||||
if ($this->isEmpty('deadline')) {
|
||||
$this->_diff = 9999;
|
||||
} else {
|
||||
$dead = strtotime($this->get('deadline'));
|
||||
$this->_diff = ($dead - intval(APP_TODAY)) / 3600 / 24;
|
||||
}
|
||||
}
|
||||
|
||||
public function isOpened($user_id) {
|
||||
// -TODO- if no "validate" option, do not allow on closed tasks
|
||||
return ($this->get('status') < 2 && (!$this->get('archived')) && ($this->get('member_id') == $user_id));
|
||||
}
|
||||
|
||||
public function curCss($default='') {
|
||||
$arr = array();
|
||||
if ($this->_diff < 0) {
|
||||
$arr[] = 'overdue';
|
||||
} else if ($this->_diff == 0) {
|
||||
$arr[] = 'today';
|
||||
} else {
|
||||
$arr[] = 'future';
|
||||
}
|
||||
if ($default) {
|
||||
$arr[] = $default;
|
||||
}
|
||||
if (count($arr)) {
|
||||
return ' class="'.implode(' ',$arr).'"';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function htmlDate() {
|
||||
$str = $this->html('end_date',APP_DATE_FRM,'no_date');
|
||||
if ($css = $this->curCss()) {
|
||||
return '<span'.$css.'>'.$str.'</span>';
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
public static function htmlTime($spent, $stopped=true) {
|
||||
if (empty($spent)) {
|
||||
if ($stopped) {
|
||||
return '--:--';
|
||||
} else {
|
||||
return 'running';
|
||||
}
|
||||
}
|
||||
$h = floor($spent / 60);
|
||||
$m = $spent - ($h*60);
|
||||
return str_pad($h, 2, '0',STR_PAD_LEFT).':'.str_pad($m, 2, '0',STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* update current task status
|
||||
*/
|
||||
public function updateStatus($status) {
|
||||
$this->connectDb();
|
||||
$this->set('status',$status);
|
||||
$this->fields('status');
|
||||
return parent::update();
|
||||
}
|
||||
|
||||
/**
|
||||
* override load function
|
||||
*/
|
||||
public function load($filter='') {
|
||||
$this->select('id, title, begin, deadline, start, stop, status, archived, '
|
||||
.'CEIL(spent/60) as spent');
|
||||
$this->from('task');
|
||||
$this->leftJoin('timer','task.id=timer.task_id');
|
||||
return parent::load($filter, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* load current running timer
|
||||
*/
|
||||
public static function loadCurrent($id=0) {
|
||||
$obj = new TaskSummary();
|
||||
$obj->connectDb();
|
||||
if ($id) {
|
||||
$obj->setUid($id);
|
||||
if ($obj->load()) {
|
||||
return $obj;
|
||||
}
|
||||
} else {
|
||||
$ftr = "stop='0000-00-00 00:00:00'";
|
||||
if (!empty($_SESSION['appUserId'])) {
|
||||
$ftr .= " AND member_id='".$_SESSION['appUserId']."'";
|
||||
}
|
||||
if ($obj->load($ftr)) {
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function loadCompactList() {
|
||||
/*
|
||||
SELECT task.*, MIN(start) as start, MAX(stop) as stop, SUM(CEIL(spent/60)) as spent
|
||||
FROM `task`
|
||||
LEFT JOIN timer ON task.id = timer.task_id
|
||||
WHERE status < 2
|
||||
GROUP BY id
|
||||
*/
|
||||
$this->select('task.*, MIN(start) as start, MAX(stop) as stop, '
|
||||
.'SUM(CEIL(spent/60)) as spent, COUNT(timer.task_id) AS timers');
|
||||
$this->from('task');
|
||||
$this->leftJoin('timer','task.id=timer.task_id');
|
||||
$this->groupBy('id');
|
||||
return parent::loadList(false);
|
||||
}
|
||||
|
||||
public function loadExpandList() {
|
||||
$this->select('task.*, start, stop, CEIL(spent/60) as spent');
|
||||
$this->from('task');
|
||||
$this->leftJoin('timer','task.id=timer.task_id');
|
||||
return parent::loadList(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak! Time Tracker
|
||||
*
|
||||
* @package taskfreak_tt
|
||||
* @author Stan Ozier <taskfreak@gmail.com>
|
||||
* @version 0.1
|
||||
* @copyright GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Timer
|
||||
*
|
||||
* Class representing a task time log
|
||||
* @since 0.1
|
||||
*/
|
||||
class TimerModel extends Model {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('timer');
|
||||
$this->addProperties(array(
|
||||
'task_id' => 'NUM',
|
||||
'start' => 'DTM',
|
||||
'stop' => 'DTM',
|
||||
'spent' => 'DUR',
|
||||
'manual' => 'BOL', // 0:auto, 1:manual
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* check submitted data before saving task
|
||||
*/
|
||||
public function check() {
|
||||
return parent::check('task_id,start,stop,spent');
|
||||
}
|
||||
|
||||
/**
|
||||
* set data and compute missing fields
|
||||
* @param integer $start number of seconds since midnight
|
||||
* @param integer $stop number of seconds since midnight
|
||||
* @param integer $spent number of seconds spent on task
|
||||
*/
|
||||
public function setCheck() {
|
||||
$start = strtotime($this->get('start'));
|
||||
$stop = strtotime($this->get('stop'));
|
||||
$spent = intval($this->get('spent'));
|
||||
if (!$this->isEmpty('start')) {
|
||||
if (!$this->isEmpty('stop')) {
|
||||
// calc diff between start and stop
|
||||
$this->set('spent',$stop-$start);
|
||||
} else if ($this->get('spent')) {
|
||||
$this->set('stop',strftime(APP_DATETIME_SQL,$start+$spent));
|
||||
}
|
||||
} else if ($spent) {
|
||||
if (!$stop) {
|
||||
$this->set('stop',APP_SQL_NOW);
|
||||
$stop = APP_NOW;
|
||||
}
|
||||
$this->set('start',strftime(APP_DATETIME_SQL,$stop-$spent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* starts a timer
|
||||
*/
|
||||
public static function start($tid) {
|
||||
$obj = new TimerModel();
|
||||
$obj->connectDb();
|
||||
$obj->set('task_id',$tid);
|
||||
$obj->set('start',APP_SQL_NOW);
|
||||
return $obj->insert();
|
||||
}
|
||||
|
||||
/**
|
||||
* stops a timer
|
||||
*/
|
||||
public static function stop($tid) {
|
||||
if (!($tid = VarUid::sanitize($tid, $err))) {
|
||||
return false;
|
||||
}
|
||||
$filter = "task_id='$tid' AND stop='0000-00-00 00:00:00'";
|
||||
$obj = new TimerModel();
|
||||
$obj->connectDb();
|
||||
if (!$obj->load($filter)) {
|
||||
return false;
|
||||
}
|
||||
$obj->set('stop',APP_SQL_NOW);
|
||||
$obj->set('spent', strtotime($obj->get('stop')) - strtotime($obj->get('start')));
|
||||
$obj->fields('stop,spent');
|
||||
return $obj->update($filter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
|
||||
?>
|
||||
<h1>Select user whose tasks you want to see</h1>
|
||||
<ul>
|
||||
<?php
|
||||
while ($this->data->next()) {
|
||||
echo '<li>';
|
||||
if ($this->data->getUid() == $this->switch_id) {
|
||||
echo $this->data->html('nickname');
|
||||
} else {
|
||||
echo '<a href="/admin/switch/id/'.$this->data->getUid().'">'.$this->data->html('nickname').'</a>';
|
||||
}
|
||||
echo '</li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<?php
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
|
||||
// echo $this->data->iAutoForm('user_edit','post','','top');
|
||||
echo '<h1>';
|
||||
if ($id = $this->data->getUid()) {
|
||||
if ($id == $this->fc->user->getUid()) {
|
||||
echo 'My preferences';
|
||||
} else {
|
||||
echo 'Edit a user';
|
||||
}
|
||||
} else {
|
||||
echo 'Create new user';
|
||||
}
|
||||
echo '</h1>';
|
||||
|
||||
|
||||
echo $this->data->iForm('user_edit','post');
|
||||
echo $this->data->iHidden('id');
|
||||
?>
|
||||
<ol class="fields side">
|
||||
<?php
|
||||
echo $this->data->iFieldLabelled('nickname','','','li class="compulsory"');
|
||||
echo $this->data->iFieldLabelled('email');
|
||||
?>
|
||||
<li>
|
||||
<label for="i_time_zone">time zone</label>
|
||||
<?php echo $this->data->iTimeZone('time_zone'); ?>
|
||||
</li>
|
||||
<?php
|
||||
echo $this->data->iFieldLabelled('username','','','li class="compulsory"');
|
||||
?>
|
||||
<li>
|
||||
<label for="i_pass1">password</label>
|
||||
<?php echo $this->data->iPass('pass1', false); ?>
|
||||
</li>
|
||||
<li>
|
||||
<label for="i_pass2">(repeat)</label>
|
||||
<?php echo $this->data->iPass('pass2', false); ?>
|
||||
</li>
|
||||
<?php
|
||||
if ($this->data->getUid() != $this->fc->user->getUid()) {
|
||||
// can only change rights for other users
|
||||
?>
|
||||
<li>
|
||||
<label>user rights</label>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="i_acl_task_see_all" name="acl_task_see_all" value="1"<?php
|
||||
if ($this->data->checkAcl('task_see_all')) echo ' checked="checked"';
|
||||
?> /> <label for="i_acl_task_see_all">task manager</label></li>
|
||||
<li><input type="checkbox" id="i_acl_admin_user" name="acl_admin_user" value="1"<?php
|
||||
if ($this->data->checkAcl('admin_user')) echo ' checked="checked"';
|
||||
?> /> <label for="i_acl_admin_user">user admin</label></li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<li class="buttons">
|
||||
<button type="submit" name="save" value="1" class="save">Save</button>
|
||||
<?php
|
||||
if ($this->canDeleteThisUser) {
|
||||
?>
|
||||
<a href="<?php echo $this->fc->getUrl('admin','delete',array('id'=>$this->data->getUid())); ?>"
|
||||
onclick="return confirm('really delete the dude ?');" class="button marge delete">Delete</a>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</li>
|
||||
</ol>
|
||||
<?php
|
||||
|
||||
$this->incView('include/page-bot', false);
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
|
||||
?>
|
||||
<div id="dmain" class="full">
|
||||
<div id="dfilters">
|
||||
<span>
|
||||
<a href="<?php echo $this->fc->getUrl('admin/edit');?>" class="ajax box new inv" title="Create new user">Create user</a>
|
||||
</span>
|
||||
<ul class="links horiz">
|
||||
<?php
|
||||
$arr = array('all'=>0,'task managers'=>1,'user admins'=>2);
|
||||
foreach($arr as $lbl => $val) {
|
||||
echo '<li';
|
||||
if ($this->filter == $val) {
|
||||
echo ' class="active"';
|
||||
}
|
||||
echo '><a href='.$this->fc->thisUrl(array('userfilter'=>$val)).'>'.$lbl.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="links horiz">
|
||||
<?php
|
||||
$arr = array('10'=>10,'25'=>25,'50'=>50,'all'=>0);
|
||||
foreach($arr as $lbl => $val) {
|
||||
echo '<li';
|
||||
if ($this->limit == $val) {
|
||||
echo ' class="active"';
|
||||
}
|
||||
echo '><a href='.$this->fc->thisUrl(array('userlimit'=>$val)).'>'.$lbl.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<form id="search" action="<?php $this->fc->thisUrl(); ?>" method="get">
|
||||
<p>
|
||||
<input type="text" name="search" value="<?php echo $this->search; ?>" tabindex="4" />
|
||||
<button type="submit" name="go" value="1">search</button>
|
||||
<button type="button" onclick="this.form.elements[0].value='';this.form.submit()">x</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div id="dlist" class="users">
|
||||
<?php
|
||||
if ($this->data->count()) {
|
||||
?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>last visit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
while ($this->data->next()) {
|
||||
$id = $this->data->getUid();
|
||||
echo '<tr>';
|
||||
echo '<td>';
|
||||
echo '<a href="'.$this->fc->getUrl('admin','edit',array('id'=>$id)).'" class="onhold ajax box" title="Edit user">edit</a>';
|
||||
echo $this->data->html('nickname');
|
||||
if ($tmp = $this->data->htmlRights()) {
|
||||
echo ' <small>'.$tmp.'</small>';
|
||||
}
|
||||
echo '</td>';
|
||||
echo '<td>'.$this->data->html('last_login_date').'</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<p class="empty">sorry, no user found</p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
?>
|
||||
<div id="sidepanel">
|
||||
<p>Enter one task per line.</p>
|
||||
<h4>Task format</h4>
|
||||
<p>Task format : [date] [priority] [label :] task title<br />
|
||||
<small>fields within brackets are optional</small></p>
|
||||
<p><em>date</em> can be :</p>
|
||||
<ul>
|
||||
<li>a date in format dd/mm[/yy]</li>
|
||||
<li>a + followed by number of days in the future</li>
|
||||
<li>a - means no deadline</li>
|
||||
<li>nothing means deadline is today</li>
|
||||
</ul>
|
||||
<p><em>priority</em> is a number between 1 and 9, followed by a )<br />
|
||||
<small>« 1) » for urgent tasks, « 5) » for normal priority</small></p>
|
||||
<p><em>label</em> is optional</p>
|
||||
<h4>Defaults for multiple tasks</h4>
|
||||
<p>a line starting by a * sets up defaults</p>
|
||||
<p>Format is : * [date] [label]<br />
|
||||
<small>« * +1 taskfreak » or « * 12/04 »</small></p>
|
||||
<p>reset defaults with a line with « ** »</p>
|
||||
</div>
|
||||
<?php
|
||||
$hh = new HtmlFormHelper();
|
||||
echo $hh->iForm('task_batch','post',$this->fc->thisUrl());
|
||||
echo '<p>'.$hh->iTextArea('data').'</p>';
|
||||
echo '<p><button type="submit" name="save" value="1" class="save">Save</button></p>';
|
||||
echo '</form>';
|
||||
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
|
||||
// echo $this->data->iAutoForm('task_edit','post','','top');
|
||||
echo $this->data->iForm('task_edit','post');
|
||||
echo $this->data->iHidden('id');
|
||||
?>
|
||||
<ol class="fields multicol top">
|
||||
<?php
|
||||
echo $this->data->iFieldLabelled('title','','','li class="nline"');
|
||||
// $this->data->iFieldLabelled('begin'); -TODO- unused ATM
|
||||
echo $this->data->iFieldLabelled('deadline','','','li class="nline"');
|
||||
?>
|
||||
<li>
|
||||
<label for="i_priority">priority</label>
|
||||
<?php echo $this->data->iSelect('priority'); ?>
|
||||
</li>
|
||||
<?php
|
||||
echo $this->data->iFieldLabelled('note','','','li class="nline"');
|
||||
?>
|
||||
<li class="nline inline">
|
||||
<label for="i_status">status</label> :
|
||||
<?php echo $this->data->iSelect('status'); ?>
|
||||
</li>
|
||||
<li class="inline">
|
||||
<?php echo $this->data->iCheckBox('archived'); ?>
|
||||
<label for="i_archived">mark task as archived</label>
|
||||
</li>
|
||||
<li class="nline buttons">
|
||||
<button type="submit" name="save" value="1" class="save">Save Task</button>
|
||||
</li>
|
||||
</ol>
|
||||
<?php
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
if ($this->data->count()) {
|
||||
echo HtmlFormHelper::iForm('tasks');
|
||||
?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>deadline</th>
|
||||
<th>
|
||||
<small><?php echo $this->data->total(); ?> item(s) found</small>
|
||||
task
|
||||
</th>
|
||||
<th>start</th>
|
||||
<th>stop</th>
|
||||
<th>spent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$arr = array();
|
||||
$i = $total = 0;
|
||||
$cid = ($this->current)?$this->current->getUid():0;
|
||||
while ($this->data->next()) {
|
||||
$this->data->chkDeadline();
|
||||
$id = $this->data->getUid();
|
||||
echo '<tr id="tr_'.$id.'"'
|
||||
.((!$this->filter)?$this->data->curCss(($cid == $id)?'current':''):'')
|
||||
.'>';
|
||||
echo '<td>';
|
||||
if (!in_array($id, $arr)) {
|
||||
echo '<input type="checkbox" id="chk_'.$i.'" name="chk[]" '
|
||||
.'value="'.$id.'" />';
|
||||
$i++;
|
||||
$arr[] = $id;
|
||||
} else {
|
||||
echo '<input type="checkbox" disabled="disabled" />';
|
||||
}
|
||||
$total += $this->data->get('spent');
|
||||
?></td>
|
||||
<td><?php echo $this->data->htmlDeadline(); ?></td>
|
||||
<td>
|
||||
<a href="<?php echo $this->fc->getUrl('task','edit',array('id'=>$id)); ?>" class="onhold ajax box" title="Edit task">edit</a>
|
||||
<?php
|
||||
// priority
|
||||
echo '<span class="prio pr'.$this->data->get('priority');
|
||||
echo '">'.$this->data->get('priority').'</span> ';
|
||||
// note
|
||||
echo '<a href="'.$this->fc->getUrl('task','view',array('id'=>$id)).'" ';
|
||||
if ($this->data->isEmpty('note')) {
|
||||
echo 'class="ajax box clickme"';
|
||||
} else {
|
||||
echo 'class="note ajax box clickme" ';
|
||||
echo 'title="'.$this->data->html('note',200).'"';
|
||||
}
|
||||
echo '>';
|
||||
// title
|
||||
echo $this->data->html('title');
|
||||
echo '</a>';
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo $this->data->htmlBegin(); ?></td>
|
||||
<td><?php echo $this->data->htmlEnd(); ?></td>
|
||||
<td id="sts_<?php echo $id; ?>">
|
||||
<?php
|
||||
if ($this->data->isOpened($this->user_id)) {
|
||||
echo '<a href="'.$this->fc->getUrl('task','timer',array('id'=>$id)).'" '
|
||||
.'class="onhold clock ajax" title="start task" rel="drun">start</a>';
|
||||
}
|
||||
|
||||
echo '<span>';
|
||||
if (!$this->expand && $cid == $id) {
|
||||
echo 'running';
|
||||
} else {
|
||||
echo $this->data->getTimeSpent();
|
||||
}
|
||||
echo '</span>';
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<a href="javascript:checkAll('f_tasks')">select all</a> |
|
||||
<?php
|
||||
foreach ($this->actions as $key => $label) {
|
||||
echo ' <button type="submit" name="'.$key.'" '
|
||||
.'value="1">'.VarStr::html($label).'</button>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td colspan="2">TOTAL</td>
|
||||
<td><?php echo TaskSummary::htmlTime($total); ?></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
echo '<p class="empty">No Task found</p>';
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
if ($this->data->count()) {
|
||||
|
||||
// prepare array of data
|
||||
$arrData = array();
|
||||
$c = $d = $cid = -1;
|
||||
while ($this->data->next()) {
|
||||
if ($cid != $this->data->getUid()) {
|
||||
$c++;
|
||||
$d=0;
|
||||
$cid = $this->data->getUid();
|
||||
}
|
||||
$arrData[$c][$d] = clone($this->data);
|
||||
$d++;
|
||||
}
|
||||
|
||||
// start list
|
||||
echo HtmlFormHelper::iForm('tasks');
|
||||
|
||||
?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>deadline</th>
|
||||
<th>
|
||||
<small><?php echo count($arrData); ?> item(s) found</small>
|
||||
task
|
||||
</th>
|
||||
<th>start</th>
|
||||
<th>stop</th>
|
||||
<th>spent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$arr = array();
|
||||
$i = $total = 0;
|
||||
|
||||
$cid = ($this->current)?$this->current->getUid():0;
|
||||
|
||||
for($j=0;$j<=$c;$j++) {
|
||||
$arrObj = $arrData[$j];
|
||||
$d = count($arrObj);
|
||||
$k=0;
|
||||
$str = '';
|
||||
$subtotal = 0;
|
||||
$obj = $arrObj[0];
|
||||
|
||||
$id = $obj->getUid();
|
||||
|
||||
// first loop to get total time spent on task
|
||||
foreach ($arrObj as $obj) {
|
||||
$subtotal += $obj->get('spent');
|
||||
}
|
||||
$total += $subtotal;
|
||||
|
||||
$obj->chkDeadline();
|
||||
|
||||
// first row displays task information
|
||||
echo '<tr id="tr_'.$id.'"'
|
||||
.((!$this->filter)?$obj->curCss(($d>1)?'noline':''):($d>1?' class="noline"':''))
|
||||
.'>';
|
||||
|
||||
// checkbox
|
||||
echo '<td><input type="checkbox" id="chk_'.$i.'" name="chk[]" '
|
||||
.'value="'.$id.'" /></td>';
|
||||
|
||||
// deadline
|
||||
echo '<td>'.$obj->htmlDeadline().'</td>';
|
||||
|
||||
echo '<td>';
|
||||
// edit link
|
||||
echo '<a href="/task/edit/id/'.$id.'" class="onhold ajax box" title="Edit task">edit</a>';
|
||||
// priority
|
||||
echo '<span class="prio pr'.$obj->get('priority');
|
||||
echo '">'.$obj->get('priority').'</span> ';
|
||||
// note
|
||||
echo '<a href="'.$this->fc->getUrl('task','view',array('id'=>$id)).'" ';
|
||||
if ($obj->isEmpty('note')) {
|
||||
echo 'class="ajax box clickme"';
|
||||
} else {
|
||||
echo 'class="note ajax box clickme" ';
|
||||
echo 'title="'.$obj->html('note',200).'"';
|
||||
}
|
||||
echo '>';
|
||||
// title
|
||||
echo $obj->html('title');
|
||||
echo '</a>';
|
||||
echo '</td>';
|
||||
|
||||
// start and end
|
||||
if ($d>1) {
|
||||
// many timer, skip info here
|
||||
echo '<td> </td>';
|
||||
echo '<td> </td>';
|
||||
} else {
|
||||
echo '<td>'.$obj->htmlBegin().'</td>';
|
||||
echo '<td>'.$obj->htmlEnd().'</td>';
|
||||
}
|
||||
|
||||
// subtotal
|
||||
echo '<td id="sts_'.$id,'">';
|
||||
if ($obj->isOpened($this->user_id)) {
|
||||
echo '<a href="/task/timer/id/'.$id.'" class="onhold clock ajax" title="start task" rel="drun">start</a>';
|
||||
}
|
||||
echo TaskSummary::htmlTime($subtotal);
|
||||
echo '</td>';
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
if ($d == 1) {
|
||||
// no timers defined, skip to next task
|
||||
continue;
|
||||
}
|
||||
|
||||
// second loop to display timers
|
||||
foreach ($arrObj as $obj) {
|
||||
$id = $obj->getUid();
|
||||
$k++;
|
||||
echo '<tr id="tr_'.$id.'_'.$k.'" class="timer'
|
||||
.(($k<$d)?' noline':'')
|
||||
.'">';
|
||||
|
||||
// checkbox
|
||||
echo '<td> </td>';
|
||||
// deadline
|
||||
echo '<td> </td>';
|
||||
// title
|
||||
echo '<td> </td>';
|
||||
// start
|
||||
echo '<td>'.$obj->htmlBegin().'</td>';
|
||||
// stop
|
||||
echo '<td>'.$obj->htmlEnd().'</td>';
|
||||
// time spent
|
||||
echo '<td>'.$obj->getTimeSpent().'</td>';
|
||||
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<a href="javascript:checkAll('f_tasks')">select all</a> |
|
||||
<?php
|
||||
foreach ($this->actions as $key => $label) {
|
||||
echo ' <button type="submit" name="'.$key.'" '
|
||||
.'value="1">'.VarStr::html($label).'</button>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td colspan="2">TOTAL</td>
|
||||
<td><?php echo TaskSummary::htmlTime($total); ?></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</form>
|
||||
<?php
|
||||
} else {
|
||||
echo '<p>No Task found</p>';
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="dfoot">
|
||||
<div id="dcopy">
|
||||
<a href="http://www.taskfreak.com" target="_blank">TaskFreak</a>
|
||||
<span>TT v0.2</span>
|
||||
</div>
|
||||
<?php
|
||||
$err = false;
|
||||
$tmp = $this->fc->getHelper('messaging');
|
||||
$tmp = $tmp->getMessages($err);
|
||||
if ($tmp) {
|
||||
echo $tmp;
|
||||
} else {
|
||||
echo '...';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
if (isset($this->current)) {
|
||||
?>
|
||||
<form id="drun" action="/task/timer"<?php
|
||||
if ($this->current) {
|
||||
echo ' class="running"';
|
||||
}
|
||||
?> method="post">
|
||||
<?php
|
||||
$this->incView('include/timer');
|
||||
?>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div id="global">
|
||||
<div id="dtop">
|
||||
<h1><a href="/">TaskFreak</a></h1>
|
||||
<div id="duser">
|
||||
<?php
|
||||
if (APP_SETUP_USER_MODEL && $this->fc->user->isLoggedIn()) {
|
||||
echo $this->fc->user->html('nickname');
|
||||
if ($this->fc->getSessionVariable('switch_id') != $this->fc->user->getUid()) {
|
||||
echo ' as '.varStr::html($this->fc->getSessionVariable('switch_name'));
|
||||
}
|
||||
echo '<br /><small>';
|
||||
if ($this->fc->user->checkAcl('task_see_all')) {
|
||||
echo '<a href="'.APP_WWW_URI.'admin/switch" class="ajax box">switch</a> | ';
|
||||
}
|
||||
if ($this->fc->user->checkAcl('admin_user')) {
|
||||
echo '<a href="'.APP_WWW_URI.'admin">admin</a> | ';
|
||||
} else {
|
||||
echo '<a href="'.APP_WWW_URI.'admin/edit" class="ajax box">profile</a> | ';
|
||||
}
|
||||
echo '<a href="'.APP_WWW_URI.'login/out">logout</a>';
|
||||
echo '</small>';
|
||||
} else {
|
||||
echo 'TaskFreak!<br /><small>Time Tracking</small>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dwork">
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
echo $this->timer->iForm('task_timer','post',APP_WWW_URI.'timer/main');
|
||||
?>
|
||||
<input type="hidden" name="id" value="<?php echo $this->data->getUid(); ?>" />
|
||||
<ol class="fields multicol side">
|
||||
<li class="nline">
|
||||
<label>date</label>
|
||||
<input type="text" id="i_date" name="date" class="date" value="<?php echo VarDte::value(APP_SQL_TODAY); ?>" />
|
||||
</li>
|
||||
<li class="nline">
|
||||
<label>start</label>
|
||||
<input type="text" id="i_start_time" name="start_time" class="time" />
|
||||
</li>
|
||||
<li>
|
||||
<label>stop</label>
|
||||
<input type="text" id="i_stop_time" name="stop_time" class="time" />
|
||||
</li>
|
||||
<li class="nline">
|
||||
<label>spent</label>
|
||||
<input type="text" id="i_spent" name="spent" class="duration" value="00:00" />
|
||||
</li>
|
||||
<li class="nline buttons">
|
||||
<button type="submit" name="save" value="1" class="save">Save report</button>
|
||||
<a href="javascript:document.task_timer.reset()">reset</a>
|
||||
</li>
|
||||
</ol>
|
||||
<hr class="clear" />
|
||||
<div class="help">
|
||||
<p>Enter either :</p>
|
||||
<ul>
|
||||
<li>A start time only (will calculate time from then until now)</li>
|
||||
<li>A time spent only (will consider you've just finished the task)</li>
|
||||
<li>A start time and an stop time</li>
|
||||
<li>A start time and a time spent</li>
|
||||
<li>A stop time and a time spent</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
$total = 0;
|
||||
if ($this->data->get('spent')) {
|
||||
?>
|
||||
<table class="list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>start</th>
|
||||
<th>stop</th>
|
||||
<th>spent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
do {
|
||||
$params = array(
|
||||
'id' => $this->data->getUid(),
|
||||
'start' => $this->data->get('start')
|
||||
);
|
||||
$total += $this->data->get('spent');
|
||||
echo '<tr id="tr_'.$this->data->get('id').'_'.VarDtm::strToUnix($this->data->get('start')).'">';
|
||||
// start
|
||||
echo '<td>'.$this->data->htmlBegin().'</td>';
|
||||
// stop
|
||||
echo '<td>'.$this->data->htmlEnd().'</td>';
|
||||
// time spent
|
||||
echo '<td>';
|
||||
echo '<a href="'.$this->fc->getUrl('timer','delete',$params).'" class="onhold ajax confirm" rel="tab2">delete</a>';
|
||||
echo $this->data->getTimeSpent();
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
} while ($this->data->next());
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="2">Total</td>
|
||||
<td><?php echo TaskSummary::htmlTime($total); ?></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<?php
|
||||
} else {
|
||||
echo '<p class="empty">No timers yet</p>';
|
||||
}
|
||||
?>
|
||||
<p class="empty"><a href="#tab3" onclick="tabber.show(3); return false;">Report more time spent</a></p>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
if ($this->current) {
|
||||
?>
|
||||
<div id="timerstatus">
|
||||
<?php
|
||||
if ($this->current->isEmpty('stop')) {
|
||||
// task is running
|
||||
?>
|
||||
<!-- button type="submit" name="pause" value="1" class="submit" tabindex="2">pause</button -->
|
||||
<button type="submit" name="stop" value="1" class="submit" tabindex="2">stop</button>
|
||||
<button type="submit" name="close" value="1" class="warn" tabindex="3" onclick="return confirm('mark this task as done ?')">done</button>
|
||||
<?php
|
||||
} else {
|
||||
// task is paused (requested from ajax only)
|
||||
?>
|
||||
<button type="submit" name="resume" value="1" class="submit" tabindex="2">resume</button>
|
||||
<button type="submit" name="stop" value="1" class="warn" tabindex="3">stop</button>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<p>
|
||||
<input type="hidden" name="id" value="<?php echo $this->current->getUid(); ?>" />
|
||||
<input type="hidden" id="i_timer" name="timer" value="<?php echo $this->current->getRealSpentSecs(); ?>" />
|
||||
<span id="dtimer"><?php echo $this->current->getRealSpent(); ?></span>
|
||||
<?php echo $this->current->html('title'); ?>
|
||||
</p>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<div id="timerstatus">
|
||||
<button type="submit" name="save" value="1" class="saveadd" tabindex="2">Save</button>
|
||||
<button type="submit" name="start" value="1" class="save" tabindex="3">Start</button>
|
||||
</div>
|
||||
<p>
|
||||
<input type="text" name="title" value="" tabindex="1" />
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
if (isset($this->jsCode)) {
|
||||
echo '<script type="text/javascript">';
|
||||
echo $this->jsCode;
|
||||
echo '</script>';
|
||||
}
|
||||
?>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
?>
|
||||
<form action="/login" method="post">
|
||||
<?php
|
||||
if ($str = $this->fc->user->getAuthError()) {
|
||||
echo '<p>Can not login: '.VarStr::html($str).'</p>';
|
||||
}
|
||||
?>
|
||||
<ol class="fields side">
|
||||
<li>
|
||||
<label for="i_username">Username</label>
|
||||
<?php echo $this->fc->user->iText('username'); ?>
|
||||
</li>
|
||||
<li>
|
||||
<label for="i_password">Password</label>
|
||||
<?php echo $this->fc->user->iPass('password'); ?>
|
||||
</li>
|
||||
<li class="buttons">
|
||||
<button type="submit" name="login" value="1" class="submit">Login</button>
|
||||
</li>
|
||||
</ol>
|
||||
</form>
|
||||
<?php
|
||||
if ($GLOBALS['config']['log_debug'] == 2) {
|
||||
$this->fc->user->htmlAllErrors();
|
||||
echo $this->fc->user;
|
||||
}
|
||||
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
?>
|
||||
<div id="dmain" class="full">
|
||||
<div id="dfilters">
|
||||
<span>
|
||||
<a href="<?php echo $this->fc->getUrl('task/edit');?>" class="ajax box new inv" title="Create single task">Create task</a>
|
||||
<a href="<?php echo $this->fc->getUrl('task/create');?>" class="ajax bigbox new multi inv" title="Create multiple tasks">Create multiple</a>
|
||||
<a href="javascript:reloadList()" class="new reload inv" title="Reload list">Reload</a>
|
||||
</span>
|
||||
<ul class="links horiz">
|
||||
<?php
|
||||
$arr = array('todo'=>0,'done'=>1,'valid'=>2,'archived'=>3);
|
||||
foreach($arr as $lbl => $val) {
|
||||
echo '<li';
|
||||
if ($this->filter == $val) {
|
||||
echo ' class="active"';
|
||||
}
|
||||
echo '><a href='.$this->fc->thisUrl(array('filter'=>$val)).'>'.$lbl.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="links horiz">
|
||||
<?php
|
||||
$arr = array('compact'=>0,'expand'=>1);
|
||||
foreach($arr as $lbl => $val) {
|
||||
echo '<li';
|
||||
if ($this->expand == $val) {
|
||||
echo ' class="active"';
|
||||
}
|
||||
echo '><a href='.$this->fc->thisUrl(array('expand'=>$val)).'>'.$lbl.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="links horiz">
|
||||
<?php
|
||||
$arr = array('10'=>10,'25'=>25,'50'=>50,'all'=>0);
|
||||
foreach($arr as $lbl => $val) {
|
||||
echo '<li';
|
||||
if ($this->limit == $val) {
|
||||
echo ' class="active"';
|
||||
}
|
||||
echo '><a href='.$this->fc->thisUrl(array('limit'=>$val)).'>'.$lbl.'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<form id="search" action="<?php $this->fc->thisUrl(); ?>" method="get">
|
||||
<p>
|
||||
<input type="text" name="search" value="<?php echo $this->search; ?>" tabindex="4" />
|
||||
<button type="submit" name="go" value="1">search</button>
|
||||
<button type="button" onclick="this.form.elements[0].value='';this.form.submit()">x</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<div id="dlist" class="tasks">
|
||||
<?php
|
||||
if ($this->expand) {
|
||||
$this->incView('include/list-expand');
|
||||
} else {
|
||||
$this->incView('include/list-compact');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
$this->incView('include/page-top', false);
|
||||
?>
|
||||
<h1><?php echo $this->data->html('title'); ?></h1>
|
||||
<div id="tabs" class="tabs">
|
||||
<ul id="tabs-nav" class="nav">
|
||||
<li><a href="#tab1">info</a></li>
|
||||
<li><a href="#tab2">history</a></li>
|
||||
<li><a href="#tab3">report time spent</a></li>
|
||||
</ul>
|
||||
<div id="tab1" class="tab">
|
||||
<table class="info">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>deadline</th>
|
||||
<td><?php echo $this->data->htmlDeadline(); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>priority</th>
|
||||
<td><?php echo $this->data->htmlPriority(); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>status</th>
|
||||
<td><?php echo $this->data->htmlStatus(); ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
if (!$this->data->isEmpty('note')) {
|
||||
?>
|
||||
<tr>
|
||||
<th>note</th>
|
||||
<td><?php echo $this->data->html('note'); ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="tab2" class="tab">
|
||||
<?php
|
||||
$this->incView('include/timer-list');
|
||||
?>
|
||||
</div>
|
||||
<div id="tab3" class="tab">
|
||||
<?php
|
||||
$this->incView('include/timer-form');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var tabber = new Yetii({id: 'tabs'});
|
||||
$('a.ajax').makeajax();
|
||||
$('#f_task_timer').ajaxForm({
|
||||
target: '#f_task_timer',
|
||||
data: {'ajax':'1'}
|
||||
});
|
||||
// $.getScript('/asset/js/jquery.dateentry.pack.js');
|
||||
// $.getScript('/asset/js/jquery.timeentry.pack.js');
|
||||
</script>
|
||||
<script type="text/javascript" src="<?php echo APP_WWW_URI.'asset/js/jquery.dateentry.pack.js'; ?>"></script>
|
||||
<script type="text/javascript" src="<?php echo APP_WWW_URI.'asset/js/jquery.timeentry.pack.js'; ?>"></script>
|
||||
<?php
|
||||
|
||||
$this->incView('include/page-bot', false);
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
/**
|
||||
* fields should always be under a OL.fields
|
||||
* OL.side will show labels on the left
|
||||
* OL.multicol may have multi columns
|
||||
* -> LI.newrow stars a new row
|
||||
* SPAN.error for error messages
|
||||
*/
|
||||
|
||||
/* layout */
|
||||
ol.fields {
|
||||
list-style: none;
|
||||
padding: 0 0 5px 5px;
|
||||
}
|
||||
ol.lined li {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
ol li.linefree {
|
||||
border-bottom: 0px none;
|
||||
}
|
||||
ol.side li {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
ol.side li label {
|
||||
float: left;
|
||||
width: 120px;
|
||||
padding: 2px 0 0 4px;
|
||||
color: #333;
|
||||
}
|
||||
ol.top li label {
|
||||
display: block;
|
||||
}
|
||||
ol.fields li.compulsory {
|
||||
}
|
||||
ol.fields li.compulsory label {
|
||||
/* color: #600; */
|
||||
background: transparent url(../img/compulsory.png) no-repeat right top;
|
||||
}
|
||||
ol.fields li span, ol.fields li small.nline {
|
||||
padding: 2px 0 0 4px;
|
||||
}
|
||||
ol.fields li span.ui-icon {
|
||||
padding: 0;
|
||||
}
|
||||
ol.side li span, ol.side li small.nline {
|
||||
display: block;
|
||||
margin-left: 120px;
|
||||
}
|
||||
ol.fields li.buttons {
|
||||
border-bottom: 0px none;
|
||||
}
|
||||
ol.side li.buttons {
|
||||
padding-left: 122px;
|
||||
}
|
||||
ol.fields ul {
|
||||
clear: left;
|
||||
list-style: none;
|
||||
}
|
||||
ol.fields ul li {
|
||||
border-bottom: 0 none;
|
||||
}
|
||||
ol.fields li.inline {
|
||||
padding: 6px 4px;
|
||||
}
|
||||
ol.fields li.inline span {
|
||||
display: inline;
|
||||
}
|
||||
ol.side ul {
|
||||
margin: 0 0 -18px 100px;
|
||||
position:relative;
|
||||
top:-18px;
|
||||
}
|
||||
ol.side ul li label, ol li.inline label {
|
||||
padding: 0;
|
||||
width: auto;
|
||||
float: none;
|
||||
display: inline;
|
||||
}
|
||||
ol.multicol li {
|
||||
float: left;
|
||||
margin-left: 12px;
|
||||
}
|
||||
ol.multicol li.nline {
|
||||
clear: left;
|
||||
margin-left: 0;
|
||||
}
|
||||
ol.side li strong {
|
||||
display: block;
|
||||
padding-left: 124px;
|
||||
}
|
||||
ol.side li span.error {
|
||||
display: block;
|
||||
/* padding-left: 124px; */
|
||||
font-size: .917em;
|
||||
color: #900;
|
||||
}
|
||||
/* fields */
|
||||
input, textarea, option {
|
||||
font-style: Helvetica, Arial, sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
ol.styled input, ol.styled select, ol.styled textarea {
|
||||
padding: 2px;
|
||||
border: 2px solid #666;
|
||||
background-color: #fff;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
ol.styled input:focus, ol.styled select:focus, ol.styled textarea:focus {
|
||||
border-color: #333;
|
||||
outline: none;
|
||||
}
|
||||
.wxxs {
|
||||
width: 30px;
|
||||
}
|
||||
.wxs {
|
||||
width: 50px;
|
||||
}
|
||||
.ws {
|
||||
width: 80px;
|
||||
}
|
||||
.wm {
|
||||
width: 120px;
|
||||
}
|
||||
.wl {
|
||||
width: 250px;
|
||||
}
|
||||
.wxl {
|
||||
width: 400px;
|
||||
}
|
||||
.wxxl {
|
||||
width: 99%;
|
||||
}
|
||||
textarea.hs {
|
||||
height: 50px;
|
||||
}
|
||||
textarea.hm {
|
||||
height: 100px;
|
||||
}
|
||||
textarea.hl {
|
||||
height: 200px;
|
||||
}
|
||||
textarea.hxl {
|
||||
height: 350px;
|
||||
}
|
||||
input.fake, textarea.fake {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
input.file {
|
||||
border: 0 none;
|
||||
}
|
||||
input.red, textarea.red {
|
||||
border: 1px solid #933;
|
||||
background-color: #fff3f3;
|
||||
}
|
||||
input.date {
|
||||
width: 80px;
|
||||
}
|
||||
input.time, input.duration {
|
||||
width: 60px;
|
||||
}
|
||||
ol.fields li span.dateEntry_wrap, ol.fields li span.timeEntry_wrap {
|
||||
padding: 0;
|
||||
margin-left: 3px;
|
||||
display: inline;
|
||||
}
|
||||
ol.fields li span.dateEntry_control, ol.fields li span.timeEntry_control {
|
||||
padding: 0;
|
||||
margin: 0 0 0 3px;
|
||||
display: inline;
|
||||
}
|
||||
/* captcha */
|
||||
ol li.form_captcha {
|
||||
}
|
||||
ol li.form_captcha span.cms_captcha {
|
||||
display:block;
|
||||
margin: 0 0 12px 0;
|
||||
width: 360px;
|
||||
height: 40px;
|
||||
border: 2px solid #369;
|
||||
background-color: #fff;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
ol li.form_captcha span.cms_captcha img {
|
||||
float: left;
|
||||
}
|
||||
ol li.form_captcha span.cms_captcha input {
|
||||
float: left;
|
||||
border: 0 none;
|
||||
border-left: 2px dotted #69c;
|
||||
width: 140px;
|
||||
height: 24px;
|
||||
padding: 8px 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
ol li.form_captcha span.tznError {
|
||||
display: block;
|
||||
padding: 3px 0;
|
||||
font-size: 1em;
|
||||
color: #900;
|
||||
}
|
||||
ol.fields li.form_captcha span.cms_captcha {
|
||||
margin: 0 0 12px 122px;
|
||||
}
|
||||
/* buttons */
|
||||
button, a.button {
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 1px 4px;
|
||||
/* height: 22px; */
|
||||
background-image: url(../img/bg-buttons.png);
|
||||
background-position: 0 0;
|
||||
background-repeat: repeat-x;
|
||||
text-decoration: none;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
a.button {
|
||||
padding: 2px 4px;
|
||||
height: auto;
|
||||
}
|
||||
button:hover, a.button:hover, button:focus, a.button:focus {
|
||||
color: #000;
|
||||
border-color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
button.create, a.create {
|
||||
background-position: -30px -22px;
|
||||
}
|
||||
button.submit, a.submit {
|
||||
background-position: -30px -22px;
|
||||
}
|
||||
button.save {
|
||||
padding-left: 30px;
|
||||
background-position: 0 -22px;
|
||||
}
|
||||
button.saveclose {
|
||||
padding-left: 30px;
|
||||
background-position: 0 -44px;
|
||||
}
|
||||
button.saveadd {
|
||||
padding-left: 30px;
|
||||
background-position: 0 -66px;
|
||||
}
|
||||
button.delete, a.delete {
|
||||
padding-left: 30px;
|
||||
background-position: 0 -88px;
|
||||
}
|
||||
button.warn, a.warn {
|
||||
background-position: -30px -88px;
|
||||
}
|
||||
.close {
|
||||
margin-left: 10px;
|
||||
padding: 0 4px 2px 10px;
|
||||
background: transparent url(../img/cross.png) no-repeat left center;
|
||||
}
|
||||
a.close {
|
||||
color: #333;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a.close:hover {
|
||||
color: #000;
|
||||
}
|
||||
.faded {
|
||||
opacity: 0.3;
|
||||
-moz-opacity: 0.3;
|
||||
filter: alpha(opacity=30);
|
||||
}
|
||||
.marge {
|
||||
margin-left: 10px;
|
||||
}
|
||||
/*
|
||||
#ajax-load {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.7;
|
||||
-moz-opacity: 0.7;
|
||||
filter: alpha(opacity=70);
|
||||
background: #fff url(../img/loading.gif) no-repeat center center;
|
||||
z-index: 200;
|
||||
behavior: url(/assets/css/iedivfix.htc);
|
||||
}
|
||||
.loading {
|
||||
opacity: 0.5;
|
||||
-moz-opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
background: url(../img/loading.gif) no-repeat center center;
|
||||
}
|
||||
*/
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?php $this->callHelper('html_asset','footerStuff'); ?>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
||||
<title><?php echo $this->html('title'); ?></title>
|
||||
<?php
|
||||
if (!$this->isEmpty('description')) {
|
||||
?>
|
||||
<meta name="description" content="<?php echo $this->html('description'); ?>" />
|
||||
<?php
|
||||
}
|
||||
|
||||
if (!$this->isEmpty('keywords')) {
|
||||
?>
|
||||
<meta name="keywords" content="<?php echo $this->html('keywords'); ?>" />
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<link rel="SHORTCUT ICON" href="/favicon.ico" />
|
||||
<?php $this->callHelper('html_asset','headerStuff'); ?>
|
||||
</head>
|
||||
<body>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 90 B |
|
After Width: | Height: | Size: 351 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 432 B |
|
After Width: | Height: | Size: 966 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 270 B |
|
|
@ -0,0 +1,154 @@
|
|||
/*!
|
||||
* jQuery JavaScript Library v1.4.2
|
||||
* http://jquery.com/
|
||||
*
|
||||
* Copyright 2010, John Resig
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* Includes Sizzle.js
|
||||
* http://sizzlejs.com/
|
||||
* Copyright 2010, The Dojo Foundation
|
||||
* Released under the MIT, BSD, and GPL Licenses.
|
||||
*
|
||||
* Date: Sat Feb 13 22:33:48 2010 -0500
|
||||
*/
|
||||
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
|
||||
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
|
||||
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
|
||||
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
|
||||
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
|
||||
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
|
||||
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
|
||||
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
|
||||
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
|
||||
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
|
||||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
|
||||
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
|
||||
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
|
||||
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
|
||||
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
|
||||
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
|
||||
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
|
||||
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
|
||||
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
|
||||
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
|
||||
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
|
||||
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
|
||||
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
|
||||
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
|
||||
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
|
||||
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
|
||||
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
|
||||
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
|
||||
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
|
||||
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
|
||||
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
|
||||
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
|
||||
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
|
||||
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
|
||||
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
|
||||
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
|
||||
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
|
||||
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
|
||||
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
|
||||
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
||||
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
|
||||
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
|
||||
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
|
||||
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
|
||||
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
|
||||
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
|
||||
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
|
||||
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
|
||||
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
|
||||
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
|
||||
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
|
||||
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
|
||||
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
|
||||
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
|
||||
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
|
||||
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
|
||||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
|
||||
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
|
||||
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
|
||||
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
|
||||
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
|
||||
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
|
||||
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
|
||||
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
|
||||
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
|
||||
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
|
||||
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
|
||||
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
|
||||
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
|
||||
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
|
||||
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
|
||||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
|
||||
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
|
||||
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
|
||||
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
|
||||
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
|
||||
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
|
||||
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
|
||||
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
|
||||
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
|
||||
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
|
||||
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
|
||||
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
|
||||
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
|
||||
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
|
||||
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
|
||||
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
|
||||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
|
||||
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
|
||||
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
|
||||
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
|
||||
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
|
||||
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
|
||||
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
|
||||
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
|
||||
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
|
||||
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
|
||||
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
|
||||
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
|
||||
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
|
||||
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
|
||||
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
|
||||
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
|
||||
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
|
||||
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
|
||||
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
|
||||
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
|
||||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
|
||||
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
|
||||
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
|
||||
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
|
||||
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
|
||||
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
|
||||
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
|
||||
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
|
||||
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
|
||||
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
|
||||
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
|
||||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
|
||||
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
|
||||
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
|
||||
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
|
||||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
|
||||
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
|
||||
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
|
||||
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
|
||||
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
|
||||
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
|
||||
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
|
||||
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
|
||||
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
|
||||
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
|
||||
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
|
||||
|
|
@ -0,0 +1,675 @@
|
|||
/*!
|
||||
* jQuery Form Plugin
|
||||
* version: 2.43 (12-MAR-2010)
|
||||
* @requires jQuery v1.3.2 or later
|
||||
*
|
||||
* Examples and documentation at: http://malsup.com/jquery/form/
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
;(function($) {
|
||||
|
||||
/*
|
||||
Usage Note:
|
||||
-----------
|
||||
Do not use both ajaxSubmit and ajaxForm on the same form. These
|
||||
functions are intended to be exclusive. Use ajaxSubmit if you want
|
||||
to bind your own submit handler to the form. For example,
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#myForm').bind('submit', function() {
|
||||
$(this).ajaxSubmit({
|
||||
target: '#output'
|
||||
});
|
||||
return false; // <-- important!
|
||||
});
|
||||
});
|
||||
|
||||
Use ajaxForm when you want the plugin to manage all the event binding
|
||||
for you. For example,
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#myForm').ajaxForm({
|
||||
target: '#output'
|
||||
});
|
||||
});
|
||||
|
||||
When using ajaxForm, the ajaxSubmit function will be invoked for you
|
||||
at the appropriate time.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ajaxSubmit() provides a mechanism for immediately submitting
|
||||
* an HTML form using AJAX.
|
||||
*/
|
||||
$.fn.ajaxSubmit = function(options) {
|
||||
// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
|
||||
if (!this.length) {
|
||||
log('ajaxSubmit: skipping submit process - no element selected');
|
||||
return this;
|
||||
}
|
||||
|
||||
if (typeof options == 'function')
|
||||
options = { success: options };
|
||||
|
||||
var url = $.trim(this.attr('action'));
|
||||
if (url) {
|
||||
// clean url (don't include hash vaue)
|
||||
url = (url.match(/^([^#]+)/)||[])[1];
|
||||
}
|
||||
url = url || window.location.href || '';
|
||||
|
||||
options = $.extend({
|
||||
url: url,
|
||||
type: this.attr('method') || 'GET',
|
||||
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
|
||||
}, options || {});
|
||||
|
||||
// hook for manipulating the form data before it is extracted;
|
||||
// convenient for use with rich editors like tinyMCE or FCKEditor
|
||||
var veto = {};
|
||||
this.trigger('form-pre-serialize', [this, options, veto]);
|
||||
if (veto.veto) {
|
||||
log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
|
||||
return this;
|
||||
}
|
||||
|
||||
// provide opportunity to alter form data before it is serialized
|
||||
if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
|
||||
log('ajaxSubmit: submit aborted via beforeSerialize callback');
|
||||
return this;
|
||||
}
|
||||
|
||||
var a = this.formToArray(options.semantic);
|
||||
if (options.data) {
|
||||
options.extraData = options.data;
|
||||
for (var n in options.data) {
|
||||
if(options.data[n] instanceof Array) {
|
||||
for (var k in options.data[n])
|
||||
a.push( { name: n, value: options.data[n][k] } );
|
||||
}
|
||||
else
|
||||
a.push( { name: n, value: options.data[n] } );
|
||||
}
|
||||
}
|
||||
|
||||
// give pre-submit callback an opportunity to abort the submit
|
||||
if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
|
||||
log('ajaxSubmit: submit aborted via beforeSubmit callback');
|
||||
return this;
|
||||
}
|
||||
|
||||
// fire vetoable 'validate' event
|
||||
this.trigger('form-submit-validate', [a, this, options, veto]);
|
||||
if (veto.veto) {
|
||||
log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
|
||||
return this;
|
||||
}
|
||||
|
||||
var q = $.param(a);
|
||||
|
||||
if (options.type.toUpperCase() == 'GET') {
|
||||
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
||||
options.data = null; // data is null for 'get'
|
||||
}
|
||||
else
|
||||
options.data = q; // data is the query string for 'post'
|
||||
|
||||
var $form = this, callbacks = [];
|
||||
if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
|
||||
if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
|
||||
|
||||
// perform a load on the target only if dataType is not provided
|
||||
if (!options.dataType && options.target) {
|
||||
var oldSuccess = options.success || function(){};
|
||||
callbacks.push(function(data) {
|
||||
var fn = options.replaceTarget ? 'replaceWith' : 'html';
|
||||
$(options.target)[fn](data).each(oldSuccess, arguments);
|
||||
});
|
||||
}
|
||||
else if (options.success)
|
||||
callbacks.push(options.success);
|
||||
|
||||
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
|
||||
for (var i=0, max=callbacks.length; i < max; i++)
|
||||
callbacks[i].apply(options, [data, status, xhr || $form, $form]);
|
||||
};
|
||||
|
||||
// are there files to upload?
|
||||
var files = $('input:file', this).fieldValue();
|
||||
var found = false;
|
||||
for (var j=0; j < files.length; j++)
|
||||
if (files[j])
|
||||
found = true;
|
||||
|
||||
var multipart = false;
|
||||
// var mp = 'multipart/form-data';
|
||||
// multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
|
||||
|
||||
// options.iframe allows user to force iframe mode
|
||||
// 06-NOV-09: now defaulting to iframe mode if file input is detected
|
||||
if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
|
||||
// hack to fix Safari hang (thanks to Tim Molendijk for this)
|
||||
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
|
||||
if (options.closeKeepAlive)
|
||||
$.get(options.closeKeepAlive, fileUpload);
|
||||
else
|
||||
fileUpload();
|
||||
}
|
||||
else
|
||||
$.ajax(options);
|
||||
|
||||
// fire 'notify' event
|
||||
this.trigger('form-submit-notify', [this, options]);
|
||||
return this;
|
||||
|
||||
|
||||
// private function for handling file uploads (hat tip to YAHOO!)
|
||||
function fileUpload() {
|
||||
var form = $form[0];
|
||||
|
||||
if ($(':input[name=submit]', form).length) {
|
||||
alert('Error: Form elements must not be named "submit".');
|
||||
return;
|
||||
}
|
||||
|
||||
var opts = $.extend({}, $.ajaxSettings, options);
|
||||
var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
|
||||
|
||||
var id = 'jqFormIO' + (new Date().getTime());
|
||||
var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" onload="(jQuery(this).data(\'form-plugin-onload\'))()" />');
|
||||
var io = $io[0];
|
||||
|
||||
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
||||
|
||||
var xhr = { // mock object
|
||||
aborted: 0,
|
||||
responseText: null,
|
||||
responseXML: null,
|
||||
status: 0,
|
||||
statusText: 'n/a',
|
||||
getAllResponseHeaders: function() {},
|
||||
getResponseHeader: function() {},
|
||||
setRequestHeader: function() {},
|
||||
abort: function() {
|
||||
this.aborted = 1;
|
||||
$io.attr('src', opts.iframeSrc); // abort op in progress
|
||||
}
|
||||
};
|
||||
|
||||
var g = opts.global;
|
||||
// trigger ajax global events so that activity/block indicators work like normal
|
||||
if (g && ! $.active++) $.event.trigger("ajaxStart");
|
||||
if (g) $.event.trigger("ajaxSend", [xhr, opts]);
|
||||
|
||||
if (s.beforeSend && s.beforeSend(xhr, s) === false) {
|
||||
s.global && $.active--;
|
||||
return;
|
||||
}
|
||||
if (xhr.aborted)
|
||||
return;
|
||||
|
||||
var cbInvoked = false;
|
||||
var timedOut = 0;
|
||||
|
||||
// add submitting element to data if we know it
|
||||
var sub = form.clk;
|
||||
if (sub) {
|
||||
var n = sub.name;
|
||||
if (n && !sub.disabled) {
|
||||
opts.extraData = opts.extraData || {};
|
||||
opts.extraData[n] = sub.value;
|
||||
if (sub.type == "image") {
|
||||
opts.extraData[n+'.x'] = form.clk_x;
|
||||
opts.extraData[n+'.y'] = form.clk_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// take a breath so that pending repaints get some cpu time before the upload starts
|
||||
function doSubmit() {
|
||||
// make sure form attrs are set
|
||||
var t = $form.attr('target'), a = $form.attr('action');
|
||||
|
||||
// update form attrs in IE friendly way
|
||||
form.setAttribute('target',id);
|
||||
if (form.getAttribute('method') != 'POST')
|
||||
form.setAttribute('method', 'POST');
|
||||
if (form.getAttribute('action') != opts.url)
|
||||
form.setAttribute('action', opts.url);
|
||||
|
||||
// ie borks in some cases when setting encoding
|
||||
if (! opts.skipEncodingOverride) {
|
||||
$form.attr({
|
||||
encoding: 'multipart/form-data',
|
||||
enctype: 'multipart/form-data'
|
||||
});
|
||||
}
|
||||
|
||||
// support timout
|
||||
if (opts.timeout)
|
||||
setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
|
||||
|
||||
// add "extra" data to form if provided in options
|
||||
var extraInputs = [];
|
||||
try {
|
||||
if (opts.extraData)
|
||||
for (var n in opts.extraData)
|
||||
extraInputs.push(
|
||||
$('<input type="hidden" name="'+n+'" value="'+opts.extraData[n]+'" />')
|
||||
.appendTo(form)[0]);
|
||||
|
||||
// add iframe to doc and submit the form
|
||||
$io.appendTo('body');
|
||||
$io.data('form-plugin-onload', cb);
|
||||
form.submit();
|
||||
}
|
||||
finally {
|
||||
// reset attrs and remove "extra" input elements
|
||||
form.setAttribute('action',a);
|
||||
t ? form.setAttribute('target', t) : $form.removeAttr('target');
|
||||
$(extraInputs).remove();
|
||||
}
|
||||
};
|
||||
|
||||
if (opts.forceSync)
|
||||
doSubmit();
|
||||
else
|
||||
setTimeout(doSubmit, 10); // this lets dom updates render
|
||||
|
||||
var domCheckCount = 100;
|
||||
|
||||
function cb() {
|
||||
if (cbInvoked)
|
||||
return;
|
||||
|
||||
var ok = true;
|
||||
try {
|
||||
if (timedOut) throw 'timeout';
|
||||
// extract the server response from the iframe
|
||||
var data, doc;
|
||||
|
||||
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
|
||||
|
||||
var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
|
||||
log('isXml='+isXml);
|
||||
if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
|
||||
if (--domCheckCount) {
|
||||
// in some browsers (Opera) the iframe DOM is not always traversable when
|
||||
// the onload callback fires, so we loop a bit to accommodate
|
||||
log('requeing onLoad callback, DOM not available');
|
||||
setTimeout(cb, 250);
|
||||
return;
|
||||
}
|
||||
log('Could not access iframe DOM after 100 tries.');
|
||||
return;
|
||||
}
|
||||
|
||||
log('response detected');
|
||||
cbInvoked = true;
|
||||
xhr.responseText = doc.body ? doc.body.innerHTML : null;
|
||||
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
||||
xhr.getResponseHeader = function(header){
|
||||
var headers = {'content-type': opts.dataType};
|
||||
return headers[header];
|
||||
};
|
||||
|
||||
if (opts.dataType == 'json' || opts.dataType == 'script') {
|
||||
// see if user embedded response in textarea
|
||||
var ta = doc.getElementsByTagName('textarea')[0];
|
||||
if (ta)
|
||||
xhr.responseText = ta.value;
|
||||
else {
|
||||
// account for browsers injecting pre around json response
|
||||
var pre = doc.getElementsByTagName('pre')[0];
|
||||
if (pre)
|
||||
xhr.responseText = pre.innerHTML;
|
||||
}
|
||||
}
|
||||
else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
|
||||
xhr.responseXML = toXml(xhr.responseText);
|
||||
}
|
||||
data = $.httpData(xhr, opts.dataType);
|
||||
}
|
||||
catch(e){
|
||||
log('error caught:',e);
|
||||
ok = false;
|
||||
xhr.error = e;
|
||||
$.handleError(opts, xhr, 'error', e);
|
||||
}
|
||||
|
||||
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
||||
if (ok) {
|
||||
opts.success(data, 'success');
|
||||
if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
|
||||
}
|
||||
if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
|
||||
if (g && ! --$.active) $.event.trigger("ajaxStop");
|
||||
if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
|
||||
|
||||
// clean up
|
||||
setTimeout(function() {
|
||||
$io.removeData('form-plugin-onload');
|
||||
$io.remove();
|
||||
xhr.responseXML = null;
|
||||
}, 100);
|
||||
};
|
||||
|
||||
function toXml(s, doc) {
|
||||
if (window.ActiveXObject) {
|
||||
doc = new ActiveXObject('Microsoft.XMLDOM');
|
||||
doc.async = 'false';
|
||||
doc.loadXML(s);
|
||||
}
|
||||
else
|
||||
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
||||
return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* ajaxForm() provides a mechanism for fully automating form submission.
|
||||
*
|
||||
* The advantages of using this method instead of ajaxSubmit() are:
|
||||
*
|
||||
* 1: This method will include coordinates for <input type="image" /> elements (if the element
|
||||
* is used to submit the form).
|
||||
* 2. This method will include the submit element's name/value data (for the element that was
|
||||
* used to submit the form).
|
||||
* 3. This method binds the submit() method to the form for you.
|
||||
*
|
||||
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
|
||||
* passes the options argument along after properly binding events for submit elements and
|
||||
* the form itself.
|
||||
*/
|
||||
$.fn.ajaxForm = function(options) {
|
||||
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).ajaxSubmit(options);
|
||||
}).bind('click.form-plugin', function(e) {
|
||||
var target = e.target;
|
||||
var $el = $(target);
|
||||
if (!($el.is(":submit,input:image"))) {
|
||||
// is this a child element of the submit el? (ex: a span within a button)
|
||||
var t = $el.closest(':submit');
|
||||
if (t.length == 0)
|
||||
return;
|
||||
target = t[0];
|
||||
}
|
||||
var form = this;
|
||||
form.clk = target;
|
||||
if (target.type == 'image') {
|
||||
if (e.offsetX != undefined) {
|
||||
form.clk_x = e.offsetX;
|
||||
form.clk_y = e.offsetY;
|
||||
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
||||
var offset = $el.offset();
|
||||
form.clk_x = e.pageX - offset.left;
|
||||
form.clk_y = e.pageY - offset.top;
|
||||
} else {
|
||||
form.clk_x = e.pageX - target.offsetLeft;
|
||||
form.clk_y = e.pageY - target.offsetTop;
|
||||
}
|
||||
}
|
||||
// clear form vars
|
||||
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
|
||||
});
|
||||
};
|
||||
|
||||
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
||||
$.fn.ajaxFormUnbind = function() {
|
||||
return this.unbind('submit.form-plugin click.form-plugin');
|
||||
};
|
||||
|
||||
/**
|
||||
* formToArray() gathers form element data into an array of objects that can
|
||||
* be passed to any of the following ajax functions: $.get, $.post, or load.
|
||||
* Each object in the array has both a 'name' and 'value' property. An example of
|
||||
* an array for a simple login form might be:
|
||||
*
|
||||
* [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
|
||||
*
|
||||
* It is this array that is passed to pre-submit callback functions provided to the
|
||||
* ajaxSubmit() and ajaxForm() methods.
|
||||
*/
|
||||
$.fn.formToArray = function(semantic) {
|
||||
var a = [];
|
||||
if (this.length == 0) return a;
|
||||
|
||||
var form = this[0];
|
||||
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
||||
if (!els) return a;
|
||||
for(var i=0, max=els.length; i < max; i++) {
|
||||
var el = els[i];
|
||||
var n = el.name;
|
||||
if (!n) continue;
|
||||
|
||||
if (semantic && form.clk && el.type == "image") {
|
||||
// handle image inputs on the fly when semantic == true
|
||||
if(!el.disabled && form.clk == el) {
|
||||
a.push({name: n, value: $(el).val()});
|
||||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var v = $.fieldValue(el, true);
|
||||
if (v && v.constructor == Array) {
|
||||
for(var j=0, jmax=v.length; j < jmax; j++)
|
||||
a.push({name: n, value: v[j]});
|
||||
}
|
||||
else if (v !== null && typeof v != 'undefined')
|
||||
a.push({name: n, value: v});
|
||||
}
|
||||
|
||||
if (!semantic && form.clk) {
|
||||
// input type=='image' are not found in elements array! handle it here
|
||||
var $input = $(form.clk), input = $input[0], n = input.name;
|
||||
if (n && !input.disabled && input.type == 'image') {
|
||||
a.push({name: n, value: $input.val()});
|
||||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializes form data into a 'submittable' string. This method will return a string
|
||||
* in the format: name1=value1&name2=value2
|
||||
*/
|
||||
$.fn.formSerialize = function(semantic) {
|
||||
//hand off to jQuery.param for proper encoding
|
||||
return $.param(this.formToArray(semantic));
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializes all field elements in the jQuery object into a query string.
|
||||
* This method will return a string in the format: name1=value1&name2=value2
|
||||
*/
|
||||
$.fn.fieldSerialize = function(successful) {
|
||||
var a = [];
|
||||
this.each(function() {
|
||||
var n = this.name;
|
||||
if (!n) return;
|
||||
var v = $.fieldValue(this, successful);
|
||||
if (v && v.constructor == Array) {
|
||||
for (var i=0,max=v.length; i < max; i++)
|
||||
a.push({name: n, value: v[i]});
|
||||
}
|
||||
else if (v !== null && typeof v != 'undefined')
|
||||
a.push({name: this.name, value: v});
|
||||
});
|
||||
//hand off to jQuery.param for proper encoding
|
||||
return $.param(a);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value(s) of the element in the matched set. For example, consider the following form:
|
||||
*
|
||||
* <form><fieldset>
|
||||
* <input name="A" type="text" />
|
||||
* <input name="A" type="text" />
|
||||
* <input name="B" type="checkbox" value="B1" />
|
||||
* <input name="B" type="checkbox" value="B2"/>
|
||||
* <input name="C" type="radio" value="C1" />
|
||||
* <input name="C" type="radio" value="C2" />
|
||||
* </fieldset></form>
|
||||
*
|
||||
* var v = $(':text').fieldValue();
|
||||
* // if no values are entered into the text inputs
|
||||
* v == ['','']
|
||||
* // if values entered into the text inputs are 'foo' and 'bar'
|
||||
* v == ['foo','bar']
|
||||
*
|
||||
* var v = $(':checkbox').fieldValue();
|
||||
* // if neither checkbox is checked
|
||||
* v === undefined
|
||||
* // if both checkboxes are checked
|
||||
* v == ['B1', 'B2']
|
||||
*
|
||||
* var v = $(':radio').fieldValue();
|
||||
* // if neither radio is checked
|
||||
* v === undefined
|
||||
* // if first radio is checked
|
||||
* v == ['C1']
|
||||
*
|
||||
* The successful argument controls whether or not the field element must be 'successful'
|
||||
* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
|
||||
* The default value of the successful argument is true. If this value is false the value(s)
|
||||
* for each element is returned.
|
||||
*
|
||||
* Note: This method *always* returns an array. If no valid value can be determined the
|
||||
* array will be empty, otherwise it will contain one or more values.
|
||||
*/
|
||||
$.fn.fieldValue = function(successful) {
|
||||
for (var val=[], i=0, max=this.length; i < max; i++) {
|
||||
var el = this[i];
|
||||
var v = $.fieldValue(el, successful);
|
||||
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
|
||||
continue;
|
||||
v.constructor == Array ? $.merge(val, v) : val.push(v);
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of the field element.
|
||||
*/
|
||||
$.fieldValue = function(el, successful) {
|
||||
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
||||
if (typeof successful == 'undefined') successful = true;
|
||||
|
||||
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
||||
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
||||
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
||||
tag == 'select' && el.selectedIndex == -1))
|
||||
return null;
|
||||
|
||||
if (tag == 'select') {
|
||||
var index = el.selectedIndex;
|
||||
if (index < 0) return null;
|
||||
var a = [], ops = el.options;
|
||||
var one = (t == 'select-one');
|
||||
var max = (one ? index+1 : ops.length);
|
||||
for(var i=(one ? index : 0); i < max; i++) {
|
||||
var op = ops[i];
|
||||
if (op.selected) {
|
||||
var v = op.value;
|
||||
if (!v) // extra pain for IE...
|
||||
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
|
||||
if (one) return v;
|
||||
a.push(v);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return el.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the form data. Takes the following actions on the form's input fields:
|
||||
* - input text fields will have their 'value' property set to the empty string
|
||||
* - select elements will have their 'selectedIndex' property set to -1
|
||||
* - checkbox and radio inputs will have their 'checked' property set to false
|
||||
* - inputs of type submit, button, reset, and hidden will *not* be effected
|
||||
* - button elements will *not* be effected
|
||||
*/
|
||||
$.fn.clearForm = function() {
|
||||
return this.each(function() {
|
||||
$('input,select,textarea', this).clearFields();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the selected form elements.
|
||||
*/
|
||||
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||
return this.each(function() {
|
||||
var t = this.type, tag = this.tagName.toLowerCase();
|
||||
if (t == 'text' || t == 'password' || tag == 'textarea')
|
||||
this.value = '';
|
||||
else if (t == 'checkbox' || t == 'radio')
|
||||
this.checked = false;
|
||||
else if (tag == 'select')
|
||||
this.selectedIndex = -1;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets the form data. Causes all form elements to be reset to their original value.
|
||||
*/
|
||||
$.fn.resetForm = function() {
|
||||
return this.each(function() {
|
||||
// guard against an input with the name of 'reset'
|
||||
// note that IE reports the reset function as an 'object'
|
||||
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
|
||||
this.reset();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables or disables any matching elements.
|
||||
*/
|
||||
$.fn.enable = function(b) {
|
||||
if (b == undefined) b = true;
|
||||
return this.each(function() {
|
||||
this.disabled = !b;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks/unchecks any matching checkboxes or radio buttons and
|
||||
* selects/deselects and matching option elements.
|
||||
*/
|
||||
$.fn.selected = function(select) {
|
||||
if (select == undefined) select = true;
|
||||
return this.each(function() {
|
||||
var t = this.type;
|
||||
if (t == 'checkbox' || t == 'radio')
|
||||
this.checked = select;
|
||||
else if (this.tagName.toLowerCase() == 'option') {
|
||||
var $sel = $(this).parent('select');
|
||||
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
||||
// deselect all other options
|
||||
$sel.find('option').selected(false);
|
||||
}
|
||||
this.selected = select;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// helper fn for console logging
|
||||
// set $.fn.ajaxSubmit.debug to true to enable debug logging
|
||||
function log() {
|
||||
if ($.fn.ajaxSubmit.debug) {
|
||||
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
|
||||
if (window.console && window.console.log)
|
||||
window.console.log(msg);
|
||||
else if (window.opera && window.opera.postError)
|
||||
window.opera.postError(msg);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/**
|
||||
Vertigo Tip by www.vertigo-project.com
|
||||
Requires jQuery
|
||||
*/
|
||||
this.vtip=function(){this.xOffset=-10;this.yOffset=10;$("*[title]").unbind().hover(function(a){this.t=this.title;this.title="";this.top=(a.pageY+yOffset);this.left=(a.pageX+xOffset);$("body").append('<p id="vtip"><img id="vtipArrow" />'+this.t+"</p>");$("p#vtip #vtipArrow").attr("src","/asset/img/vtip_arrow.png");$("p#vtip").css("top",this.top+"px").css("left",this.left+"px").fadeIn("slow")},function(){this.title=this.t;$("p#vtip").fadeOut("slow").remove()}).mousemove(function(a){this.top=(a.pageY+yOffset);this.left=(a.pageX+xOffset);$("p#vtip").css("top",this.top+"px").css("left",this.left+"px")})};jQuery(document).ready(function(a){vtip()});
|
||||
|
|
@ -0,0 +1 @@
|
|||
/*Yetii - Yet (E)Another Tab Interface Implementation,version 1.6,http://www.kminek.pl/lab/yetii/,Copyright (c) Grzegorz Wojcik,Code licensed under the BSD License: http://www.kminek.pl/bsdlicense.txt*/function Yetii(){this.defaults={id:null,active:1,interval:null,wait:null,persist:null,tabclass:'tab',activeclass:'active',callback:null,leavecallback:null};this.activebackup=null;for(var n in arguments[0]){this.defaults[n]=arguments[0][n]};this.getTabs=function(){var a=[];var b=document.getElementById(this.defaults.id).getElementsByTagName('*');var c=new RegExp("(^|\\s)"+this.defaults.tabclass.replace(/\-/g,"\\-")+"(\\s|$)");for(var i=0;i<b.length;i++){if(c.test(b[i].className))a.push(b[i])}return a};this.links=document.getElementById(this.defaults.id+'-nav').getElementsByTagName('a');this.listitems=document.getElementById(this.defaults.id+'-nav').getElementsByTagName('li');this.show=function(a){for(var i=0;i<this.tabs.length;i++){this.tabs[i].style.display=((i+1)==a)?'block':'none';if((i+1)==a){this.addClass(this.links[i],this.defaults.activeclass);this.addClass(this.listitems[i],this.defaults.activeclass+'li')}else{this.removeClass(this.links[i],this.defaults.activeclass);this.removeClass(this.listitems[i],this.defaults.activeclass+'li')}}if(this.defaults.leavecallback&&(a!=this.activebackup))this.defaults.leavecallback(this.defaults.active);this.activebackup=a;this.defaults.active=a;if(this.defaults.callback)this.defaults.callback(a)};this.rotate=function(a){this.show(this.defaults.active);this.defaults.active++;if(this.defaults.active>this.tabs.length)this.defaults.active=1;var b=this;if(this.defaults.wait)clearTimeout(this.timer2);this.timer1=setTimeout(function(){b.rotate(a)},a*1000)};this.next=function(){var a=(this.defaults.active+1>this.tabs.length)?1:this.defaults.active+1;this.show(a);this.defaults.active=a};this.previous=function(){var a=((this.defaults.active-1)==0)?this.tabs.length:this.defaults.active-1;this.show(a);this.defaults.active=a};this.previous=function(){this.defaults.active--;if(!this.defaults.active)this.defaults.active=this.tabs.length;this.show(this.defaults.active)};this.gup=function(a){a=a.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");var b="[\\?&]"+a+"=([^&#]*)";var c=new RegExp(b);var d=c.exec(window.location.href);if(d==null)return null;else return d[1]};this.parseurl=function(a){var b=this.gup(a);if(b==null)return null;if(parseInt(b))return parseInt(b);if(document.getElementById(b)){for(var i=0;i<this.tabs.length;i++){if(this.tabs[i].id==b)return(i+1)}}return null};this.createCookie=function(a,b,c){if(c){var d=new Date();d.setTime(d.getTime()+(c*24*60*60*1000));var e="; expires="+d.toGMTString()}else var e="";document.cookie=a+"="+b+e+"; path=/"};this.readCookie=function(a){var b=a+"=";var d=document.cookie.split(';');for(var i=0;i<d.length;i++){var c=d[i];while(c.charAt(0)==' ')c=c.substring(1,c.length);if(c.indexOf(b)==0)return c.substring(b.length,c.length)}return null};this.contains=function(a,b,c){return a.indexOf(b,c)!=-1};this.hasClass=function(a,b){return this.contains(a.className,b,' ')};this.addClass=function(a,b){if(!this.hasClass(a,b))a.className=(a.className+' '+b).replace(/\s{2,}/g,' ').replace(/^\s+|\s+$/g,'')};this.removeClass=function(a,b){a.className=a.className.replace(new RegExp('(^|\\s)'+b+'(?:\\s|$)'),'$1');a.className.replace(/\s{2,}/g,' ').replace(/^\s+|\s+$/g,'')};this.tabs=this.getTabs();this.defaults.active=(this.parseurl(this.defaults.id))?this.parseurl(this.defaults.id):this.defaults.active;if(this.defaults.persist&&this.readCookie(this.defaults.id))this.defaults.active=this.readCookie(this.defaults.id);this.activebackup=this.defaults.active;this.show(this.defaults.active);var f=this;for(var i=0;i<this.links.length;i++){this.links[i].customindex=i+1;this.links[i].onclick=function(){if(f.timer1)clearTimeout(f.timer1);if(f.timer2)clearTimeout(f.timer2);f.show(this.customindex);if(f.defaults.persist)f.createCookie(f.defaults.id,this.customindex,0);if(f.defaults.wait)f.timer2=setTimeout(function(){f.rotate(f.defaults.interval)},f.defaults.wait*1000);return false}}if(this.defaults.interval)this.rotate(this.defaults.interval)};
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Yetii - Yet (E)Another Tab Interface Implementation
|
||||
version 1.6
|
||||
http://www.kminek.pl/lab/yetii/
|
||||
Copyright (c) Grzegorz Wojcik
|
||||
Code licensed under the BSD License:
|
||||
http://www.kminek.pl/bsdlicense.txt
|
||||
*/
|
||||
|
||||
function Yetii() {
|
||||
|
||||
this.defaults = {
|
||||
|
||||
id: null,
|
||||
active: 1,
|
||||
interval: null,
|
||||
wait: null,
|
||||
persist: null,
|
||||
tabclass: 'tab',
|
||||
activeclass: 'active',
|
||||
callback: null,
|
||||
leavecallback: null
|
||||
|
||||
};
|
||||
|
||||
this.activebackup = null;
|
||||
|
||||
for (var n in arguments[0]) { this.defaults[n]=arguments[0][n]; };
|
||||
|
||||
this.getTabs = function() {
|
||||
|
||||
var retnode = [];
|
||||
var elem = document.getElementById(this.defaults.id).getElementsByTagName('*');
|
||||
|
||||
var regexp = new RegExp("(^|\\s)" + this.defaults.tabclass.replace(/\-/g, "\\-") + "(\\s|$)");
|
||||
|
||||
for (var i = 0; i < elem.length; i++) {
|
||||
if (regexp.test(elem[i].className)) retnode.push(elem[i]);
|
||||
}
|
||||
|
||||
return retnode;
|
||||
|
||||
};
|
||||
|
||||
this.links = document.getElementById(this.defaults.id + '-nav').getElementsByTagName('a');
|
||||
this.listitems = document.getElementById(this.defaults.id + '-nav').getElementsByTagName('li');
|
||||
|
||||
this.show = function(number) {
|
||||
|
||||
for (var i = 0; i < this.tabs.length; i++) {
|
||||
|
||||
this.tabs[i].style.display = ((i+1)==number) ? 'block' : 'none';
|
||||
|
||||
if ((i+1)==number) {
|
||||
this.addClass(this.links[i], this.defaults.activeclass);
|
||||
this.addClass(this.listitems[i], this.defaults.activeclass + 'li');
|
||||
} else {
|
||||
this.removeClass(this.links[i], this.defaults.activeclass);
|
||||
this.removeClass(this.listitems[i], this.defaults.activeclass + 'li');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (this.defaults.leavecallback && (number != this.activebackup)) this.defaults.leavecallback(this.defaults.active);
|
||||
|
||||
this.activebackup = number;
|
||||
|
||||
|
||||
this.defaults.active = number;
|
||||
|
||||
if (this.defaults.callback) this.defaults.callback(number);
|
||||
|
||||
|
||||
};
|
||||
|
||||
this.rotate = function(interval) {
|
||||
|
||||
this.show(this.defaults.active);
|
||||
this.defaults.active++;
|
||||
|
||||
if (this.defaults.active > this.tabs.length) this.defaults.active = 1;
|
||||
|
||||
|
||||
var self = this;
|
||||
|
||||
if (this.defaults.wait) clearTimeout(this.timer2);
|
||||
|
||||
this.timer1 = setTimeout(function(){self.rotate(interval);}, interval*1000);
|
||||
|
||||
};
|
||||
|
||||
this.next = function() {
|
||||
|
||||
var _target = (this.defaults.active + 1 > this.tabs.length) ? 1 : this.defaults.active + 1;
|
||||
this.show(_target);
|
||||
this.defaults.active = _target;
|
||||
|
||||
};
|
||||
|
||||
this.previous = function() {
|
||||
|
||||
var _target = ((this.defaults.active - 1) == 0) ? this.tabs.length : this.defaults.active - 1;
|
||||
this.show(_target);
|
||||
this.defaults.active = _target;
|
||||
|
||||
};
|
||||
|
||||
this.previous = function() {
|
||||
|
||||
this.defaults.active--;
|
||||
if(!this.defaults.active) this.defaults.active = this.tabs.length;
|
||||
this.show(this.defaults.active);
|
||||
|
||||
};
|
||||
|
||||
this.gup = function(name) {
|
||||
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
|
||||
var regexS = "[\\?&]"+name+"=([^&#]*)";
|
||||
var regex = new RegExp( regexS );
|
||||
var results = regex.exec( window.location.href );
|
||||
if (results == null) return null;
|
||||
else return results[1];
|
||||
};
|
||||
|
||||
this.parseurl = function(tabinterfaceid) {
|
||||
|
||||
var result = this.gup(tabinterfaceid);
|
||||
|
||||
if (result==null) return null;
|
||||
if (parseInt(result)) return parseInt(result);
|
||||
if (document.getElementById(result)) {
|
||||
for (var i=0;i<this.tabs.length;i++) {
|
||||
if (this.tabs[i].id == result) return (i+1);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
};
|
||||
|
||||
this.createCookie = function(name,value,days) {
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
var expires = "; expires="+date.toGMTString();
|
||||
}
|
||||
else var expires = "";
|
||||
document.cookie = name+"="+value+expires+"; path=/";
|
||||
};
|
||||
|
||||
this.readCookie = function(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.contains = function(el, item, from) {
|
||||
return el.indexOf(item, from) != -1;
|
||||
};
|
||||
|
||||
this.hasClass = function(el, className){
|
||||
return this.contains(el.className, className, ' ');
|
||||
};
|
||||
|
||||
this.addClass = function(el, className){
|
||||
if (!this.hasClass(el, className)) el.className = (el.className + ' ' + className).replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
|
||||
this.removeClass = function(el, className){
|
||||
el.className = el.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
|
||||
el.className.replace(/\s{2,}/g, ' ').replace(/^\s+|\s+$/g, '');
|
||||
};
|
||||
|
||||
|
||||
this.tabs = this.getTabs();
|
||||
this.defaults.active = (this.parseurl(this.defaults.id)) ? this.parseurl(this.defaults.id) : this.defaults.active;
|
||||
if (this.defaults.persist && this.readCookie(this.defaults.id)) this.defaults.active = this.readCookie(this.defaults.id);
|
||||
this.activebackup = this.defaults.active;
|
||||
this.show(this.defaults.active);
|
||||
|
||||
var self = this;
|
||||
for (var i = 0; i < this.links.length; i++) {
|
||||
this.links[i].customindex = i+1;
|
||||
this.links[i].onclick = function(){
|
||||
|
||||
if (self.timer1) clearTimeout(self.timer1);
|
||||
if (self.timer2) clearTimeout(self.timer2);
|
||||
|
||||
self.show(this.customindex);
|
||||
if (self.defaults.persist) self.createCookie(self.defaults.id, this.customindex, 0);
|
||||
|
||||
if (self.defaults.wait) self.timer2 = setTimeout(function(){self.rotate(self.defaults.interval);}, self.defaults.wait*1000);
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
if (this.defaults.interval) this.rotate(this.defaults.interval);
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* TaskFreak
|
||||
*
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
$GLOBALS['config']['lang']['specialchars'] = 2;
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
// load config file
|
||||
include './app/config/core.php'; // load up core config (paths, etc..)
|
||||
include APP_CONFIG_PATH.'app.php'; // load up application specific settings (customizable)
|
||||
|
||||
// minimum needed classes
|
||||
include APP_CLASS_PATH.'helpable.php';
|
||||
include APP_HELPER_PATH.'string.php';
|
||||
include APP_CLASS_PATH.'front.php';
|
||||
|
||||
// start session
|
||||
session_start();
|
||||
|
||||
// initialize front controller
|
||||
$fc = FrontController::getInstance();
|
||||
|
||||
// launch up (app) controller
|
||||
$fc->run();
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controller super class (abstract)
|
||||
*
|
||||
* All controllers must extend this class
|
||||
* @since 0.1
|
||||
* @todo constuctor parameter login : could require specific level
|
||||
*/
|
||||
abstract class AppController extends Pluginable {
|
||||
|
||||
private $view;
|
||||
|
||||
protected $fc;
|
||||
protected $page;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param mixed $login is user login required
|
||||
*/
|
||||
public function __construct($login=false) {
|
||||
parent::__construct();
|
||||
|
||||
// get front controller instance
|
||||
$this->fc = FrontController::getInstance();
|
||||
|
||||
// instantiate page
|
||||
$this->page = new PageModel();
|
||||
|
||||
// check login ?
|
||||
if ($login && APP_SETUP_USER_MODEL) {
|
||||
if (!$this->fc->user->isLoggedIn()) {
|
||||
NaviHelper::redirect('/login');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setting the file containing HTML which is sent to the browser
|
||||
*/
|
||||
protected function setView($view) {
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatch controller's action view
|
||||
* @todo search in other folders, such as plugins
|
||||
*/
|
||||
protected function view() {
|
||||
$this->page->dispatchHeader();
|
||||
include APP_VIEW_PATH.$this->view.'.php';
|
||||
$this->page->dispatchFooter();
|
||||
}
|
||||
|
||||
/**
|
||||
* include another view (called within a view)
|
||||
* @todo search in other folders, such as plugins
|
||||
*/
|
||||
protected function incView($file, $evenOnAjax=true) {
|
||||
if ($evenOnAjax || !$this->fc->getReqVar('ajax')) {
|
||||
include APP_VIEW_PATH.$file.'.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reset Navi::referrers to the current page
|
||||
* this should be called in any top level controller action
|
||||
*/
|
||||
protected function resetReferrer() {
|
||||
$this->fc->setReferrer($this->fc->thisUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* any controller must inmplement at least the default action
|
||||
*/
|
||||
abstract function mainAction();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Colectable
|
||||
*
|
||||
* A FIFO implementation
|
||||
* @since 0.1
|
||||
*/
|
||||
class Collectable extends Pluginable {
|
||||
|
||||
protected $skip;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->skip = array();
|
||||
foreach(get_object_vars($this) as $key => $val) {
|
||||
if ($key == 'skip') {
|
||||
continue;
|
||||
}
|
||||
$this->_init($key);
|
||||
$this->skip[$key] = array();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* initialize an empty stack
|
||||
*/
|
||||
protected function _init($key,$reset=false) {
|
||||
if (!is_array($this->$key) || $reset) {
|
||||
$this->$key = array();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* reset a stack
|
||||
*/
|
||||
public function clean($key, $full=false) {
|
||||
$this->_init($key, true);
|
||||
if ($full) {
|
||||
$this->skip[$key] = array();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* initialize the stack with a value
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
$this->add($key,$value,true,true);
|
||||
}
|
||||
/**
|
||||
* add a value in the stack
|
||||
*/
|
||||
public function add($key, $value, $force=false, $reset=false) {
|
||||
if (!$reset && !$force) {
|
||||
if ($this->checkSkip($key, $value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$this->$key = array_unique(array_merge($this->$key, $value));
|
||||
} else if (!in_array($value, $this->$key)) {
|
||||
$this->{$key}[] = $value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* remove value from the stack
|
||||
*/
|
||||
public function remove($key, $value) {
|
||||
$this->addSkip($key, $value);
|
||||
if (is_array($this->$key) && in_array($value, $this->$key)) {
|
||||
$newArray = array();
|
||||
foreach ($this->$key as $val) {
|
||||
if ($val == $value) {
|
||||
continue;
|
||||
}
|
||||
$newArray[] = $val;
|
||||
}
|
||||
$this->$key = $newArray;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* skip a value : use remove is a safer option
|
||||
*/
|
||||
protected function addSkip($key, $value) {
|
||||
if (!in_array($value,$this->skip[$key])) {
|
||||
$this->skip[$key][] = $value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* check if a value must be skipped
|
||||
* @return boolean true if value must be ignored
|
||||
*/
|
||||
protected function checkSkip($key, $value) {
|
||||
if (!is_array($this->skip[$key])) {
|
||||
return false;
|
||||
}
|
||||
return in_array($value, $this->skip[$key]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Database Connector
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
class DbConnector { // extends HelpableSingleton
|
||||
|
||||
protected $connector;
|
||||
protected $critical;
|
||||
protected $debug;
|
||||
|
||||
protected $sqlQueryCount;
|
||||
|
||||
public function __construct() {
|
||||
$this->debug = APP_DB_DEBUG;
|
||||
$this->critical = APP_DB_CRITICAL;
|
||||
$this->sqlQueryCount = 0;
|
||||
}
|
||||
|
||||
// ---- Managing CONNECTION --------------------------------------------------
|
||||
|
||||
/**
|
||||
* get DB connection
|
||||
*/
|
||||
public static function getConnection($i=0) {
|
||||
// -TODO-
|
||||
// connections shouldn't be hold by the front controller,
|
||||
// but by this class instantiated as a singleton
|
||||
$fc = FrontController::getInstance();
|
||||
if (empty($fc->db[$i])) {
|
||||
throw new AppException('Connection #'.$i.' does not exists');
|
||||
}
|
||||
try {
|
||||
if ($fc->db[$i]->isConnected()) {
|
||||
return $fc->db[$i];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new AppException('Connection #'.$i.' not established : '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected function connectTheConnector(DbEngine $obj) {
|
||||
$this->connector = $obj;
|
||||
}
|
||||
|
||||
public function connect($host=APP_DB_HOST, $user=APP_DB_USER, $pass=APP_DB_PASS, $base=APP_DB_BASE) {
|
||||
if ($this->connector) {
|
||||
return true;
|
||||
}
|
||||
// not connected yet, just do it
|
||||
$dbc = 'Db'.ucfirst(APP_DB_CONNECTOR);
|
||||
$con = new $dbc($host, $user, $pass, $base);
|
||||
if ($con->connect()) {
|
||||
$this->connectTheConnector($con);
|
||||
return true;
|
||||
}
|
||||
// reaching this point means an error as occured
|
||||
// $this->reportError();
|
||||
// return false;
|
||||
echo 'Cannot connect to database "'.APP_DB_BASE.'" on host "'.APP_DB_HOST.'" with user "'.APP_DB_USER.'"';
|
||||
exit;
|
||||
}
|
||||
|
||||
public function isConnected() {
|
||||
return is_a($this->connector, 'DbEngine');
|
||||
}
|
||||
|
||||
public function setDbDebug($level) {
|
||||
$this->debug = $level;
|
||||
}
|
||||
|
||||
public function setDbCritical($mode=true) {
|
||||
$this->critical = $mode;
|
||||
}
|
||||
|
||||
// ---- QUERYING the Database ---------------------------------------------
|
||||
|
||||
public static function query($qry, $dbi=0) {
|
||||
$db = self::getConnection($dbi);
|
||||
return $db->_query($qry);
|
||||
}
|
||||
protected function _query($qry) {
|
||||
$this->sqlQueryCount++;
|
||||
|
||||
switch ($this->debug) {
|
||||
case 4:
|
||||
FC::log_debug($qry);
|
||||
break;
|
||||
case 5:
|
||||
echo "<code>".$qry."</code><br/>";
|
||||
break;
|
||||
}
|
||||
|
||||
if (preg_match("/^(SELECT|SHOW)/i",ltrim($qry))) {
|
||||
$r = $this->connector->querySelect($qry);
|
||||
} else {
|
||||
$r = $this->connector->queryAffect($qry);
|
||||
}
|
||||
|
||||
if ($r === false) {
|
||||
// error !
|
||||
$this->reportError($qry);
|
||||
}
|
||||
|
||||
$this->setDbDebug(APP_DB_DEBUG); // back to normal debug level
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function transactionQueries($arrSql) {
|
||||
if (!is_array($arrSql)) {
|
||||
if (empty($arrSql)) {
|
||||
return false;
|
||||
}
|
||||
$arrSql = array($arrSql);
|
||||
}
|
||||
if (!$this->transactionBegin()) {
|
||||
FC::log_warn('can not begin transaction');
|
||||
}
|
||||
$ok = true;
|
||||
foreach($arrSql as $sql) {
|
||||
if (!$this->query($sql)) {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($ok) {
|
||||
return $this->transactionCommit();
|
||||
} else {
|
||||
$this->transactionRollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- MISCELLANEOUS --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* log or display DB errors in the browser
|
||||
*/
|
||||
public function reportError($qry='') {
|
||||
|
||||
if (empty($this->debug)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if critical, should at least show an error code in browser
|
||||
$debug = ($this->critical && $this->debug < 2)?2:$this->debug;
|
||||
|
||||
$html = '';
|
||||
$str = 'DB Error #'.$this->connector->getErrorNo().' : '.$this->connector->getErrorMsg();
|
||||
switch ($debug) {
|
||||
case 2:
|
||||
echo '<p>DB Error #'.$this->connector->getErrorNo().'</p>';
|
||||
case 1:
|
||||
if ($qry) {
|
||||
FC::log_error($qry);
|
||||
}
|
||||
case 4:
|
||||
FC::log_error($str);
|
||||
break;
|
||||
case 3:
|
||||
if ($qry) {
|
||||
$htm = '<br /><code>'.htmlentities($qry).'</code>';
|
||||
}
|
||||
case 5:
|
||||
$htm = nl2br(htmlentities($str)).$htm;
|
||||
break;
|
||||
default:
|
||||
echo '<p>DB DEBUG level undefined</p>';
|
||||
break;
|
||||
}
|
||||
echo '<p>'.$htm.'</p>';
|
||||
if ($this->critical) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pass on undefined method to selected connector
|
||||
*/
|
||||
public function __call($name, $args) {
|
||||
if ($this->connector) {
|
||||
if (method_exists($this->connector, $name)) {
|
||||
return call_user_func_array(array($this->connector, $name), $args);
|
||||
}
|
||||
}
|
||||
throw new AppException('Unknown method '.$name.' in '.__CLASS__.' or in the Db Connector ('.APP_DB_CONNECTOR.')');
|
||||
}
|
||||
}
|
||||
|
||||
interface DbEngine {
|
||||
public function connect();
|
||||
public function escapeString($str);
|
||||
public function querySelect($qry);
|
||||
public function queryAffect($qry);
|
||||
public function getTable($table);
|
||||
public function getErrorNo();
|
||||
public function getErrorMsg();
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_deprecated
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Database Connector
|
||||
*
|
||||
* singleton database connector
|
||||
*/
|
||||
class DbConnector extends HelpableSingleton {
|
||||
|
||||
private static $instance;
|
||||
|
||||
protected $connector;
|
||||
protected $critical;
|
||||
protected $debug;
|
||||
|
||||
protected $sqlQueryCount;
|
||||
|
||||
private function __construct() {
|
||||
$this->debug = APP_DB_DEBUG;
|
||||
$this->critical = APP_DB_CRITICAL;
|
||||
$this->sqlQueryCount = 0;
|
||||
$this->connector = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* the getInstance() method returns a single instance of the object
|
||||
*/
|
||||
public static function getInstance() {
|
||||
if(!isset(self::$instance)){
|
||||
$object= __CLASS__;
|
||||
self::$instance=new $object;
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
// ---- Managing CONNECTION --------------------------------------------------
|
||||
|
||||
/**
|
||||
* get DB connection
|
||||
*/
|
||||
public static function getConnection($i=0) {
|
||||
$db = self::getInstance();
|
||||
if (empty($db[$i])) {
|
||||
throw new AppException('Connection #'.$i.' does not exists');
|
||||
}
|
||||
try {
|
||||
if ($fc->db[$i]->isConnected()) {
|
||||
return $obj->db[$i];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new AppException('Connection #'.$i.' not established : '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected function connectTheConnector(DbEngine $obj) {
|
||||
$this->connector = $obj;
|
||||
}
|
||||
|
||||
public function connect($host=APP_DB_HOST, $user=APP_DB_USER, $pass=APP_DB_PASS, $base=APP_DB_BASE) {
|
||||
// -TODO-
|
||||
if ($this->connector) {
|
||||
return true;
|
||||
}
|
||||
// not connected yet, just do it
|
||||
$dbc = 'Db'.ucfirst(APP_DB_CONNECTOR);
|
||||
$con = new $dbc($host, $user, $pass, $base);
|
||||
if ($con->connect()) {
|
||||
$this->connectTheConnector($con);
|
||||
return true;
|
||||
}
|
||||
// reaching this point means an error as occured
|
||||
$this->reportError();
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isConnected() {
|
||||
return is_a($this->connector, 'DbEngine');
|
||||
}
|
||||
|
||||
public function setDbDebug($level) {
|
||||
$this->debug = $level;
|
||||
}
|
||||
|
||||
// ---- QUERYING the Database ---------------------------------------------
|
||||
|
||||
public static function query($qry, $dbi=0) {
|
||||
$db = self::getConnection($dbi);
|
||||
return $db->_query($qry);
|
||||
}
|
||||
protected function _query($qry) {
|
||||
$this->sqlQueryCount++;
|
||||
|
||||
switch ($this->debug) {
|
||||
case 3:
|
||||
FC::log_debug($qry);
|
||||
break;
|
||||
case 4:
|
||||
echo "<code>".$qry."</code><br/>";
|
||||
break;
|
||||
}
|
||||
|
||||
if (preg_match("/^(SELECT|SHOW)/i",ltrim($qry))) {
|
||||
$r = $this->connector->querySelect($qry);
|
||||
} else {
|
||||
$r = $this->connector->queryAffect($qry, $this->debug, $this->critical);
|
||||
}
|
||||
|
||||
if ($r === false) {
|
||||
// error !
|
||||
$this->reportError();
|
||||
}
|
||||
|
||||
$this->setDbDebug(APP_DB_DEBUG); // back to normal debug level
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function transactionQueries($arrSql) {
|
||||
if (!is_array($arrSql)) {
|
||||
if (empty($arrSql)) {
|
||||
return false;
|
||||
}
|
||||
$arrSql = array($arrSql);
|
||||
}
|
||||
if (!$this->transactionBegin()) {
|
||||
FC::log_warn('can not begin transaction');
|
||||
}
|
||||
$ok = true;
|
||||
foreach($arrSql as $sql) {
|
||||
if (!$this->query($sql)) {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($ok) {
|
||||
return $this->transactionCommit();
|
||||
} else {
|
||||
$this->transactionRollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- MISCELLANEOUS --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* log or display DB errors in the browser
|
||||
*/
|
||||
public function reportError($qry='') {
|
||||
if (!$this->debug) {
|
||||
return false;
|
||||
}
|
||||
$str = 'DB Error #'.$this->connector->getErrorNo().' : '.$this->connector->getErrorMsg();
|
||||
switch ($this->debug) {
|
||||
case 1:
|
||||
case 3:
|
||||
FC::log_error($str);
|
||||
if ($qry) {
|
||||
FC::log_error($str);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 4:
|
||||
echo '<p>'.nl2br(htmlentities($str));
|
||||
echo '<br /><code>'.htmlentities($qry).'</code></p>';
|
||||
break;
|
||||
default:
|
||||
echo '<p>DB DEBUG level undefined</p>';
|
||||
break;
|
||||
}
|
||||
if ($this->critical) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pass on undefined method to selected connector
|
||||
*/
|
||||
public function __call($name, $args) {
|
||||
if ($this->connector) {
|
||||
if (method_exists($this->connector, $name)) {
|
||||
return call_user_func_array(array($this->connector, $name), $args);
|
||||
}
|
||||
}
|
||||
throw new AppException('Unknown method '.$name.' in '.__CLASS__.' or in the Db Connector ('.APP_DB_CONNECTOR.')');
|
||||
}
|
||||
}
|
||||
|
||||
interface DbEngine {
|
||||
public function connect();
|
||||
public function querySelect($qry, $debug, $critical);
|
||||
public function queryAffect($qry, $debug, $critical);
|
||||
public function getTable($table);
|
||||
public function getErrorNo();
|
||||
public function getErrorMsg();
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* DbMysql
|
||||
*
|
||||
* MySQL connector
|
||||
* @since 0.1
|
||||
*/
|
||||
class DbMysql implements DbEngine {
|
||||
|
||||
private $host, $user, $pass, $base;
|
||||
|
||||
protected $isConnected;
|
||||
protected $dblink;
|
||||
|
||||
public function __construct($host, $user, $pass, $base) {
|
||||
$this->host = $host;
|
||||
$this->user = $user;
|
||||
$this->pass = $pass;
|
||||
$this->base = $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to mysql and select database
|
||||
*/
|
||||
public function connect() {
|
||||
$this->isConnected = false;
|
||||
|
||||
if (@constant('APP_DB_PERMANENT')) {
|
||||
$this->dblink = @mysql_pconnect($this->host,$this->user,$this->pass);
|
||||
} else {
|
||||
$this->dblink = @mysql_connect($this->host,$this->user,$this->pass);
|
||||
}
|
||||
if (!$this->dblink) {
|
||||
return false;
|
||||
}
|
||||
if (!@mysql_select_db($this->base,$this->dblink)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* escape string for mySQL
|
||||
*/
|
||||
public function escapeString($str) {
|
||||
return mysql_real_escape_string($str,$this->dblink);
|
||||
}
|
||||
|
||||
// ---- TRANSACTIONS ---------------------------------------------------------
|
||||
|
||||
public function transactionBegin() {
|
||||
@mysql_query('SET AUTOCOMMIT=0',$this->dblink);
|
||||
$r = @mysql_query('BEGIN',$this->dblink);
|
||||
// error_log('BEGIN : '.$r);
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function transactionCommit() {
|
||||
$r = @mysql_query('COMMIT',$this->dblink);
|
||||
@mysql_query('SET AUTOCOMMIT=1',$this->dblink);
|
||||
// error_log('COMMIT : '.$r);
|
||||
return $r;
|
||||
}
|
||||
|
||||
public function transactionRollBack() {
|
||||
$r = @mysql_query('ROLLBACK',$this->dblink);
|
||||
@mysql_query('SET AUTOCOMMIT=1',$this->dblink);
|
||||
//error_log('ROLLBACK : '.$r);
|
||||
return $r;
|
||||
}
|
||||
|
||||
// ---- QUERIES -----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* SELECT and SHOW queries
|
||||
*/
|
||||
public function querySelect($qry) {
|
||||
$r = @mysql_query($qry, $this->dblink);
|
||||
if (!$r) {
|
||||
// there's obviously an error
|
||||
return false;
|
||||
}
|
||||
$data = array();
|
||||
$i = 0;
|
||||
while ($row = mysql_fetch_assoc($r)) {
|
||||
$data[$i++] = $row;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* INSERT, REPLACE, UPDATE and DELETE queries
|
||||
*/
|
||||
public function queryAffect($qry) {
|
||||
if (!@mysql_query($qry,$this->dblink)) {
|
||||
// error_log('queryAffect (mysql) fails : '.$qry);
|
||||
return false;
|
||||
}
|
||||
$r = mysql_affected_rows($this->dblink);
|
||||
// error_log('queryAffect (mysql) returns : '.$r);
|
||||
if ($r == -1) {
|
||||
return false;
|
||||
} else {
|
||||
if ($r == 1) {
|
||||
if ($id = mysql_insert_id($this->dblink)) {
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
return ($r)?$r:true;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- TABLE operations --------------------------------------------------
|
||||
|
||||
public function getTable($table) {
|
||||
if ($result = @mysql_query('SHOW TABLES LIKE \''.$table.'\'')) {
|
||||
if ($row = mysql_fetch_row($result)) {
|
||||
if (strtolower($row[0]) == strtolower($table)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getTables($table=null) {
|
||||
$arrTables = array();
|
||||
$sql = 'SHOW TABLES';
|
||||
if ($table) {
|
||||
$sql .= ' LIKE \''.$table.'\'';
|
||||
}
|
||||
if ($result = @mysql_query($sql))
|
||||
{
|
||||
while($row = mysql_fetch_row($result)) {
|
||||
$arrTables[] = $row[0];
|
||||
}
|
||||
}
|
||||
return $arrTables;
|
||||
}
|
||||
|
||||
// ---- ERROR reporting ------------------------------------------------------
|
||||
|
||||
public function getErrorNo() {
|
||||
return mysql_errno();
|
||||
}
|
||||
|
||||
public function getErrorMsg() {
|
||||
return mysql_error();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,623 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Front Controller
|
||||
*
|
||||
* The is the root class of the application, the mother of initialization process
|
||||
* It's a singleton, defining mostly static methods
|
||||
* @since 0.1
|
||||
*/
|
||||
class FrontController extends HelpableSingleton {
|
||||
|
||||
private static $instance;
|
||||
|
||||
protected $autoPath;
|
||||
|
||||
public $controller;
|
||||
public $action;
|
||||
public $request;
|
||||
|
||||
public $settings;
|
||||
public $user;
|
||||
public $db;
|
||||
|
||||
/**
|
||||
* private constructor (singleton)
|
||||
*/
|
||||
private function __construct() {
|
||||
|
||||
$this->autoPath = $authoPath = array();
|
||||
include APP_CONFIG_PATH.'path.php';
|
||||
$this->autoPath = $autoPath;
|
||||
unset($autoPath);
|
||||
|
||||
$this->controller = $GLOBALS['config']['app']['default_controller'];
|
||||
$this->action = $GLOBALS['config']['app']['default_action'];
|
||||
$this->request = array();
|
||||
|
||||
$this->_helpers = array();
|
||||
|
||||
$this->db = array();
|
||||
|
||||
if (!isset($_SESSION['appVariables'])) {
|
||||
$_SESSION['appVariables'] = array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* the getInstance() method returns a single instance of the object
|
||||
*/
|
||||
public static function getInstance() {
|
||||
if(!isset(self::$instance)){
|
||||
spl_autoload_register(array('FrontController','autoLoad'));
|
||||
$object= __CLASS__;
|
||||
self::$instance=new $object;
|
||||
self::$instance->initApp();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
// ---- APP INITIALIZATION ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* app initialization (from config)
|
||||
*/
|
||||
protected function initApp() {
|
||||
|
||||
if (APP_SETUP_DATABASE) {
|
||||
|
||||
// load up database settings (host, username, etc...)
|
||||
include APP_CONFIG_PATH.'db.php';
|
||||
|
||||
// connect to database
|
||||
$this->initDatabase();
|
||||
|
||||
}
|
||||
|
||||
if (APP_SETUP_MESSAGING) {
|
||||
// initialize messaging (trans-pages messages)
|
||||
$this->initMessaging();
|
||||
}
|
||||
|
||||
if (APP_SETUP_DATABASE) {
|
||||
|
||||
// load general settings
|
||||
if (APP_SETUP_GLOBAL_SETTINGS) {
|
||||
$this->loadSettings();
|
||||
}
|
||||
|
||||
// load user (if needed)
|
||||
$this->loadUser(APP_SETUP_USER_MODEL);
|
||||
|
||||
// load user preferences
|
||||
if (APP_SETUP_USER_SETTINGS) {
|
||||
$this->loadUserSettings();
|
||||
}
|
||||
}
|
||||
|
||||
if (APP_SETUP_TRANSLATOR) {
|
||||
// initialize translations system
|
||||
$this->initTranslator();
|
||||
}
|
||||
|
||||
if (APP_SETUP_NAVI) {
|
||||
// initialize navigation (referers, redirects and URL manipulation)
|
||||
$this->initNavi();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize database connection
|
||||
*/
|
||||
public function initDatabase() {
|
||||
$i = count($this->db);
|
||||
$this->db[$i] = new DbConnector();
|
||||
$this->db[$i]->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* load application settings
|
||||
* @todo load settings
|
||||
* @todo set default controller and action
|
||||
*/
|
||||
public function loadSettings() {
|
||||
$this->settings = new SettingModel();
|
||||
// -TODO- load 'em up
|
||||
}
|
||||
|
||||
/**
|
||||
* load and authenticate user
|
||||
*/
|
||||
public function loadUser($class) {
|
||||
if (empty($class)) {
|
||||
return false;
|
||||
}
|
||||
$class = StringHelper::flatToCamel($class,true).'Model';
|
||||
$this->user = new $class;
|
||||
$this->user->enableAuthentication();
|
||||
$this->user->connectDb();
|
||||
$this->user->checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* load user settings
|
||||
* @todo load user settings and override global settings
|
||||
*/
|
||||
public function loadUserSettings() {
|
||||
// might overload default controller and action
|
||||
// -TODO-
|
||||
if ($this->user->isLoggedIn()) {
|
||||
$this->setSessionDefault('usertask', $this->user->getUid());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize messaging system
|
||||
*/
|
||||
public function initMessaging() {
|
||||
$this->addHelper('messaging');
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize referrers system
|
||||
*/
|
||||
public function initNavi() {
|
||||
$this->addHelper('navi');
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize translator
|
||||
*/
|
||||
public function initTranslator() {
|
||||
$this->addHelper('translator');
|
||||
}
|
||||
|
||||
/**
|
||||
* launch application controller
|
||||
*/
|
||||
public function run() {
|
||||
// parse URL : look for controller, action, parameters...
|
||||
$this->parseUrl();
|
||||
|
||||
// load up requested Application Controller
|
||||
$con = self::loadController($this->controller);
|
||||
|
||||
if (!$con) {
|
||||
// controller not found, throw exception
|
||||
if (isset($GLOBALS['config']['error']['not_found'])) {
|
||||
$this->_sendErrorCodeToRobots('404');
|
||||
include $GLOBALS['config']['error']['not_found'];
|
||||
exit;
|
||||
} else {
|
||||
try {
|
||||
throw new AppException('Controller '.$this->controller.' not defined in '.implode(', ', $this->autoPath['controller']));
|
||||
} catch(Exception $e) {
|
||||
error_log('error loading controller '.$this->controller);
|
||||
echo $e;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$obj = new $con;
|
||||
$act = $this->action;
|
||||
|
||||
// if submitted, call requested action (mainReaction by default)
|
||||
if (!empty($_POST)) {
|
||||
if (method_exists($obj, $act.'Reaction')) {
|
||||
if (!call_user_func(array($obj,$act.'Reaction'))) {
|
||||
// stop here
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
self::log_error('method '.$act.'Reaction not defined in controller '.$this->controller);
|
||||
}
|
||||
}
|
||||
|
||||
// if still needed, call requested action (mainAction by default)
|
||||
if (method_exists($obj, $act.'Action')) {
|
||||
call_user_func(array($obj, $act.'Action'));
|
||||
} else {
|
||||
if (isset($GLOBALS['config']['error']['not_found'])) {
|
||||
$this->_sendErrorCodeToRobots('404');
|
||||
include $GLOBALS['config']['error']['not_found'];
|
||||
exit;
|
||||
}
|
||||
self::log_error('method '.$act.'Action not defined in controller '.$this->controller);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- HTTP QUERY PARSER ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* clean $_POST, $_GET and $_REQUEST if magic quotes are on
|
||||
*/
|
||||
protected static function cleanRequest() {
|
||||
if (!get_magic_quotes_gpc()) {
|
||||
return true;
|
||||
}
|
||||
$arrReq = array('_POST','_GET','_REQUEST');
|
||||
foreach ($arrReq as $key) {
|
||||
if (isset($$key)) {
|
||||
array_walk($$key, 'stripslashes');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets HTTP variable
|
||||
* @return null if not found, value if set
|
||||
*/
|
||||
public function getReqVar($key) {
|
||||
if (isset($this->request[$key])) {
|
||||
return $this->request[$key];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if variable is submitted by HTTP request
|
||||
* @param $mix an array or string containing key(s) to be checked
|
||||
* @return first found in request
|
||||
*/
|
||||
public function chkReqVar($mix) {
|
||||
$arr = StringHelper::mixedToArray($mix);
|
||||
foreach($arr as $key) {
|
||||
if (isset($this->request[$key])) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse request for controller, action and other parameters
|
||||
*/
|
||||
public function parseUrl() {
|
||||
|
||||
// clean ugly magic quotes
|
||||
self::cleanRequest();
|
||||
|
||||
// parse URL path
|
||||
$req = trim($_SERVER['REQUEST_URI'],'/');
|
||||
if ($req) {
|
||||
if ($pos = strrpos($_SERVER['REQUEST_URI'],'.html')) {
|
||||
$req = substr($req, 0, $pos-1);
|
||||
} else if ($pos = strrpos($_SERVER['REQUEST_URI'],'?')) {
|
||||
$req = substr($req, 0, $pos-1);
|
||||
}
|
||||
$arrReq = explode('/',$req);
|
||||
if (count($arrReq)) {
|
||||
$this->controller = array_shift($arrReq);
|
||||
}
|
||||
if (count($arrReq)) {
|
||||
$this->action = array_shift($arrReq);
|
||||
} else {
|
||||
$this->action = 'main';
|
||||
}
|
||||
|
||||
while(count($arrReq)) {
|
||||
$key = array_shift($arrReq);
|
||||
if (count($arrReq)) {
|
||||
$val = array_shift($arrReq);
|
||||
$this->request[$key] = urldecode($val);
|
||||
} else {
|
||||
$this->request[$key] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse query string
|
||||
if (count($_REQUEST)) {
|
||||
foreach($_REQUEST as $key => $val) {
|
||||
switch($key) {
|
||||
case 'controller' :
|
||||
$this->controller = $val;
|
||||
break;
|
||||
case 'action' :
|
||||
$this->action = $val;
|
||||
break;
|
||||
default :
|
||||
$this->request[$key] = $val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get real names
|
||||
$this->controller = StringHelper::flatToCamel($this->controller, true,'-');
|
||||
$this->action = StringHelper::flatToCamel($this->action, false,'-');
|
||||
}
|
||||
|
||||
/**
|
||||
* generate URL
|
||||
*/
|
||||
public static function getUrl($controller='', $action = '', $params = '') {
|
||||
if (!$controller) {
|
||||
return APP_WWW_URI;
|
||||
}
|
||||
if (!$action) {
|
||||
return APP_WWW_URI.$controller;
|
||||
}
|
||||
$url = APP_WWW_URI.StringHelper::camelToFlat($controller,'-')
|
||||
.'/'.StringHelper::camelToFlat($action,'-');
|
||||
if (is_array($params)) {
|
||||
foreach ($params as $key => $val) {
|
||||
$url .= '/'.urlencode($key).'/'.urlencode($val);
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns current URL
|
||||
* @param mixed params false if no parameter, true if all current parameters, array to submit other parameters
|
||||
*/
|
||||
public function thisUrl($params=false) {
|
||||
if (is_array($params)) {
|
||||
return self::getUrl($this->controller, $this->action, $params);
|
||||
} else {
|
||||
return self::getUrl($this->controller, $this->action, $params?$this->request:false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return navigation menu
|
||||
*/
|
||||
public function menu($id='pages') {
|
||||
$str = '<ul id="'.$id.'">';
|
||||
foreach ($GLOBALS['config'][$id] as $key => $url) {
|
||||
$arr = explode('/',$url);
|
||||
$arr[0] = ucfirst($arr[0]);
|
||||
if (!$arr[1]) {
|
||||
$arr[1] = 'main';
|
||||
}
|
||||
$str .= '<li';
|
||||
if ($this->controller == $arr[0] && $this->action == $arr[1]) {
|
||||
$str .= ' class="active"';
|
||||
}
|
||||
$str .= '><a href="'.FrontController::getUrl($url).'">'.$key.'</a></li>';
|
||||
}
|
||||
$str .= '</ul>';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* send error code (http header) to robots
|
||||
*/
|
||||
protected function _sendErrorCodeToRobots($code) {
|
||||
if (preg_match('/'.APP_ROBOT_AGENT.'/', $_SERVER['HTTP_USER_AGENT'])) {
|
||||
header("Status : 404 Not Found");
|
||||
header("HTTP/1.1 404 Not Found");
|
||||
}
|
||||
}
|
||||
|
||||
// ---- APPLICATION VARIABLES ------------------------------------------------
|
||||
|
||||
/**
|
||||
* get a persistent variable
|
||||
* try first from $_REQUEST, then look into session variables
|
||||
* if found in $_REQUEST, save it in session for later use
|
||||
*/
|
||||
public function sessionVariable($key) {
|
||||
if (isset($this->request[$key])) {
|
||||
$this->setSessionVariable($key, $this->request[$key]);
|
||||
}
|
||||
return $this->getSessionVariable($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* set a session variable
|
||||
*/
|
||||
public function setSessionVariable($key, $value) {
|
||||
$_SESSION['appVariables'][$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* set a session variable default's value
|
||||
*/
|
||||
public function setSessionDefault($key, $default) {
|
||||
if (!isset($_SESSION['appVariables'][$key])) {
|
||||
$_SESSION['appVariables'][$key] = $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a session variable
|
||||
*/
|
||||
public function getSessionVariable($key) {
|
||||
if (!isset($_SESSION['appVariables'][$key])) {
|
||||
return NULL;
|
||||
} else {
|
||||
return $_SESSION['appVariables'][$key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reset a session variable
|
||||
*/
|
||||
public function cleanSessionVariable($keys) {
|
||||
$keys = StringHelper::mixedToArray($keys);
|
||||
foreach($keys as $key) {
|
||||
if (isset($_SESSION['appVariables'][$key])) {
|
||||
unset($_SESSION['appVariables'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- AUTOLOAD setup -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* generic method loading classes
|
||||
*/
|
||||
public function _load($file, $type) {
|
||||
self::log_front("loading $file [$type]");
|
||||
foreach($this->autoPath[$type] as $path) {
|
||||
if (file_exists($path.$file)) {
|
||||
self::log_front("-> Yes in $path");
|
||||
include_once($path.$file);
|
||||
return true;
|
||||
} else {
|
||||
self::log_front("!> No $file in $path");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* static method loading any type of class definition
|
||||
* check all accessible folder that may contain the class definition
|
||||
* and include it if necessary
|
||||
*/
|
||||
protected static function load($class, $type) {
|
||||
$file = StringHelper::camelToFlat($class);
|
||||
if ($idx = strrpos($file, '_'.$type)) {
|
||||
$file = substr($file, 0, $idx);
|
||||
}
|
||||
$file .= '.php';
|
||||
if (!class_exists($class)) {
|
||||
$obj = self::getInstance();
|
||||
if (!$obj->_load($file, $type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* load core class
|
||||
*/
|
||||
public static function loadClass($class) {
|
||||
return self::load($class, 'class');
|
||||
}
|
||||
|
||||
/**
|
||||
* load helper class
|
||||
*/
|
||||
public static function loadHelper($class) {
|
||||
return self::load($class, 'helper');
|
||||
}
|
||||
|
||||
/**
|
||||
* load a model class
|
||||
*/
|
||||
public static function loadModel($class) {
|
||||
return self::load($class, 'model');
|
||||
}
|
||||
|
||||
/**
|
||||
* load a controller class
|
||||
*/
|
||||
public static function loadController($class) {
|
||||
return self::load($class, 'controller');
|
||||
}
|
||||
|
||||
/**
|
||||
* load a view class
|
||||
*/
|
||||
public static function loadView($class) {
|
||||
return self::load($class, 'view');
|
||||
}
|
||||
|
||||
/**
|
||||
* autoload class
|
||||
* @parameter would require the type of class to be said in there
|
||||
*/
|
||||
private static function autoLoad($name) {
|
||||
$str = StringHelper::camelToFlat($name);
|
||||
$type = 'class';
|
||||
$sep = strrpos($str,'_');
|
||||
if ($sep) {
|
||||
$class = substr($str, 0, $sep);
|
||||
$type = substr($str, $sep+1);
|
||||
switch ($type){
|
||||
case 'helper':
|
||||
case 'class':
|
||||
case 'controller':
|
||||
case 'model':
|
||||
case 'view':
|
||||
// valid type
|
||||
break;
|
||||
default:
|
||||
// invalid type, must be a core class
|
||||
$type = 'class';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return self::load($name, $type);
|
||||
}
|
||||
|
||||
// ---- LOGGING and DEBUGGING ------------------------------------------------
|
||||
|
||||
public static function log_front($str) {
|
||||
self::log_any($GLOBALS['config']['log_front'], 'front', $str);
|
||||
}
|
||||
|
||||
public static function log_debug($str) {
|
||||
self::log_any($GLOBALS['config']['log_debug'], 'debug', $str);
|
||||
}
|
||||
|
||||
public static function log_message($str) {
|
||||
self::log_any($GLOBALS['config']['log_message'], 'message', $str);
|
||||
}
|
||||
|
||||
public static function log_warn($str) {
|
||||
self::log_any($GLOBALS['config']['log_warn'], 'warning', $str);
|
||||
}
|
||||
|
||||
public static function log_error($str) {
|
||||
self::log_any($GLOBALS['config']['log_error'], 'error', $str);
|
||||
}
|
||||
|
||||
public static function log_core_debug($str) {
|
||||
self::log_any($GLOBALS['config']['log_core'], 'error', $str);
|
||||
}
|
||||
|
||||
public static function log_any($mode, $head, $str) {
|
||||
switch ($mode) {
|
||||
case 1:
|
||||
$arr = explode("\n", trim($str));
|
||||
foreach ($arr as $s) {
|
||||
error_log($GLOBALS['config']['log_signature']." $head : $s");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
echo VarStr::html($GLOBALS['config']['log_signature']." $head : ".nl2br($str));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FC extends FrontController
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class AppException extends Exception {
|
||||
|
||||
// Redefine the exception so message isn't optional
|
||||
public function __construct($message, $code = 0, Exception $previous = null) {
|
||||
// make sure everything is assigned properly
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
// custom string representation of object
|
||||
public function __toString() {
|
||||
echo "<pre>".parent::__toString()."</pre>";
|
||||
return __CLASS__;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helpable
|
||||
*
|
||||
* add possibility to have helpers, and call helper method if it doesn't exist
|
||||
* @since 0.1
|
||||
*/
|
||||
abstract class Helpable {
|
||||
|
||||
protected $_helpers;
|
||||
|
||||
public function __construct() {
|
||||
$this->_helpers = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* add helper to the class
|
||||
* @param string $helper name of helper (flat format)
|
||||
* @param object $obj object to be passed on
|
||||
*/
|
||||
public function addHelper() {
|
||||
$args = func_get_args();
|
||||
// helper's name
|
||||
$helper = array_shift($args);
|
||||
$class = StringHelper::flatToCamel($helper, true).'Helper';
|
||||
// reference to this object
|
||||
$obj = array_shift($args);
|
||||
if (is_null($obj)) {
|
||||
$obj = $this;
|
||||
}
|
||||
// add helper (didn't find any better way to deal with variable constructor parameters)
|
||||
switch(count($args)) {
|
||||
case 4:
|
||||
$this->_helpers[$helper] = new $class($obj, $args[0], $args[1], $args[2], $args[3]);
|
||||
break;
|
||||
case 3:
|
||||
$this->_helpers[$helper] = new $class($obj, $args[0], $args[1], $args[2]);
|
||||
break;
|
||||
case 2:
|
||||
$this->_helpers[$helper] = new $class($obj, $args[0], $args[1]);
|
||||
break;
|
||||
case 1:
|
||||
$this->_helpers[$helper] = new $class($obj, $args[0]);
|
||||
break;
|
||||
default:
|
||||
$this->_helpers[$helper] = new $class($obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call helper method
|
||||
* @param string $key the helper key
|
||||
* @param string $method the method to be called
|
||||
*/
|
||||
public function callHelper() {
|
||||
$args = func_get_args();
|
||||
$helper = array_shift($args);
|
||||
$method = array_shift($args);
|
||||
return call_user_func_array(array($this->_helpers[$helper], $method), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* call helper's method (arguments are passed as an array
|
||||
*/
|
||||
public function callHelperArray() {
|
||||
$args = func_get_args();
|
||||
$helper = array_shift($args);
|
||||
$method = array_shift($args);
|
||||
if (!empty($args)) {
|
||||
return call_user_func_array(array($this->_helpers[$helper], $method), $args[0]);
|
||||
} else {
|
||||
return $this->_helpers[$helper]->$method();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call all available helpers method
|
||||
* @param string $method the method to be called
|
||||
*/
|
||||
protected function callHelpers($method) {
|
||||
if (!count($this->_helpers)) {
|
||||
return false;
|
||||
}
|
||||
$arr = array();
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
foreach ($this->_helpers as $key => $obj) {
|
||||
if (!method_exists($obj, $method)) {
|
||||
continue;
|
||||
}
|
||||
$r = call_user_func_array(array($obj,$method),$args);
|
||||
$arr[$key] = $r;
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if helper is available
|
||||
*/
|
||||
public function hasHelper($helper) {
|
||||
return array_key_exists($helper, $this->_helpers);
|
||||
}
|
||||
|
||||
/**
|
||||
* get helper
|
||||
*/
|
||||
public function &getHelper($helper) {
|
||||
if ($this->hasHelper($helper)) {
|
||||
return $this->_helpers[$helper];
|
||||
} else {
|
||||
throw new AppException('Unknown helper '.$helper.' in '.get_class($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call helper method if not defined here
|
||||
*/
|
||||
public function __call($name, $args) {
|
||||
if (!count($this->_helpers)) {
|
||||
throw new AppException('Unknown method '.$name.' in '.get_class($this).' (and no helper available)');
|
||||
}
|
||||
|
||||
// check if helper's name has been added to method's name eg. methodHelper
|
||||
/* TOO UGLY, TOO COSTY
|
||||
$subname = StringHelper::camelToFlat($name);
|
||||
if ($idx = strrpos($subname, '__')) {
|
||||
$subhelp = substr($subname, $idx+1);
|
||||
if (array_key_exists($subhelp, $this->_helpers)) {
|
||||
$subname = StringHelper::flatToCamel(substr($subname, 0, $idx));
|
||||
$obj = $this->_helpers[$subhelp];
|
||||
if (method_exists($obj, $name)) {
|
||||
return call_user_func_array(array($obj, $name), $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// check if method exists in one of the helper
|
||||
foreach ($this->_helpers as $key => $obj) {
|
||||
if (method_exists($obj, $name)) {
|
||||
return call_user_func_array(array($obj, $name), $args);
|
||||
}
|
||||
}
|
||||
|
||||
// try again within helper if __call is available
|
||||
foreach ($this->_helpers as $key => $obj) {
|
||||
if (method_exists($obj, '__call')) {
|
||||
return call_user_func_array(array($obj, $name), $args);
|
||||
}
|
||||
}
|
||||
|
||||
// nope, forget it
|
||||
throw new AppException('Unknown method '.$name.' in '.get_class($this).' or any helper ('.implode(', ',array_keys($this->_helpers)).')');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton helpable super class
|
||||
*
|
||||
* sucks duplicating code, but needed for singletons as constructor must be private
|
||||
* @since 0.1
|
||||
*/
|
||||
|
||||
abstract class HelpableSingleton {
|
||||
|
||||
private $_helpers;
|
||||
|
||||
private function __construct() {
|
||||
$this->_helpers = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* add helper to the class
|
||||
*/
|
||||
protected function addHelper($helper, $obj=null) {
|
||||
$class = StringHelper::flatToCamel($helper, true).'Helper';
|
||||
$this->_helpers[$helper] = new $class($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if helper is available
|
||||
*/
|
||||
public function hasHelper($helper) {
|
||||
return array_key_exists($helper, $this->_helpers);
|
||||
}
|
||||
|
||||
/**
|
||||
* get helper
|
||||
*/
|
||||
public function &getHelper($helper) {
|
||||
if ($this->hasHelper($helper)) {
|
||||
return $this->_helpers[$helper];
|
||||
} else {
|
||||
throw new AppException('Unknown helper '.$helper.' in '.get_class($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* call helper method if not defined here
|
||||
*/
|
||||
public function __call($name, $args) {
|
||||
if (!count($this->_helpers)) {
|
||||
throw new AppException('Unknown method '.$name.' in '.__CLASS__.' (and no helper available)');
|
||||
}
|
||||
foreach ($this->_helpers as $key => $obj) {
|
||||
foreach ($this->_helpers as $key => $obj) {
|
||||
if (method_exists($obj, $name)) {
|
||||
return call_user_func_array(array($obj, $name), $args);
|
||||
}
|
||||
}
|
||||
if (is_a($obj, 'Callable')) {
|
||||
return call_user_func_array(array($obj, $name), $args);
|
||||
}
|
||||
}
|
||||
throw new AppException('Unknown method '.$name.' in '.__CLASS__.' or any helper ('.implode(', ',array_keys($this->_helpers)).')');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callable interface
|
||||
*
|
||||
* class implementing this will be able to send calls to other nested classes
|
||||
*/
|
||||
interface Callable {
|
||||
public function __call($name, $args);
|
||||
/*
|
||||
public function __call($name, $args) {
|
||||
$arr = array('class1','class2');
|
||||
foreach ($arr as $class) {
|
||||
if (method_exists($this->$class, $name)) {
|
||||
return call_user_func_array(array($this->$class, $name), $args);
|
||||
}
|
||||
}
|
||||
throw new AppException('Unknown method '.$name.' in '.__CLASS__.', '.implode(', ',$arr));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
/**
|
||||
* Helper
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
abstract class Helper {
|
||||
|
||||
protected $obj;
|
||||
|
||||
public function __construct($obj=null) {
|
||||
if (is_object($obj)) {
|
||||
$this->obj = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_core_classes
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pluginable
|
||||
*
|
||||
* Abstract class implementing all plugin related methods
|
||||
* All extendable / customizable class should implement Pluginable
|
||||
*/
|
||||
abstract class Pluginable extends Helpable {
|
||||
|
||||
private $_plugins;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->_plugins = array();
|
||||
$class = get_class($this); // get class name of implemented object (not the super class name)
|
||||
/*
|
||||
if (is_array($GLOBALS['config']['plugin']) && count($GLOBALS['config']['plugin'][$class])) {
|
||||
foreach ($GLOBALS['config']['plugin'][$class] as $key) {
|
||||
// error_log("INIT plugin for $class : $key");
|
||||
$this->addPlugin($key);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
protected function addPlugin($key, $obj=null) {
|
||||
if (is_null($obj)) {
|
||||
$class = StringHelper::flatToCamel($key, true);
|
||||
$this->_plugins[$key] = new $class;
|
||||
} else {
|
||||
$this->_plugins[$key] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getPlugin($key) {
|
||||
if (!is_array($this->_plugins)) {
|
||||
return false;
|
||||
}
|
||||
if (array_key_exists($key, $this->_plugins)) {
|
||||
return $this->_plugins[$key];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function setPlugin($key, $obj) {
|
||||
if (!is_array($this->_plugins)) {
|
||||
return false;
|
||||
}
|
||||
if (array_key_exists($key, $this->_plugins)) {
|
||||
$this->_plugins[$key] = $obj;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function callPlugin() {
|
||||
$args = func_get_args();
|
||||
$key = array_shift($args);
|
||||
$method = array_shift($args);
|
||||
$obj = $this->getPlugin($key);
|
||||
if (!$obj) {
|
||||
return false;
|
||||
}
|
||||
$obj = $this->_plugins[$key];
|
||||
call_user_func_array(array($obj,$method),$args);
|
||||
}
|
||||
|
||||
protected function callPlugins($method) {
|
||||
if (!count($this->_plugins)) {
|
||||
return false;
|
||||
}
|
||||
$arr = array();
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
foreach ($this->_plugins as $key => $obj) {
|
||||
if (!method_exists($obj, $method)) {
|
||||
continue;
|
||||
}
|
||||
if ($this->id) {
|
||||
$obj->id = $this->id;
|
||||
}
|
||||
$r = call_user_func_array(array($obj,$method),$args);
|
||||
$arr[$key] = $r;
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Array Helper
|
||||
*
|
||||
* common functions to manipulate arrays
|
||||
*/
|
||||
class ArrayHelper {
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public static function arrayTrim(&$arr)
|
||||
{
|
||||
array_walk($arr,"_trim");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _trim(&$value)
|
||||
{
|
||||
$value = trim($value);
|
||||
}
|
||||
|
|
@ -0,0 +1,555 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* AuthHelper
|
||||
*
|
||||
* authentication system
|
||||
*/
|
||||
class AuthHelper extends Helper {
|
||||
|
||||
protected $isLoggedIn;
|
||||
protected $isLoggingOut;
|
||||
|
||||
protected $fc;
|
||||
protected $error;
|
||||
|
||||
public function __construct($obj) {
|
||||
parent::__construct($obj);
|
||||
$this->fc = FrontController::getInstance();
|
||||
$this->error = '';
|
||||
$this->isLoggedIn = $this->isLoggingOut = false;
|
||||
|
||||
}
|
||||
|
||||
public function checkPassword($password) {
|
||||
$pass = $this->obj->get('password');
|
||||
$salt = $this->obj->get('salt');
|
||||
switch (APP_AUTH_PASSWORD_MODE) {
|
||||
case 1:
|
||||
if ($pass == "") {
|
||||
$pass = crypt("", $salt);
|
||||
}
|
||||
if (crypt($password, $salt) != $pass) {
|
||||
// password invalid
|
||||
$this->error = 'user_pass_invalid';
|
||||
$this->badAccess();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
$sql = "ENCRYPT('$password','$salt')";
|
||||
if (!self::checkDbPass($sql, $pass)) {
|
||||
// password not OK
|
||||
$this->error = 'user_pass_invalid';
|
||||
$this->badAccess();
|
||||
return false; // error or password mismatch
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
$sql = "ENCODE('$password','$pass')";
|
||||
if (!self::checkDbPass($sql, $pass)) {
|
||||
// password not OK
|
||||
$this->error = 'user_pass_invalid';
|
||||
$this->badAccess();
|
||||
return false; // error or password mismatch
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (!$pass && !$password) {
|
||||
break;
|
||||
}
|
||||
$sql = "MD5('$password')";
|
||||
if (!self::checkDbPass($sql, $pass)) {
|
||||
// password not OK
|
||||
$this->error = 'user_pass_invalid';
|
||||
$this->badAccess();
|
||||
return false; // error or password mismatch
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (!$pass && !$password) {
|
||||
break;
|
||||
}
|
||||
if ($_SESSION['challenge']) {
|
||||
$value = md5($pass.$_SESSION['challenge']);
|
||||
unset($_SESSION['challenge']);
|
||||
if ($value == $password) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->error = 'user_pass_invalid';
|
||||
$this->badAccess();
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
for ($i = 0; $i < strlen($pass); $i += 2) {
|
||||
$passBin .= chr(hexdec(substr($s,$i,2)));
|
||||
}
|
||||
$iv = mcrypt_create_iv (mcrypt_get_iv_size (MCRYPT_3DES,
|
||||
MCRYPT_MODE_ECB), MCRYPT_RAND);
|
||||
if (mcrypt_decrypt (MCRYPT_3DES, $pass, $passBin,
|
||||
MCRYPT_MODE_ECB, $iv) == $password)
|
||||
{
|
||||
break;
|
||||
}
|
||||
$this->error = 'user_pass_invalid';
|
||||
$this->badAccess();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function activateAccount($byUser=false) {
|
||||
// update DB
|
||||
$this->obj->set('activation','');
|
||||
$this->obj->set('enabled',1);
|
||||
if ($this->obj->isLoaded()) {
|
||||
$this->obj->fields('enabled,activation');
|
||||
$this->obj->update();
|
||||
}
|
||||
|
||||
// send Emails
|
||||
/* -TODO-
|
||||
include CMS_INCLUDE_PATH.'language/'.$GLOBALS['objCms']->settings->get('default_language').'/system.php';
|
||||
include_once(CMS_CLASS_PATH."pkg_com.php");
|
||||
|
||||
$objMessage = new EmailMessage();
|
||||
|
||||
//email admin (if account activated by user)
|
||||
if ($byUser) {
|
||||
if ($objMessage->loadByKey('description','sign_up_new')) {
|
||||
$bodyMessage = "\r\n\t"
|
||||
.$this->obj->getName()."\r\n\r\n"
|
||||
.CMS_WWW_URL.'admin/member.php?id='.$this->obj->getUid()."\r\n";
|
||||
if ($objMessage->send($bodyMessage, $this->obj->email)) {
|
||||
// well, ok, fine
|
||||
} else {
|
||||
$pErrorMessage = $GLOBALS['langSystemEmailStuff']['send_error'];
|
||||
}
|
||||
} else {
|
||||
$pErrorMessage = $GLOBALS['langSystemEmailStuff']['send_not_found'];
|
||||
}
|
||||
}
|
||||
|
||||
// email user
|
||||
if ($this->obj->email) {
|
||||
if ($objMessage->loadByKey('description','sign_up_confirmation')) {
|
||||
$bodyMessage = CMS_WWW_URL.'login.php?username='.$this->obj->username;
|
||||
if ($_POST['password1']) {
|
||||
$bodyMessage .= "\r\n\t"
|
||||
.$GLOBALS['langTznUser']['login_username'].': '
|
||||
.$this->obj->username."\r\n\t"
|
||||
.$GLOBALS['langTznUser']['login_password'].': '
|
||||
.$_POST['password1']."\r\n";
|
||||
}
|
||||
if ($objMessage->send($bodyMessage, $this->obj->email)) {
|
||||
// well, ok, fine
|
||||
} else {
|
||||
$this->_error['activation'] = $GLOBALS['langSystemEmailStuff']['send_error'];
|
||||
}
|
||||
} else {
|
||||
$this->_error['activation'] = $GLOBALS['langSystemEmailStuff']['send_not_found'];
|
||||
}
|
||||
} else {
|
||||
$this->_error['activation'] = $GLOBALS['langSystemEmailStuff']['send_no_address'];
|
||||
}
|
||||
*/
|
||||
|
||||
return (empty($this->error));
|
||||
}
|
||||
/**
|
||||
* login and update DB
|
||||
*/
|
||||
protected function _activateLogin() {
|
||||
$updTz = '';
|
||||
if (isset($_REQUEST['appUserTimeZone'])) {
|
||||
if ($this->obj->get('time_zone') != $_REQUEST['appUserTimeZone']) {
|
||||
$this->obj->set('time_zone',$_REQUEST['appUserTimeZone']);
|
||||
$updTz = ',time_zone';
|
||||
}
|
||||
}
|
||||
// register session
|
||||
$_SESSION["appUserId"] = $this->obj->getUid();
|
||||
$_SESSION["appUserLastLogin"] = $this->obj->get('last_login_date');
|
||||
$_SESSION["appUserLastAddress"] = $this->obj->get('last_login_address');
|
||||
$this->updateSessionVariables();
|
||||
|
||||
// update last login
|
||||
$this->obj->set('last_login_date',APP_SQL_NOW);
|
||||
$this->obj->set('last_login_address', $_SERVER['REMOTE_ADDR']);
|
||||
$_SESSION['appUserCurrentAddress'] = $this->obj->get('last_login_address');
|
||||
$this->obj->_isLoggedIn = true;
|
||||
$this->obj->set('bad_access',0);
|
||||
$this->obj->set('visits',$this->obj->get('visits')+1);
|
||||
$this->obj->fields('last_login_date,last_login_address,bad_access,visits'.$updTz);
|
||||
$this->obj->update();
|
||||
}
|
||||
|
||||
/**
|
||||
* update sessions variables (on login and when updating own profile)
|
||||
*/
|
||||
public function updateSessionVariables() {
|
||||
$_SESSION["appUserName"] = $this->obj->get('username');
|
||||
$_SESSION["appUserTimeZone"] = $this->obj->get('time_zone');
|
||||
$this->obj->setupTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify username and password
|
||||
*/
|
||||
public function login($username, $password, $activation=false) {
|
||||
$this->error = '';
|
||||
if ($username == '') {
|
||||
$this->error = 'user_name_empty';
|
||||
return false;
|
||||
}
|
||||
if (APP_AUTH_FIELD == 'username' && (!VarUsr::sanitize($username, $error))) {
|
||||
$this->error = $error;
|
||||
return false;
|
||||
}
|
||||
$this->obj->set(APP_AUTH_FIELD,$username);
|
||||
if ($this->obj->load(APP_AUTH_FIELD)) {
|
||||
$activ = $this->obj->get('activation');
|
||||
if (!$this->obj->get('enabled')) {
|
||||
if (!$activation || $activation != $activ) {
|
||||
//Account Disabled
|
||||
$this->error = 'user_disabled';
|
||||
}
|
||||
}
|
||||
if (!$this->checkPassword($password)) {
|
||||
$this->error = 'user_password_invalid';
|
||||
} else if ($activation && $activation == $activ) {
|
||||
// activate account
|
||||
$this->activateAccount(true);
|
||||
}
|
||||
if (!empty($this->error)) {
|
||||
$this->badAccess();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->error = 'user_name_not_found';
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_activateLogin();
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
*coming soon
|
||||
*/
|
||||
public function silentLogin($username, $password) {
|
||||
$this->error = '';
|
||||
if ($username == '') {
|
||||
return false;
|
||||
}
|
||||
$this->obj->set(APP_AUTH_FIELD, $username);
|
||||
if ($this->obj->load(APP_AUTH_FIELD)) {
|
||||
if (!$this->obj->get('enabled')) {
|
||||
//Account Disabled
|
||||
$this->error = 'user_disabled';
|
||||
}
|
||||
if (!$this->checkPassword($password)) {
|
||||
$this->error = 'user_password_invalid';
|
||||
}
|
||||
} else {
|
||||
$this->error = 'user_name_not_found';
|
||||
return false;
|
||||
}
|
||||
return (empty($this->error));
|
||||
}
|
||||
/**
|
||||
* Is there a cookie for AutoLogin ??
|
||||
*/
|
||||
public function checkAutoLogin($forReal=true) {
|
||||
if (empty($_COOKIE['auto_login'])) {
|
||||
return false;
|
||||
}
|
||||
$arrVal = explode(":",$_COOKIE['auto_login']);
|
||||
$id = VarUid::sanitize($arrVal[0]);
|
||||
$salt = VarStr::sanitize($arrVal[1]);
|
||||
if (!$id || !$salt) {
|
||||
return false;
|
||||
}
|
||||
if ($this->obj->load($this->dbUid(true)."='".$id
|
||||
."' AND ".$this->dbField('salt', $salt)." AND "
|
||||
.$this->dbField('auto_login',1)." AND ".$this->dbField('enabled',1))
|
||||
) {
|
||||
if (!$forReal) {
|
||||
return true;
|
||||
}
|
||||
setCookie('auto_login',$this->obj->getUid().":".$this->obj->get('salt')
|
||||
,time()+(3600*24*30));
|
||||
$this->activateLogin();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Activate AutoLogin
|
||||
*/
|
||||
public function setAutoLogin() {
|
||||
if (($this->obj->getUid()) && ($this->obj->get('salt'))) {
|
||||
setCookie('autoLogin',$this->obj->getUid().":".$this->obj->get('salt')
|
||||
,time()+(3600*24*30));
|
||||
$this->obj->set('auto_login','1');
|
||||
$this->obj->fields('auto_login');
|
||||
$this->obj->update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* De-activate AutoLogin
|
||||
*/
|
||||
public function resetAutoLogin() {
|
||||
if (($this->obj->getUid()) && ($this->obj->get('salt'))) {
|
||||
setCookie('autoLogin');
|
||||
if ($this->obj->get('auto_login')) {
|
||||
$this->obj->set('auto_login', 0);
|
||||
$this->obj->fields('auto_login');
|
||||
$this->obj->update();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Logout logs the user out (yes indeed)
|
||||
* Note: This will destroy the session, and not just the session data!
|
||||
*/
|
||||
public function logout() {
|
||||
$_SESSION = array();
|
||||
// If you want to kill the session, also delete the session cookie.
|
||||
// Note: This will destroy the session, and not just the session data!
|
||||
if (isset($_COOKIE[session_name()])) {
|
||||
setcookie(session_name(), '', time()-42000, '/');
|
||||
}
|
||||
// Finally, destroy the session.
|
||||
@session_destroy();
|
||||
// while you're at it, delete auto login
|
||||
$this->resetAutoLogin();
|
||||
// set internal variable
|
||||
$this->isLoggedIn = false;
|
||||
$this->isLoggingOut = true;
|
||||
}
|
||||
/**
|
||||
* check if user is logged in. Do not load from DB by default
|
||||
*/
|
||||
public function isLoggedIn($load=false) {
|
||||
|
||||
// --- login previously checked ---
|
||||
|
||||
if (empty($_SESSION['appUserId'])) {
|
||||
$_SESSION['appUserId'] = 0;
|
||||
}
|
||||
|
||||
if ($this->isLoggedIn && !$this->isLoggingOut && $this->obj->getUid()) {
|
||||
// user seems already logged in
|
||||
if ($load) {
|
||||
// load is requested
|
||||
if ($this->obj->load() != $_SESSION['appUserId']) {
|
||||
return false;
|
||||
}
|
||||
} else if ($this->obj->getUid() != $_SESSION['appUserId']) {
|
||||
// ID in session and in object are different
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- first login check ---
|
||||
if ($_SESSION['appUserId'] == 0 || $this->isLoggingOut) {
|
||||
// invalid ID in session or currently logging out
|
||||
// $this->fc->addMessage('ERROR:#security_expired');
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// login seems OK : initialize properties
|
||||
$this->obj->set('id',$_SESSION['appUserId']);
|
||||
$this->obj->set('username', $_SESSION['appUserName']);
|
||||
|
||||
// time zone
|
||||
$this->obj->set('time_zone', $_SESSION['appUserTimeZone']);
|
||||
$this->obj->setupTimeZone();
|
||||
|
||||
$this->isLoggedIn = true;
|
||||
|
||||
// check user IP
|
||||
if ($_SESSION['appUserCurrentAddress'] && $_SERVER['REMOTE_ADDR'] != $_SESSION['appUserCurrentAddress']) {
|
||||
$this->fc->addMessage('ERROR:#security_ip '.$_SERVER['REMOTE_ADDR'].' / '.$_SESSION['appUserCurrentAddress']);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check that User ID is same in cookie and in session
|
||||
if ($load) {
|
||||
if ($this->obj->load() != $_SESSION['appUserId']) {
|
||||
$this->fc->addMessage('ERROR:#security_expired');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// reset last session stats with previous login info
|
||||
$this->obj->set('last_login_date', $_SESSION['appUserLastLogin']);
|
||||
$this->obj->set('last_login_address', $_SESSION['appUserLastAddress']);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All in one user login and access check function
|
||||
*/
|
||||
public function checkLogin($canAutoLogin=true) {
|
||||
|
||||
if ($this->isLoggedIn(true)) {
|
||||
return true;
|
||||
} else {
|
||||
if ($canAutoLogin && $this->checkAutoLogin()) {
|
||||
// auto logged in
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* forgotten password? Try to get it back or generate new one
|
||||
* type can be 'username' or 'email'
|
||||
*/
|
||||
public function forgotPassword($key, $value) {
|
||||
if ($this->obj->get('salt') == "") {
|
||||
if (!$this->obj->loadByKey($key,$value)) {
|
||||
// user not found
|
||||
$this->_error['forgot'] = $key." not found";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
switch (APP_AUTH_PASSWORD_MODE) {
|
||||
case 1:
|
||||
$this->generateNewSalt();
|
||||
$newpass = StringHelper::genRandom(6,"123456789");
|
||||
$this->obj->set('password', crypt($pass1 , $this->obj->get('salt')));
|
||||
$this->updatePassword();
|
||||
break;
|
||||
case 2:
|
||||
$this->generateNewSalt();
|
||||
$newpass = StringHelper::genRandom(6,"123456789");
|
||||
$this->obj->set('password', self::getDbPass("ENCRYPT(\"".$pass1."\",\"".$this->obj->get('salt')."\")"));
|
||||
$this->updatePassword();
|
||||
break;
|
||||
case 3:
|
||||
$strSql = "SELECT DECODE(password, '".$this->obj->get('salt')
|
||||
."') as pass FROM ".$this->_table
|
||||
." WHERE ".$this->obj->dbUid()."='".$this->obj->getUid()."'";
|
||||
if ($rows = DbConnnector::query($strSql)) {
|
||||
if (!empty($rows[0])) {
|
||||
$this->obj->password = $rows[0]->pass;
|
||||
return $this->obj->password;
|
||||
}
|
||||
}
|
||||
$this->_error['forgot'] = "can not decode?";
|
||||
return false;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
$this->generateNewSalt();
|
||||
$newpass = StringHelper::genRandom(6,"123456789");
|
||||
$this->password = "MD5('$newpass')";
|
||||
$this->updatePassword();
|
||||
break;
|
||||
default:
|
||||
$iv = mcrypt_create_iv (mcrypt_get_iv_size (MCRYPT_3DES,
|
||||
MCRYPT_MODE_ECB), MCRYPT_RAND);
|
||||
$this->password = mcrypt_decrypt (MCRYPT_3DES, $this->obj->get('salt'),
|
||||
$passBin, MCRYPT_MODE_ECB, $iv);
|
||||
return $this->password;
|
||||
break;
|
||||
}
|
||||
return $newpass;
|
||||
}
|
||||
|
||||
public function getLoginCountry() {
|
||||
$myIP = escapeshellarg($_SERVER['REMOTE_ADDR']);
|
||||
$pCountry = '00000'; // $_SERVER['REMOTE_ADDR'];
|
||||
if (@defined('APP_GEOLOCATION_SCRIPT') && is_file(APP_GEOLOCATION_SCRIPT)) {
|
||||
$arrOutput = array();
|
||||
exec(APP_GEOLOCATION_SCRIPT.' '.$myIP, $arrOutput);
|
||||
$strOutput = implode(' ',$arrOutput);
|
||||
if (preg_match('/(located in)/i',$strOutput)) {
|
||||
$strOutput = trim(substr($strOutput,strpos($strOutput,'in')+2));
|
||||
$pCountry = $strOutput;
|
||||
}
|
||||
}
|
||||
return $pCountry;
|
||||
}
|
||||
|
||||
/**
|
||||
* get error
|
||||
*/
|
||||
public function getAuthError($clean=true) {
|
||||
if (!$this->error) {
|
||||
return false;
|
||||
} else {
|
||||
$str = $this->error;
|
||||
if ($clean) {
|
||||
$this->error = '';
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Database manipulation ---------------------------------------------
|
||||
|
||||
protected function generateNewSalt() {
|
||||
$this->obj->set('salt',
|
||||
StringHelper::genRandom(
|
||||
8,
|
||||
'abcdefghijklmnopqrstuvwxyz'
|
||||
.'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function checkDbPass($mode, $pass) {
|
||||
return (self::getDbPass($mode) == $pass);
|
||||
}
|
||||
|
||||
public static function getDbPass($mode) {
|
||||
$sql = 'SELECT '.$mode.' as passhash';
|
||||
if ($rows = DbConnector::query($sql)) {
|
||||
if (!empty($rows[0])) {
|
||||
return $rows[0]['passhash'];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function badAccess() {
|
||||
$sql = "UPDATE ".$this->obj->dbTable()." SET"
|
||||
." bad_access=bad_access+1"
|
||||
." WHERE ".$this->obj->dbUid()." = '".$this->obj->getUid()."'";
|
||||
DbConnector::query($sql);
|
||||
}
|
||||
|
||||
protected function updatePassword() {
|
||||
$sql = "UPDATE ".$this->obj->dbTable()." SET"
|
||||
." password=".$this->obj->sql('password')
|
||||
." WHERE ".$this->obj->dbUid()." = '".$this->obj->getUid()."'";
|
||||
DbConnector::query($sql);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.2
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* AuthHelper ACL
|
||||
*
|
||||
* authentication system with ACL support
|
||||
*/
|
||||
class AuthAclHelper extends AuthHelper {
|
||||
|
||||
public $_arrAcl;
|
||||
|
||||
public function __construct($obj) {
|
||||
parent::__construct($obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* check ACL
|
||||
*/
|
||||
public function checkAcl($code) {
|
||||
if (!is_array($this->_arrAcl)) {
|
||||
$this->_arrAcl = explode(',', $this->obj->get('actags'));
|
||||
}
|
||||
return in_array($code, $this->_arrAcl);
|
||||
}
|
||||
|
||||
/**
|
||||
* update sessions variables (on login and when updating own profile)
|
||||
*/
|
||||
public function updateSessionVariables() {
|
||||
parent::updateSessionVariables();
|
||||
if ($this->obj->getPropertyType('actags')) {
|
||||
$_SESSION['appUserAcl'] = $this->obj->get('actags');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout logs the user out (yes indeed)
|
||||
*/
|
||||
public function logout() {
|
||||
parent::logout();
|
||||
$this->obj->set('actags',''); // -TODO- set guest tags
|
||||
}
|
||||
|
||||
/**
|
||||
* check if user is logged in. Do not load from DB by default
|
||||
*/
|
||||
public function isLoggedIn($load=false) {
|
||||
|
||||
if (parent::isLoggedIn($load)) {
|
||||
$this->obj->set('actags', $_SESSION['appUserAcl']);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* save User ACL settings
|
||||
*/
|
||||
public function updateACL($section='') {
|
||||
$id = $this->obj->getUid();
|
||||
if (!$id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$objLst = new AclModel();
|
||||
$objLst->connectDb();
|
||||
if (is_string($section)) {
|
||||
$objLst->where("section='$section'");
|
||||
}
|
||||
if (!$objLst->loadList()) {
|
||||
return false;
|
||||
}
|
||||
$i=0;
|
||||
$fc = FrontController::getInstance();
|
||||
$db = DbConnector::getConnection();
|
||||
$table = $objLst->dbTable('acl_user');
|
||||
while ($objLst->next()) {
|
||||
if ($fc->getReqVar('acl_'.$objLst->get('name'))) {
|
||||
$db->query('INSERT IGNORE INTO `'.$table.'` SET `user_id`='.$id.', `acl_id`='.$objLst->getUid());
|
||||
} else {
|
||||
$db->query('DELETE IGNORE FROM `'.$table.'` WHERE `user_id`='.$id.' AND `acl_id`='.$objLst->getUid());
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $i;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_deprecated
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* DbHelper
|
||||
*
|
||||
* Database helper to give Models (or other classes) database capabilities
|
||||
*/
|
||||
class DbHelper extends Helpable {
|
||||
|
||||
protected $obj;
|
||||
protected $db;
|
||||
protected $qry;
|
||||
|
||||
protected $idx;
|
||||
protected $rows;
|
||||
|
||||
public function __construct($obj) {
|
||||
parent::__construct();
|
||||
$this->obj = $obj;
|
||||
$this->db = DbConnector::getInstance();
|
||||
$this->qry = new DbQueryHelper();
|
||||
}
|
||||
|
||||
// ----- INSERTion queries ---------------------------------------------------
|
||||
|
||||
public function insert() {
|
||||
|
||||
}
|
||||
|
||||
public function replace() {
|
||||
|
||||
}
|
||||
|
||||
public function update() {
|
||||
// -TODO- what about files ?
|
||||
}
|
||||
|
||||
// ----- DELETE query -------------------------------------------------------
|
||||
|
||||
public function delete($filter) {
|
||||
// -TODO- what about files ?
|
||||
}
|
||||
|
||||
|
||||
// ----- LOAD queries --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* build default SELECT query
|
||||
*/
|
||||
public function buildSelect() {
|
||||
$this->qry->select('*');
|
||||
// -TODO- only selected fields
|
||||
$this->qry->from($this->obj->table);
|
||||
// -TODO- JOIN for objects, and GROUP BY if necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* load first item
|
||||
*/
|
||||
public function load($filter) {
|
||||
$this->buildSelect();
|
||||
$this->qry->where($filter);
|
||||
$this->qry->limit(0,1); // only the first item
|
||||
if ($data = $this->db->query($this->qry->build())) {
|
||||
$this->obj->set($data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load a list of items
|
||||
*/
|
||||
public function loadList() {
|
||||
$this->buildSelect();
|
||||
if ($data = $this->db->query($this->qry->build())) {
|
||||
$this->idx = 0;
|
||||
$this->rows = $data;
|
||||
}
|
||||
}
|
||||
|
||||
public function count() {
|
||||
return count($this->rows);
|
||||
}
|
||||
|
||||
public function next() {
|
||||
if (array_key_exists($this->idx, $this->rows)) {
|
||||
$this->obj->set($this->rows[$this->idx]);
|
||||
$this->idx++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set limit by giving a page size and page number
|
||||
*/
|
||||
public function page($size=10, $page=1) {
|
||||
if (!$size) {
|
||||
$this->qry->reset('limit');
|
||||
}
|
||||
if (!$page) {
|
||||
$page = 1;
|
||||
}
|
||||
$this->qry->limit(($page - 1) * $size, $size);
|
||||
}
|
||||
|
||||
// ---- MISCELLANEOUS --------------------------------------------------------
|
||||
|
||||
public function setDbDebug($level) {
|
||||
$this->db->setDbDebug($level);
|
||||
}
|
||||
|
||||
public function __call($name, $args) {
|
||||
if (method_exists($this->db, $name)) {
|
||||
return call_user_func_array(array($this->db, $name), $args);
|
||||
}
|
||||
if (method_exists($this->qry, $name)) {
|
||||
return call_user_func_array(array($this->qry, $name), $args);
|
||||
}
|
||||
throw new Exception('Unknown method '.$name.' in '.__CLASS__.', dbConnector or dbQueryHelper');
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* DbQueryHelper
|
||||
*
|
||||
* SQL SELECT Query Builder
|
||||
*/
|
||||
class DbQueryHelper {
|
||||
|
||||
protected $sql;
|
||||
|
||||
public function __construct() {
|
||||
$this->sql = array(
|
||||
'select' => '',
|
||||
'from' => '',
|
||||
'join' => array(),
|
||||
'where' => '',
|
||||
'groupBy' => '',
|
||||
'orderBy' => '',
|
||||
'having' => '',
|
||||
'limit' => ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset all or part of the SQL query
|
||||
*/
|
||||
public function reset($part='') {
|
||||
if ($part) {
|
||||
$this->sql[$part] = '';
|
||||
} else {
|
||||
foreach (array_keys($this->sql) as $key) {
|
||||
$this->sql[$key] = '';
|
||||
}
|
||||
$this->sql['join'] = array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* add fields in SELECT
|
||||
*/
|
||||
public function select($field) {
|
||||
if ($field == '*') {
|
||||
$this->sql['select'] = '';
|
||||
} else if (is_array($field)) {
|
||||
$this->sql['select'] = implode(', ',$field);
|
||||
} else {
|
||||
$this->sql['select'] = $this->concatSQL($this->sql['select'], $field, ',');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add FROM statement
|
||||
*/
|
||||
public function from($table) {
|
||||
if (is_array($table)) {
|
||||
$this->sql['from'] = $table[0].' AS '.$table[1];
|
||||
} else {
|
||||
$this->sql['from'] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add any JOIN
|
||||
*/
|
||||
public function join($table, $on, $how = '') {
|
||||
$str = ($how?($how.' '):'').'JOIN';
|
||||
if (is_array($table)) {
|
||||
$str .= $table[0].' AS '.$table[1];
|
||||
} else {
|
||||
$str .= $table;
|
||||
}
|
||||
$str .= ' ON ';
|
||||
if (is_array($on)) {
|
||||
$str .= $on[0].'='.$on[1];
|
||||
} else {
|
||||
$str .= $on;
|
||||
}
|
||||
$this->sql['join'][] = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* add INNDER JOIN
|
||||
*/
|
||||
public function innerJoin() {
|
||||
$this->join($table, $on, 'INNER');
|
||||
}
|
||||
|
||||
/**
|
||||
* add LEFT JOIN
|
||||
*/
|
||||
public function leftJoin($table, $on) {
|
||||
$this->join($table, $on, 'LEFT');
|
||||
}
|
||||
|
||||
/**
|
||||
* add WHERE condition
|
||||
*/
|
||||
public function where($filter, $sep='AND') {
|
||||
$this->sql['where'] = $this->concatSQL($this->sql['where'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add GROUP BY condition
|
||||
*/
|
||||
public function groupBy($filter, $sep=',') {
|
||||
$this->sql['groupBy'] = $this->concatSQL($this->sql['groupBy'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add ORDER BY statement
|
||||
*/
|
||||
public function orderBy($filter, $sep=',') {
|
||||
$this->sql['orderBy'] = $this->concatSQL($this->sql['orderBy'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add HAVING condition
|
||||
*/
|
||||
public function having($filter, $sep='AND') {
|
||||
$this->sql['having'] = $this->concatSQL($this->sql['having'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a LIMIT statement (only one statement allowed)
|
||||
*/
|
||||
public function limit($start=0, $length=1) {
|
||||
$this->sql['limit'] = $start.', '.$length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder routine
|
||||
*/
|
||||
public function build() {
|
||||
if (!$this->sql['select']) {
|
||||
$this->sql['select'] = '*';
|
||||
}
|
||||
$sql = 'SELECT '.$this->sql['select']
|
||||
.' FROM '.$this->sql['from'];
|
||||
foreach ($this->sql['join'] as $j) {
|
||||
$sql .= ' '.$j;
|
||||
}
|
||||
if ($this->sql['where']) {
|
||||
$sql .= ' WHERE '.$this->sql['where'];
|
||||
}
|
||||
if ($this->sql['groupBy']) {
|
||||
$sql .= ' GROUP BY '.$this->sql['groupBy'];
|
||||
}
|
||||
if ($this->sql['orderBy']) {
|
||||
$sql .= ' ORDER BY '.$this->sql['orderBy'];
|
||||
}
|
||||
if ($this->sql['having']) {
|
||||
$sql .= ' HAVING '.$this->sql['having'];
|
||||
}
|
||||
if ($this->sql['limit']) {
|
||||
$sql .= ' LIMIT '.$this->sql['limit'];
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// --- MISCELLANEOUS ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* concat string for SQL
|
||||
*/
|
||||
protected function concatSQL($begin, $end, $separator = 'AND', $instruction = '') {
|
||||
$separator = ' '.trim($separator).' ';
|
||||
if (!empty($instruction)) {
|
||||
$instruction .= ' ';
|
||||
}
|
||||
if (empty($begin)) {
|
||||
if (empty($end)) {
|
||||
return false;
|
||||
} else {
|
||||
return $instruction.$end;
|
||||
}
|
||||
} else if (empty($end)) {
|
||||
return $instruction.$begin;
|
||||
} else {
|
||||
return $begin.$separator.$end;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,628 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* DbHelper
|
||||
*
|
||||
* Database helper to give Models (or other classes) database capabilities
|
||||
*/
|
||||
class DbHelper extends Helper implements Callable {
|
||||
|
||||
protected $db;
|
||||
protected $qry;
|
||||
|
||||
protected $idx;
|
||||
protected $rows;
|
||||
protected $total;
|
||||
|
||||
protected $table;
|
||||
|
||||
public function __construct($obj, $table) {
|
||||
parent::__construct($obj);
|
||||
$this->db = DbConnector::getConnection();
|
||||
$this->qry = new DbQueryHelper();
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
// ----- INSERTion queries ---------------------------------------------------
|
||||
|
||||
public function save() {
|
||||
// check UID
|
||||
$uid = $this->obj->getUid();
|
||||
if (empty($uid)) {
|
||||
return $this->insert();
|
||||
} else {
|
||||
return $this->update();
|
||||
}
|
||||
}
|
||||
|
||||
public function insert() {
|
||||
// set creation date
|
||||
if (!$this->_creationDate()) {
|
||||
// if no field creation date, update last change date
|
||||
$this->_lastChangeDate();
|
||||
}
|
||||
// -TODO- INSERT IGNORE INTO
|
||||
$this->obj->ignore($this->obj->dbUid());
|
||||
// INSERT
|
||||
$sql = 'INSERT INTO `'.$this->obj->dbTable().'` SET '.$this->fields();
|
||||
if ($id = $this->db->query($sql)) {
|
||||
$this->obj->setUid($id);
|
||||
return $id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function replace() {
|
||||
$sql = 'REPLACE `'.$this->obj->dbTable().'` SET '.$this->fields();
|
||||
return $this->db->query($sql);
|
||||
}
|
||||
|
||||
public function update($filter='') {
|
||||
if (!$this->buildWhere($filter)) {
|
||||
return false;
|
||||
}
|
||||
// update last change date (if field is defined)
|
||||
$this->_lastChangeDate();
|
||||
// UPDATE
|
||||
$sql = 'UPDATE `'.$this->obj->dbTable().'` SET '.$this->fields();
|
||||
$sql .= ' WHERE '.$filter;
|
||||
return $this->db->query($sql);
|
||||
}
|
||||
|
||||
protected function fields() {
|
||||
$fields = $this->obj->getFields();
|
||||
$arr = '';
|
||||
foreach ($fields as $key => $type) {
|
||||
if (preg_match('/^OBJ/',$type)) {
|
||||
$arr[] = "`${key}_id`=".$this->sql($key.'::id');
|
||||
} else {
|
||||
$arr[] = "`$key`=".$this->sql($key);
|
||||
}
|
||||
}
|
||||
return implode(', ',$arr);
|
||||
}
|
||||
|
||||
public function sql($key) {
|
||||
$val = $this->obj->get($key);
|
||||
return $this->sqlValue($val);
|
||||
}
|
||||
|
||||
public function sqlValue($val) {
|
||||
if (is_integer($val)) {
|
||||
return $val;
|
||||
} else if (empty($val)) {
|
||||
return "''";
|
||||
} else {
|
||||
return "'".$this->db->escapeString($val)."'";
|
||||
}
|
||||
}
|
||||
|
||||
// ----- DELETE query -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* delete entry
|
||||
* @param string $filter if not set, will delete by UID
|
||||
* @todo delete files from IMG and DOC fields
|
||||
*/
|
||||
public function delete($filter='') {
|
||||
if (!$this->buildWhere($filter)) {
|
||||
return false;
|
||||
}
|
||||
$sql = 'DELETE FROM `'.$this->obj->dbTable().'`';
|
||||
$sql .= ' WHERE '.$filter;
|
||||
return $this->db->query($sql);
|
||||
}
|
||||
|
||||
|
||||
// ----- LOAD queries --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* load one item
|
||||
* @param mixed filter either an array (key/value), a string, or nothing if you want to load by ID
|
||||
* @param boolean $auto use automatic query (set to false if query has been generated before)
|
||||
*/
|
||||
public function load($filter='', $auto=true) {
|
||||
if ($auto) {
|
||||
$this->buildSelect();
|
||||
}
|
||||
if ($this->buildWhere($filter)) {
|
||||
$this->qry->where($filter);
|
||||
} else {
|
||||
$this->obj->setUid(0);
|
||||
return false;
|
||||
}
|
||||
$this->qry->limit(0,1); // only the first item
|
||||
if ($data = $this->db->query($this->qry->build())) {
|
||||
if (!empty($data[0])) {
|
||||
$this->obj->set($data[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->obj->setUid(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* load a list of items
|
||||
*/
|
||||
public function loadList($auto=true) {
|
||||
if ($auto) {
|
||||
$this->buildSelect();
|
||||
}
|
||||
$this->obj->all();
|
||||
if ($data = $this->db->query($this->qry->build())) {
|
||||
$this->idx = 0;
|
||||
$this->total = 0;
|
||||
$this->rows = $data;
|
||||
if ($this->doesLimit()) {
|
||||
$res = $this->db->query($this->qry->build(true));
|
||||
if (count($res) == 1) {
|
||||
// simple result with one row
|
||||
$this->total = intval($res[0]['total']);
|
||||
} else {
|
||||
// multiple rows, probably because of a group by
|
||||
$this->total = count($res);
|
||||
}
|
||||
} else {
|
||||
$this->total = count($this->rows);
|
||||
}
|
||||
return $this->total;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function count() {
|
||||
return count($this->rows);
|
||||
}
|
||||
|
||||
public function total() {
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
public function next() {
|
||||
if (array_key_exists($this->idx, $this->rows)) {
|
||||
$this->obj->set($this->rows[$this->idx]);
|
||||
$this->idx++;
|
||||
return true;
|
||||
} else {
|
||||
// $this->obj->resetProperties();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
$this->rows = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* set limit by giving a page size and page number
|
||||
*/
|
||||
public function page($size=10, $page=1) {
|
||||
if (!$size) {
|
||||
$this->qry->reset('limit');
|
||||
}
|
||||
if (!$page) {
|
||||
$page = 1;
|
||||
}
|
||||
$this->qry->limit(($page - 1) * $size, $size);
|
||||
}
|
||||
|
||||
// ---- TABLE & FIELDS MANIPULATION ------------------------------------------
|
||||
|
||||
/**
|
||||
* Get database table
|
||||
* @todo add DB table prefix
|
||||
*/
|
||||
public function dbTable($table='') {
|
||||
if (empty($table)) {
|
||||
$table = $this->table;
|
||||
}
|
||||
return $this->qry->prefixTable($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a SQL statement table.field = value
|
||||
*/
|
||||
public function dbField($field, $value='') {
|
||||
$str = $this->dbTable().'.'.$field;
|
||||
if ($value) {
|
||||
$str .= '='.$this->sqlValue($value);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function dbUid($ext=false) {
|
||||
if ($ext) {
|
||||
return $this->dbField($this->obj->proUid());
|
||||
} else {
|
||||
return $this->obj->proUid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get SQL formatted UID
|
||||
*/
|
||||
public function sqlUid() {
|
||||
return $this->sql($this->obj->proUid());
|
||||
}
|
||||
|
||||
// ---- MISC QUERIES ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* check if value already exists in table
|
||||
*/
|
||||
public function findOccurences($key, $val) {
|
||||
$sql = 'SELECT COUNT(*) AS cnt FROM `'.$this->obj->dbTable().'`'
|
||||
." WHERE `$key`='$val'";
|
||||
if ($data = $this->db->query($sql)) {
|
||||
if (!empty($data[0])) {
|
||||
return intval($data[0]->cnt);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---- QUERY BUILDER Methods ------------------------------------------------
|
||||
|
||||
/**
|
||||
* build default SELECT query
|
||||
* @todo might not want to reset query every time
|
||||
*/
|
||||
public function buildSelect() {
|
||||
// reset query -TODO- not if in cache
|
||||
$this->qry->reset('select,from,join');
|
||||
// get list of fields to be selected
|
||||
$select = $this->buildFields();
|
||||
// add SELECT clause
|
||||
$this->qry->select($select);
|
||||
// add FROM clause
|
||||
$this->qry->from($this->dbTable());
|
||||
}
|
||||
|
||||
/**
|
||||
* build SELECT and JOIN clauses
|
||||
*/
|
||||
public function buildFields($nested='') {
|
||||
$select = array();
|
||||
$arr = $this->obj->getFields();
|
||||
foreach ($arr as $key => $type) {
|
||||
if ($this->obj->isObjectProperty($key, $class, $nkey)) {
|
||||
$obj = new $class;
|
||||
$obj->connectDb();
|
||||
$select = array_merge($select, $obj->buildFields($nkey));
|
||||
// add table join
|
||||
$this->qry->leftJoin($obj->dbTable(), array($this->dbField($key.'_id'),$obj->dbUid(true)));
|
||||
} else if ($nested) {
|
||||
// add joined table field to select
|
||||
$select[] = '`'.$nested.'`.`'.$key.'` AS '.$nested.'__'.$key;
|
||||
} else if ($key == 'id') {
|
||||
// aah IDs...
|
||||
$select[] = $this->dbUid(true);
|
||||
} else {
|
||||
// add field to select
|
||||
$select[] = '`'.$key.'`';
|
||||
}
|
||||
}
|
||||
return $select;
|
||||
}
|
||||
|
||||
/**
|
||||
* build WHERE clause based on filter
|
||||
*/
|
||||
public function buildWhere(&$filter) {
|
||||
if (is_array($filter)) {
|
||||
// filter
|
||||
$filter = '`'.$filter[0]."`='".$filter[1]."'";
|
||||
} else if (preg_match('/^[a-zA-Z0-9\_]+$/',$filter)) {
|
||||
// filter on a field already set in DB
|
||||
$filter .= "=".$this->sql($filter);
|
||||
} else if (empty($filter)) {
|
||||
// nothing set, try on ID
|
||||
if ($id = $this->obj->getUid()) {
|
||||
$filter = $this->obj->dbUid($this->qry->doesJoin())."=".$this->obj->sqlUid();
|
||||
} else {
|
||||
// not filter and no ID provided, don't even try
|
||||
$filter = '';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// overwise, consider param as a ready set where statement
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- MISCELLANEOUS --------------------------------------------------------
|
||||
|
||||
protected function _creationDate() {
|
||||
$fields = $this->obj->getFields();
|
||||
if (array_key_exists('creation_date', $fields)) {
|
||||
$this->obj->set('creation_date',APP_SQL_NOW);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function _lastChangeDate() {
|
||||
$fields = $this->obj->getFields();
|
||||
if (array_key_exists('last_change_date', $fields)) {
|
||||
$this->obj->set('last_change_date',APP_SQL_NOW);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __call($name, $args) {
|
||||
$arr = array('db','qry');
|
||||
foreach ($arr as $class) {
|
||||
if (method_exists($this->$class, $name)) {
|
||||
return call_user_func_array(array($this->$class, $name), $args);
|
||||
}
|
||||
}
|
||||
throw new AppException('Unknown method '.$name.' in '.__CLASS__.', '.implode(', ',$arr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* DbQueryHelper
|
||||
*
|
||||
* SQL SELECT Query Builder
|
||||
*/
|
||||
class DbQueryHelper {
|
||||
|
||||
protected $sql;
|
||||
|
||||
public function __construct() {
|
||||
$this->sql = array(
|
||||
'select' => '',
|
||||
'from' => '',
|
||||
'join' => array(),
|
||||
'where' => '',
|
||||
'groupBy' => '',
|
||||
'orderBy' => '',
|
||||
'having' => '',
|
||||
'limit' => ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset all or part of the SQL query
|
||||
*/
|
||||
public function reset($part='') {
|
||||
if ($part) {
|
||||
$this->sql[$part] = '';
|
||||
} else {
|
||||
foreach (array_keys($this->sql) as $key) {
|
||||
$this->sql[$key] = '';
|
||||
}
|
||||
$this->sql['join'] = array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* add fields in SELECT
|
||||
*/
|
||||
public function select($field) {
|
||||
if (empty($field)) {
|
||||
return false;
|
||||
} else if ($field == '*') {
|
||||
$this->sql['select'] = '';
|
||||
} else {
|
||||
$field = StringHelper::mixedToArray($field);
|
||||
$this->sql['select'] = (($this->sql['select'])?($this->sql['select'].','):'').implode(',', $field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add FROM statement
|
||||
*/
|
||||
public function from($table) {
|
||||
if (is_array($table)) {
|
||||
$this->sql['from'] = '`'.$this->prefixTable($table[0]).'` AS '.$table[1];
|
||||
} else {
|
||||
$this->sql['from'] = '`'.$this->prefixTable($table).'`';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add any JOIN
|
||||
*/
|
||||
public function join($table, $on, $how = '') {
|
||||
$str = ($how?($how.' '):'').'JOIN ';
|
||||
if (is_array($table)) {
|
||||
$str .= '`'.$this->prefixTable($table[0]).'` AS '.$table[1];
|
||||
} else {
|
||||
$str .= $this->prefixTable($table);
|
||||
}
|
||||
$str .= ' ON ';
|
||||
if (is_array($on)) {
|
||||
$str .= $on[0].'='.$on[1];
|
||||
} else {
|
||||
$str .= $on;
|
||||
}
|
||||
$this->sql['join'][] = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* add INNER JOIN
|
||||
*/
|
||||
public function innerJoin($table, $on) {
|
||||
$this->join($table, $on, 'INNER');
|
||||
}
|
||||
|
||||
/**
|
||||
* add LEFT JOIN
|
||||
*/
|
||||
public function leftJoin($table, $on) {
|
||||
$this->join($table, $on, 'LEFT');
|
||||
}
|
||||
|
||||
/**
|
||||
* add WHERE condition
|
||||
*/
|
||||
public function where($filter, $sep='AND') {
|
||||
$this->sql['where'] = $this->concatSQL($this->sql['where'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add GROUP BY condition
|
||||
*/
|
||||
public function groupBy($filter, $sep=',') {
|
||||
$this->sql['groupBy'] = $this->concatSQL($this->sql['groupBy'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add ORDER BY statement
|
||||
*/
|
||||
public function orderBy($filter, $sep=',') {
|
||||
$this->sql['orderBy'] = $this->concatSQL($this->sql['orderBy'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add HAVING condition
|
||||
*/
|
||||
public function having($filter, $sep='AND') {
|
||||
$this->sql['having'] = $this->concatSQL($this->sql['having'], $filter, $sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a LIMIT statement (only one statement allowed)
|
||||
*/
|
||||
public function limit($start=0, $length=1) {
|
||||
if ($length == 0) {
|
||||
return false;
|
||||
}
|
||||
$this->sql['limit'] = $start.', '.$length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder routine
|
||||
* @param boolean $total will query for total number of rows when set to true
|
||||
*/
|
||||
public function build($total=false) {
|
||||
$sql = 'SELECT ';
|
||||
if ($total) {
|
||||
$sql .= 'COUNT(*) AS total';
|
||||
/*
|
||||
if ($this->doesJoin()) {
|
||||
$sql .= 'COUNT(DISTINCT '.$this->sql['from'].'.id) AS total';
|
||||
} else {
|
||||
$sql .= 'COUNT(*) AS total';
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
if (!$this->sql['select']) {
|
||||
$this->sql['select'] = '*';
|
||||
}
|
||||
$sql .= $this->sql['select'];
|
||||
}
|
||||
$sql .= ' FROM '.$this->sql['from'];
|
||||
foreach ($this->sql['join'] as $j) {
|
||||
$sql .= ' '.$j;
|
||||
}
|
||||
if ($this->sql['where']) {
|
||||
$sql .= ' WHERE '.$this->sql['where'];
|
||||
}
|
||||
if ($this->sql['groupBy']) {
|
||||
$sql .= ' GROUP BY '.$this->sql['groupBy'];
|
||||
}
|
||||
if ($this->sql['having']) {
|
||||
$sql .= ' HAVING '.$this->sql['having'];
|
||||
}
|
||||
if ($this->sql['orderBy']) {
|
||||
$sql .= ' ORDER BY '.$this->sql['orderBy'];
|
||||
}
|
||||
if ($this->sql['limit'] && !$total) {
|
||||
$sql .= ' LIMIT '.$this->sql['limit'];
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
// --- MISCELLANEOUS ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* add prefix to table name
|
||||
*/
|
||||
public function prefixTable($table) {
|
||||
if (defined('APP_DB_PREFIX') && APP_DB_PREFIX) {
|
||||
if (preg_match('/^'.APP_DB_PREFIX.'_/', $table)) {
|
||||
return $table;
|
||||
} else {
|
||||
return APP_DB_PREFIX.'_'.$table;
|
||||
}
|
||||
} else {
|
||||
return $table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if joigning multi tables
|
||||
*/
|
||||
public function doesJoin() {
|
||||
return empty($this->sql['join'])?false:true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if limit has been set
|
||||
*/
|
||||
public function doesLimit() {
|
||||
return empty($this->sql['limit'])?false:true;
|
||||
}
|
||||
|
||||
/**
|
||||
* concat string for SQL
|
||||
*/
|
||||
protected function concatSQL($begin, $end, $separator = 'AND', $instruction = '') {
|
||||
$separator = ' '.trim($separator).' ';
|
||||
if (!empty($instruction)) {
|
||||
$instruction .= ' ';
|
||||
}
|
||||
if (empty($begin)) {
|
||||
if (empty($end)) {
|
||||
return false;
|
||||
} else {
|
||||
return $instruction.$end;
|
||||
}
|
||||
} else if (empty($end)) {
|
||||
return $instruction.$begin;
|
||||
} else {
|
||||
return $begin.$separator.$end;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build condition to include in a WHERE clause
|
||||
* @param string param the value searched. Can contain wildcards.
|
||||
*/
|
||||
public static function parseSearch($param) {
|
||||
if ($param = trim($param)) {
|
||||
if ($param == '*') {
|
||||
return false;
|
||||
}
|
||||
if (preg_match('/^".*"$/i',$param)) {
|
||||
$param = '%'.str_replace('"','',$param).'%';
|
||||
} else if (preg_match('/\*/',$param)) {
|
||||
$param = str_replace('*','%',$param);
|
||||
} else {
|
||||
$param = '%'.str_replace(' ','%',$param).'%';
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$db = DbConnector::getConnection();
|
||||
return $db->escapeString($param);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* HtmlAsset Helper
|
||||
*
|
||||
* HTML Asset, links to CSS, Javascripts, etc...
|
||||
*/
|
||||
class HtmlAssetHelper extends Collectable {
|
||||
|
||||
protected $css, $cssCode, $js, $jsCode, $jsEditor, $jsCalendar, $jsOnLoad, $rss;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function _init($key,$reset=false) {
|
||||
if (!is_array($this->$key) || $reset) {
|
||||
$this->$key = array();
|
||||
if (!$reset && !empty($GLOBALS['config']['header'][$key])) {
|
||||
$this->$key = StringHelper::mixedToArray($GLOBALS['config']['header'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function headerStuff() {
|
||||
|
||||
if (count($this->jsCalendar)) {
|
||||
$this->add('css',APP_WWW_URI.'asset/css/calendar.css');
|
||||
$this->add('js', APP_WWW_URI.'asset/js/calendar.js');
|
||||
foreach($this->jsCalendar as $it) {
|
||||
if (is_string($it)) {
|
||||
$it=trim($it);
|
||||
$this->add('jsOnLoad',"new Calendar({ '$it': 'd/m/y' })");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($this->jsEditor)) {
|
||||
$this->add('js',APP_WWW_URI.'asset/ckeditor/ckeditor.js');
|
||||
$str = '';
|
||||
foreach ($this->jsEditor as $kit => $mode) {
|
||||
$str .= "CKEDITOR.replace('$kit',{toolbar:'$mode'";
|
||||
if (strpos($mode, 'Upl')) {
|
||||
$base = APP_WWW_URI.'asset/fmanager/';
|
||||
$str .= ", filebrowserBrowseUrl : '${base}browser.php', "
|
||||
."filebrowserImageBrowseUrl : '${base}browser.php?Type=images', "
|
||||
."filebrowserFlashBrowseUrl : '${base}browser.php?Type=flash'"; //,
|
||||
/*
|
||||
."filebrowserUploadUrl : '${base}uploader.php?command=QuickUpload&type=docs', "
|
||||
."filebrowserImageUploadUrl : '${base}uploader.php?command=QuickUpload&type=images', "
|
||||
."filebrowserFlashUploadUrl : '${base}uploader.php?command=QuickUpload&type=flash'";
|
||||
*/
|
||||
}
|
||||
$str .= "});\n";
|
||||
}
|
||||
$this->add('jsOnLoad',$str);
|
||||
}
|
||||
|
||||
// css
|
||||
if (count($this->css)) {
|
||||
foreach($this->css as $it) {
|
||||
if (preg_match('/(^\/|http:\/\/)/', $it)) {
|
||||
echo '<link rel="stylesheet" type="text/css" href="'.$it.'" />'."\n";
|
||||
} else {
|
||||
foreach ($GLOBALS['config']['path']['css'] as $p) {
|
||||
if (file_exists(APP_WWW_PATH.$p.$it)) {
|
||||
echo '<link rel="stylesheet" type="text/css" href="'.APP_WWW_URI.$p.$it.'" />'."\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// css code (ie tests)
|
||||
if (count($this->cssCode)) {
|
||||
echo implode("\n",$this->cssCode)."\n";
|
||||
}
|
||||
|
||||
// javascrpt direct code
|
||||
if (count($this->jsCode)) {
|
||||
echo '<script type="text/javascript">'."\n";
|
||||
echo implode("\n",$this->jsCode);
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
|
||||
// javascript on load function
|
||||
if (count($this->jsOnLoad)) {
|
||||
echo '<script type="text/javascript">'."\n";
|
||||
echo "window.onload=function(){\n";
|
||||
echo implode("\n",$this->jsOnLoad);
|
||||
echo "\n}\n</script>\n";
|
||||
|
||||
}
|
||||
|
||||
// xml/rss
|
||||
if (count($this->rss)) {
|
||||
foreach($this->rss as $it) {
|
||||
echo '<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="'
|
||||
.CMS_WWW_URL.$it.'" />'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function footerStuff() {
|
||||
// javascript (include)
|
||||
if (count($this->js)) {
|
||||
foreach($this->js as $it) {
|
||||
$it = trim($it);
|
||||
if (preg_match('/^(\/|http:\/\/)/', $it)) {
|
||||
echo '<script type="text/javascript" src="'.$it.'" language="javascript"></script>'."\n";
|
||||
} else {
|
||||
foreach ($GLOBALS['config']['path']['js'] as $p) {
|
||||
if (file_exists(APP_WWW_PATH.$p.$it)) {
|
||||
echo '<script type="text/javascript" src="'.APP_WWW_URI.$p.$it.'" language="javascript"></script>'."\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* HtmlFormHelper
|
||||
*
|
||||
* HTML form fields helper
|
||||
*/
|
||||
class HtmlFormHelper extends Helper {
|
||||
|
||||
// protected $fc;
|
||||
|
||||
public function __construct($obj=null) {
|
||||
parent::__construct($obj);
|
||||
// $this->fc = FrontController::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a complete form for model object given to constructor
|
||||
*/
|
||||
public function iAutoForm($name, $method='post', $action='', $class='') {
|
||||
if (!isset($this->obj)) {
|
||||
throw AppException('Can not generate form : no object given in Helper');
|
||||
}
|
||||
$str = $this->iForm($name, $method, $action);
|
||||
$str .= $this->obj->iFields($class);
|
||||
$str .= '</form>';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a <FORM> tag
|
||||
* @param string $name name of form (id will be i_$name)
|
||||
* @param string $method post, get, or file (post by default)
|
||||
* @param string $action URL to which form is sent (current page by default)
|
||||
*/
|
||||
public function iForm($name, $method='post', $action='', $class='') {
|
||||
$fc = FrontController::getInstance();
|
||||
if (!$action) {
|
||||
$action = $fc->thisUrl();
|
||||
}
|
||||
$str = '<form id="f_'.$name.'" name="'.$name.'"';
|
||||
if ($method == 'file') {
|
||||
$str .= ' method="post" enctype="multipart/form-data"';
|
||||
} else {
|
||||
$str .= ' method="'.$method.'"';
|
||||
}
|
||||
if ($class) {
|
||||
$str .= ' class="'.$class.'"';
|
||||
}
|
||||
$str .= ' action="'.$action.'">';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates form field (only selected fields)
|
||||
*/
|
||||
public function iFields($class='side') {
|
||||
if (!isset($this->obj)) {
|
||||
throw AppException('Can not generate fields : no object given in Helper');
|
||||
}
|
||||
$str = '<ol class="fields'.($class?(' '.$class):'').'">';
|
||||
foreach ($this->obj->getFields() as $key => $type) {
|
||||
$type = substr($type,0,3);
|
||||
// error_log(get_class($this->obj).' iFields : '.$key.' / '.$type);
|
||||
if ($type == 'UID') {
|
||||
// put UID in hidden field before <OL>
|
||||
$str = $this->iHidden($key).$str;
|
||||
continue;
|
||||
} else if ($this->obj->isObjectProperty($key, $class, $nkey)) {
|
||||
// get a simple input field for the ID
|
||||
// error_log(get_class($this->obj).' iFields found '.$key.' as an object of '.$class.' ('.$nkey.')');
|
||||
$obj = new $class;
|
||||
$obj->addHelper('html_form');
|
||||
$str .= '<li><label for="i_'.$nkey.'_id">'.$nkey.'</label>'
|
||||
.$this->obj->iNested('id', $nkey);
|
||||
|
||||
} else if ($sf = $this->iFieldLabelled($key, $key, $type)) {
|
||||
$str .= $sf;
|
||||
}
|
||||
}
|
||||
$str .= '<li class="buttons"><button type="submit" name="save" value="1">Save</button></li>';
|
||||
$str .= '</ol>';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a field along with LABEL, all wrapped in a LI
|
||||
* @todo make the wrapper optional
|
||||
* @todo missing types
|
||||
*/
|
||||
public function iFieldLabelled($key, $label='', $type='', $wrap='li') {
|
||||
if (empty($type)) {
|
||||
$type = $this->obj->getPropertyType($key);
|
||||
}
|
||||
$sf = '';
|
||||
switch($type) {
|
||||
case 'UID': //-TODO- hidden ?
|
||||
case 'INT':
|
||||
case 'NUM':
|
||||
case 'DEC':
|
||||
case 'STR':
|
||||
case 'EML':
|
||||
case 'URL':
|
||||
case 'TIM': // -TODO-
|
||||
$sf = $this->iText($key);
|
||||
break;
|
||||
case 'DTE':
|
||||
$sf = $this->iDate($key);
|
||||
break;
|
||||
case 'DTM':
|
||||
$sf = $this->iDateTime($key);
|
||||
break;
|
||||
case 'USR':
|
||||
$sf = $this->iText($key);
|
||||
break;
|
||||
case 'PSS':
|
||||
$sf = $this->iPass($key);
|
||||
break;
|
||||
case 'TXT':
|
||||
case 'BBS': // -TODO-
|
||||
case 'HTM': // -TODO-
|
||||
case 'XML': // -TODO-
|
||||
$sf = $this->iTextArea($key);
|
||||
break;
|
||||
case 'BOL':
|
||||
$sf = $this->iCheckBox($key);
|
||||
break;
|
||||
case 'LVL': // -TODO-
|
||||
case 'DOC': // -TODO-
|
||||
case 'IMG': // -TODO-
|
||||
case 'OBJ': // -TODO-
|
||||
break;
|
||||
}
|
||||
if (!$sf) {
|
||||
return false;
|
||||
}
|
||||
if (empty($label)) {
|
||||
$label = str_replace('_',' ',$key); // -TODO- translate
|
||||
}
|
||||
return $this->_htmlWrapBegin($wrap)
|
||||
.'<label for="i_'.$key.'">'.$label.'</label>'
|
||||
.$sf
|
||||
.$this->_htmlWrapEnd($wrap);
|
||||
}
|
||||
|
||||
/*
|
||||
* generates a hidden field
|
||||
*/
|
||||
public function iHidden($key) {
|
||||
$str = '<input type="hidden" id="i_'.$key.'" name="'.$key.'" value="'
|
||||
.$this->_value($key)
|
||||
.'" />';
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*
|
||||
* generates a text field
|
||||
*/
|
||||
public function iText($key) {
|
||||
$str = '<input type="text" id="i_'.$key.'" name="'.$key.'" value="'
|
||||
.$this->_value($key)
|
||||
.'" />';
|
||||
if ($err = $this->_htmlError($key)) {
|
||||
$str .= $err;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/*
|
||||
* generates a text field
|
||||
*/
|
||||
public function iNested($key, $nested) {
|
||||
$str = '<input type="text" id="i_'.$nested.'__'.$key.'" name="'.$nested.'__'.$key.'" value="'
|
||||
.$this->_value("$nested::$key")
|
||||
.'" />';
|
||||
if ($err = $this->_htmlError($key)) {
|
||||
$str .= $err;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates date field
|
||||
* @todo real date field
|
||||
*/
|
||||
public function iDate() {
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array($this,'iText'),$args);
|
||||
}
|
||||
/**
|
||||
* generates date time field
|
||||
* @todo real date time field
|
||||
*/
|
||||
public function iDateTime() {
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array($this,'iText'),$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a password field
|
||||
*/
|
||||
public function iPass($key, $autocomplete=true) {
|
||||
$str = '<input type="password" id="i_'.$key.'" name="'.$key.'" value=""';
|
||||
if (!$autocomplete) {
|
||||
$str .= ' autocomplete="off"';
|
||||
}
|
||||
$str .= ' />';
|
||||
if ($err = $this->_htmlError($key)) {
|
||||
$str .= $err;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a simple text area
|
||||
*/
|
||||
public function iTextArea($key) {
|
||||
$str = '<textarea id="i_'.$key.'" name="'.$key.'">'
|
||||
.$this->_value($key)
|
||||
.'</textarea>';
|
||||
if ($err = $this->_htmlError($key)) {
|
||||
$str .= $err;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a check box
|
||||
*/
|
||||
public function iCheckBox($key, $label='') {
|
||||
$str = '<input type="checkbox" id="i_'.$key.'" name="'.$key.'"';
|
||||
if ($this->_value($key)) {
|
||||
$str .= ' checked="checked"';
|
||||
}
|
||||
$str .= ' value="1" />';
|
||||
if (empty($label)) {
|
||||
$options = $this->obj->getPropertyOptions($key);
|
||||
if (!empty($options['label'])) {
|
||||
// -TODO- translate
|
||||
$label = $options['label'];
|
||||
}
|
||||
}
|
||||
if (!empty($label)) {
|
||||
$str .= '<label for="_'.$key.'" class="inline">'.VarStr::html($label).'</label>';
|
||||
}
|
||||
if ($err = $this->_htmlError($key)) {
|
||||
$str .= $err;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a series of radio inputs
|
||||
*/
|
||||
public function iRadio($key, $options='', $wrap='ul', $subwrap='li') {
|
||||
if (isset($this->obj)) {
|
||||
$options = $this->obj->getPropertyOptions($key);
|
||||
}
|
||||
if (empty($options['options'])) {
|
||||
FC::log_warn("iRadio $key does not provide options");
|
||||
return $key.' (no option)';
|
||||
}
|
||||
$str = $this->_htmlWrapBegin($wrap);
|
||||
$i = 1;
|
||||
foreach($options['options'] as $val => $lbl) {
|
||||
$str .= $this->_htmlWrapBegin($subwrap);
|
||||
$str .= '<input type="radio" id="i_'.$key.'_'.$i.'" name="'.$key.'"';
|
||||
if ($options['value'] == $val) {
|
||||
$str .= ' checked="checked"';
|
||||
}
|
||||
$str .= ' value="'.$val.'" />';
|
||||
$str .= '<label for="i_'.$key.'_'.$i.'">'.$lbl.'</label>';
|
||||
$str .= $this->_htmlWrapEnd($subwrap);
|
||||
$i++;
|
||||
}
|
||||
return $str.$this->_htmlWrapEnd($wrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a select (drop down)
|
||||
*/
|
||||
public function iSelect($key, $options='') {
|
||||
if (isset($this->obj)) {
|
||||
$options = $this->obj->getPropertyOptions($key);
|
||||
}
|
||||
if (empty($options['options'])) {
|
||||
FC::log_warn("iRadio $key does not provide options");
|
||||
return $key.' (no option)';
|
||||
}
|
||||
$str = '<select id="i_'.$key.'" name="'.$key.'">';
|
||||
$i = 1;
|
||||
foreach($options['options'] as $val => $lbl) {
|
||||
$str .= '<option value="'.$val.'"';
|
||||
if ($options['value'] == $val) {
|
||||
$str .= ' selected="selected"';
|
||||
}
|
||||
$str .= ' value="'.$val.'">'.$lbl.'</option>';
|
||||
$i++;
|
||||
}
|
||||
return $str.'</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a time zone drop down list
|
||||
*/
|
||||
public function iTimeZone($key, $options='') {
|
||||
if (isset($this->obj)) {
|
||||
$default = $this->obj->get($key);
|
||||
// $options = $this->obj->getPropertyOptions($key);
|
||||
}
|
||||
|
||||
$timezone_identifiers = DateTimeZone::listIdentifiers();
|
||||
$str = '<select id="id_'.$key.'" name="'.$key.'">';
|
||||
$continent = '';
|
||||
foreach( $timezone_identifiers as $value ) {
|
||||
if ( preg_match( '/^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)\//', $value ) ) {
|
||||
$ex=explode("/",$value);//obtain continent,city
|
||||
if ($continent!=$ex[0]){
|
||||
if ($continent!="") echo '</optgroup>';
|
||||
$str .= '<optgroup label="'.$ex[0].'">';
|
||||
}
|
||||
$city=$ex[1];
|
||||
$continent=$ex[0];
|
||||
$str .= '<option value="'.$value.'"';
|
||||
if ($value == $default) {
|
||||
$str .= ' selected="selected"';
|
||||
}
|
||||
$str .='>'.$city.'</option>';
|
||||
}
|
||||
}
|
||||
$str .= '</optgroup>';
|
||||
return $str.'</select>';
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a form field formatted value
|
||||
*/
|
||||
protected function _value($key) {
|
||||
if (!isset($this->obj)) {
|
||||
return '';
|
||||
}
|
||||
return $this->obj->value($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns error (HTML formatted)
|
||||
*/
|
||||
protected function _htmlError($key) {
|
||||
if (!isset($this->obj)) {
|
||||
return '';
|
||||
}
|
||||
return $this->obj->htmlError($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML wrapper begin tag
|
||||
*/
|
||||
protected function _htmlWrapBegin($wrap) {
|
||||
if ($wrap) {
|
||||
return '<'.$wrap.'>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML wrapper end tag
|
||||
*/
|
||||
protected function _htmlWrapEnd($wrap) {
|
||||
if ($wrap) {
|
||||
if ($idx = strpos($wrap, ' ')) {
|
||||
$wrap = substr($wrap,0,$idx);
|
||||
}
|
||||
return '</'.$wrap.'>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Messaging
|
||||
*
|
||||
* manages session messages, alerts, error messages
|
||||
*/
|
||||
class MessagingHelper {
|
||||
|
||||
public function __construct() {
|
||||
if (!isset($_SESSION['appMessage'])) {
|
||||
$_SESSION['appMessage'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
public function addMessage($str) {
|
||||
if (!array_search($str, $_SESSION['appMessage'])) {
|
||||
$_SESSION['appMessage'][] = $str;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasMessage() {
|
||||
return count($_SESSION['appMessage']);
|
||||
}
|
||||
|
||||
public function getMessages(&$isError, $html=true, $clean=true) {
|
||||
$str = '';
|
||||
foreach($_SESSION['appMessage'] as $mess) {
|
||||
if (preg_match('/^ERROR:/i', $mess)) {
|
||||
$isError = true;
|
||||
$mess = substr($mess,6);
|
||||
}
|
||||
if ($str) {
|
||||
$str .= "\n";
|
||||
}
|
||||
$str .= $mess;
|
||||
}
|
||||
if ($clean) {
|
||||
$this->cleanMessages();
|
||||
}
|
||||
if ($html) {
|
||||
return VarTxt::html($str);
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
public function cleanMessages() {
|
||||
unset($_SESSION['appMessage']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Navi
|
||||
*
|
||||
* manages referers, redirection and provides URL manipulation
|
||||
*/
|
||||
class NaviHelper {
|
||||
|
||||
public function __construct() {
|
||||
if (!isset($_SESSION['appReferrers'])) {
|
||||
$_SESSION['appReferrers'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
// ---- REFERERS handling ----------------------------------------------------
|
||||
|
||||
public function autoReferrer($historic=false) {
|
||||
|
||||
$url = $_SERVER['REQUEST_URI'];
|
||||
if ($historic) {
|
||||
$url = substr($_SERVER['HTTP_REFERER'],strlen(APP_WWW_URL));
|
||||
} else {
|
||||
/*
|
||||
$url = $_SERVER['PHP_SELF']
|
||||
.(($_SERVER['QUERY_STRING'])?('?'.$_SERVER['QUERY_STRING']):'');
|
||||
*/
|
||||
}
|
||||
|
||||
if (!preg_match('/login/',$url)) {
|
||||
return $url;
|
||||
} else {
|
||||
// skip login, register, logout and password reminder pages
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function setReferrer($url='') {
|
||||
$_SESSION['appReferrers'] = array();
|
||||
if ($url) {
|
||||
$_SESSION['appReferrers'][] = StringHelper::camelToFlat($url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function addReferrer($url='', $historic=false) {
|
||||
if (!$url) {
|
||||
if (!$url = $this->autoReferrer($historic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$url = StringHelper::camelToFlat($url);
|
||||
|
||||
$arr = $_SESSION['appReferrers']; // copy
|
||||
|
||||
// search for previous entry with same url
|
||||
while ($tmp = @array_pop($arr)) {
|
||||
if ($tmp == $url) {
|
||||
// been to this page, need to clean referrers
|
||||
$_SESSION['appReferrers'] = $arr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add url to referrer
|
||||
$_SESSION['appReferrers'][] = $url;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function addAppReferrer($params=NULL) {
|
||||
$fc = FrontController::getInstance();
|
||||
if (!empty($params)) {
|
||||
$params = StringHelper::mixedToArray($params);
|
||||
$arr = array();
|
||||
foreach($params as $p) {
|
||||
if (array_key_exists($p, $fc->request)) {
|
||||
$arr[$p] = $fc->request[$p];
|
||||
}
|
||||
}
|
||||
$this->addReferrer($fc->thisUrl($arr));
|
||||
} else {
|
||||
$this->addReferrer($fc->thisUrl());
|
||||
}
|
||||
}
|
||||
|
||||
public function getReferrer($skip=true, $clean=false) {
|
||||
$url = './';
|
||||
$arr = $_SESSION['appReferrers']; // copy
|
||||
if ($clean) {
|
||||
$arr =& $_SESSION['appReferrers']; // point
|
||||
}
|
||||
if (!is_array($arr)) {
|
||||
// normally not needed, but seems to happen for some reason
|
||||
$arr = array();
|
||||
}
|
||||
FrontController::log_debug('Refs : '.implode(', ',$arr));
|
||||
if ($skip) {
|
||||
array_pop($arr); // skip last one
|
||||
}
|
||||
while (count($arr)) {
|
||||
if ($tmp = array_pop($arr)) {
|
||||
$url = $tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function naturalReferrer($default, $avoid='') {
|
||||
$ref = $default;
|
||||
if ($_REQUEST['ref']) {
|
||||
$ref = $_REQUEST['ref'];
|
||||
} else if ($_SERVER['HTTP_REFERER']) {
|
||||
$ref = $_SERVER['HTTP_REFERER'];
|
||||
}
|
||||
if ($avoid && preg_match("/$avoid/i",$ref)) {
|
||||
$ref = $default;
|
||||
}
|
||||
return $ref;
|
||||
}
|
||||
|
||||
public function delReferrer() {
|
||||
array_pop($_SESSION['appReferrers']);
|
||||
}
|
||||
|
||||
public function printReferrers() {
|
||||
foreach ($_SESSION['appReferrers'] as $url) {
|
||||
echo ' > <a href="'.$url.'">'.$url.'</a>';
|
||||
}
|
||||
}
|
||||
|
||||
// ---- URLs and REDIRECTION -------------------------------------------------
|
||||
|
||||
public function autoRedirect($message='') {
|
||||
$this->redirect($this->getReferrer(true, true), $message);
|
||||
}
|
||||
|
||||
public static function redirect($url,$message='',$forceRef=false)
|
||||
{
|
||||
if (@constant('TZN_TRANS_ID')) {
|
||||
if (session_id() && (!preg_match('/'.session_id().'/i',$url))) {
|
||||
$url = $this->concatUrl($url,session_name()
|
||||
.'='.session_id());
|
||||
}
|
||||
}
|
||||
if ($message) {
|
||||
$message = preg_replace("/<script[^>]*>[^<]+<\/script[^>]*>/is"
|
||||
,"", $message);
|
||||
$message = preg_replace("/<\/?(div|span|iframe|frame|input|"
|
||||
."textarea|script|style|applet|object|embed|form)[^>]*>/is"
|
||||
,"", $message);
|
||||
if (@constant('TZN_TRANS_STATUS')) {
|
||||
$fc = FrontController::getInstance();
|
||||
$fc->addMessage($message);
|
||||
} else {
|
||||
$url = self::concatUrl($url,'tznMessage='.urlencode($message));
|
||||
}
|
||||
}
|
||||
if ($forceRef) {
|
||||
$url = self::concatUrl($url,'ref='.rawurlencode($_SERVER['REQUEST_URI']));
|
||||
}
|
||||
header("Location: ".str_replace('&','&',$url));
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function concatUrl($url,$param)
|
||||
{
|
||||
// hash
|
||||
$hash = '';
|
||||
if ($pos = strpos($url,'#')) {
|
||||
$hash = substr($url,$pos);
|
||||
$url = substr($url,0,$pos);
|
||||
}
|
||||
if ($pos = strpos($param,'#')) {
|
||||
$hash = substr($param,$pos);
|
||||
}
|
||||
// params
|
||||
$url = str_replace('&','&',$url);
|
||||
if ($pos = strpos($url,'?')) {
|
||||
$arrParam = explode('=',$param);
|
||||
if (strpos($url,$arrParam[0].'=')) {
|
||||
// parameter already in url
|
||||
$strQuery = substr($url,$pos+1);
|
||||
$arrQuery = explode('&',$strQuery);
|
||||
$arrResult = array();
|
||||
$found = false;
|
||||
foreach ($arrQuery as $value) {
|
||||
if (preg_match('/^'.$arrParam[0].'=/', $value)) {
|
||||
if ($arrParam[1]) {
|
||||
// add only if has a value
|
||||
$arrResult[] = $param;
|
||||
}
|
||||
$found = true;
|
||||
} else {
|
||||
$arrResult[] = $value;
|
||||
}
|
||||
}
|
||||
if ($found) {
|
||||
$url = substr($url,0,$pos).'?'.implode('&',$arrResult);
|
||||
} else {
|
||||
$url .= '&'.$param;
|
||||
}
|
||||
} else {
|
||||
$url .= '&'.$param;
|
||||
}
|
||||
} else {
|
||||
$url .= '?'.$param;
|
||||
}
|
||||
return str_replace('&','&',$url).$hash;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.1
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* String Helper
|
||||
*
|
||||
* common functions to manipulate strings
|
||||
*/
|
||||
class StringHelper {
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* transforms a string from CamelCasing to flat_with_underscores
|
||||
*/
|
||||
public static function camelToFlat($str, $sep='_') {
|
||||
$str = preg_replace('/(?<=\\w)(?=[A-Z])/',"$sep$1", trim($str));
|
||||
return strtolower($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* transforms a string from flat_with_underscores to CamelCasing
|
||||
*/
|
||||
public static function flatToCamel($str, $firstCap=false, $sep='_') {
|
||||
$arr = explode($sep,trim($str));
|
||||
$str = '';
|
||||
foreach($arr as $sep) {
|
||||
if ((!$str && $firstCap) || $str) {
|
||||
$str .= ucfirst($sep);
|
||||
} else {
|
||||
$str .= $sep;
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets any kind of arguments and returns an array
|
||||
* (an array, a string containing values separated by commas, or many arguments)
|
||||
*/
|
||||
public static function mixedToArray() {
|
||||
$arg = func_get_arg(0);
|
||||
if (empty($arg)) {
|
||||
return array();
|
||||
} else if (is_array($arg)) {
|
||||
return $arg;
|
||||
} else if (func_num_args() == 1) {
|
||||
$arr = explode(',',$arg);
|
||||
array_walk($arr, 'trim');
|
||||
return $arr;
|
||||
} else {
|
||||
return func_get_args();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generate random string
|
||||
*/
|
||||
public static function genRandom($len = APP_KEY_LENGTH, $strChars = APP_KEY_STRING)
|
||||
{
|
||||
$strCode = "";
|
||||
$intLenChars = strlen($strChars);
|
||||
for ( $i = 0; $i < $len; $i++ ) {
|
||||
$n = mt_rand(1, $intLenChars);
|
||||
$strCode .= substr($strChars, ($n-1), 1);
|
||||
}
|
||||
return $strCode;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_helpers
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @since 0.3
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Translator Helper
|
||||
*
|
||||
* translates everything
|
||||
* @todo test it all
|
||||
*/
|
||||
class TranslatorHelper {
|
||||
|
||||
protected $langDefault;
|
||||
protected $langUser;
|
||||
|
||||
public function __construct() {
|
||||
$this->langDefault = $GLOBALS['config']['lang']['default'];
|
||||
$this->langUser = $GLOBALS['config']['lang']['user'];
|
||||
}
|
||||
|
||||
public function loadLangConfig() {
|
||||
include_once(APP_LANGUAGE_PATH.$this->langDefault.'/config.php');
|
||||
include_once(APP_LANGUAGE_PATH.$this->langUser.'/config.php');
|
||||
}
|
||||
|
||||
public function loadLangFile($file) {
|
||||
if (file_exists(APP_LANGUAGE_PATH.$this->langUser.'/'.$file.'.php')) {
|
||||
include_once(APP_LANGUAGE_PATH.$this->langUser.'/'.$file.'.php');
|
||||
}
|
||||
if (file_exists(APP_LANGUAGE_PATH.$this->langDefault.'/'.$file.'.php')) {
|
||||
include_once(APP_LANGUAGE_PATH.$this->langDefault.'/'.$file.'.php');
|
||||
}
|
||||
}
|
||||
|
||||
public function getTranslation($label, $section, $field='') {
|
||||
if (!array_key_exists($section, $GLOBALS['lang'][$this->langDefault])) {
|
||||
return $label;
|
||||
}
|
||||
if (array_key_exists($label, $GLOBALS['lang'][$this->langUser][$section])) {
|
||||
if (is_array($GLOBALS['lang'][$this->langUser][$section][$label])) {
|
||||
return $GLOBALS['lang'][$this->langUser][$section][$label][$field];
|
||||
} else {
|
||||
return $GLOBALS['lang'][$this->langUser][$section][$label];
|
||||
}
|
||||
} else if (array_key_exists($label, $GLOBALS['lang'][$this->langDefault][$section])) {
|
||||
if (is_array($GLOBALS['lang'][$this->langDefault][$section][$label])) {
|
||||
return $GLOBALS['lang'][$this->langDefault][$section][$label][$field];
|
||||
} else {
|
||||
return $GLOBALS['lang'][$this->langDefault][$section][$label];
|
||||
}
|
||||
} else {
|
||||
return $label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_models
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.2
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* ACL
|
||||
*
|
||||
* Object representing user rights
|
||||
*/
|
||||
class AclModel extends Model {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('acl');
|
||||
$this->addProperties(array(
|
||||
'id' => 'UID',
|
||||
'name' => 'STR',
|
||||
'section' => 'STR'
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* User ACL
|
||||
*
|
||||
* Object representing association between users and rights
|
||||
*/
|
||||
class AclUserModel extends Model {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('acl_user');
|
||||
$this->addProperties(array(
|
||||
'user_id' => 'NUM',
|
||||
'acl_id' => 'NUM'
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_models
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Page
|
||||
*
|
||||
* Object representing a page : contain title, headers, browsing history, and stuff
|
||||
*/
|
||||
class PageModel extends Model {
|
||||
|
||||
public $header;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->addProperties(array(
|
||||
'title' => 'STR',
|
||||
'description' => 'STR',
|
||||
'keywords' => 'STR',
|
||||
'rank' => 'INT'
|
||||
));
|
||||
$this->addHelper('html_asset');
|
||||
}
|
||||
|
||||
public function dispatchHeader() {
|
||||
if ($this->isEmpty('description') && isset($GLOBALS['config']['page']['description'])) {
|
||||
$this->set('description',$GLOBALS['config']['page']['description']);
|
||||
}
|
||||
if ($this->isEmpty('keywords') && isset($GLOBALS['config']['page']['keywords'])) {
|
||||
$this->set('keywords',$GLOBALS['config']['page']['keywords']);
|
||||
}
|
||||
include APP_ASSET_PATH.'html/page-header.php';
|
||||
}
|
||||
|
||||
public function dispatchFooter() {
|
||||
include APP_ASSET_PATH.'html/page-footer.php';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_models
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* Setting
|
||||
*
|
||||
* @todo try it
|
||||
*/
|
||||
class SettingModel extends Model {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('setting');
|
||||
$this->addProperties(array(
|
||||
'setting_key' => 'STR',
|
||||
'setting_value' => 'XML',
|
||||
'section' => 'STR',
|
||||
'user_id' => 'NUM'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_models
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.1
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* abstract model implementing common user properties and methods
|
||||
*/
|
||||
abstract class UserModel extends Model {
|
||||
|
||||
public function __construct($table) {
|
||||
parent::__construct($table);
|
||||
$this->_properties = array(
|
||||
'id' => 'UID',
|
||||
'username' => 'USR',
|
||||
'password' => 'PSS',
|
||||
'salt' => 'STR',
|
||||
'auto_login' => 'BOL',
|
||||
'time_zone' => 'STR',
|
||||
'date_format_us' => 'BOL',
|
||||
'creation_date' => 'DTM',
|
||||
'expiration_date' => 'DTE',
|
||||
'last_login_date' => 'DTM',
|
||||
'last_login_address' => 'STR',
|
||||
'last_change_date' => 'DTM',
|
||||
'visits' => 'NUM',
|
||||
'bad_access' => 'NUM',
|
||||
'activation' => 'STR',
|
||||
'enabled' => 'BOL',
|
||||
);
|
||||
}
|
||||
|
||||
public function enableAuthentication() {
|
||||
$this->addHelper('auth', $this);
|
||||
}
|
||||
|
||||
public function setLogin($login)
|
||||
{
|
||||
if (!trim($login)) {
|
||||
return false;
|
||||
}
|
||||
switch (APP_AUTH_FIELD) {
|
||||
case 'email':
|
||||
// login ID is email
|
||||
if (!$this->set('email',$login)) {
|
||||
return false;
|
||||
}
|
||||
if ($this->findOccurences('email',$login)) {
|
||||
$this->_error["email"] = 'email_exists';
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (!$this->set('username',$username)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check nickname (username) is unique
|
||||
if ($this->findOccurences('username',$login)) {
|
||||
$this->_error['username'] = 'user_name_exists';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setPassword($pass1, $pass2=false, $emptyIsOk=false)
|
||||
{
|
||||
if ($pass1 || $emptyIsOk) {
|
||||
// a pass has been set
|
||||
if (($pass2 !== false) && ($pass1 != $pass2)) {
|
||||
// a confirmation has been set but is different
|
||||
$this->_error['password'] = 'user_pass_mismatch';
|
||||
return false;
|
||||
}
|
||||
$this->set('salt',StringHelper::genRandom(8,
|
||||
'abcdefghijklmnopqrstuvwxyz'
|
||||
.'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'));
|
||||
if ($pass1) {
|
||||
if ((strlen($pass1) >= APP_USER_PASS_MIN)
|
||||
&& (strlen($pass1) <= APP_USER_PASS_MAX))
|
||||
{
|
||||
$salt = $this->get('salt');
|
||||
|
||||
switch (APP_AUTH_PASSWORD_MODE) {
|
||||
case 1:
|
||||
$this->set('password',crypt($pass1 , $salt));
|
||||
break;
|
||||
case 2:
|
||||
$this->set('password',AuthHelper::getDbPass("ENCRYPT('$pass1','$salt')"));
|
||||
break;
|
||||
case 3:
|
||||
$this->set('password',AuthHelper::getDbPass("ENCODE('$pass1','$salt')"));
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
$this->set('password',AuthHelper::getDbPass("MD5('$pass1')"));
|
||||
break;
|
||||
default:
|
||||
$iv = mcrypt_create_iv (mcrypt_get_iv_size(MCRYPT_3DES
|
||||
, MCRYPT_MODE_ECB), MCRYPT_RAND);
|
||||
$crypttext = mcrypt_encrypt(APP_AUTH_PASSWORD_MODE, $salt
|
||||
, $pass1, MCRYPT_MODE_ECB, $iv);
|
||||
$this->set('password',bin2hex($crypttext));
|
||||
}
|
||||
} else {
|
||||
$this->_error['password'] = 'user_pass_length';
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->set('password','');
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (!$emptyIsOk) {
|
||||
$this->_error['password'] = 'user_pass_empty';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function setupTimeZone() {
|
||||
if (!$this->isEmpty('time_zone')) {
|
||||
try {
|
||||
$GLOBALS['config']['datetime']['timezone_user'] = new DateTimeZone($this->get('time_zone'));
|
||||
// FC::log_debug('User::setupTimeZone : new time zone '.$this->get('time_zone'));
|
||||
} catch (Exception $e) {
|
||||
FC::log_error('User::setupTimeZone : unknown time zone ('.$this->get('time_zone').')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* Tzn Framework
|
||||
*
|
||||
* @package tzn_models
|
||||
* @author Stan Ozier <framework@tirzen.com>
|
||||
* @version 0.2
|
||||
* @since 0.2
|
||||
* @copyright GNU Lesser General Public License (LGPL) version 3
|
||||
*/
|
||||
|
||||
/**
|
||||
* User ACL
|
||||
*
|
||||
* abstract model implementing common user properties and methods
|
||||
* with ACL support
|
||||
*/
|
||||
|
||||
abstract class UserAclModel extends UserModel {
|
||||
|
||||
public function __construct($table) {
|
||||
parent::__construct($table);
|
||||
}
|
||||
|
||||
public function enableAuthentication() {
|
||||
$this->addProperties(array(
|
||||
'actags' => 'STR'
|
||||
));
|
||||
$this->addHelper('auth_acl', $this);
|
||||
}
|
||||
|
||||
public function load($filter='') {
|
||||
$db = $this->getHelper('db');
|
||||
if ($this->getPropertyType('actags')) {
|
||||
$this->_generateQuery($db);
|
||||
return $db->load($filter, false);
|
||||
} else {
|
||||
$args = func_get_args();
|
||||
return $this->callHelperArray('db','load',$args);
|
||||
}
|
||||
}
|
||||
|
||||
public function loadList() {
|
||||
$db = $this->getHelper('db');
|
||||
if ($this->getPropertyType('actags')) {
|
||||
$this->_generateQuery($db);
|
||||
return $db->loadList(false);
|
||||
} else {
|
||||
return $db->loadList(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function save($acl=false) {
|
||||
$this->removeProperties('actags');
|
||||
if (parent::save()) {
|
||||
if ($acl) {
|
||||
$this->saveACL($acl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function saveACL($section='') {
|
||||
$this->addHelper('auth_acl', $this);
|
||||
$this->updateACL($section);
|
||||
}
|
||||
|
||||
protected function _generateQuery(&$db) {
|
||||
$db->select($db->dbTable().".*, GROUP_CONCAT(ac.name SEPARATOR ',') as actags");
|
||||
$db->from($db->dbTable());
|
||||
$db->leftJoin(array('acl_user','aa'),array($this->dbUid(true),'aa.user_id'));
|
||||
$db->leftJoin(array('acl','ac'),array('aa.acl_id','ac.id'));
|
||||
$db->groupBy('member.id');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
ColorBox Core Style
|
||||
The following rules are the styles that are consistant between themes.
|
||||
Avoid changing this area to maintain compatability with future versions of ColorBox.
|
||||
*/
|
||||
#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:98; overflow:hidden;}
|
||||
#cboxOverlay{position:fixed; width:100%; height:100%;}
|
||||
#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
|
||||
#cboxContent{position:relative; overflow:visible;}
|
||||
#cboxLoadedContent{overflow:auto;}
|
||||
#cboxLoadedContent iframe{display:block; width:100%; height:100%; border:0;}
|
||||
#cboxTitle{margin:0;}
|
||||
#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%;}
|
||||
#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
|
||||
|
||||
/*
|
||||
ColorBox example user style
|
||||
The following rules are ordered and tabbed in a way that represents the
|
||||
order/nesting of the generated HTML, so that the structure easier to understand.
|
||||
*/
|
||||
#cboxOverlay{background:#fff;}
|
||||
|
||||
#colorbox{}
|
||||
#cboxContent{
|
||||
border:5px solid #ccc;-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
margin-top:32px;
|
||||
}
|
||||
#cboxLoadedContent{background:#eee; padding:1px;}
|
||||
#cboxLoadedContent>div { padding:5px; }
|
||||
#cboxLoadingGraphic{background:url(../img/loading.gif) center center no-repeat;}
|
||||
#cboxLoadingOverlay{background:#eee;}
|
||||
#cboxTitle{position:absolute; top:-22px; left:9px; color:#999;}
|
||||
#cboxCurrent{position:absolute; top:-22px; right:205px; text-indent:-9999px;}
|
||||
#cboxSlideshow, #cboxPrevious, #cboxNext, #cboxClose{text-indent:-9999px; width:20px; height:20px; position:absolute; top:-20px; background:url(../img/controls.png) 0 0 no-repeat;}
|
||||
#cboxPrevious{background-position:0px 0px; right:44px;}
|
||||
#cboxPrevious.hover{background-position:0px -25px;}
|
||||
#cboxNext{background-position:-25px 0px; right:22px;}
|
||||
#cboxNext.hover{background-position:-25px -25px;}
|
||||
#cboxClose{background-position:-50px 0px; right:0; margin-top:-5px}
|
||||
#cboxClose.hover{background-position:-50px -25px;}
|
||||
.cboxSlideshow_on #cboxPrevious, .cboxSlideshow_off #cboxPrevious{right:66px;}
|
||||
.cboxSlideshow_on #cboxSlideshow{background-position:-75px -25px; right:44px;}
|
||||
.cboxSlideshow_on #cboxSlideshow.hover{background-position:-100px -25px;}
|
||||
.cboxSlideshow_off #cboxSlideshow{background-position:-100px 0px; right:44px;}
|
||||
.cboxSlideshow_off #cboxSlideshow.hover{background-position:-75px -25px;}
|
||||
|
||||
#cboxLoadedContent h1 {
|
||||
color: #369;
|
||||
font-size: 12px;
|
||||
padding: 9px 20px 12px;
|
||||
text-align: center;
|
||||
}
|
||||
#cboxLoadedContent table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 1px;
|
||||
}
|
||||
#cboxLoadedContent #tab1 table {
|
||||
width: 100%;
|
||||
}
|
||||
#cboxLoadedContent #tab1 table tr {
|
||||
vertical-align: top;
|
||||
}
|
||||
#cboxLoadedContent #tab1 table tr th {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
color: #666;
|
||||
padding: 2px;
|
||||
width: 20%;
|
||||
}
|
||||
#cboxLoadedContent #tab1 table tr td {
|
||||
text-align: left;
|
||||
padding: 2px;
|
||||
width: 80%;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table {
|
||||
width: 100%;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tr {
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tr td {
|
||||
padding: 2px;
|
||||
width: 40%;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tr td:last-child {
|
||||
text-align: right;
|
||||
width: 20%;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table thead tr th {
|
||||
padding: 2px;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table thead tr th:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tbody tr td {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tfoot tr td {
|
||||
border-top: 1px solid #999;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tbody tr td a.onhold {
|
||||
display: none;
|
||||
float: left;
|
||||
background-image: url(../img/b-delete.png);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: left;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tbody tr:hover td {
|
||||
background-color: #fff;
|
||||
}
|
||||
#cboxLoadedContent #tab2 table tbody tr:hover td a.onhold {
|
||||
display: block;
|
||||
}
|
||||
#cboxLoadedContent #sidepanel {
|
||||
float: right;
|
||||
color: #666;
|
||||
font-size: 10px;
|
||||
}
|
||||
#cboxLoadedContent #sidepanel h4 {
|
||||
padding: 6px 0 3px;
|
||||
}
|
||||
#cboxLoadedContent #sidepanel p {
|
||||
padding-bottom: 4px;
|
||||
line-height: 1.35em;
|
||||
}
|
||||
#cboxLoadedContent #sidepanel small {
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
}
|
||||
#cboxLoadedContent #sidepanel ul li {
|
||||
padding: 1px 0 2px 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
html, body, div, h1, h2, h3, h4, h5, h6, ul, ol, dl, li, dt, dd, p, blockquote,
|
||||
pre, form, fieldset, table, th, td, hr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
height: 100%;
|
||||
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
min-width: 960px;
|
||||
background: #f3f3f3;
|
||||
}
|
||||
#global {
|
||||
position: relative;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
* html #global {
|
||||
height: 100%;
|
||||
}
|
||||
h1 {
|
||||
}
|
||||
h2 {
|
||||
}
|
||||
h3 {
|
||||
}
|
||||
p {
|
||||
padding-bottom: 9px;
|
||||
}
|
||||
ul, ol {
|
||||
padding: 0 0 5px 25px;
|
||||
}
|
||||
ul ul, ol ol {
|
||||
padding: 0 0 5px 15px;
|
||||
}
|
||||
ul li {
|
||||
padding: 2px 0 3px 0;
|
||||
}
|
||||
ol li {
|
||||
padding: 2px 0 3px 0;
|
||||
}
|
||||
a img {
|
||||
border: 0 none;
|
||||
}
|
||||
:focus, a, a:active {
|
||||
outline: 0 none;
|
||||
}
|
||||
/* alignment */
|
||||
.lft {
|
||||
text-align: left;
|
||||
}
|
||||
.ctr {
|
||||
text-align: center;
|
||||
}
|
||||
.rgt {
|
||||
text-align: right;
|
||||
}
|
||||
.jty {
|
||||
text-align: justify;
|
||||
}
|
||||
/* floating */
|
||||
.flft {
|
||||
float: left;
|
||||
}
|
||||
.frgt {
|
||||
float: right;
|
||||
}
|
||||
.clft {
|
||||
clear: left;
|
||||
}
|
||||
.crgt {
|
||||
clear: right;
|
||||
}
|
||||
img.flft {
|
||||
margin-right: 6px;
|
||||
}
|
||||
img.frgt {
|
||||
margin-left: 6px;
|
||||
}
|
||||
/* header */
|
||||
#dtop {
|
||||
background: #1f87bb url(../img/top-back.png) repeat-x 0 bottom;
|
||||
color: #fff;
|
||||
height: 40px;
|
||||
}
|
||||
#dtop a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
#dtop a:hover {
|
||||
color: #000;
|
||||
}
|
||||
#dtop h1 {
|
||||
float: left;
|
||||
height: 40px;
|
||||
margin-right: 20px;
|
||||
width: 150px;
|
||||
}
|
||||
#dtop h1 a {
|
||||
background: url(../img/logo.png) no-repeat;
|
||||
display: block;
|
||||
height: 40px;
|
||||
text-indent: -999px;
|
||||
width: 150px;
|
||||
}
|
||||
#dtop #duser {
|
||||
float: right;
|
||||
line-height: 1.125em;
|
||||
padding: 4px 8px;
|
||||
text-align: right;
|
||||
width: 150px;
|
||||
}
|
||||
#dtop form#search {
|
||||
float: right;
|
||||
padding: 16px 30px 0 0;
|
||||
}
|
||||
#dtop form#search input {
|
||||
background: url(../img/top-search.png) no-repeat left center;
|
||||
border: 0 none;
|
||||
color: #069;
|
||||
float: left;
|
||||
font-size: 10px;
|
||||
padding: 3px 0 3px 4px;
|
||||
width: 76px;
|
||||
height: 10px;
|
||||
}
|
||||
#dtop form#search button {
|
||||
background: url(../img/top-search.png) no-repeat right center;
|
||||
border: 0 none;
|
||||
padding: 0;
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
#dtop ul {
|
||||
padding: 12px 0 0 0;
|
||||
height: 28px;
|
||||
}
|
||||
#dtop ul li {
|
||||
float: left;
|
||||
list-style: none;
|
||||
margin-right: 8px;
|
||||
padding: 0 0 8px 10px;
|
||||
height: 20px;
|
||||
}
|
||||
#dtop ul li.active {
|
||||
background: url(../img/top-tab.png) no-repeat left 0;
|
||||
}
|
||||
#dtop ul li a {
|
||||
display: block;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
padding: 6px 10px 0 0;
|
||||
}
|
||||
#dtop ul li a:hover {
|
||||
}
|
||||
#dtop ul li.active a {
|
||||
color: #000;
|
||||
background: url(../img/top-tab.png) no-repeat right 0;
|
||||
}
|
||||
/* working area */
|
||||
#dwork {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
/* layout : 1 column */
|
||||
#dmain.full {
|
||||
margin: 0 1%;
|
||||
}
|
||||
/* layout : 2 columns */
|
||||
#dmain.two, #dmain.three {
|
||||
margin-left: 135px;
|
||||
}
|
||||
#dleft {
|
||||
float: left;
|
||||
width: 110px;
|
||||
overflow: hidden;
|
||||
padding: 50px 10px 0 10px;
|
||||
}
|
||||
#dleft h4 {
|
||||
color: #333;
|
||||
font-size: 11px;
|
||||
border-bottom: 1px solid #666;
|
||||
padding-left: 4px;
|
||||
margin: 5px 0 5px;
|
||||
}
|
||||
#dmain.three #dlist {
|
||||
margin-right: 250px;
|
||||
}
|
||||
/* right panel (calendar) */
|
||||
#dright {
|
||||
float: right;
|
||||
width: 220px;
|
||||
padding-right: 15px;
|
||||
background-color: aqua;
|
||||
}
|
||||
/* footer */
|
||||
#dfoot {
|
||||
background: #3298cb url(../img/bot-back.png) repeat-x 0 top;
|
||||
font-size: 11px;
|
||||
color: #fff;
|
||||
height: 16px;
|
||||
margin-top: -22px;
|
||||
padding: 3px 10px;
|
||||
position: relative;
|
||||
}
|
||||
#dfoot a {
|
||||
color: #fff;
|
||||
}
|
||||
#dfoot.exp {
|
||||
margin-top: -306px;
|
||||
height: 300px;
|
||||
}
|
||||
#dfoot #dcopy {
|
||||
float: right;
|
||||
font-size: 10px;
|
||||
}
|
||||
#dfoot #dcopy a {
|
||||
background: url(../img/bot-logo.png);
|
||||
display: block;
|
||||
float: left;
|
||||
height: 16px;
|
||||
text-indent: -9999px;
|
||||
width: 70px;
|
||||
}
|
||||
#dfoot #dcopy span {
|
||||
vertical-align: bottom;
|
||||
font-size: 9px;
|
||||
}
|
||||
hr.clear {
|
||||
clear: left;
|
||||
border: 0 none;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
hr.sep {
|
||||
clear: right;
|
||||
border: 0 none;
|
||||
height: 8px;
|
||||
visibility: hidden;
|
||||
}
|
||||
hr.separator {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
hr.footer {
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
ul.links {
|
||||
list-style: none;
|
||||
}
|
||||
ul.links li a, p.links a {
|
||||
color: #333;
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
padding: 1px 4px 2px;
|
||||
line-height: 1.25em;
|
||||
text-decoration: none;
|
||||
}
|
||||
ul.verti {
|
||||
padding-left: 0;
|
||||
}
|
||||
ul.verti li a, p.links a {
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
ul.horiz {
|
||||
float: left;
|
||||
}
|
||||
ul.horiz li {
|
||||
float: left;
|
||||
}
|
||||
ul.horiz li a {
|
||||
background: #ccc;
|
||||
border-right: 1px solid #fff;
|
||||
}
|
||||
ul.horiz li:first-child a {
|
||||
padding-left: 7px;
|
||||
-webkit-border-top-left-radius: 8px;
|
||||
-webkit-border-bottom-left-radius: 8px;
|
||||
-moz-border-radius-topleft: 8px;
|
||||
-moz-border-radius-bottomleft: 8px;
|
||||
border-radius: 8px 0 0 8px;
|
||||
}
|
||||
ul.horiz li:last-child a {
|
||||
padding-right: 7px;
|
||||
-webkit-border-top-right-radius: 8px;
|
||||
-webkit-border-bottom-right-radius: 8px;
|
||||
-moz-border-radius-topright: 8px;
|
||||
-moz-border-radius-bottomright: 8px;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
ul.links li a:hover {
|
||||
background-color: #9cf;
|
||||
}
|
||||
ul.links li.active a, p.links a.active {
|
||||
color: #fff;
|
||||
background-color: #39c;
|
||||
}
|
||||
/* main panel : filters */
|
||||
#dfilters {
|
||||
padding: 0 20px 6px 0;
|
||||
}
|
||||
#dfilters p {
|
||||
text-align: center;
|
||||
}
|
||||
#dfilters span {
|
||||
float: right;
|
||||
}
|
||||
#dfilters form input {
|
||||
padding: 1px 4px;
|
||||
border: 1px solid #333;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#dfilters form input:focus {
|
||||
background-color: #ffc;
|
||||
}
|
||||
#dfilters form button {
|
||||
padding: 1px 2px;
|
||||
}
|
||||
/* main panel (list) */
|
||||
#dlist {
|
||||
background: #fff;
|
||||
border: 1px solid #e3e3e3;
|
||||
margin: 0 10px 0 0;
|
||||
min-height: 300px;
|
||||
padding: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
/* table */
|
||||
#dlist table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 1px;
|
||||
/* border: 1px solid #ccc; */
|
||||
font-size: 9pt;
|
||||
width: 100%;
|
||||
}
|
||||
#dlist table th, #dlist table td {
|
||||
padding: 4px 6px;
|
||||
}
|
||||
#dlist table thead th {
|
||||
font-weight: normal;
|
||||
background-color: #999;
|
||||
color: #fff;
|
||||
border-top: 1px solid #bbb;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
#dlist table thead th small {
|
||||
padding-top: 2px;
|
||||
float: right;
|
||||
}
|
||||
#dlist table tbody tr td {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
#dlist table tbody tr.overdue td {
|
||||
color: #c00;
|
||||
}
|
||||
#dlist table tbody tr.today td {
|
||||
color: #36c;
|
||||
}
|
||||
#dlist table tbody tr.future td {
|
||||
/* font-size: .87em; */
|
||||
color: #999;
|
||||
border-bottom-color: #eee;
|
||||
}
|
||||
#dlist table tbody tr.current td {
|
||||
color: #000;
|
||||
background-color: #cef;
|
||||
}
|
||||
#dlist table tbody tr.noline td {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
#dlist table tbody tr.timer td {
|
||||
color: #666;
|
||||
}
|
||||
/* task list columns */
|
||||
#dlist.tasks table thead th:first-child, #dlist.tasks table tbody td:first-child {
|
||||
width: 2%;
|
||||
}
|
||||
#dlist.tasks table thead th:nth-child(2), #dlist.tasks table tbody td:nth-child(2) {
|
||||
text-align: left;
|
||||
width: 9%;
|
||||
}
|
||||
#dlist.tasks table thead th:nth-child(3), #dlist.tasks table tbody td:nth-child(3) {
|
||||
text-align: left;
|
||||
width: 62%;
|
||||
}
|
||||
#dlist.tasks table thead th:nth-child(4), #dlist.tasks table tbody td:nth-child(4),
|
||||
#dlist.tasks table thead th:nth-child(5), #dlist.tasks table tbody td:nth-child(5) {
|
||||
text-align: center;
|
||||
width: 9%;
|
||||
}
|
||||
#dlist.tasks table thead th:nth-child(6), #dlist.tasks table tbody td:nth-child(6) {
|
||||
text-align: right;
|
||||
width: 9%;
|
||||
}
|
||||
/* user list columns */
|
||||
#dlist.users table thead th:first-child, #dlist.users table tbody td:first-child {
|
||||
text-align: left;
|
||||
width: 80%;
|
||||
}
|
||||
#dlist.users table thead th:nth-child(2), #dlist.users table tbody td:nth-child(2) {
|
||||
text-align: center;
|
||||
width: 20%;
|
||||
}
|
||||
#dlist.users table tbody td small {
|
||||
margin-left: 9px;
|
||||
color: #369;
|
||||
}
|
||||
/* priorities */
|
||||
#dlist table tbody tr td span.prio {
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
padding: 1px 3px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
#dlist table tbody tr td span.pr0 {
|
||||
background-color: #bbb;
|
||||
}
|
||||
#dlist table tbody tr td span.pr1 {
|
||||
background-color: #f00;
|
||||
}
|
||||
#dlist table tbody tr td span.pr2 {
|
||||
background-color: #f63;
|
||||
}
|
||||
#dlist table tbody tr td span.pr3 {
|
||||
background-color: #c69;
|
||||
}
|
||||
#dlist table tbody tr td span.pr4 {
|
||||
background-color: #96c;
|
||||
}
|
||||
#dlist table tbody tr td span.pr5 {
|
||||
background-color: #69c;
|
||||
}
|
||||
#dlist table tbody tr td span.pr6 {
|
||||
background-color: #7ac;
|
||||
}
|
||||
#dlist table tbody tr td span.pr6 {
|
||||
background-color: #8bc;
|
||||
}
|
||||
#dlist table tbody tr td span.pr7 {
|
||||
background-color: #acc;
|
||||
}
|
||||
#dlist table tbody tr td span.pr8 {
|
||||
background-color: #bcc;
|
||||
}
|
||||
#dlist table tbody tr td span.pr9 {
|
||||
background-color: #ccc;
|
||||
}
|
||||
#dlist table tbody tr.future td span.prio {
|
||||
background-color: #ccc;
|
||||
}
|
||||
#dlist table tbody tr.overdue td span.prio {
|
||||
background-color: #f00;
|
||||
}
|
||||
/* links */
|
||||
#dlist table tbody tr td a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
#dlist table tbody tr td a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#dlist table tbody tr td a.onhold {
|
||||
display: none;
|
||||
float: right;
|
||||
background-image: url(../img/b-edit.png);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: left;
|
||||
text-indent: -9999px;
|
||||
}
|
||||
#dlist table tbody tr td a.onlock {
|
||||
display: none;
|
||||
}
|
||||
#dlist table tbody tr td a.clock {
|
||||
float: left;
|
||||
background-image: url(../img/b-run.png);
|
||||
}
|
||||
#dlist table tbody tr td a.note {
|
||||
padding-right: 20px;
|
||||
background: url(../img/b-note.png) no-repeat right center;
|
||||
}
|
||||
/* hover */
|
||||
#dlist table tbody tr:hover td {
|
||||
background-color: #fec;
|
||||
}
|
||||
#dlist table tbody tr:hover td a.onhold {
|
||||
display: block;
|
||||
}
|
||||
#dlist table tbody tr.current:hover td a.clock {
|
||||
display: none;
|
||||
}
|
||||
#dlist table tbody tr.current:hover td {
|
||||
background-color: #9cf;
|
||||
}
|
||||
/* footer */
|
||||
#dlist table tfoot tr td {
|
||||
background-color: #ddd;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
#dlist table tfoot tr td:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
#dlist table tfoot tr td a {
|
||||
font-weight: normal;
|
||||
}
|
||||
/* buttons */
|
||||
span.button, span.button a {
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
line-height: 1.5em;
|
||||
text-decoration: none;
|
||||
padding: 5px 0;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
span.button {
|
||||
padding-left: 30px;
|
||||
background-position: left center;
|
||||
}
|
||||
span.button a {
|
||||
padding-right: 10px;
|
||||
background-position: right center;
|
||||
}
|
||||
span.button a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
span.new, span.new a {
|
||||
background-image: url('../img/b-new.png');
|
||||
}
|
||||
span a.new {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
text-indent: -9999px;
|
||||
background: url('../img/b-new.png') no-repeat left center;
|
||||
float: left;
|
||||
}
|
||||
span a.multi {
|
||||
margin-left: 6px;
|
||||
background-position: -24px center;
|
||||
}
|
||||
span a.reload {
|
||||
margin-left: 6px;
|
||||
background-position: -48px center;
|
||||
}
|
||||
p.empty {
|
||||
padding: 20px 0 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
form {
|
||||
position: relative;
|
||||
top: 60px;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
margin-left: -150px;
|
||||
}
|
||||
form p {
|
||||
color: #c00;
|
||||
text-align: center;
|
||||
}
|
||||
form input {
|
||||
width: 120px;
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/* timer */
|
||||
#drun {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
margin-left: -250px;
|
||||
padding: 6px 10px;
|
||||
width: 500px;
|
||||
color: #036;
|
||||
background-color: transparent;
|
||||
z-index: 10;
|
||||
}
|
||||
#drun.running {
|
||||
color: #036;
|
||||
background-color: #6cf;
|
||||
-webkit-border-bottom-left-radius: 5px;
|
||||
-webkit-border-bottom-right-radius: 5px;
|
||||
-moz-border-radius-bottomleft: 5px;
|
||||
-moz-border-radius-bottomright: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
-moz-box-shadow: 0 0 5px #036;
|
||||
-webkit-box-shadow: 0 0 5px #036;
|
||||
box-shadow: 0 0 5px #036;
|
||||
text-align: center;
|
||||
}
|
||||
#drun.paused {
|
||||
color: #036;
|
||||
background-color: #39c;
|
||||
border: 1px solid #39c;
|
||||
text-align: center;
|
||||
}
|
||||
#drun p {
|
||||
font-size: 11px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.75em;
|
||||
}
|
||||
#drun p input {
|
||||
color: #036;
|
||||
width: 300px;
|
||||
border: 0;
|
||||
padding: 2px 5px 3px;
|
||||
background-color: #39c;
|
||||
-moz-box-shadow: 0 0 3px #069;
|
||||
-webkit-box-shadow: 0 0 3px #069;
|
||||
box-shadow: 0 0 3px #069;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#drun p input:focus {
|
||||
color: #000;
|
||||
background-color: #5be;
|
||||
}
|
||||
#drun p span#dtimer {
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 2px #333;
|
||||
}
|
||||
#drun div {
|
||||
float: right;
|
||||
}
|
||||
#drun button {
|
||||
opacity: 0.5;
|
||||
-moz-opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
#drun button:hover, #drun button:focus {
|
||||
opacity: 1;
|
||||
-moz-opacity: 1;
|
||||
filter: alpha(opacity=100);
|
||||
outline: 0 none;
|
||||
}
|
||||
#timerstatus.loading {
|
||||
background: url(../img/barloader.gif) no-repeat center center;
|
||||
}
|
||||
#timerstatus.loading button {
|
||||
opacity: 0;
|
||||
-moz-opacity: 0;
|
||||
filter: alpha(opacity=0);
|
||||
visibility: hidden;
|
||||
}
|
||||
/* form */
|
||||
form#f_task_batch {
|
||||
padding: 10px;
|
||||
}
|
||||
form#f_task_batch textarea {
|
||||
width: 360px;
|
||||
height: 280px;
|
||||
}
|
||||
form#f_task_edit label {
|
||||
color: #666;
|
||||
}
|
||||
form#f_task_edit input#i_title {
|
||||
width: 360px;
|
||||
}
|
||||
form#f_task_edit input#i_deadline {
|
||||
width: 80px;
|
||||
}
|
||||
form#f_task_edit textarea {
|
||||
width: 360px;
|
||||
height: 150px;
|
||||
}
|
||||
form#f_task_timer ol.side li {
|
||||
line-height: 2em;
|
||||
}
|
||||
form#f_task_timer ol.side li label {
|
||||
color: #666;
|
||||
width: 55px;
|
||||
margin-right: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
p#vtip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
left: 5px;
|
||||
margin-right: 8px;
|
||||
max-width: 340px;
|
||||
font-size: 0.8em;
|
||||
background-color: white;
|
||||
border: 1px solid #69c;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-box-shadow: 0 0 5px #ccc;
|
||||
-webkit-box-shadow: 0 0 5px #ccc;
|
||||
box-shadow: 0 0 5px #ccc;
|
||||
z-index: 9999;
|
||||
}
|
||||
p#vtip #vtipArrow {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: 5px;
|
||||
}
|
||||
p#vtip.inv {
|
||||
max-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
p#vtip.inv #vtipArrow {
|
||||
left: 40px;
|
||||
}
|
||||
div.tabs {
|
||||
|
||||
}
|
||||
div.tabs ul.nav {
|
||||
height: 20px;
|
||||
padding: 0 0 0 10px;
|
||||
margin: 0 5px;
|
||||
border-bottom: 2px solid #999;
|
||||
}
|
||||
div.tabs ul.nav li {
|
||||
float: left;
|
||||
list-style: none;
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
div.tabs ul.nav li a {
|
||||
display: block;
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
color: #fff;
|
||||
background-color: #ccc;
|
||||
text-decoration: none;
|
||||
-webkit-border-top-left-radius: 5px;
|
||||
-webkit-border-top-right-radius: 5px;
|
||||
-moz-border-radius-topleft: 5px;
|
||||
-moz-border-radius-topright: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
div.tabs ul.nav li a:hover {
|
||||
background-color: #bbb;
|
||||
}
|
||||
div.tabs ul.nav li.activeli a {
|
||||
background-color: #999;
|
||||
}
|
||||
div.tabs div.tab {
|
||||
padding: 5px;
|
||||
}
|
||||
div.help {
|
||||
font-size: 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1020 B |
|
After Width: | Height: | Size: 784 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 408 B |
|
After Width: | Height: | Size: 946 B |