FINAL suepr merge step : added all modules to this super repos
This commit is contained in:
339
sites/all/modules/contrib/fields/addressfield/LICENSE.txt
Normal file
339
sites/all/modules/contrib/fields/addressfield/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
298
sites/all/modules/contrib/fields/addressfield/addresses.txt
Normal file
298
sites/all/modules/contrib/fields/addressfield/addresses.txt
Normal file
@@ -0,0 +1,298 @@
|
||||
AT NULL Feldkirch NULL 6800 Pater Grimm Weg 20
|
||||
AU NULL Melbourne NULL
|
||||
AU NULL Sydney NULL
|
||||
AU 04 NULL NORMANBY NULL 4059 30 Normanby Terrace
|
||||
BD NULL Dhaka NULL 1205 23, Subal Das Road, Chowdhury Bazar, Lalbagh
|
||||
BD NULL Dhaka NULL 1207 R-1,H-19,Kallaynpur,Mirpur,Dhaka
|
||||
BD NULL Dhaka NULL 1207 World Bank Office Dhaka, Plot E 32, Agargaon, Sher-E-Bangla Nagar
|
||||
BD NULL Dhaka NULL 1209 House# 66B, Flat# B2 Zigatola
|
||||
BD NULL Dhaka NULL 1219 390 West Rampura Dhaka
|
||||
BD NULL Dhaka NULL 1230 Uttara
|
||||
BD 81 NULL Dhaka NULL 1000 Institute of Water and Flood Management
|
||||
BD 81 NULL Dhaka NULL 1203 84/a maniknagar
|
||||
BD 81 NULL Dhaka NULL 1205 Dhaka Bangladesh
|
||||
BD 81 NULL Dhaka NULL 1207 BetterStories Limited 17 West Panthopath
|
||||
BD 81 NULL Dhaka NULL 1216 Mirpur, Dhaka
|
||||
BD 81 NULL Dhaka NULL 1230 830, Prembagan, Dhakshin Khan
|
||||
BD 82 NULL khulna NULL 9203
|
||||
BD NULL NULL Dhaka NULL 1000 Institute of Water and Flood Management
|
||||
BD NULL NULL Dhaka NULL 1207 World Bank Office Dhaka, Plot E 32, Agargaon, Sher-E-Bangla Nagar
|
||||
BE NULL Brussels NULL
|
||||
BE NULL Watermael-Boitsfort NULL 1170 Avenue des Staphylins
|
||||
BH NULL Manama NULL 00973 Manama Bahrain Manama Bahrain
|
||||
BR NULL Porto Alegre NULL
|
||||
BR NULL Recife NULL
|
||||
BR RJ NULL Rio de Janeiro NULL
|
||||
BW NULL Francistown NULL NULL
|
||||
BW NULL NULL Francistown NULL NULL
|
||||
CA NULL Montreal NULL
|
||||
CA NULL Toronto NULL
|
||||
CA BC NULL Vancouver NULL
|
||||
CA ON NULL Kitchener NULL
|
||||
CA ON NULL wterloo NULL n2l3g1 200 University Avenue West
|
||||
CH NULL Geneva NULL 1202 15, chemin Louis-Dunant
|
||||
CH 25 NULL Zurich NULL 8098 UBS Optimus Foundation Augustinerhof 1
|
||||
DE NULL Berlin NULL
|
||||
DE 05 NULL Frankfurt am Main NULL 60386 Johanna-Tesch-Platz 7
|
||||
DK NULL Aarhus NULL
|
||||
ES NULL Bilbao NULL
|
||||
ET 44 NULL ADDIS ABABA NULL 11945 ADDIS ABABA,P.O.BOX 11945
|
||||
FI NULL Espoo NULL 02130 Mahlarinne 3B
|
||||
FI NULL Helsinki NULL 00580 Hermannin rantatie 2 A Hermannin rantatie 2 A
|
||||
FI NULL Tampere NULL 33101 Tampere Univerity of Technology
|
||||
FI 13 NULL Espoo NULL 02150 Aalto Venture Garage Betonimiehenkuja 3
|
||||
GB NULL Exeter NULL
|
||||
GB NULL London NULL
|
||||
GB NULL London NULL N4 2DP 2 Myddleton Ave
|
||||
GB NULL London NULL N7 0AH 104 St George’s Avenue
|
||||
GB NULL London NULL SE16 3UL 25 Blue Anchor Lane
|
||||
GB NULL London NULL SW18 5SP Flat 1 150 Merton road
|
||||
GB NULL London NULL W1T 4BQ 13 Fitzroy Street
|
||||
GB NULL Oxford NULL
|
||||
GB NULL Southampton NULL
|
||||
GB C3 NULL NULL cb244qg 32 market street swavesey
|
||||
GB E7 NULL London NULL SE3 7TP
|
||||
GB F3 NULL Wood Green NULL N22 5RU 6 Cedar House
|
||||
GB H1 NULL London NULL SE11 5JD 47-49 Durham Street
|
||||
GB H6 NULL London NULL SE8 4DD 8 Harton St Deptford
|
||||
GB K2 NULL Oxford NULL OX2 6QY 3 The Villas, Rutherway
|
||||
GH 05 NULL NSAWAM NULL NULL P.O.BOX 455
|
||||
GH NULL NULL Accra NULL NULL
|
||||
ID NULL Bandung NULL 40134 Jalan Sadang Hegar 1 No. 12 RT04 RW13 Sadang Serang
|
||||
ID NULL Bekasi NULL 17411 Jl.Binadharma 1 No.62. Jatiwaringin
|
||||
ID NULL Jakarta NULL
|
||||
ID NULL Jakarta NULL 12440 Jl. H. Niin 7 Lebak Bulus, Cilandak
|
||||
ID NULL Jakarta NULL 13330 Otista
|
||||
ID NULL Jakarta selatan NULL 12000 jl. rawa jati timur 6 no. 10
|
||||
ID NULL Jakarta Timur NULL Jl.Mulia No.15B Kel.Bidara Cina, Kec.Jatinegara, Jakarta Timur
|
||||
ID NULL Pematang Siantar NULL 51511 Jl. Durian I 30
|
||||
ID 04 NULL Bogor NULL 16165
|
||||
ID 04 NULL jakarta NULL otista
|
||||
ID 04 NULL Jakarta NULL 12520 Jl. Pertanian Raya III No.42 Jakarta Selatan Pasar Minggu
|
||||
ID 04 NULL Jakarta NULL 13330 Jakarta
|
||||
ID 04 NULL Jakarta NULL 13330 Jl Sensus IIC Bidaracina Jaktim
|
||||
ID 04 NULL Jakarta NULL 13330 Jl. Bonasut 2 no.22
|
||||
ID 04 NULL Jakarta NULL 13330 Otista 64c
|
||||
ID 04 NULL jakarta NULL 13330 Otista jaktim
|
||||
ID 04 NULL Jakarta Timur NULL 13330 Kebon Sayur I no. 1 RT 10/15
|
||||
ID 04 NULL Jakarta Timur NULL 13460 Jl. Pondok Kopi Blok G4/5 RT. 005/08 Jakarta Timur
|
||||
ID 04 NULL Jakarta Timur NULL 13810 Jl. Raya Pondok Gede Rt03 Rw08 no.35 , Lubang Buaya, Jakarta Timur Jl. Raya Pondok Gede Rt03 Rw08 no.35 , Lubang Buaya, Jakarta Timur
|
||||
ID 07 NULL Brebes NULL 54321 Jl Kersem Blok D14 Perum Taman Indo Kaligangsa Wetan Brebes
|
||||
ID 07 NULL Semarang NULL 50143 Puspowarno Tengah 2/2
|
||||
ID 08 NULL Lumajang NULL 67373 Desa Tumpeng Kecamatan Candipuro Lumajang
|
||||
ID 30 NULL Bandung NULL 55241 Jl Pelesiran No 55A/56
|
||||
ID 30 NULL Bekasi NULL 17510 bekasi West Java Indonesia
|
||||
ID 30 NULL Depok NULL 16245 Jalan juragan sinda 2 no 10
|
||||
ID 30 NULL Depok NULL 16424 Jalan Margonda RayaJalan Kober Gang Mawar
|
||||
ID 30 NULL Depok NULL 16424 Jl. Haji Yahya Nuih no.24, Pondok Cina
|
||||
ID 30 NULL Depok NULL 16425 Kukusan Kelurahan
|
||||
ID 30 NULL Depok NULL 16518 Jl. Salak No.1/C.88 Durenseribu Bojongsari
|
||||
ID 30 NULL Depok NULL 16952 Jl. Merak No.34 -36 Rt.004/014 Jl. Merak No. 34 -36 Rt. 004/014
|
||||
ID 36 NULL biak numfor NULL 98111 jl. s. mamberamo no 6782 biak numfor
|
||||
IL NULL Tel Aviv NULL
|
||||
IN NULL Bangalore NULL
|
||||
IN NULL India NULL
|
||||
IN NULL new delhi NULL 110003 55 lodi estate
|
||||
IN 07 NULL NEW DELHI NULL 110018 15/11 A 1ST FLOOR TILAK NAGAR
|
||||
IN 07 NULL New Delhu NULL 110075 B 54 Hilansh Apartments Plot No 1, Sector 10, Dwarka
|
||||
IN 10 NULL Gurgaon NULL D- 201 Ivy Apartments Sushant Lok 1 Gurgaon Haryana
|
||||
IN 13 NULL Trivandrum NULL 695010 TC 9/1615, SRMH Road, Sasthamangalam, Trivandrum
|
||||
IN 16 NULL Mumbai NULL 400020 Bharat Mahal, Flat#55 Marine Drive
|
||||
IN 16 NULL Mumbai NULL 400028 303,Shree Parvati Co-Op Housing Society, D.L.Vaidya Road,Dadar
|
||||
IN 16 NULL Pune NULL
|
||||
IN 16 NULL Pune NULL Infosys Campus Hinjewadi Phase 2
|
||||
IN 16 NULL Pune NULL 400705 #22 Iris Garden Gokhale Road
|
||||
IN 16 NULL PUNE NULL 411043
|
||||
IN 16 NULL Pune NULL 411051
|
||||
IN 16 NULL Pune NULL 411057 Infosys Ltd. Rajiv gandhi infostech park Hinjewadi phase 2
|
||||
IN 16 NULL Pune NULL 412108 Pune Maharatshtra
|
||||
IN 16 NULL Pune NULL 433011 502 utkarsh vihar golande state pune
|
||||
IN 19 NULL Bangalore NULL 560080 Indian Institute for Human Settlements IIHS Bangalore City Campus, Sadashivanagar,
|
||||
IN 19 NULL Bangalore NULL 560100 electronic city
|
||||
IN 19 NULL Bhalki NULL 585411 bhalki,bidar ,karnataka karnataka
|
||||
IN 24 NULL Jaipur NULL 302011 Institute of Health Management Research 1, Prabhu Dayal Marg
|
||||
IR 26 NULL Tehran NULL 1118844454 Baharestan sq. mostafa khomeini str., javahery Ave., no. 11,
|
||||
IT NULL Trento NULL
|
||||
JM 08 NULL Kingston NULL Kgn 7 MOna Campus UWI
|
||||
KE NULL Nairobi NULL
|
||||
KE 05 NULL Nairobi NULL 30300 212,kapsabet
|
||||
KH NULL NULL Phnom Penh NULL
|
||||
LR NULL Monrovia NULL 00000
|
||||
NG 11 NULL Abuja NULL 930001 17 Bechar street Wuse zone 2
|
||||
PE 15 NULL Lima NULL 18 Lima Lima
|
||||
PE 15 NULL Lima NULL Lima 18 123 Miraflores
|
||||
PE NULL NULL Lima NULL 03 Calle Granada 104
|
||||
PE NULL NULL Lima NULL 18 Lima Lima
|
||||
PH NULL Manila NULL Globe Telepark 111 Valero Street
|
||||
PH NULL Quezon Coty NULL 1109 86 Harvard Street, Cubao, Quezon City, Philippines 84 Harvard Street, Cubao, Quezon City,hilippines
|
||||
PH 20 NULL Silang NULL 4118 370 Bayungan Kaong Silang Cavite
|
||||
PH 57 NULL Kidapawan NULL 9400 Kidapawan City Kidapawan City
|
||||
PH 66 NULL zamboanga NULL 7000 29-tripplet rd san jose 29-tripplet rd san jose
|
||||
PH D9 NULL Pasig City NULL World Bank Office Manila, 20/F Taipan Place F. Ortigas Jr. Road, Ortigas Center
|
||||
PK NULL Lahore NULL 54000 17-R Model Town Lahore
|
||||
PK NULL Lahore NULL 54000 53- chamber lane road Lahore
|
||||
PK NULL Lahore NULL 54000 85 E block Model Town
|
||||
PK NULL Lahore NULL 54000 House no 227, street no 5, Imamia Colony Shahadra Lahore
|
||||
PK NULL LAHORE NULL 54000 room no.6 khalid bim waleed hall, near New Anarkali, LAHORE room no.6 khalid bim waleed hall, near New Anarkali, LAHORE
|
||||
PK NULL Lahore NULL pk097 LUMS, Lahore,
|
||||
PK NULL Sheikhupura NULL 03935 D.H.Q.Hospital Sheikhupura House number 08. Room no 109 Khalid bin waleed haal, punjab University lahore old campus.
|
||||
PK 02 NULL Quetta NULL 87000 Postal Address 87000, Kuchlak, Quetta, Balochistan. H#24 Peer Abul Khair road Quetta, Balochistan.
|
||||
PK 02 NULL Quetta NULL 87300 block no-1 falt no. 7 New Crime Branch Abbas Ali Road Cantt
|
||||
PK 02 NULL Quetta NULL 87300 Flat no. 3 Shafeen Centre Jinnah Town ,Near I.T university , Quetta
|
||||
PK 02 NULL Quetta NULL 87300 H-no. C-220 Zarghoonabad Phase-2 , Nawa Killi ,Quetta
|
||||
PK 04 NULL burewala NULL 60101 Fatima Fayyaz Hazrat Sakina hall girls hostel number 9 Punjab university Lahore Pakistan Sardar Wajid Azim Azeem abad Burewala dist Vehari Pakistan
|
||||
PK 04 NULL Faisalabad NULL 38000 P 101/1, Green Town, Millat Road, Faisalabad
|
||||
PK 04 NULL Islamabad NULL 44000 P.O Tarlai kalan chappar Islamabad
|
||||
PK 04 NULL lahore NULL
|
||||
PK 04 NULL Lahore NULL 54000
|
||||
PK 04 NULL lahore NULL 54000 Street No.63 House 36/A Al-madad Pak Colony Ravi Road, Lahore. Street No.63 House 36/A Al-madad Pak Colony Ravi Road, Lahore.
|
||||
PK 04 NULL Lahore NULL 54000 1149-1-D2 Green Town Lahore
|
||||
PK 04 NULL Lahore NULL 54000 124, street# 2, karim block Allama Iqbal Town lahore. 124, street# 2, karim block Allama Iqbal Town lahore.
|
||||
PK 04 NULL Lahore NULL 54000 150 A Qila Lachman Singh Ravi Road lahore
|
||||
PK 04 NULL Lahore NULL 54000 166/1L DHA Lahore
|
||||
PK 04 NULL Lahore NULL 54000 172 A2 Township Lahore
|
||||
PK 04 NULL Lahore NULL 54000 183,S/Block, Model Town, Lhr
|
||||
PK 04 NULL lahore NULL 54000 19- A block ,Eden Lane Villas Raiwind Road ,Lahore
|
||||
PK 04 NULL lahore NULL 54000 3-c kaliyar road opposite kids lyceum, rustam park near mor samnabad
|
||||
PK 04 NULL Lahore NULL 54000 31 Saeed Block, Canal Bank Scheme
|
||||
PK 04 NULL Lahore NULL 54000 31c DHA Lahore
|
||||
PK 04 NULL Lahore NULL 54000 387 E1 wapda town, Lahore
|
||||
PK 04 NULL Lahore NULL 54000 45-D dha eme sector multan road,lahore
|
||||
PK 04 NULL Lahore NULL 54000 5 Zafar Ali Road
|
||||
PK 04 NULL Lahore NULL 54000 54-R PGECHS
|
||||
PK 04 NULL lahore NULL 54000 566 E-1 johar town lahore 566 E-1 johar town lahore
|
||||
PK 04 NULL Lahore NULL 54000 82/1 Z Block, Phase 3 DHA
|
||||
PK 04 NULL Lahore NULL 54000 A-1 VRI Zarrar shaheed road lahore cantt A-1 VRI Zarrar shaheed road lahore cantt
|
||||
PK 04 NULL lahore NULL 54000 e5/39D street 6 zaman colony cavalry ground ext
|
||||
PK 04 NULL Lahore NULL 54000 Ho # 61, Block G3, Johar Town Lahore
|
||||
PK 04 NULL LAhore NULL 54000 House #19-A street #5 Usman nagr Ghaziabad Lahore
|
||||
PK 04 NULL lahore NULL 54000 House no 692 street no 67 sadar bazar
|
||||
PK 04 NULL Lahore NULL 54000 Khosa Law Chamber 1 Turner Road
|
||||
PK 04 NULL Lahore NULL 54000 Lahore,Pakistan Lahore,Pakistan
|
||||
PK 04 NULL Lahore NULL 54000 room no 69, khalid bin waleed hall, anarkali
|
||||
PK 04 NULL Lahore NULL 54000 Suite # 8, Al-Hafeez Suites, Gulberg II
|
||||
PK 04 NULL Lahore NULL 54085 199 Shadman 2
|
||||
PK 04 NULL Lahore NULL 54300 Mughalpura Lahore Pakistan
|
||||
PK 04 NULL Lahore NULL 54660 SD 69 falcon complex gulberg III lahore
|
||||
PK 04 NULL lahore NULL 54800 764-G4 johar town ,lahore
|
||||
PK 04 NULL Rawalpindi NULL 44000 House 522, F-Block Sattellite Town, Rawalpindi
|
||||
PK 04 NULL Rawalpindi NULL 46000 1950/c, Indusroad 2, Tariqabad, Rawalpindi Cantt
|
||||
PK 04 NULL Rawalpindi NULL 46000 House 54-E Lane 9 Sector 4, AECHS Chaklala Rawalpindi
|
||||
PK 04 NULL Rawalpindi NULL 46000 House B-1343, Sattellite town Rawalpindi
|
||||
PK 04 NULL Rawalpindi NULL 46000 House CB-299F, Street 1, Lane 4 Peshawar Road Rawalpindi
|
||||
PK 04 NULL Rawalpindi NULL 46300 House No 1518 Umer Block phase 8 BehriaTown
|
||||
PK 04 NULL sialkot NULL 51310 The National Model School, Ismaiealabad, Pacca Garah Sialkot
|
||||
PK 08 NULL Islamabad NULL CIomsats Institute of Information Technology Islamabad
|
||||
PK 08 NULL Islamabad NULL 38700 COMSATS tarlai boys hostel Islamabad. COMSATS tarlai boys hostel Islamabad (Room 30)
|
||||
PK 08 NULL Islamabad NULL 44000
|
||||
PK 08 NULL Islamabad NULL 44000 House # 256, Street # 9, Shahzad Town, Islamabad.
|
||||
PK 08 NULL Islamabad NULL 44000 Islamabad , Comsats University Islamabd ,Pakistan
|
||||
PK 08 NULL Islamabad NULL 44000 World Bank Building Sector G 5
|
||||
PK 08 NULL lahore NULL 54000 3c zafar ali road gulburg 5 3c zafar ali road gulburg 5
|
||||
PK 08 NULL lahore NULL 54000 49-a bilal park, chaburgy 49-a bilal park, chaburgy
|
||||
PK NULL NULL Lahore NULL 54000
|
||||
PK NULL NULL Lahore NULL 54000 85 E block Model Town
|
||||
SN 01 NULL NULL ouakam cité comico en face 217
|
||||
SN 01 NULL Dakar NULL
|
||||
SN 01 NULL Dakar NULL IDEV-ic Patte d'oie Builder's Villa B11
|
||||
SN 01 NULL Dakar NULL liberte 6/ dakar
|
||||
SN 01 NULL Dakar NULL ngor
|
||||
SN 01 NULL Dakar NULL 4027 ZAC Mbao Cité Fadia
|
||||
SN NULL NULL Dakar NULL IDEV-ic Patte d'oie Builder's Villa B11
|
||||
TZ NULL Dar es Salaam NULL NULL
|
||||
TZ NULL Dar es salaam NULL NULL 76021 Dar es salaam 1507 Morogoro
|
||||
TZ NULL Dar es salaam NULL NULL dar es salaam nassoro.ahmedy@yahoo.com
|
||||
TZ NULL DAR ES SALAAM NULL NULL dar es salaam UDSM
|
||||
TZ NULL Dar es salaam NULL NULL NA
|
||||
TZ NULL DAR ES SALAAM NULL NULL P O BOX 23409
|
||||
TZ NULL dar es salaam NULL NULL p. o. box 104994
|
||||
TZ NULL Dar es Salaam NULL NULL P.o. BOX 71415 Dar es Salaam
|
||||
TZ NULL Dar es Salaam NULL NULL P.O.BOx 66675 DSM
|
||||
TZ NULL Dar es salaam NULL NULL Tz Tz
|
||||
TZ NULL dsm NULL NULL
|
||||
TZ 02 NULL Bagamoyo NULL NULL PO.Box 393
|
||||
TZ 02 NULL Dar es salaam NULL NULL 22548
|
||||
TZ 03 NULL Dar-es-salaam NULL NULL Dodoma Municipal Kimara, Dar-es-salaa,
|
||||
TZ 23 NULL Dar es Salaam NULL NULL
|
||||
TZ 23 NULL dar es salaam NULL NULL 35074
|
||||
TZ 23 NULL dar es salaam NULL NULL 67389
|
||||
TZ 23 NULL Dar es Salaam NULL NULL COSTECH, Dar es Salaam, Tanzania
|
||||
TZ 23 NULL Dar es salaam NULL NULL na
|
||||
TZ 23 NULL dar es salaam NULL NULL p o box 60164
|
||||
TZ 23 NULL dar es salaam NULL NULL P. O. Box 77588
|
||||
TZ 23 NULL dar es salaam NULL NULL P.O BOX 78144
|
||||
TZ 23 NULL Dar es Salaam NULL NULL P.O.BOX 78373
|
||||
TZ 23 NULL Dar es salaam NULL NULL UDSM Dar es Salaam
|
||||
TZ 23 NULL Dar es salaam NULL NULL udsm udsm
|
||||
TZ 23 NULL Temeke NULL NULL P.O. Box 50127
|
||||
TZ NULL NULL Dar es Salaam NULL NULL
|
||||
TZ NULL NULL Dar es Salaam NULL NULL Kigoma
|
||||
TZ NULL NULL Dar es Salaam NULL NULL Mwanza
|
||||
UG NULL Kampala NULL NULL
|
||||
UG NULL Kampala NULL NULL Kampala Uganda East Africa
|
||||
US NULL London NULL SE1 8RT Capital Tower 91 Waterloo Road
|
||||
US CA NULL Los Angeles NULL
|
||||
US CA NULL Pleasanton NULL 94588 3412 Pickens Lane
|
||||
US CA NULL Sacramento NULL
|
||||
US CA NULL San Francisco NULL
|
||||
US CA NULL seattle NULL 98113 1234 1st st
|
||||
US CO NULL Denver NULL 80235 6666 West Quincy Ave
|
||||
US CT NULL Greenwich NULL 06830 140 Milbank
|
||||
US CT NULL Hartford NULL 06106 Center for Urban and Global Studies at Trinity College, 70 Vernon Street
|
||||
US DC NULL Washington NULL
|
||||
US DC NULL Washington NULL 20007 World Bank Headquarters 1818 H Street NW
|
||||
US DC NULL Washington NULL 20010
|
||||
US DC NULL Washington NULL 20036
|
||||
US DC NULL Washington NULL 20405 1889 F St NW
|
||||
US DC NULL Washington NULL 20433
|
||||
US DC NULL Washington NULL 20433 1818 H Street NW
|
||||
US DC NULL Washington NULL 20433 1818H St
|
||||
US DC NULL Washington NULL 20433 1818 H Street NW
|
||||
US DC NULL Washington DC NULL 20005 1424, K Street, NW Suite 600
|
||||
US DC NULL Washington DC NULL 20010 1818 H Street, NW
|
||||
US DC NULL Washington, DC NULL 20003 1818 H Street NW
|
||||
US DE NULL Virgin Islands|Charlotte Amalie,Cruz Bay,Christiansted NULL Morocco|Tafraout,Rabat,Tangier,Tetouan,Casablanca,Marrakesh,Fez,Oujda,Meknes,Agadir United Arab Emirates|Garhoud,Dubai,Bur Dubai,Ras al Khaymah,Abu Dhabi,Ajman,Al Fujayrah,Sharjah
|
||||
US FL NULL Falmouth NULL Falmouth Falmouth
|
||||
US FL NULL Lilongwe NULL Lilongwe Lilongwe
|
||||
US GA NULL Atlanta NULL
|
||||
US GU NULL Herndon NULL 15642 Ht USA
|
||||
US GU NULL Miami NULL Miami Miami
|
||||
US MD NULL Gaithersburg NULL 20877 554 N Frederick Avenue Suite 216
|
||||
US MD NULL Potomac NULL 20854 14 Sandalfoot Court
|
||||
US MD NULL Silver Spring NULL 20901 9202 Whitney St.
|
||||
US MI NULL Traverse City NULL 49685 PO Box 792
|
||||
US ND NULL Pirassununga NULL Pirassununga Pirassununga
|
||||
US NJ NULL Princeton NULL
|
||||
US NY NULL Brooklyn NULL 11206-1980 25 Montrose Ave. Apt 304
|
||||
US NY NULL Brooklyn NULL 11225 975 washington ave 2d
|
||||
US NY NULL Brooklyn NULL 11217 150 4TH AVE APT 9E
|
||||
US NY NULL New York NULL
|
||||
US NY NULL New York NULL 10013 148 Lafayette St. PH
|
||||
US NY NULL New York NULL 10017 UNICEF 3 UN Plaza
|
||||
US NY NULL New York NULL 10019 25 Columbus Circle Suite 52E
|
||||
US NY NULL New York NULL 10024 65 West 85th Street 3A
|
||||
US NY NULL New York NULL 10027 606 W. 116th Street #22
|
||||
US NY NULL New York NULL 10037
|
||||
US NY NULL Rochester NULL
|
||||
US NY NULL Scarsdale NULL 10583-1423 54 Walworth Avenue
|
||||
US OR NULL Portland NULL
|
||||
US PA NULL Philadelphia NULL
|
||||
US PA NULL Philadelphia NULL
|
||||
US PR NULL Colonel Hill NULL Colonel Hill Colonel Hill
|
||||
US SD NULL Banjul NULL Banjul Banjul
|
||||
US SD NULL London NULL London London
|
||||
US TX NULL Aledo NULL 76008 1588 Hunterglenn Dr
|
||||
US TX NULL Keller NULL 76248 810 Placid View Ct.
|
||||
US WA NULL Seattle NULL
|
||||
ZA NULL Cape Town NULL
|
||||
ZA NULL Cape Town NULL 7945 Alexander Road Muizenberg
|
||||
ZA NULL Pretoria NULL
|
||||
ZA 11 NULL Cape Town NULL
|
||||
ZA 11 NULL Cape Town NULL 7435 PostNet Suite #57, Private Bag X18 Milnerton
|
||||
ZA 11 NULL Cape town NULL 7508 24 Solyet Court, Lansdowne Road Claremont
|
||||
ZA 11 NULL Cape Town NULL 7701
|
||||
ZA 11 NULL Cape Town NULL 7785 10 Nyamakazi Road Luzuko Park Phillipi East
|
||||
ZA 11 NULL Cape Town NULL 7915 66 Albert Rd
|
||||
ZA 11 NULL Cape Town NULL 8001 210 Long Street
|
||||
ZM NULL Lusaka NULL
|
||||
ZM 09 NULL LUSAKA NULL 10101 P.O. BOX FW 174
|
||||
@@ -0,0 +1,10 @@
|
||||
.addressfield-container-inline > div.form-item {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.addressfield-container-inline.country-GB > div.form-item {
|
||||
margin-left: auto;
|
||||
margin-right: 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* API documentation for Addressfield.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Format generation callback.
|
||||
*
|
||||
* @param $format
|
||||
* The address format being generated.
|
||||
* @param $address
|
||||
* The address this format is generated for.
|
||||
* @param $context
|
||||
* An associative array of context information pertaining to how the address
|
||||
* format should be generated. If no mode is given, it will initialize to the
|
||||
* default value. The remaining context keys should only be present when the
|
||||
* address format is being generated for a field:
|
||||
* - mode: either 'form' or 'render'; defaults to 'render'.
|
||||
* - field: the field info array.
|
||||
* - instance: the field instance array.
|
||||
* - langcode: the langcode of the language the field is being rendered in.
|
||||
* - delta: the delta value of the given address.
|
||||
*
|
||||
* @ingroup addressfield_format
|
||||
*/
|
||||
function CALLBACK_addressfield_format_callback(&$format, $address, $context = array()) {
|
||||
// No example.
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows modules to add arbitrary AJAX commands to the array returned from the
|
||||
* standard address field widget refresh.
|
||||
*
|
||||
* @param &$commands
|
||||
* The array of AJAX commands used to refresh the address field widget.
|
||||
* @param $form
|
||||
* The rebuilt form array.
|
||||
* @param $form_state
|
||||
* The form state array from the form.
|
||||
*
|
||||
* @see addressfield_standard_widget_refresh()
|
||||
*/
|
||||
function hook_addressfield_standard_widget_refresh_alter(&$commands, $form, $form_state) {
|
||||
// Display an alert message.
|
||||
$commands[] = ajax_command_alert(t('The address field widget has been updated.'));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
div.addressfield-container-inline > div.form-item {
|
||||
float: left; /* LTR */
|
||||
margin-right: 1em; /* LTR */
|
||||
}
|
||||
|
||||
div.addressfield-container-inline.country-GB > div.form-item {
|
||||
float: none;
|
||||
margin-right: auto; /* LTR */
|
||||
}
|
||||
|
||||
/* Clear-fix markup for the inline container */
|
||||
div.addressfield-container-inline:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
}
|
||||
/* IE6 */
|
||||
* html div.addressfield-container-inline {
|
||||
height: 1%;
|
||||
}
|
||||
/* IE7 */
|
||||
*:first-child + html div.addressfield-container-inline {
|
||||
min-height: 1%;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @file
|
||||
* Devel Generate for addressfield module
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implements hook_devel_generate();
|
||||
*/
|
||||
function addressfield_devel_generate($object, $field, $instance, $bundle) {
|
||||
if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
|
||||
return devel_generate_multiple('_addressfield_devel_generate', $object, $field, $instance, $bundle);
|
||||
}
|
||||
else {
|
||||
return _addressfield_devel_generate($object, $field, $instance, $bundle);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to generate a greeky US-based address
|
||||
*/
|
||||
function _addressfield_devel_generate($object, $field, $instance, $bundle) {
|
||||
// Set default value
|
||||
$object_field = addressfield_default_values();
|
||||
$addresses = _addressfield_sample_addresses();
|
||||
$object_field = array_merge($object_field, $addresses[array_rand($addresses)]);
|
||||
unset($object_field['data']);
|
||||
return $object_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of sample addresses.
|
||||
*
|
||||
* @return
|
||||
* An array of addressfield arrays
|
||||
*/
|
||||
function _addressfield_sample_addresses() {
|
||||
$fields = &drupal_static(__FUNCTION__);
|
||||
if (!isset($fields)) {
|
||||
$filepath = DRUPAL_ROOT . '/' . drupal_get_path('module', 'addressfield');
|
||||
$fields = array();
|
||||
if ($handle = @fopen("$filepath/addresses.txt",'r')) {
|
||||
if (is_resource($handle)) {
|
||||
$addresses = array();
|
||||
while (($buffer = fgets($handle)) !== false) {
|
||||
list($country, $administrative_area, $sub_administrative_area, $locality, $dependent_locality, $postal_code, $thoroughfare, $premise) = explode("\t", $buffer);
|
||||
$fields[] = array(
|
||||
'country' => ($country == 'NULL') ? NULL : trim($country),
|
||||
'administrative_area' => ($administrative_area == 'NULL') ? NULL : trim($administrative_area),
|
||||
'sub_administrative_area' => ($sub_administrative_area == 'NULL') ? NULL : trim($sub_administrative_area),
|
||||
'locality' => ($locality == 'NULL') ? NULL : trim($locality),
|
||||
'dependent_locality' => ($dependent_locality == 'NULL') ? NULL : trim($dependent_locality),
|
||||
'postal_code' => ($postal_code == 'NULL') ? NULL : trim($postal_code),
|
||||
'thoroughfare' => ($thoroughfare == 'NULL') ? NULL : trim($thoroughfare),
|
||||
'premise' => ($premise == 'NULL') ? NULL : trim($premise),
|
||||
);
|
||||
}
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Integration with the Feeds module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_feeds_node_processor_targets_alter().
|
||||
*/
|
||||
function addressfield_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
|
||||
foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
|
||||
$info = field_info_field($name);
|
||||
if ($info['type'] == 'addressfield') {
|
||||
foreach ($info['columns'] as $sub_field => $schema_info) {
|
||||
$name_label = $instance['label'] . ': ' . drupal_ucfirst(str_replace('_', ' ', $sub_field));
|
||||
$targets[$name . ':' . $sub_field] = array(
|
||||
'name' => $name_label,
|
||||
'callback' => 'addressfield_set_target',
|
||||
'real_target' => $info['field_name'],
|
||||
'description' => $schema_info['description'],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for hook_feeds_processor_targets_alter().
|
||||
*
|
||||
* @param $source
|
||||
* Field mapper source settings.
|
||||
* @param $entity
|
||||
* An entity object, for instance a node object.
|
||||
* @param $target
|
||||
* A string identifying the target on the node.
|
||||
* @param $value
|
||||
* The value to populate the target with.
|
||||
*/
|
||||
function addressfield_set_target($source, $entity, $target, $values) {
|
||||
list($field_name, $sub_field) = explode(':', $target, 2);
|
||||
|
||||
// Convert the values into an array if it isn't one already to correspond to
|
||||
// Drupal's handling of field value arrays.
|
||||
if (!is_array($values)) {
|
||||
$values = array($values);
|
||||
}
|
||||
|
||||
// If the field is already set on the given entity, update the existing value
|
||||
// array. Otherwise start with a fresh field value array.
|
||||
$field = isset($entity->$field_name) ? $entity->$field_name : array();
|
||||
|
||||
// Loop over the field values array...
|
||||
foreach ($values as $delta => $value) {
|
||||
$field[LANGUAGE_NONE][$delta][$sub_field] = $value;
|
||||
}
|
||||
|
||||
$entity->$field_name = $field;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
name = Address Field
|
||||
description = Manage a flexible address field, implementing the xNAL standard.
|
||||
core = 7.x
|
||||
package = Fields
|
||||
|
||||
dependencies[] = ctools
|
||||
|
||||
files[] = views/addressfield_views_handler_filter_country.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-05-07
|
||||
version = "7.x-1.0-beta4"
|
||||
core = "7.x"
|
||||
project = "addressfield"
|
||||
datestamp = "1367945112"
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema()
|
||||
*/
|
||||
function addressfield_field_schema() {
|
||||
$columns = array(
|
||||
'country' => array(
|
||||
'description' => 'Two letter ISO country code of this address.',
|
||||
'type' => 'varchar',
|
||||
'length' => 2,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'administrative_area' => array(
|
||||
'description' => 'The administrative area of this address. (i.e. State/Province)',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'sub_administrative_area' => array(
|
||||
'description' => 'The sub administrative area of this address.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'locality' => array(
|
||||
'description' => 'The locality of this address. (i.e. City)',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'dependent_locality' => array(
|
||||
'description' => 'The dependent locality of this address.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'postal_code' => array(
|
||||
'description' => 'The postal code of this address.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'thoroughfare' => array(
|
||||
'description' => 'The thoroughfare of this address. (i.e. Street address)',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'premise' => array(
|
||||
'description' => 'The premise of this address. (i.e. Apartment / Suite number)',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'sub_premise' => array(
|
||||
'description' => 'The sub_premise of this address.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'default' => '',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'organisation_name' => array(
|
||||
'description' => 'Contents of a primary OrganisationName element in the xNL XML.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'name_line' => array(
|
||||
'description' => 'Contents of a primary NameLine element in the xNL XML.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'first_name' => array(
|
||||
'description' => 'Contents of the FirstName element of a primary PersonName element in the xNL XML.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'last_name' => array(
|
||||
'description' => 'Contents of the LastName element of a primary PersonName element in the xNL XML.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'data' => array(
|
||||
'description' => 'Additional data for this address.',
|
||||
'type' => 'text',
|
||||
'size' => 'big',
|
||||
'not null' => FALSE,
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
// TODO Add indexes.
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the field configuration to the new plugin structure.
|
||||
*/
|
||||
function addressfield_update_7000() {
|
||||
// Enable ctools.
|
||||
if (!module_enable(array('ctools'))) {
|
||||
throw new Exception('This version of addressfield requires ctools, but it could not be enabled.');
|
||||
}
|
||||
|
||||
// Get the list of fields of type 'addressfield'.
|
||||
$address_fields = array();
|
||||
foreach (field_info_fields() as $field_name => $field_info) {
|
||||
if ($field_info['type'] == 'addressfield') {
|
||||
$address_fields[$field_name] = $field_name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (field_info_instances() as $entity_type => $bundles) {
|
||||
foreach ($bundles as $bundle_name => $instances) {
|
||||
foreach (array_intersect_key($instances, $address_fields) as $field_name => $instance) {
|
||||
$widget_settings = &$instance['widget']['settings'];
|
||||
|
||||
if ($instance['widget']['type'] == 'addressfield_standard') {
|
||||
// Default to use the country-based address widget.
|
||||
$format_handlers = array('address');
|
||||
|
||||
// Map the old 'name_format' setting to the name and organization widgets.
|
||||
if (in_array($widget_settings['name_format'], array('name_line_organisation', 'first_last_organisation'))) {
|
||||
$format_handlers[] = 'organisation';
|
||||
}
|
||||
if (in_array($widget_settings['name_format'], array('name_line', 'name_line_organisation'))) {
|
||||
$format_handlers[] = 'name-oneline';
|
||||
}
|
||||
else {
|
||||
$format_handlers[] = 'name-full';
|
||||
}
|
||||
unset($widget_settings['name_format']);
|
||||
$widget_settings['format_handlers'] = $format_handlers;
|
||||
}
|
||||
|
||||
// Update displays.
|
||||
foreach ($instance['display'] as $view_mode => &$view_mode_info) {
|
||||
$display_settings = &$view_mode_info['settings'];
|
||||
|
||||
if ($view_mode_info['type'] == 'addressfield_default') {
|
||||
if (isset($widget_settings['format_handlers'])) {
|
||||
$display_settings['use_widget_handlers'] = 1;
|
||||
}
|
||||
else {
|
||||
// If the widget is non-standard, just use a sane default.
|
||||
$display_settings['use_widget_handlers'] = 0;
|
||||
$display_settings['format_handlers'] = array('address', 'name-oneline');
|
||||
}
|
||||
}
|
||||
else if ($view_mode_info['type'] == 'addressfield_name') {
|
||||
// Migrate the 'addressfield_name' formatter to the new framework.
|
||||
$view_mode_info['type'] = 'addressfield_default';
|
||||
// Start from the widget configuration.
|
||||
$display_settings['use_widget_handlers'] = 0;
|
||||
$display_settings['format_handlers'] = isset($widget_settings['format_handlers']) ? $widget_settings['format_handlers'] : array('address', 'name-oneline');
|
||||
|
||||
if (empty($display_settings['organisation'])) {
|
||||
$display_settings['format_handlers'] = array_diff( $display_settings['format_handlers'], array('organisation'));
|
||||
}
|
||||
unset($display_settings['organisation']);
|
||||
}
|
||||
}
|
||||
|
||||
field_update_instance($instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,784 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines a field for attaching country-specific addresses to entities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_plugin_directory().
|
||||
*/
|
||||
function addressfield_ctools_plugin_directory($module, $plugin) {
|
||||
if ($module == 'addressfield') {
|
||||
return 'plugins/' . $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_plugin_type().
|
||||
*/
|
||||
function addressfield_ctools_plugin_type() {
|
||||
$plugins['format'] = array(
|
||||
'load themes' => TRUE,
|
||||
);
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_views_api().
|
||||
*/
|
||||
function addressfield_views_api() {
|
||||
return array(
|
||||
'api' => 3,
|
||||
'path' => drupal_get_path('module', 'addressfield') . '/views',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of format plugins.
|
||||
*/
|
||||
function addressfield_format_plugins() {
|
||||
ctools_include('plugins');
|
||||
$plugins = ctools_get_plugins('addressfield', 'format');
|
||||
uasort($plugins, 'ctools_plugin_sort');
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of format plugins in a format suitable for #options.
|
||||
*/
|
||||
function addressfield_format_plugins_options() {
|
||||
$options = array();
|
||||
foreach (addressfield_format_plugins() as $widget => $info) {
|
||||
$options[$widget] = check_plain($info['title']);
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @defgroup addressfield_format Address format API
|
||||
* @{
|
||||
* API for generating address forms and display formats.
|
||||
*
|
||||
* Addresses forms and display formats are collaboratively generated by one or
|
||||
* more format handler plugins. An address with a name and a company, for example,
|
||||
* will be generated by three handlers:
|
||||
* - 'address' that will generate the country, locality, street blocks
|
||||
* - 'organisation' that will add the organisation block to the address
|
||||
* - 'name-full' that will add a first name and last name block to the address
|
||||
*
|
||||
* A format handler is a CTools plugin of type 'addressfield' / 'format'. Each
|
||||
* handler is passed the format in turn, and can add to or modify the format.
|
||||
*
|
||||
* The format itself is a renderable array stub. This stub will be transformed
|
||||
* into either a Form API array suitable for use as part of a form or into a
|
||||
* renderable array suitable for use with drupal_render(). The following
|
||||
* modifications are done:
|
||||
* - when rendering as a form, every element which name (its key in the array)
|
||||
* is a valid addressfield column (see addressfield_field_schema()), will
|
||||
* be transformed into a form element, either using a type explicitly
|
||||
* defined in '#widget_type' or using 'select' if '#options' is set or
|
||||
* 'textfield' if it is not. In addition, the '#default_value' of every
|
||||
* field will be populated from the address being edited.
|
||||
* - when rendering as a formatter, every element which name (its key in the array)
|
||||
* is a valid addressfield column (see addressfield_field_schema()), will
|
||||
* be transformed into a renderable element, either using a type explicitly
|
||||
* defined in '#render_type' or else using 'addressfield_container'. When
|
||||
* the type is 'addressfield_container' the element will be rendered as
|
||||
* an HTML element set by '#tag' (default: span).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate a format for a given address.
|
||||
*
|
||||
* @param $address
|
||||
* The address format being generated.
|
||||
* @param $handlers
|
||||
* The format handlers to use to generate the format.
|
||||
* @param $context
|
||||
* An associative array of context information pertaining to how the address
|
||||
* format should be generated. If no mode is given, it will initialize to the
|
||||
* default value. The remaining context keys should only be present when the
|
||||
* address format is being generated for a field:
|
||||
* - mode: either 'form' or 'render'; defaults to 'render'.
|
||||
* - field: the field info array.
|
||||
* - instance: the field instance array.
|
||||
* - langcode: the langcode of the language the field is being rendered in.
|
||||
* - delta: the delta value of the given address.
|
||||
*
|
||||
* @return
|
||||
* A renderable array suitable for use as part of a form (if 'mode' is 'form')
|
||||
* or for formatted address output when passed to drupal_render().
|
||||
*/
|
||||
function addressfield_generate($address, array $handlers, array $context = array()) {
|
||||
// If no mode is given in the context array, default it to 'render'.
|
||||
if (empty($context['mode'])) {
|
||||
$context['mode'] = 'render';
|
||||
}
|
||||
|
||||
ctools_include('plugins');
|
||||
$format = array();
|
||||
$format['#handlers'] = $handlers;
|
||||
foreach ($format['#handlers'] as $handler) {
|
||||
if ($callback = ctools_plugin_load_function('addressfield', 'format', $handler, 'format callback')) {
|
||||
$callback($format, $address, $context);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the address in the format, for processing.
|
||||
$format['#address'] = $address;
|
||||
|
||||
// Post-process the format stub, depending on the rendering mode.
|
||||
if ($context['mode'] == 'form') {
|
||||
$format['#addressfield'] = TRUE;
|
||||
$format['#process'][] = 'addressfield_process_format_form';
|
||||
$format['#required'] = FALSE;
|
||||
}
|
||||
elseif ($context['mode'] == 'render') {
|
||||
$format['#pre_render'][] = 'addressfield_render_address';
|
||||
}
|
||||
|
||||
return $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a full-fledged form from a format snippet, as returned by addressfield_formats().
|
||||
*/
|
||||
function addressfield_process_format_form($format, &$form_state, $complete_form) {
|
||||
// Make sure to load all the plugins that participated in this format.
|
||||
ctools_include('plugins');
|
||||
foreach ($format['#handlers'] as $handler) {
|
||||
ctools_plugin_load_function('addressfield', 'format', $handler, 'format callback');
|
||||
}
|
||||
|
||||
_addressfield_process_format_form($format, $format['#address'], $format['#required']);
|
||||
return $format;
|
||||
}
|
||||
|
||||
function _addressfield_process_format_form(&$format, $address, $required) {
|
||||
foreach (element_children($format) as $key) {
|
||||
$child = &$format[$key];
|
||||
|
||||
// Automatically expand elements that matches one of the field of the
|
||||
// address structure.
|
||||
if (in_array($key, array('name_line', 'first_name', 'last_name', 'organisation_name', 'country', 'administrative_area', 'sub_administrative_area', 'locality', 'dependent_locality', 'postal_code', 'thoroughfare', 'premise', 'sub_premise'))) {
|
||||
// Set the type.
|
||||
if (isset($child['#widget_type'])) {
|
||||
$child['#type'] = $child['#widget_type'];
|
||||
}
|
||||
else {
|
||||
if (isset($child['#options'])) {
|
||||
$child['#type'] = 'select';
|
||||
$child['#size'] = 0;
|
||||
}
|
||||
else {
|
||||
$child['#type'] = 'textfield';
|
||||
}
|
||||
}
|
||||
if (!$required) {
|
||||
unset($child['#required']);
|
||||
}
|
||||
|
||||
$child['#default_value'] = $address[$key];
|
||||
}
|
||||
|
||||
// Recurse through the child.
|
||||
_addressfield_process_format_form($child, $address, $required);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an address in a given format.
|
||||
*/
|
||||
function addressfield_render_address($format) {
|
||||
_addressfield_render_address($format, $format['#address']);
|
||||
return $format;
|
||||
}
|
||||
|
||||
function _addressfield_render_address(&$format, $address) {
|
||||
foreach (element_children($format) as $key) {
|
||||
$child = &$format[$key];
|
||||
|
||||
// Automatically expand elements that matches one of the field of the
|
||||
// address structure.
|
||||
if (in_array($key, array('name_line', 'first_name', 'last_name', 'organisation_name', 'country', 'administrative_area', 'sub_administrative_area', 'locality', 'dependent_locality', 'postal_code', 'thoroughfare', 'premise', 'sub_premise'), TRUE)) {
|
||||
if (isset($child['#render_type'])) {
|
||||
$child['#type'] = $child['#render_type'];
|
||||
}
|
||||
else {
|
||||
$child['#type'] = 'addressfield_container';
|
||||
if (!isset($child['#tag'])) {
|
||||
$child['#tag'] = 'span';
|
||||
}
|
||||
}
|
||||
|
||||
// If the element instructs us to render the option value instead of the
|
||||
// raw address element value and its #options array has a matching key,
|
||||
// swap it out for the option value now.
|
||||
if (!empty($child['#render_option_value']) && isset($child['#options'][$address[$key]])) {
|
||||
$child['#children'] = check_plain($child['#options'][$address[$key]]);
|
||||
}
|
||||
else {
|
||||
$child['#children'] = check_plain($address[$key]);
|
||||
}
|
||||
|
||||
// Skip empty elements.
|
||||
if ((string) $child['#children'] === '') {
|
||||
$child['#access'] = FALSE;
|
||||
}
|
||||
|
||||
// Add #field_prefix and #field_suffix to the prefixes and suffixes.
|
||||
if (isset($child['#field_prefix'])) {
|
||||
$child['#prefix'] = (isset($child['#prefix']) ? $child['#prefix'] : '') . $child['#field_prefix'];
|
||||
}
|
||||
if (isset($child['#field_suffix'])) {
|
||||
$child['#suffix'] = (isset($child['#suffix']) ? $child['#suffix'] : '') . $child['#field_suffix'];
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse through the child.
|
||||
_addressfield_render_address($child, $address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "ingroup addressfield_format"
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_theme().
|
||||
*/
|
||||
function addressfield_theme() {
|
||||
$hooks['addressfield_container'] = array(
|
||||
'render element' => 'element',
|
||||
);
|
||||
return $hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a container for a set of address fields.
|
||||
*/
|
||||
function theme_addressfield_container($variables) {
|
||||
$element = $variables['element'];
|
||||
|
||||
$element['#children'] = trim($element['#children']);
|
||||
if (strlen($element['#children']) > 0) {
|
||||
$output = '<' . $element['#tag'] . drupal_attributes($element['#attributes']) . '>';
|
||||
$output .= $element['#children'];
|
||||
$output .= '</' . $element['#tag'] . ">";
|
||||
return $output;
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_element_info().
|
||||
*/
|
||||
function addressfield_element_info() {
|
||||
$types['addressfield_container'] = array(
|
||||
'#theme_wrappers' => array('addressfield_container'),
|
||||
'#process' => array('addressfield_widget_process'),
|
||||
'#attributes' => array(),
|
||||
'#tag' => 'div',
|
||||
);
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form API process function: set the #parents of the children of this element so they appear at the same level as the parent.
|
||||
*/
|
||||
function addressfield_widget_process($element) {
|
||||
foreach (element_children($element) as $key) {
|
||||
$element[$key]['#parents'] = $element['#parents'];
|
||||
$element[$key]['#parents'][count($element[$key]['#parents']) - 1] = $key;
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_info()
|
||||
*/
|
||||
function addressfield_field_info() {
|
||||
$fields = array();
|
||||
|
||||
$fields['addressfield'] = array(
|
||||
'label' => t('Postal address'),
|
||||
'description' => t('A field type used for storing postal addresses according the xNAL standard.'),
|
||||
'settings' => array(),
|
||||
'instance_settings' => array(),
|
||||
'default_widget' => 'addressfield_standard',
|
||||
'default_formatter' => 'addressfield_default',
|
||||
'property_type' => 'addressfield',
|
||||
'property_callbacks' => array('addressfield_property_info_callback'),
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of default values for the addressfield form elements.
|
||||
*/
|
||||
function addressfield_default_values($available_countries = NULL) {
|
||||
if (!isset($available_countries)) {
|
||||
$available_countries = _addressfield_country_options_list();
|
||||
}
|
||||
|
||||
// Use the default country of the site if possible.
|
||||
$default_country = variable_get('site_default_country', NULL);
|
||||
|
||||
// If the default country is undefined or not in the list of available countries,
|
||||
// just fallback to the first country in the list.
|
||||
if (!$default_country || !isset($available_countries[$default_country])) {
|
||||
$default_country = key($available_countries);
|
||||
}
|
||||
|
||||
return array(
|
||||
'country' => $default_country,
|
||||
'name_line' => '',
|
||||
'first_name' => '',
|
||||
'last_name' => '',
|
||||
'organisation_name' => '',
|
||||
'administrative_area' => '',
|
||||
'sub_administrative_area' => '',
|
||||
'locality' => '',
|
||||
'dependent_locality' => '',
|
||||
'postal_code' => '',
|
||||
'thoroughfare' => '',
|
||||
'premise' => '',
|
||||
'sub_premise' => '',
|
||||
'data' => '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_is_empty().
|
||||
*/
|
||||
function addressfield_field_is_empty($item, $field) {
|
||||
// Every address field must have at least a country value or it is considered
|
||||
// empty, even if it has name information.
|
||||
return empty($item['country']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_info()
|
||||
*/
|
||||
function addressfield_field_widget_info() {
|
||||
$widgets = array();
|
||||
|
||||
$widgets['addressfield_standard'] = array(
|
||||
'label' => t('Dynamic address form'),
|
||||
'field types' => array('addressfield'),
|
||||
'settings' => array(
|
||||
'available_countries' => array(),
|
||||
'format_handlers' => array('address'),
|
||||
),
|
||||
);
|
||||
|
||||
return $widgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_settings_form()
|
||||
*/
|
||||
function addressfield_field_widget_settings_form($field, $instance) {
|
||||
$widget = $instance['widget'];
|
||||
$defaults = field_info_widget_settings($widget['type']);
|
||||
$settings = array_merge($defaults, $widget['settings']);
|
||||
$form = array();
|
||||
|
||||
if ($widget['type'] == 'addressfield_standard') {
|
||||
$form['available_countries'] = array(
|
||||
'#type' => 'select',
|
||||
'#multiple' => TRUE,
|
||||
'#title' => t('Available countries'),
|
||||
'#description' => t('If no countries are selected, all countries will be available.'),
|
||||
'#options' => _addressfield_country_options_list(),
|
||||
'#default_value' => $settings['available_countries'],
|
||||
);
|
||||
|
||||
$form['format_handlers'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => t('Format handlers'),
|
||||
'#options' => addressfield_format_plugins_options(),
|
||||
'#default_value' => $settings['format_handlers'],
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_form()
|
||||
*/
|
||||
function addressfield_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
||||
$settings = $instance['widget']['settings'];
|
||||
|
||||
// Generate a specific key used to identify this element to restore a default
|
||||
// value upon AJAX submission regardless of where this element is in the
|
||||
// $form array.
|
||||
$element_key = implode('|', array($element['#entity_type'], $element['#bundle'], $element['#field_name'], $element['#language'], $element['#delta']));
|
||||
|
||||
// Store the key in the element array as a value so it can be easily retrieved
|
||||
// in context in the $form_state['values'] array in the element validator.
|
||||
$element['element_key'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $element_key,
|
||||
);
|
||||
|
||||
// Get the default address used to build the widget form elements, looking
|
||||
// first in the form state, then in the stored value for the field, and then
|
||||
// in the default values of the instance.
|
||||
$address = array();
|
||||
|
||||
if (!empty($form_state['addressfield'][$element_key])) {
|
||||
// Use the value from the form_state if available.
|
||||
$address = $form_state['addressfield'][$element_key];
|
||||
}
|
||||
elseif (!empty($items[$delta]['country'])) {
|
||||
// Else use the saved value for the field.
|
||||
$address = $items[$delta];
|
||||
}
|
||||
else {
|
||||
// Otherwise use the instance default.
|
||||
$address = (array) $instance['default_value'][0];
|
||||
}
|
||||
|
||||
// Determine the list of available countries, and if the currently selected
|
||||
// country is not in it, unset it so it can be reset to the default country.
|
||||
$countries = _addressfield_country_options_list($field, $instance);
|
||||
if (!empty($address['country']) && !isset($countries[$address['country']])) {
|
||||
unset($address['country']);
|
||||
}
|
||||
|
||||
// Merge in default values to provide a value for every expected array key.
|
||||
$address += addressfield_default_values($countries);
|
||||
|
||||
// Add the form elements for the standard widget, which includes a country
|
||||
// select list at the top that reloads the available address elements when the
|
||||
// country is changed.
|
||||
if ($instance['widget']['type'] == 'addressfield_standard') {
|
||||
// Wrap everything in a fieldset. This is not the best looking element,
|
||||
// but it's the only wrapper available in Drupal we can properly use
|
||||
// in that context, and it is overridable if necessary.
|
||||
$element['#type'] = 'fieldset';
|
||||
|
||||
// Generate the address form.
|
||||
$context = array(
|
||||
'mode' => 'form',
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'langcode' => $langcode,
|
||||
'delta' => $delta,
|
||||
);
|
||||
$element += addressfield_generate($address, $settings['format_handlers'], $context);
|
||||
|
||||
// Mark the form element as required if necessary.
|
||||
$element['#required'] = $delta == 0 && $instance['required'];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element validate callback: rebuilds the form on country change and stores the
|
||||
* current address value in the $form_state for retrieval on rebuild.
|
||||
*/
|
||||
function addressfield_standard_country_validate($element, &$form_state) {
|
||||
// If the country was changed, rebuild the form.
|
||||
if ($element['#default_value'] != $element['#value']) {
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
$parents = $element['#parents'];
|
||||
array_pop($parents);
|
||||
|
||||
// Search through the form values to find the current address.
|
||||
$address = drupal_array_get_nested_value($form_state['values'], $parents);
|
||||
|
||||
// Store the present address values in the form state for retrieval by the
|
||||
// widget form regardless of where the widget sits in the $form array.
|
||||
$form_state['addressfield'][$address['element_key']] = array_diff_key($address, array('element_key' => ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback in response to a change of country in an address field.
|
||||
*
|
||||
* The only thing we have to do is to find the proper element to render.
|
||||
*/
|
||||
function addressfield_standard_widget_refresh($form, $form_state) {
|
||||
// The target element is one element below the triggering country selector.
|
||||
$array_parents = $form_state['triggering_element']['#array_parents'];
|
||||
array_pop($array_parents);
|
||||
|
||||
// Iterate over the form parents to find the element.
|
||||
$element = $form;
|
||||
foreach ($array_parents as $name) {
|
||||
$element = &$element[$name];
|
||||
if (!empty($element['#addressfield'])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the address block, but remove the '_weight' element inserted
|
||||
// by the field API.
|
||||
unset($element['_weight']);
|
||||
|
||||
// Replace the address field widget with the updated widget and focus on the
|
||||
// new country select list.
|
||||
$commands[] = ajax_command_replace(NULL, render($element));
|
||||
$commands[] = ajax_command_invoke('#' . $element['country']['#id'], 'focus');
|
||||
|
||||
// Allow other modules to add arbitrary AJAX commands on the refresh.
|
||||
drupal_alter('addressfield_standard_widget_refresh', $commands, $form, $form_state);
|
||||
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_info().
|
||||
*/
|
||||
function addressfield_field_formatter_info() {
|
||||
return array(
|
||||
'addressfield_default' => array(
|
||||
'label' => t('Default'),
|
||||
'field types' => array('addressfield'),
|
||||
'settings' => array(
|
||||
'use_widget_handlers' => 1,
|
||||
'format_handlers' => array('address'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_settings_form().
|
||||
*/
|
||||
function addressfield_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$settings = $display['settings'];
|
||||
|
||||
$element['use_widget_handlers'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Use the same configuration as the widget.'),
|
||||
'#default_value' => !empty($settings['use_widget_handlers']),
|
||||
);
|
||||
|
||||
$element['format_handlers'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => t('Format handlers'),
|
||||
'#options' => addressfield_format_plugins_options(),
|
||||
'#default_value' => $settings['format_handlers'],
|
||||
'#process' => array('form_process_checkboxes', '_addressfield_field_formatter_settings_form_process_add_state'),
|
||||
'#element_validate' => array('_addressfield_field_formatter_settings_form_validate')
|
||||
);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: set the proper #states to the use widget handlers checkbox.
|
||||
*/
|
||||
function _addressfield_field_formatter_settings_form_process_add_state($element, $form_state) {
|
||||
// Build a #parents based on the current checkbox.
|
||||
$target_parents = array_slice($element['#parents'], 0, -1);
|
||||
$target_parents[] = 'use_widget_handlers';
|
||||
$target_parents = array_shift($target_parents) . ($target_parents ? '[' . implode('][', $target_parents) . ']' : '');
|
||||
|
||||
$element['#states']['visible'] = array(
|
||||
':input[name="' . $target_parents . '"]' => array('checked' => FALSE),
|
||||
);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: filter the results of the checkboxes form element.
|
||||
*/
|
||||
function _addressfield_field_formatter_settings_form_validate($element, &$element_state) {
|
||||
form_set_value($element, array_filter($element['#value']), $element_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_settings_summary().
|
||||
*/
|
||||
function addressfield_field_formatter_settings_summary($field, $instance, $view_mode) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$settings = $display['settings'];
|
||||
|
||||
$summary = '';
|
||||
|
||||
if ($settings['use_widget_handlers']) {
|
||||
return t('Use widget configuration');
|
||||
}
|
||||
else {
|
||||
$summary = array();
|
||||
$plugins = addressfield_format_plugins();
|
||||
foreach ($settings['format_handlers'] as $handler) {
|
||||
$summary[] = $plugins[$handler]['title'];
|
||||
}
|
||||
return $summary ? implode(', ', $summary) : t('No handler');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_view().
|
||||
*/
|
||||
function addressfield_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
|
||||
$settings = $display['settings'];
|
||||
$element = array();
|
||||
|
||||
switch ($display['type']) {
|
||||
case 'addressfield_default':
|
||||
if (!empty($settings['use_widget_handlers'])) {
|
||||
$handlers = $instance['widget']['settings']['format_handlers'];
|
||||
}
|
||||
else {
|
||||
$handlers = $settings['format_handlers'];
|
||||
}
|
||||
foreach ($items as $delta => $address) {
|
||||
// Generate the address format.
|
||||
$context = array(
|
||||
'mode' => 'render',
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'langcode' => $langcode,
|
||||
'delta' => $delta,
|
||||
);
|
||||
$element[$delta] = addressfield_generate($address, $handlers, $context);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to alter the property info of address fields.
|
||||
*
|
||||
* @see addressfield_field_info().
|
||||
*/
|
||||
function addressfield_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
|
||||
$name = $field['field_name'];
|
||||
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
|
||||
|
||||
$property['type'] = ($field['cardinality'] != 1) ? 'list<addressfield>' : 'addressfield';
|
||||
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
|
||||
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
|
||||
$property['auto creation'] = 'addressfield_auto_creation';
|
||||
$property['property info'] = addressfield_data_property_info();
|
||||
|
||||
unset($property['query callback']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto creation callback for an addressfield value array.
|
||||
*
|
||||
* @see addressfield_property_info_callback()
|
||||
*/
|
||||
function addressfield_auto_creation() {
|
||||
// We can't call addressfield_default_values() directly, because it has an
|
||||
// optional array argument that will receive an invalid value when Entity API
|
||||
// tries to call it directly with its usual $property_name and $context
|
||||
// arguments.
|
||||
return addressfield_default_values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines info for the properties of the address field data structure.
|
||||
*/
|
||||
function addressfield_data_property_info($name = NULL) {
|
||||
// Build an array of basic property information for the address field.
|
||||
$properties = array(
|
||||
'country' => array(
|
||||
'label' => t('Country'),
|
||||
'options list' => '_addressfield_country_options_list',
|
||||
),
|
||||
'name_line' => array(
|
||||
'label' => t('Full name'),
|
||||
),
|
||||
'first_name' => array(
|
||||
'label' => t('First name'),
|
||||
),
|
||||
'last_name' => array(
|
||||
'label' => t('Last name'),
|
||||
),
|
||||
'organisation_name' => array(
|
||||
'label' => t('Company'),
|
||||
),
|
||||
'administrative_area' => array(
|
||||
'label' => t('Administrative area (i.e. State / Province)'),
|
||||
),
|
||||
'sub_administrative_area' => array(
|
||||
'label' => t('Sub administrative area'),
|
||||
),
|
||||
'locality' => array(
|
||||
'label' => t('Locality (i.e. City)'),
|
||||
),
|
||||
'dependent_locality' => array(
|
||||
'label' => t('Dependent locality'),
|
||||
),
|
||||
'postal_code' => array(
|
||||
'label' => t('Postal code'),
|
||||
),
|
||||
'thoroughfare' => array(
|
||||
'label' => t('Thoroughfare (i.e. Street address)'),
|
||||
),
|
||||
'premise' => array(
|
||||
'label' => t('Premise (i.e. Apartment / Suite number)'),
|
||||
),
|
||||
);
|
||||
|
||||
// Add the default values for each of the address field properties.
|
||||
foreach ($properties as $key => &$value) {
|
||||
$value += array(
|
||||
'description' => !empty($name) ? t('!label of field %name', array('!label' => $value['label'], '%name' => $name)) : '',
|
||||
'type' => 'text',
|
||||
'getter callback' => 'entity_property_verbatim_get',
|
||||
'setter callback' => 'entity_property_verbatim_set',
|
||||
);
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps country_get_list() for use as an Entity API options list.
|
||||
*/
|
||||
function _addressfield_country_options_list($field = NULL, $instance = NULL) {
|
||||
// Necessary for country_get_list().
|
||||
require_once DRUPAL_ROOT . '/includes/locale.inc';
|
||||
|
||||
$countries = country_get_list();
|
||||
|
||||
if (isset($field)) {
|
||||
// If the instance is not specified, loop against all the instances of the field.
|
||||
if (!isset($instance)) {
|
||||
$instances = array();
|
||||
foreach ($field['bundles'] as $entity_type => $bundles) {
|
||||
foreach ($bundles as $bundle_name) {
|
||||
$instances[] = field_info_instance($entity_type, $field['field_name'], $bundle_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$instances = array($instance);
|
||||
}
|
||||
|
||||
foreach ($instances as $instance) {
|
||||
if (!empty($instance['widget']['settings']['available_countries'])) {
|
||||
$countries = array_intersect_key($countries, $instance['widget']['settings']['available_countries']);
|
||||
}
|
||||
else {
|
||||
// This instance allow all the countries.
|
||||
$countries = country_get_list();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $countries;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
name = Address Field Example
|
||||
description = Example module for how to implement an addressfield format handler.
|
||||
core = 7.x
|
||||
package = Fields
|
||||
hidden = TRUE
|
||||
|
||||
dependencies[] = ctools
|
||||
dependencies[] = addressfield
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-05-07
|
||||
version = "7.x-1.0-beta4"
|
||||
core = "7.x"
|
||||
project = "addressfield"
|
||||
datestamp = "1367945112"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_ctools_plugin_directory().
|
||||
*/
|
||||
function addressfield_example_ctools_plugin_directory($module, $plugin) {
|
||||
if ($module == 'addressfield') {
|
||||
return 'plugins/' . $plugin;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hide the country when only one country is available.
|
||||
*/
|
||||
|
||||
$plugin = array(
|
||||
'title' => t('Hide the country when only one is available'),
|
||||
'format callback' => 'addressfield_format_address_hide_country',
|
||||
'type' => 'address',
|
||||
'weight' => -80,
|
||||
);
|
||||
|
||||
/**
|
||||
* Format callback.
|
||||
*
|
||||
* @see CALLBACK_addressfield_format_callback()
|
||||
*/
|
||||
function addressfield_format_address_hide_country(&$format, $address, $context = array()) {
|
||||
// When building the format for a form, we expect the country element to have
|
||||
// an #options list. If it does, and there is only one option, hide the field
|
||||
// by setting #access to FALSE.
|
||||
if ($context['mode'] == 'form') {
|
||||
if (!empty($format['country']['#options']) && count($format['country']['#options']) == 1) {
|
||||
$format['country']['#access'] = FALSE;
|
||||
}
|
||||
}
|
||||
elseif ($context['mode'] == 'render') {
|
||||
// However, in render mode, the element does not have an #options list, so
|
||||
// we look instead in the field instance settings if given. If we find a
|
||||
// single country option and it matches the country of the current address,
|
||||
// go ahead and hide it.
|
||||
if (!empty($context['instance']['widget']['settings']['available_countries']) &&
|
||||
count($context['instance']['widget']['settings']['available_countries']) == 1) {
|
||||
if (isset($context['instance']['widget']['settings']['available_countries'][$address['country']])) {
|
||||
$format['country']['#access'] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The default format for adresses.
|
||||
*/
|
||||
|
||||
$plugin = array(
|
||||
'title' => t('Address form (country-specific)'),
|
||||
'format callback' => 'addressfield_format_address_generate',
|
||||
'type' => 'address',
|
||||
'weight' => -100,
|
||||
);
|
||||
|
||||
/**
|
||||
* Format callback.
|
||||
*
|
||||
* @see CALLBACK_addressfield_format_callback()
|
||||
*/
|
||||
function addressfield_format_address_generate(&$format, $address, $context = array()) {
|
||||
// We start with a reasonable default: a simple block format suitable
|
||||
// for international shipping. We extend it with country-specific heuristics
|
||||
// below.
|
||||
|
||||
// The street block.
|
||||
$format['street_block'] = array(
|
||||
'#type' => 'addressfield_container',
|
||||
'#attributes' => array('class' => array('street-block')),
|
||||
'#weight' => 0,
|
||||
);
|
||||
$format['street_block']['thoroughfare'] = array(
|
||||
'#title' => t('Address 1'),
|
||||
'#tag' => 'div',
|
||||
'#attributes' => array('class' => array('thoroughfare')),
|
||||
'#size' => 30,
|
||||
// The #required will be automatically set to FALSE when processing.
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$format['street_block']['premise'] = array(
|
||||
'#title' => t('Address 2'),
|
||||
'#tag' => 'div',
|
||||
'#attributes' => array('class' => array('premise')),
|
||||
'#size' => 30,
|
||||
);
|
||||
$format['locality_block'] = array(
|
||||
'#type' => 'addressfield_container',
|
||||
'#attributes' => array('class' => array('addressfield-container-inline', 'locality-block', 'country-' . $address['country'])),
|
||||
'#weight' => 50,
|
||||
);
|
||||
$format['locality_block']['#attached']['css'][] = drupal_get_path('module', 'addressfield') . '/addressfield.css';
|
||||
$format['locality_block']['postal_code'] = array(
|
||||
'#title' => t('Postal code'),
|
||||
'#size' => 10,
|
||||
'#required' => TRUE,
|
||||
'#attributes' => array('class' => array('postal-code')),
|
||||
);
|
||||
$format['locality_block']['locality'] = array(
|
||||
'#title' => t('City'),
|
||||
'#size' => 30,
|
||||
'#required' => TRUE,
|
||||
'#prefix' => ' ',
|
||||
'#attributes' => array('class' => array('locality')),
|
||||
);
|
||||
$format['country'] = array(
|
||||
'#title' => t('Country'),
|
||||
'#options' => _addressfield_country_options_list(),
|
||||
'#render_option_value' => TRUE,
|
||||
'#required' => TRUE,
|
||||
'#attributes' => array('class' => array('country')),
|
||||
'#weight' => 100,
|
||||
);
|
||||
|
||||
// Those countries do not seem to have a relevant postal code.
|
||||
static $countries_no_postal_code = array('AF', 'AG', 'AL', 'AO', 'BB', 'BI', 'BJ', 'BO', 'BS', 'BW', 'BZ', 'CF', 'CG', 'CM', 'CO', 'DJ', 'DM', 'EG', 'ER', 'FJ', 'GD', 'GH', 'GM', 'GQ', 'GY', 'HK', 'IE', 'KI', 'KM', 'KP', 'KY', 'LC', 'LY', 'ML', 'MR', 'NA', 'NR', 'RW', 'SB', 'SC', 'SL', 'SR', 'ST', 'TD', 'TG', 'TL', 'TO', 'TT', 'TV', 'TZ', 'UG', 'VC', 'VU', 'WS', 'ZW');
|
||||
if (in_array($address['country'], $countries_no_postal_code)) {
|
||||
unset($format['locality_block']['postal_code']);
|
||||
|
||||
// Remove the prefix from the first widget of the block.
|
||||
$element_children = element_children($format['locality_block']);
|
||||
$first_child = reset($element_children);
|
||||
unset($format['locality_block'][$first_child]['#prefix']);
|
||||
}
|
||||
|
||||
// Those countries generally use the administrative area in postal addresses.
|
||||
static $countries_administrative_area = array('AR', 'AU', 'BR', 'BS', 'BY', 'BZ', 'CA', 'CN', 'DO', 'EG', 'ES', 'FJ', 'FM', 'GB', 'HN', 'ID', 'IE', 'IN', 'IT', 'JO', 'JP', 'KI', 'KN', 'KR', 'KW', 'KY', 'KZ', 'MX', 'MY', 'MZ', 'NG', 'NI', 'NR', 'NZ', 'OM', 'PA', 'PF', 'PG', 'PH', 'PR', 'PW', 'RU', 'SM', 'SO', 'SR', 'SV', 'TH', 'TW', 'UA', 'US', 'UY', 'VE', 'VI', 'VN', 'YU', 'ZA');
|
||||
if (in_array($address['country'], $countries_administrative_area)) {
|
||||
$format['locality_block']['administrative_area'] = array(
|
||||
'#title' => t('State', array(), array('context' => 'addressfield')),
|
||||
'#size' => 10,
|
||||
'#required' => TRUE,
|
||||
'#prefix' => ' ',
|
||||
'#attributes' => array('class' => array('state')),
|
||||
);
|
||||
}
|
||||
|
||||
// A few countries have a well-known list of administrative divisions.
|
||||
if ($address['country'] == 'US') {
|
||||
$format['locality_block']['administrative_area']['#options'] = array(
|
||||
'' => t('--'),
|
||||
'AL' => t('Alabama'),
|
||||
'AK' => t('Alaska'),
|
||||
'AZ' => t('Arizona'),
|
||||
'AR' => t('Arkansas'),
|
||||
'CA' => t('California'),
|
||||
'CO' => t('Colorado'),
|
||||
'CT' => t('Connecticut'),
|
||||
'DE' => t('Delaware'),
|
||||
'DC' => t('District Of Columbia'),
|
||||
'FL' => t('Florida'),
|
||||
'GA' => t('Georgia'),
|
||||
'HI' => t('Hawaii'),
|
||||
'ID' => t('Idaho'),
|
||||
'IL' => t('Illinois'),
|
||||
'IN' => t('Indiana'),
|
||||
'IA' => t('Iowa'),
|
||||
'KS' => t('Kansas'),
|
||||
'KY' => t('Kentucky'),
|
||||
'LA' => t('Louisiana'),
|
||||
'ME' => t('Maine'),
|
||||
'MD' => t('Maryland'),
|
||||
'MA' => t('Massachusetts'),
|
||||
'MI' => t('Michigan'),
|
||||
'MN' => t('Minnesota'),
|
||||
'MS' => t('Mississippi'),
|
||||
'MO' => t('Missouri'),
|
||||
'MT' => t('Montana'),
|
||||
'NE' => t('Nebraska'),
|
||||
'NV' => t('Nevada'),
|
||||
'NH' => t('New Hampshire'),
|
||||
'NJ' => t('New Jersey'),
|
||||
'NM' => t('New Mexico'),
|
||||
'NY' => t('New York'),
|
||||
'NC' => t('North Carolina'),
|
||||
'ND' => t('North Dakota'),
|
||||
'OH' => t('Ohio'),
|
||||
'OK' => t('Oklahoma'),
|
||||
'OR' => t('Oregon'),
|
||||
'PA' => t('Pennsylvania'),
|
||||
'RI' => t('Rhode Island'),
|
||||
'SC' => t('South Carolina'),
|
||||
'SD' => t('South Dakota'),
|
||||
'TN' => t('Tennessee'),
|
||||
'TX' => t('Texas'),
|
||||
'UT' => t('Utah'),
|
||||
'VT' => t('Vermont'),
|
||||
'VA' => t('Virginia'),
|
||||
'WA' => t('Washington'),
|
||||
'WV' => t('West Virginia'),
|
||||
'WI' => t('Wisconsin'),
|
||||
'WY' => t('Wyoming'),
|
||||
' ' => t('--'),
|
||||
'AA' => t('Armed Forces (Americas)'),
|
||||
'AE' => t('Armed Forces (Europe, Canada, Middle East, Africa)'),
|
||||
'AP' => t('Armed Forces (Pacific)'),
|
||||
'AS' => t('American Samoa'),
|
||||
'FM' => t('Federated States of Micronesia'),
|
||||
'GU' => t('Guam'),
|
||||
'MH' => t('Marshall Islands'),
|
||||
'MP' => t('Northern Mariana Islands'),
|
||||
'PW' => t('Palau'),
|
||||
'PR' => t('Puerto Rico'),
|
||||
'VI' => t('Virgin Islands'),
|
||||
);
|
||||
$format['locality_block']['postal_code']['#title'] = t('ZIP Code');
|
||||
|
||||
if ($context['mode'] == 'render') {
|
||||
$format['locality_block']['locality']['#suffix'] = ',';
|
||||
}
|
||||
}
|
||||
else if ($address['country'] == 'IT') {
|
||||
$format['locality_block']['administrative_area']['#options'] = array(
|
||||
'' => t('--'),
|
||||
'AG' => t('Agrigento'),
|
||||
'AL' => t('Alessandria'),
|
||||
'AN' => t('Ancona'),
|
||||
'AO' => t("Valle d'Aosta/Vallée d'Aoste"),
|
||||
'AP' => t('Ascoli Piceno'),
|
||||
'AQ' => t("L'Aquila"),
|
||||
'AR' => t('Arezzo'),
|
||||
'AT' => t('Asti'),
|
||||
'AV' => t('Avellino'),
|
||||
'BA' => t('Bari'),
|
||||
'BG' => t('Bergamo'),
|
||||
'BI' => t('Biella'),
|
||||
'BL' => t('Belluno'),
|
||||
'BN' => t('Benevento'),
|
||||
'BO' => t('Bologna'),
|
||||
'BR' => t('Brindisi'),
|
||||
'BS' => t('Brescia'),
|
||||
'BT' => t('Barletta-Andria-Trani'),
|
||||
'BZ' => t('Bolzano/Bozen'),
|
||||
'CA' => t('Cagliari'),
|
||||
'CB' => t('Campobasso'),
|
||||
'CE' => t('Caserta'),
|
||||
'CH' => t('Chieti'),
|
||||
'CI' => t('Carbonia-Iglesias'),
|
||||
'CL' => t('Caltanissetta'),
|
||||
'CN' => t('Cuneo'),
|
||||
'CO' => t('Como'),
|
||||
'CR' => t('Cremona'),
|
||||
'CS' => t('Cosenza'),
|
||||
'CT' => t('Catania'),
|
||||
'CZ' => t('Catanzaro'),
|
||||
'EN' => t('Enna'),
|
||||
'FC' => t('Forlì-Cesena'),
|
||||
'FE' => t('Ferrara'),
|
||||
'FG' => t('Foggia'),
|
||||
'FI' => t('Firenze'),
|
||||
'FM' => t('Fermo'),
|
||||
'FR' => t('Frosinone'),
|
||||
'GE' => t('Genova'),
|
||||
'GO' => t('Gorizia'),
|
||||
'GR' => t('Grosseto'),
|
||||
'IM' => t('Imperia'),
|
||||
'IS' => t('Isernia'),
|
||||
'KR' => t('Crotone'),
|
||||
'LC' => t('Lecco'),
|
||||
'LE' => t('Lecce'),
|
||||
'LI' => t('Livorno'),
|
||||
'LO' => t('Lodi'),
|
||||
'LT' => t('Latina'),
|
||||
'LU' => t('Lucca'),
|
||||
'MB' => t('Monza e Brianza'),
|
||||
'MC' => t('Macerata'),
|
||||
'ME' => t('Messina'),
|
||||
'MI' => t('Milano'),
|
||||
'MN' => t('Mantova'),
|
||||
'MO' => t('Modena'),
|
||||
'MS' => t('Massa-Carrara'),
|
||||
'MT' => t('Matera'),
|
||||
'NA' => t('Napoli'),
|
||||
'NO' => t('Novara'),
|
||||
'NU' => t('Nuoro'),
|
||||
'OG' => t('Ogliastra'),
|
||||
'OR' => t('Oristano'),
|
||||
'OT' => t('Olbia-Tempio'),
|
||||
'PA' => t('Palermo'),
|
||||
'PC' => t('Piacenza'),
|
||||
'PD' => t('Padova'),
|
||||
'PE' => t('Pescara'),
|
||||
'PG' => t('Perugia'),
|
||||
'PI' => t('Pisa'),
|
||||
'PN' => t('Pordenone'),
|
||||
'PO' => t('Prato'),
|
||||
'PR' => t('Parma'),
|
||||
'PT' => t('Pistoia'),
|
||||
'PU' => t('Pesaro e Urbino'),
|
||||
'PV' => t('Pavia'),
|
||||
'PZ' => t('Potenza'),
|
||||
'RA' => t('Ravenna'),
|
||||
'RC' => t('Reggio di Calabria'),
|
||||
'RE' => t("Reggio nell'Emilia"),
|
||||
'RG' => t('Ragusa'),
|
||||
'RI' => t('Rieti'),
|
||||
'RM' => t('Roma'),
|
||||
'RN' => t('Rimini'),
|
||||
'RO' => t('Rovigo'),
|
||||
'SA' => t('Salerno'),
|
||||
'SI' => t('Siena'),
|
||||
'SO' => t('Sondrio'),
|
||||
'SP' => t('La Spezia'),
|
||||
'SR' => t('Siracusa'),
|
||||
'SS' => t('Sassari'),
|
||||
'SV' => t('Savona'),
|
||||
'TA' => t('Taranto'),
|
||||
'TE' => t('Teramo'),
|
||||
'TN' => t('Trento'),
|
||||
'TO' => t('Torino'),
|
||||
'TP' => t('Trapani'),
|
||||
'TR' => t('Terni'),
|
||||
'TS' => t('Trieste'),
|
||||
'TV' => t('Treviso'),
|
||||
'UD' => t('Udine'),
|
||||
'VA' => t('Varese'),
|
||||
'VB' => t('Verbano-Cusio-Ossola'),
|
||||
'VC' => t('Vercelli'),
|
||||
'VE' => t('Venezia'),
|
||||
'VI' => t('Vicenza'),
|
||||
'VR' => t('Verona'),
|
||||
'VS' => t('Medio Campidano'),
|
||||
'VT' => t('Viterbo'),
|
||||
'VV' => t('Vibo Valentia'),
|
||||
);
|
||||
$format['locality_block']['administrative_area']['#title'] = t('Province');
|
||||
}
|
||||
else if ($address['country'] == 'BR') {
|
||||
$format['locality_block']['administrative_area']['#render_option_value'] = TRUE;
|
||||
$format['locality_block']['administrative_area']['#options'] = array(
|
||||
'' => t('--'),
|
||||
'AC' => t('Acre'),
|
||||
'AL' => t('Alagoas'),
|
||||
'AM' => t('Amazonas'),
|
||||
'AP' => t('Amapá'),
|
||||
'BA' => t('Bahia'),
|
||||
'CE' => t('Ceará'),
|
||||
'DF' => t('Distrito Federal'),
|
||||
'ES' => t('Espírito Santo'),
|
||||
'GO' => t('Goiás'),
|
||||
'MA' => t('Maranhão'),
|
||||
'MG' => t('Minas Gerais'),
|
||||
'MS' => t('Mato Grosso do Sul'),
|
||||
'MT' => t('Mato Grosso'),
|
||||
'PA' => t('Pará'),
|
||||
'PB' => t('Paraíba'),
|
||||
'PE' => t('Pernambuco'),
|
||||
'PI' => t('Piauí'),
|
||||
'PR' => t('Paraná'),
|
||||
'RJ' => t('Rio de Janeiro'),
|
||||
'RN' => t('Rio Grande do Norte'),
|
||||
'RO' => t('Rondônia'),
|
||||
'RR' => t('Roraima'),
|
||||
'RS' => t('Rio Grande do Sul'),
|
||||
'SC' => t('Santa Catarina'),
|
||||
'SE' => t('Sergipe'),
|
||||
'SP' => t('São Paulo'),
|
||||
'TO' => t('Tocantins'),
|
||||
);
|
||||
}
|
||||
else if ($address['country'] == 'CA') {
|
||||
$format['locality_block']['administrative_area']['#options'] = array(
|
||||
'' => t('--'),
|
||||
'AB' => t('Alberta'),
|
||||
'BC' => t('British Columbia'),
|
||||
'MB' => t('Manitoba'),
|
||||
'NB' => t('New Brunswick'),
|
||||
'NL' => t('Newfoundland and Labrador'),
|
||||
'NT' => t('Northwest Territories'),
|
||||
'NS' => t('Nova Scotia'),
|
||||
'NU' => t('Nunavut'),
|
||||
'ON' => t('Ontario'),
|
||||
'PE' => t('Prince Edward Island'),
|
||||
'QC' => t('Quebec'),
|
||||
'SK' => t('Saskatchewan'),
|
||||
'YT' => t('Yukon Territory'),
|
||||
);
|
||||
$format['locality_block']['administrative_area']['#title'] = t('Province');
|
||||
|
||||
if ($context['mode'] == 'render') {
|
||||
$format['locality_block']['locality']['#suffix'] = ',';
|
||||
}
|
||||
}
|
||||
else if ($address['country'] == 'AU') {
|
||||
$format['locality_block']['administrative_area']['#options'] = array(
|
||||
'' => t('--'),
|
||||
'ACT' => t('Australian Capital Territory'),
|
||||
'NSW' => t('New South Wales'),
|
||||
'NT' => t('Northern Territory'),
|
||||
'QLD' => t('Queensland'),
|
||||
'SA' => t('South Australia'),
|
||||
'TAS' => t('Tasmania'),
|
||||
'VIC' => t('Victoria'),
|
||||
'WA' => t('Western Australia'),
|
||||
);
|
||||
}
|
||||
else if ($address['country'] == 'NZ') {
|
||||
$format['locality_block']['locality']['#title'] = ('Town/City');
|
||||
$format['locality_block']['postal_code']['#title'] = t('Postcode');
|
||||
$format['locality_block']['administrative_area']['#render_option_value'] = TRUE;
|
||||
$format['locality_block']['administrative_area']['#title'] = t('Region');
|
||||
$format['locality_block']['administrative_area']['#required'] = FALSE;
|
||||
$format['locality_block']['administrative_area']['#options'] = array(
|
||||
'' => t('--'),
|
||||
'AUK' => t('Auckland'),
|
||||
'BOP' => t('Bay of Plenty'),
|
||||
'CAN' => t('Canterbury'),
|
||||
'HKB' => t("Hawke's Bay"),
|
||||
'MWT' => t('Manawatu-Wanganui'),
|
||||
'NTL' => t('Northland'),
|
||||
'OTA' => t('Otago'),
|
||||
'STL' => t('Southland'),
|
||||
'TKI' => t('Taranaki'),
|
||||
'WKO' => t('Waikato'),
|
||||
'WGN' => t('Wellington'),
|
||||
'WTC' => t('West Coast'),
|
||||
'GIS' => t('Gisborne District'),
|
||||
'MBH' => t('Marlborough District'),
|
||||
'NSN' => t('Nelson City'),
|
||||
'TAS' => t('Tasman District'),
|
||||
'CIT' => t('Chatham Islands Territory'),
|
||||
);
|
||||
}
|
||||
|
||||
// Those countries tend to put the postal code after the locality.
|
||||
static $countries_postal_code_after_locality = array('AU', 'BD', 'BF', 'BH', 'BM', 'BN', 'BT', 'CA', 'FM', 'GB', 'ID', 'IN', 'JM', 'JO', 'KH', 'LB', 'LS', 'LV', 'MM', 'MN', 'MV', 'MW', 'NG', 'NP', 'NZ', 'PE', 'PK', 'PR', 'PW', 'SA', 'SG', 'SO', 'TH', 'US', 'VI', 'VG', 'VN');
|
||||
if (in_array($address['country'], $countries_postal_code_after_locality)) {
|
||||
// Take the widget out of the array.
|
||||
$postal_code_widget = $format['locality_block']['postal_code'];
|
||||
$postal_code_widget['#prefix'] = ' ';
|
||||
unset($format['locality_block']['postal_code']);
|
||||
|
||||
// Add it back.
|
||||
$format['locality_block']['postal_code'] = $postal_code_widget;
|
||||
|
||||
// Remove the prefix from the first widget of the block.
|
||||
$element_children = element_children($format['locality_block']);
|
||||
$first_child = reset($element_children);
|
||||
unset($format['locality_block'][$first_child]['#prefix']);
|
||||
}
|
||||
|
||||
// GB-specific tweaks
|
||||
if ($address['country'] == 'GB') {
|
||||
// Locality
|
||||
$format['locality_block']['locality'] = array_merge(
|
||||
$format['locality_block']['locality'],
|
||||
array(
|
||||
'#title' => t('Town/City'),
|
||||
'#weight' => 40,
|
||||
'#prefix' => '',
|
||||
'#tag' => 'div',
|
||||
)
|
||||
);
|
||||
|
||||
// Administrative
|
||||
$format['locality_block']['administrative_area'] = array_merge(
|
||||
$format['locality_block']['administrative_area'],
|
||||
array(
|
||||
'#title' => t('County'),
|
||||
'#required' => FALSE,
|
||||
'#weight' => 50,
|
||||
'#size' => 30,
|
||||
'#prefix' => '',
|
||||
'#tag' => 'div',
|
||||
)
|
||||
);
|
||||
|
||||
// Postal code
|
||||
$format['locality_block']['postal_code'] = array_merge(
|
||||
$format['locality_block']['postal_code'],
|
||||
array(
|
||||
'#title' => t('Postcode'),
|
||||
'#weight' => 60,
|
||||
'#prefix' => '',
|
||||
'#tag' => 'div',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($context['mode'] == 'form') {
|
||||
// Provide a wrapper ID for AJAX replacement based on country selection.
|
||||
if (!isset($format['#wrapper_id'])) {
|
||||
$format['#wrapper_id'] = drupal_html_id('addressfield-wrapper');
|
||||
$format['#prefix'] = '<div id="' . $format['#wrapper_id'] . '">';
|
||||
$format['#suffix'] = '</div>';
|
||||
}
|
||||
|
||||
// Form mode, move the country selector to the top of the form.
|
||||
$format['country']['#weight'] = -10;
|
||||
|
||||
// Limit it to the countries supported by the widget.
|
||||
if (isset($context['field'])) {
|
||||
$format['country']['#options'] = _addressfield_country_options_list($context['field'], $context['instance']);
|
||||
}
|
||||
|
||||
// AJAX enable it.
|
||||
$format['country']['#ajax'] = array(
|
||||
'callback' => 'addressfield_standard_widget_refresh',
|
||||
'wrapper' => $format['#wrapper_id'],
|
||||
);
|
||||
$format['country']['#element_validate'] = array('addressfield_standard_country_validate');
|
||||
// Don't validate any element when the country is changed.
|
||||
$format['country']['#limit_validation_errors'] = array();
|
||||
|
||||
if (isset($context['delta']) && $context['delta'] > 0) {
|
||||
// On subsequent elements of a field, we make the country field non
|
||||
// required and add a ' - None - ' option to it, so as to allow the
|
||||
// user to remove the address by clearing the country field.
|
||||
$format['country']['#required'] = FALSE;
|
||||
$format['country']['#empty_value'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Generates a first name + last name format.
|
||||
*/
|
||||
|
||||
$plugin = array(
|
||||
'title' => t('Name (First name, Last name)'),
|
||||
'format callback' => 'addressfield_format_name_full_generate',
|
||||
'type' => 'name',
|
||||
'weight' => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* Format callback.
|
||||
*
|
||||
* @see CALLBACK_addressfield_format_callback()
|
||||
*/
|
||||
function addressfield_format_name_full_generate(&$format, $address) {
|
||||
$format['name_block'] = array(
|
||||
'#type' => 'addressfield_container',
|
||||
'#attributes' => array('class' => array('addressfield-container-inline', 'name-block')),
|
||||
'#weight' => -100,
|
||||
);
|
||||
$format['name_block']['first_name'] = array(
|
||||
'#title' => t('First name'),
|
||||
'#size' => 30,
|
||||
'#required' => TRUE,
|
||||
'#attributes' => array('class' => array('first-name')),
|
||||
);
|
||||
$format['name_block']['last_name'] = array(
|
||||
'#title' => t('Last name'),
|
||||
'#size' => 30,
|
||||
'#required' => TRUE,
|
||||
'#prefix' => ' ',
|
||||
'#attributes' => array('class' => array('last-name')),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Generates a first name + last name format.
|
||||
*/
|
||||
|
||||
$plugin = array(
|
||||
'title' => t('Name (single line)'),
|
||||
'format callback' => 'addressfield_format_name_oneline_generate',
|
||||
'type' => 'name',
|
||||
'weight' => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* Format callback.
|
||||
*
|
||||
* @see CALLBACK_addressfield_format_callback()
|
||||
*/
|
||||
function addressfield_format_name_oneline_generate(&$format, $address) {
|
||||
$format['name_block'] = array(
|
||||
'#type' => 'addressfield_container',
|
||||
'#attributes' => array('class' => array('addressfield-container-inline', 'name-block')),
|
||||
'#weight' => -100,
|
||||
);
|
||||
$format['name_block']['name_line'] = array(
|
||||
'#title' => t('Full name'),
|
||||
'#tag' => 'div',
|
||||
'#attributes' => array('class' => array('name-block')),
|
||||
'#size' => 30,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Generates a first name + last name format.
|
||||
*/
|
||||
|
||||
$plugin = array(
|
||||
'title' => t('Organisation (single line)'),
|
||||
'format callback' => 'addressfield_format_organisation_generate',
|
||||
'type' => 'organisation',
|
||||
'weight' => -10,
|
||||
);
|
||||
|
||||
/**
|
||||
* Format callback.
|
||||
*
|
||||
* @see CALLBACK_addressfield_format_callback()
|
||||
*/
|
||||
function addressfield_format_organisation_generate(&$format, $address) {
|
||||
$format['organisation_block'] = array(
|
||||
'#type' => 'addressfield_container',
|
||||
'#attributes' => array('class' => array('addressfield-container-inline', 'name-block')),
|
||||
'#weight' => -50,
|
||||
);
|
||||
$format['organisation_block']['organisation_name'] = array(
|
||||
'#title' => t('Company'),
|
||||
'#size' => 30,
|
||||
'#attributes' => array('class' => array('organisation-name')),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_field_views_data().
|
||||
*/
|
||||
function addressfield_field_views_data($field) {
|
||||
$data = field_views_field_default_views_data($field);
|
||||
|
||||
// Add a handler for countries.
|
||||
foreach ($field['storage']['details']['sql'] as $type => $tables) {
|
||||
foreach ($tables as $table_name => $columns) {
|
||||
if (!isset($columns['country'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$column_real_name = $columns['country'];
|
||||
if (!isset($data[$table_name][$column_real_name]['filter'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[$table_name][$column_real_name]['filter']['handler'] = 'addressfield_views_handler_filter_country';
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class addressfield_views_handler_filter_country extends views_handler_filter_in_operator {
|
||||
function get_value_options() {
|
||||
$this->value_title = t('Country');
|
||||
$field = field_info_field($this->definition['field_name']);
|
||||
$this->value_options = _addressfield_country_options_list($field);
|
||||
}
|
||||
}
|
||||
339
sites/all/modules/contrib/fields/autocomplete_deluxe/LICENSE.txt
Normal file
339
sites/all/modules/contrib/fields/autocomplete_deluxe/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
Enhanced autocomplete widget for drupal 7.x
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This contains documentation only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Using the Autocomplete Deluxe element.
|
||||
*
|
||||
* When you want to use the Autocomplete Deluxe element, you have to choose
|
||||
* between two types sources for the suggestion data: Ajax Callbacks or Lists.
|
||||
* You can set the source type by using the appropriate options:
|
||||
* - #autocomplete_deluxe_path expects a string with an url, that points to the ajax
|
||||
* callback. The response should be encoded as json(like for the core
|
||||
* autocomplete).
|
||||
* - #autocomplete_options needs an array in the form of an array(similar to #options in core
|
||||
* for selects or checkboxes): array('a', 'b', 'c') or array(1 => 'a', 2 =>
|
||||
* 'b', 3 => 'c').
|
||||
*
|
||||
* Besides this two, there are three other options, wich autocomplete deluxe
|
||||
* accepts:
|
||||
* - #multiple Indicates whether the user may select more than one item. Expects
|
||||
* TRUE or FALSE, by default it is set to FALSE.
|
||||
* - #autocomplete_multiple_delimiter If #multiple is TRUE, then you can use
|
||||
* this option to set a seperator for multiple values. By default a string
|
||||
* with the follwing content will be used: ', '.
|
||||
* - #autocomplete_min_length Indicates how many characters must be entered
|
||||
* until, the suggesion list can be opened. Especially helpfull, when your
|
||||
* ajax callback returns only valid suggestion for a minimum characters.
|
||||
* The default is 0.
|
||||
*/
|
||||
function somefunction() {
|
||||
switch ($type) {
|
||||
case 'list':
|
||||
$element = array(
|
||||
'#type' => 'autocomplete_deluxe',
|
||||
'#autocomplete_options' => $options,
|
||||
'#multiple' => FALSE,
|
||||
'#autocomplete_min_length' => 0,
|
||||
);
|
||||
break;
|
||||
case 'ajax':
|
||||
$element = array(
|
||||
'#type' => 'autocomplete_deluxe',
|
||||
'#autocomplete_deluxe_path' => url('some_uri', array('absolute' => TRUE)),
|
||||
'#multiple' => TRUE,
|
||||
'#autocomplete_min_length' => 1,
|
||||
'#autocomplete_multiple_delimiter' => '|',
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
|
||||
ul.ui-autocomplete {
|
||||
max-height: 240px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
a.autocomplete-deluxe-single:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ui-autocomplete .ui-state-hover {
|
||||
background-color: #3875d7;
|
||||
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
|
||||
background-image: -webkit-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
|
||||
background-image: -moz-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
|
||||
background-image: -o-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
|
||||
background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
|
||||
background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%);
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
border: 1px solid #CCCCCC;
|
||||
background: no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
|
||||
background: no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
}
|
||||
div.autocomplete-deluxe-container input.autocomplete-deluxe-form {
|
||||
background: #fff no-repeat -38px -22px;
|
||||
padding: 4px 5px 4px 5px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.autocomplete-deluxe-container input.autocomplete-deluxe-form-single {
|
||||
width: 90%;
|
||||
border: none;
|
||||
background: no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
|
||||
background: no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-search {
|
||||
margin: 0px 0px 4px 0px;
|
||||
padding: 3px 4px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
z-index: 1010;
|
||||
}
|
||||
|
||||
span.autocomplete-deluxe-value-delete {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
background:url('x.gif') no-repeat center;
|
||||
width: 18px;
|
||||
width: 18px;
|
||||
|
||||
/* Prevent text selection. */
|
||||
-moz-user-select: -moz-none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-single-open {
|
||||
border: 1px solid #aaa;
|
||||
-webkit-box-shadow: 0 1px 0 #fff inset;
|
||||
-moz-box-shadow : 0 1px 0 #fff inset;
|
||||
-o-box-shadow : 0 1px 0 #fff inset;
|
||||
box-shadow : 0 1px 0 #fff inset;
|
||||
background-color: #eee;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 );
|
||||
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
|
||||
background-image: -moz-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
|
||||
background-image: -ms-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
|
||||
background-image: linear-gradient(top, #eeeeee 20%, #ffffff 80%);
|
||||
-webkit-border-bottom-left-radius : 0;
|
||||
-webkit-border-bottom-right-radius: 0;
|
||||
-moz-border-radius-bottomleft : 0;
|
||||
-moz-border-radius-bottomright: 0;
|
||||
border-bottom-left-radius : 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
input.autocomplete-deluxe-closed {
|
||||
}
|
||||
|
||||
div.autocomplete-deluxe-multiple {
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
position: relative;
|
||||
background-color: #FFFFFF;
|
||||
background: #fff no-repeat -38px -22px;
|
||||
background: no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
|
||||
background: no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
background: no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%);
|
||||
padding: 4px 5px 4px 20px;
|
||||
border: 1px solid #AAAAAA;
|
||||
cursor: text;
|
||||
height: auto !important;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
line-height:15pt;
|
||||
width: 503px;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
input.autocomplete-deluxe-form.autocomplete-deluxe-multiple {
|
||||
border: 3px none;
|
||||
width: 25px;
|
||||
margin-left: 5px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.autocomplete-deluxe-throbber {
|
||||
width: 16px;
|
||||
float: right;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-closed {
|
||||
background: url(throbber.gif) no-repeat 100% 6px;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-open {
|
||||
background: url(throbber.gif) no-repeat 100% -14px;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-item {
|
||||
float: left;
|
||||
background-clip: padding-box;
|
||||
background-color: #E4E4E4;
|
||||
background-image: -moz-linear-gradient(center top , #F4F4F4 20%, #F0F0F0 50%, #E8E8E8 52%, #EEEEEE 100%);
|
||||
border: 1px solid #AAAAAA;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
box-shadow: 0 0 2px #FFFFFF inset, 0 1px 0 rgba(0, 0, 0, 0.05);
|
||||
color: #333333;
|
||||
cursor: default;
|
||||
line-height: 13px;
|
||||
margin: 3px 0 3px 5px;
|
||||
padding: 3px 20px 3px 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-item-delete {
|
||||
background: url("x.gif");
|
||||
display: block;
|
||||
font-size: 1px;
|
||||
height: 13px;
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
width: 12px;
|
||||
}
|
||||
.autocomplete-deluxe-item-focus {
|
||||
background: none repeat scroll 0 0 #D4D4D4;
|
||||
}
|
||||
|
||||
.autocomplete-deluxe-highlight-char {
|
||||
color: blue;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
name = Autocomplete Deluxe
|
||||
description = Enhanced autocomplete using Jquery UI autocomplete.
|
||||
package = User interface
|
||||
core = 7.x
|
||||
files[] = autocomplete_deluxe.module
|
||||
dependencies[] = taxonomy
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-05
|
||||
version = "7.x-2.0-beta3"
|
||||
core = "7.x"
|
||||
project = "autocomplete_deluxe"
|
||||
datestamp = "1375695669"
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
|
||||
/**
|
||||
* @file:
|
||||
* Converts textfield to a autocomplete deluxe widget.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
Drupal.autocomplete_deluxe = Drupal.autocomplete_deluxe || {};
|
||||
|
||||
Drupal.behaviors.autocomplete_deluxe = {
|
||||
attach: function(context) {
|
||||
var autocomplete_settings = Drupal.settings.autocomplete_deluxe;
|
||||
|
||||
$('input.autocomplete-deluxe-form').once( function() {
|
||||
if (autocomplete_settings[$(this).attr('id')].multiple === true) {
|
||||
new Drupal.autocomplete_deluxe.MultipleWidget(this, autocomplete_settings[$(this).attr('id')]);
|
||||
} else {
|
||||
new Drupal.autocomplete_deluxe.SingleWidget(autocomplete_settings[$(this).attr('id')]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Autogrow plugin which auto resizes the input of the multiple value.
|
||||
*
|
||||
* http://stackoverflow.com/questions/931207/is-there-a-jquery-autogrow-plugin-for-text-fields
|
||||
*
|
||||
*/
|
||||
$.fn.autoGrowInput = function(o) {
|
||||
|
||||
o = $.extend({
|
||||
maxWidth: 1000,
|
||||
minWidth: 0,
|
||||
comfortZone: 70
|
||||
}, o);
|
||||
|
||||
this.filter('input:text').each(function(){
|
||||
|
||||
var minWidth = o.minWidth || $(this).width(),
|
||||
val = '',
|
||||
input = $(this),
|
||||
testSubject = $('<tester/>').css({
|
||||
position: 'absolute',
|
||||
top: -9999,
|
||||
left: -9999,
|
||||
width: 'auto',
|
||||
fontSize: input.css('fontSize'),
|
||||
fontFamily: input.css('fontFamily'),
|
||||
fontWeight: input.css('fontWeight'),
|
||||
letterSpacing: input.css('letterSpacing'),
|
||||
whiteSpace: 'nowrap'
|
||||
}),
|
||||
check = function() {
|
||||
|
||||
if (val === (val = input.val())) {return;}
|
||||
|
||||
// Enter new content into testSubject
|
||||
var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
|
||||
testSubject.html(escaped);
|
||||
|
||||
// Calculate new width + whether to change
|
||||
var testerWidth = testSubject.width(),
|
||||
newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
|
||||
currentWidth = input.width(),
|
||||
isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
|
||||
|| (newWidth > minWidth && newWidth < o.maxWidth);
|
||||
|
||||
// Animate width
|
||||
if (isValidWidthChange) {
|
||||
input.width(newWidth);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
testSubject.insertAfter(input);
|
||||
|
||||
$(this).bind('keyup keydown blur update', check);
|
||||
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Drupal.autocomplete_deluxe.empty = {label: '- ' + Drupal.t('None') + ' -', value: "" };
|
||||
|
||||
/**
|
||||
* EscapeRegex function from jquery autocomplete, is not included in drupal.
|
||||
*/
|
||||
Drupal.autocomplete_deluxe.escapeRegex = function(value) {
|
||||
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/gi, "\\$&");
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter function from jquery autocomplete, is not included in drupal.
|
||||
*/
|
||||
Drupal.autocomplete_deluxe.filter = function(array, term) {
|
||||
var matcher = new RegExp(Drupal.autocomplete_deluxe.escapeRegex(term), "i");
|
||||
return $.grep(array, function(value) {
|
||||
return matcher.test(value.label || value.value || value);
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.Widget = function() {
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.Widget.prototype.uri = null;
|
||||
|
||||
/**
|
||||
* Allows widgets to filter terms.
|
||||
* @param term
|
||||
* A term that should be accepted or not.
|
||||
* @return {Boolean}
|
||||
* True if the term should be accepted.
|
||||
*/
|
||||
Drupal.autocomplete_deluxe.Widget.prototype.acceptTerm = function(term) {
|
||||
return true;
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.Widget.prototype.init = function(settings) {
|
||||
if ($.browser.msie && $.browser.version === "6.0") {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = settings.input_id;
|
||||
this.jqObject = $('#' + this.id);
|
||||
|
||||
this.uri = settings.uri;
|
||||
this.multiple = settings.multiple;
|
||||
this.required = settings.required;
|
||||
this.limit = settings.limit;
|
||||
this.synonyms = typeof settings.use_synonyms == 'undefined' ? false : settings.use_synonyms;
|
||||
|
||||
this.wrapper = '""';
|
||||
|
||||
if (typeof settings.delimiter == 'undefined') {
|
||||
this.delimiter = true;
|
||||
} else {
|
||||
this.delimiter = settings.delimiter.charCodeAt(0);
|
||||
}
|
||||
|
||||
|
||||
this.items = {};
|
||||
|
||||
var self = this;
|
||||
var parent = this.jqObject.parent();
|
||||
var parents_parent = this.jqObject.parent().parent();
|
||||
|
||||
parents_parent.append(this.jqObject);
|
||||
parent.remove();
|
||||
parent = parents_parent;
|
||||
|
||||
var generateValues = function(data, term) {
|
||||
var result = new Array();
|
||||
for (var terms in data) {
|
||||
if (self.acceptTerm(terms)) {
|
||||
result.push({
|
||||
label: data[terms],
|
||||
value: terms
|
||||
});
|
||||
}
|
||||
}
|
||||
if ($.isEmptyObject(result)) {
|
||||
result.push({
|
||||
label: Drupal.t("The term '@term' will be added.", {'@term' : term}),
|
||||
value: term,
|
||||
newTerm: true
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var cache = {}
|
||||
var lastXhr = null;
|
||||
|
||||
this.source = function(request, response) {
|
||||
var term = request.term;
|
||||
if (term in cache) {
|
||||
response(generateValues(cache[term], term));
|
||||
return;
|
||||
}
|
||||
|
||||
// Some server collapse two slashes if the term is empty, so insert at
|
||||
// least a whitespace. This whitespace will later on be trimmed in the
|
||||
// autocomplete callback.
|
||||
if (!term) {
|
||||
term = " ";
|
||||
}
|
||||
request.synonyms = self.synonyms;
|
||||
var url = settings.uri + '/' + term +'/' + self.limit;
|
||||
lastXhr = $.getJSON(url, request, function(data, status, xhr) {
|
||||
cache[term] = data;
|
||||
if (xhr === lastXhr) {
|
||||
response(generateValues(data, term));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.jqObject.autocomplete({
|
||||
'source' : this.source,
|
||||
'minLength': settings.min_length
|
||||
});
|
||||
|
||||
var jqObject = this.jqObject;
|
||||
var throbber = $('<div class="autocomplete-deluxe-throbber autocomplete-deluxe-closed"> </div>').insertAfter(jqObject);
|
||||
|
||||
this.jqObject.bind("autocompletesearch", function(event, ui) {
|
||||
throbber.removeClass('autocomplete-deluxe-closed');
|
||||
throbber.addClass('autocomplete-deluxe-open');
|
||||
});
|
||||
|
||||
this.jqObject.bind("autocompleteopen", function(event, ui) {
|
||||
throbber.addClass('autocomplete-deluxe-closed');
|
||||
throbber.removeClass('autocomplete-deluxe-open');
|
||||
});
|
||||
|
||||
// Monkey patch the _renderItem function jquery so we can highlight the
|
||||
// text, that we already entered.
|
||||
$.ui.autocomplete.prototype._renderItem = function( ul, item) {
|
||||
var t = item.label;
|
||||
if (this.term != "") {
|
||||
var escapedValue = Drupal.autocomplete_deluxe.escapeRegex( this.term );
|
||||
var re = new RegExp('()*""' + escapedValue + '""|' + escapedValue + '()*', 'gi');
|
||||
var t = item.label.replace(re,"<span class='autocomplete-deluxe-highlight-char'>$&</span>");
|
||||
}
|
||||
return $( "<li></li>" )
|
||||
.data( "item.autocomplete", item )
|
||||
.append( "<a>" + t + "</a>" )
|
||||
.appendTo( ul );
|
||||
};
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.Widget.prototype.generateValues = function(data) {
|
||||
var result = new Array();
|
||||
for (var index in data) {
|
||||
result.push(data[index]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a single selecting widget.
|
||||
*/
|
||||
Drupal.autocomplete_deluxe.SingleWidget = function(settings) {
|
||||
this.init(settings);
|
||||
this.setup();
|
||||
this.jqObject.addClass('autocomplete-deluxe-form-single');
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.SingleWidget.prototype = new Drupal.autocomplete_deluxe.Widget();
|
||||
|
||||
Drupal.autocomplete_deluxe.SingleWidget.prototype.setup = function() {
|
||||
var jqObject = this.jqObject;
|
||||
var parent = jqObject.parent();
|
||||
|
||||
parent.mousedown(function() {
|
||||
if (parent.hasClass('autocomplete-deluxe-single-open')) {
|
||||
jqObject.autocomplete('close');
|
||||
} else {
|
||||
jqObject.autocomplete('search', '');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a multiple selecting widget.
|
||||
*/
|
||||
Drupal.autocomplete_deluxe.MultipleWidget = function(input, settings) {
|
||||
this.init(settings);
|
||||
this.setup();
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.MultipleWidget.prototype = new Drupal.autocomplete_deluxe.Widget();
|
||||
Drupal.autocomplete_deluxe.MultipleWidget.prototype.items = new Object();
|
||||
|
||||
|
||||
Drupal.autocomplete_deluxe.MultipleWidget.prototype.acceptTerm = function(term) {
|
||||
// Accept only terms, that are not in our items list.
|
||||
return !(term in this.items);
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.MultipleWidget.Item = function (widget, item) {
|
||||
if (item.newTerm === true) {
|
||||
item.label = item.value;
|
||||
}
|
||||
|
||||
this.value = item.value;
|
||||
this.element = $('<span class="autocomplete-deluxe-item">' + item.label + '</span>');
|
||||
this.widget = widget;
|
||||
this.item = item;
|
||||
var self = this;
|
||||
|
||||
var close = $('<a class="autocomplete-deluxe-item-delete" href="javascript:void(0)"></a>').appendTo(this.element);
|
||||
// Use single quotes because of the double quote encoded stuff.
|
||||
var input = $('<input type="hidden" value=\'' + this.value + '\'/>').appendTo(this.element);
|
||||
|
||||
close.mousedown(function() {
|
||||
self.remove(item);
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.MultipleWidget.Item.prototype.remove = function() {
|
||||
this.element.remove();
|
||||
var values = this.widget.valueForm.val();
|
||||
var escapedValue = Drupal.autocomplete_deluxe.escapeRegex( this.item.value );
|
||||
var regex = new RegExp('()*""' + escapedValue + '""|' + escapedValue + '()*', 'gi');
|
||||
this.widget.valueForm.val(values.replace(regex, ''));
|
||||
delete this.widget.items[this.value];
|
||||
};
|
||||
|
||||
Drupal.autocomplete_deluxe.MultipleWidget.prototype.setup = function() {
|
||||
var jqObject = this.jqObject;
|
||||
var parent = jqObject.parent();
|
||||
var value_container = jqObject.parent().parent().children('.autocomplete-deluxe-value-container');
|
||||
var value_input = value_container.children().children();
|
||||
var items = this.items;
|
||||
var self = this;
|
||||
this.valueForm = value_input;
|
||||
|
||||
// Override the resize function, so that the suggestion list doesn't resizes
|
||||
// all the time.
|
||||
jqObject.data("autocomplete")._resizeMenu = function() {};
|
||||
|
||||
jqObject.show();
|
||||
|
||||
value_container.hide();
|
||||
|
||||
// Add the default values to the box.
|
||||
var default_values = value_input.val();
|
||||
default_values = $.trim(default_values);
|
||||
default_values = default_values.substr(2, default_values.length-4);
|
||||
default_values = default_values.split('"" ""');
|
||||
|
||||
for (var index in default_values) {
|
||||
var value = default_values[index];
|
||||
if (value != '') {
|
||||
// If a terms is encoded in double quotes, then the label should have
|
||||
// no double quotes.
|
||||
var label = value.match(/["][\w|\s|\D|]*["]/gi) !== null ? value.substr(1, value.length-2) : value;
|
||||
var item = {
|
||||
label : label,
|
||||
value : value
|
||||
};
|
||||
var item = new Drupal.autocomplete_deluxe.MultipleWidget.Item(self, item);
|
||||
item.element.insertBefore(jqObject);
|
||||
items[item.value] = item;
|
||||
}
|
||||
}
|
||||
|
||||
jqObject.addClass('autocomplete-deluxe-multiple');
|
||||
parent.addClass('autocomplete-deluxe-multiple');
|
||||
|
||||
|
||||
// Adds a value to the list.
|
||||
this.addValue = function(ui_item) {
|
||||
var item = new Drupal.autocomplete_deluxe.MultipleWidget.Item(self, ui_item);
|
||||
item.element.insertBefore(jqObject);
|
||||
items[ui_item.value] = item;
|
||||
var new_value = ' ' + self.wrapper + ui_item.value + self.wrapper;
|
||||
var values = value_input.val();
|
||||
value_input.val(values + new_value);
|
||||
jqObject.val('');
|
||||
};
|
||||
|
||||
parent.mouseup(function() {
|
||||
jqObject.autocomplete('search', '');
|
||||
jqObject.focus();
|
||||
});
|
||||
|
||||
jqObject.bind("autocompleteselect", function(event, ui) {
|
||||
self.addValue(ui.item);
|
||||
jqObject.width(25);
|
||||
// Return false to prevent setting the last term as value for the jqObject.
|
||||
return false;
|
||||
});
|
||||
|
||||
jqObject.bind("autocompletechange", function(event, ui) {
|
||||
jqObject.val('');
|
||||
});
|
||||
|
||||
jqObject.blur(function() {
|
||||
var last_element = jqObject.parent().children('.autocomplete-deluxe-item').last();
|
||||
last_element.removeClass('autocomplete-deluxe-item-focus');
|
||||
});
|
||||
|
||||
var clear = false;
|
||||
|
||||
jqObject.keypress(function (event) {
|
||||
var value = jqObject.val();
|
||||
// If a comma was entered and there is none or more then one comma,or the
|
||||
// enter key was entered, then enter the new term.
|
||||
if ((event.which == self.delimiter && (value.split('"').length - 1) != 1) || (event.which == 13 && jqObject.val() != "")) {
|
||||
value = value.substr(0, value.length);
|
||||
if (typeof self.items[value] == 'undefined' && value != '') {
|
||||
var ui_item = {
|
||||
label: value,
|
||||
value: value
|
||||
};
|
||||
self.addValue(ui_item);
|
||||
}
|
||||
clear = true;
|
||||
if (event.which == 13) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the Backspace key was hit and the input is empty
|
||||
if (event.which == 8 && value == '') {
|
||||
var last_element = jqObject.parent().children('.autocomplete-deluxe-item').last();
|
||||
// then mark the last item for deletion or deleted it if already marked.
|
||||
if (last_element.hasClass('autocomplete-deluxe-item-focus')) {
|
||||
var value = last_element.children('input').val();
|
||||
self.items[value].remove(self.items[value]);
|
||||
jqObject.autocomplete('search', '');
|
||||
} else {
|
||||
last_element.addClass('autocomplete-deluxe-item-focus');
|
||||
}
|
||||
} else {
|
||||
// Remove the focus class if any other key was hit.
|
||||
var last_element = jqObject.parent().children('.autocomplete-deluxe-item').last();
|
||||
last_element.removeClass('autocomplete-deluxe-item-focus');
|
||||
}
|
||||
});
|
||||
|
||||
jqObject.autoGrowInput({
|
||||
comfortZone: 50,
|
||||
minWidth: 10,
|
||||
maxWidth: 460
|
||||
});
|
||||
|
||||
|
||||
jqObject.keyup(function (event) {
|
||||
if (clear) {
|
||||
// Trigger the search, so it display the values for an empty string.
|
||||
jqObject.autocomplete('search', '');
|
||||
jqObject.val('');
|
||||
clear = false;
|
||||
// Return false to prevent entering the last character.
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Define enhanced autocomplete wdiget.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_info().
|
||||
*/
|
||||
function autocomplete_deluxe_field_widget_info() {
|
||||
return array(
|
||||
'autocomplete_deluxe_taxonomy' => array(
|
||||
'label' => t('Autocomplete Deluxe'),
|
||||
'field types' => array('taxonomy_term_reference'),
|
||||
'settings' => array(
|
||||
'size' => 60,
|
||||
'autocomplete_deluxe_path' => 'autocomplete_deluxe/taxonomy',
|
||||
),
|
||||
'behaviors' => array(
|
||||
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom taxonomy callback, which also accepts an empty string search.
|
||||
*/
|
||||
function taxonomy_autocomplete_deluxe($field_name, $tags_typed = '', $limit = 10) {
|
||||
$field = field_info_field($field_name);
|
||||
$use_synonyms = !empty($_GET['synonyms']);
|
||||
|
||||
// The user enters a comma-separated list of tags. We only autocomplete the last tag.
|
||||
$tags_typed = drupal_explode_tags($tags_typed);
|
||||
$tag_last = drupal_strtolower(array_pop($tags_typed));
|
||||
|
||||
$matches = array();
|
||||
|
||||
// Part of the criteria for the query come from the field's own settings.
|
||||
$vids = array();
|
||||
$vocabularies = taxonomy_vocabulary_get_names();
|
||||
foreach ($field['settings']['allowed_values'] as $tree) {
|
||||
// If the content taxonomy setting content_taxonomy_ignore_in_suggestions
|
||||
// is set, then the vocabulary is ignored.
|
||||
if (empty($tree['content_taxonomy_ignore_in_suggestions'])) {
|
||||
$vids[] = $vocabularies[$tree['vocabulary']]->vid;
|
||||
}
|
||||
}
|
||||
|
||||
$query = db_select('taxonomy_term_data', 't');
|
||||
$query->addTag('translatable');
|
||||
$query->addTag('term_access');
|
||||
|
||||
if (module_exists('synonyms') && !empty($use_synonyms)) {
|
||||
$query->leftJoin('field_data_synonyms_synonym', 'fdss', 'fdss.entity_id = t.tid');
|
||||
}
|
||||
|
||||
if ($tag_last != '') {
|
||||
// Do not select already entered terms.
|
||||
if (!empty($tags_typed)) {
|
||||
$query->condition('t.name', $tags_typed, 'NOT IN');
|
||||
}
|
||||
// Select rows that match by term name.
|
||||
$query
|
||||
->fields('t', array('tid', 'name'))
|
||||
->condition('t.vid', $vids);
|
||||
|
||||
if (module_exists('synonyms') && !empty($use_synonyms)) {
|
||||
$or = db_or();
|
||||
$or->condition('fdss.synonyms_synonym_value', '%' . db_like($tag_last) . '%', 'LIKE');
|
||||
$or->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE');
|
||||
$query->condition($or);
|
||||
}
|
||||
else {
|
||||
$query->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE');
|
||||
}
|
||||
|
||||
if (isset($limit) && $limit > 0) {
|
||||
$query->range(0, $limit);
|
||||
}
|
||||
|
||||
$tags_return = $query->execute()
|
||||
->fetchAllKeyed();
|
||||
}
|
||||
else {
|
||||
$query
|
||||
->fields('t', array('tid', 'name'))
|
||||
->condition('t.vid', $vids);
|
||||
|
||||
if (isset($limit) && $limit > 0) {
|
||||
$query->range(0, $limit);
|
||||
}
|
||||
|
||||
$tags_return = $query->execute()
|
||||
->fetchAllKeyed();
|
||||
}
|
||||
|
||||
$prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
|
||||
|
||||
$term_matches = array();
|
||||
foreach ($tags_return as $tid => $name) {
|
||||
$n = $name;
|
||||
// Term names containing commas or quotes must be wrapped in quotes.
|
||||
if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
|
||||
$n = '"' . str_replace('"', '""', $name) . '"';
|
||||
}
|
||||
$term_matches[$prefix . $n] = check_plain($name);
|
||||
}
|
||||
|
||||
drupal_json_output($term_matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all allowed terms for a field without any prefix.
|
||||
*/
|
||||
function autocomplete_deluxe_allowed_terms($field) {
|
||||
$options = array();
|
||||
foreach ($field['settings']['allowed_values'] as $tree) {
|
||||
if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
|
||||
if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'])) {
|
||||
foreach ($terms as $term) {
|
||||
$options[$term->name] = $term->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_settings_form().
|
||||
*/
|
||||
function autocomplete_deluxe_field_widget_settings_form($field, $instance) {
|
||||
$widget = $instance['widget'];
|
||||
$settings = $widget['settings'];
|
||||
|
||||
$form['size'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Size of textfield'),
|
||||
'#default_value' => isset($settings['size']) ? $settings['size'] : 6,
|
||||
'#element_validate' => array('_element_validate_integer_positive'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['limit'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Limit of the output.'),
|
||||
'#description' => t('If set to zero no limit will be used'),
|
||||
'#default_value' => isset($settings['limit']) ? $settings['limit'] : 10,
|
||||
'#element_validate' => array('_element_validate_integer'),
|
||||
);
|
||||
$form['min_length'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Mininum length.'),
|
||||
'#description' => t('The minimum length of characters to enter to open the suggestion list.'),
|
||||
'#default_value' => isset($settings['min_length']) ? $settings['min_length'] : 0,
|
||||
'#element_validate' => array('_element_validate_integer'),
|
||||
);
|
||||
$form['delimiter'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Delimiter.'),
|
||||
'#description' => t('A character which should be used beside the enter key, to seperate terms.'),
|
||||
'#default_value' => isset($settings['delimiter']) ? $settings['delimiter'] : '',
|
||||
'#size' => 1,
|
||||
);
|
||||
|
||||
if (module_exists('synonyms')) {
|
||||
$form['use_synonyms'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow synonyms'),
|
||||
'#description' => t('Should users be able to search for synonyms of terms?'),
|
||||
'#default_value' => isset($settings['use_synonyms']) ? $settings['use_synonyms'] : FALSE,
|
||||
);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implodes the tags from the taxonomy module.
|
||||
*
|
||||
* This function is essentially the same as axonomy_implode_tags, with the
|
||||
* difference, that it uses only a comma instead of a comma and a space to
|
||||
* implode the tags. It will help keep problems with delimiters to a minimum.
|
||||
*/
|
||||
function autocomplete_deluxe_taxonomy_implode_tags($tags, $vid = NULL) {
|
||||
$typed_tags = array();
|
||||
foreach ($tags as $tag) {
|
||||
// Extract terms belonging to the vocabulary in question.
|
||||
if (!isset($vid) || $tag->vid == $vid) {
|
||||
// Make sure we have a completed loaded taxonomy term.
|
||||
if (isset($tag->name)) {
|
||||
// Commas and quotes in tag names are special cases, so encode 'em.
|
||||
if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
|
||||
$tag->name = '"' . str_replace('"', '""', $tag->name) . '"';
|
||||
}
|
||||
|
||||
$typed_tags[] = $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return implode(',', $typed_tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_error().
|
||||
*/
|
||||
function autocomplete_deluxe_field_widget_error($element, $error, $form, &$form_state) {
|
||||
form_error($element, $error['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_form().
|
||||
*/
|
||||
function autocomplete_deluxe_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
||||
$element += array(
|
||||
'#type' => 'autocomplete_deluxe',
|
||||
'#size' => $instance['widget']['settings']['size'],
|
||||
'#limit' => isset($instance['widget']['settings']['limit']) ? $instance['widget']['settings']['limit'] : 10,
|
||||
'#min_length' => isset($instance['widget']['settings']['min_length']) ? $instance['widget']['settings']['min_length'] : 0,
|
||||
'#use_synonyms' =>isset($instance['widget']['settings']['use_synonyms']) ? $instance['widget']['settings']['use_synonyms'] : 0,
|
||||
'#delimiter' =>isset($instance['widget']['settings']['delimiter']) ? $instance['widget']['settings']['delimiter'] : '',
|
||||
);
|
||||
|
||||
$multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED ? TRUE : FALSE;
|
||||
|
||||
$tags = array();
|
||||
foreach ($items as $item) {
|
||||
$tags[$item['tid']] = isset($item['taxonomy_term']) ? $item['taxonomy_term'] : taxonomy_term_load($item['tid']);
|
||||
}
|
||||
|
||||
$element['#element_validate'] = array('taxonomy_autocomplete_validate');
|
||||
$element += array(
|
||||
'#multiple' => $multiple,
|
||||
'#autocomplete_deluxe_path' => url($instance['widget']['settings']['autocomplete_deluxe_path'] . '/' . $field['field_name'], array('absolute' => TRUE)),
|
||||
'#default_value' => autocomplete_deluxe_taxonomy_implode_tags($tags),
|
||||
);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the basic form elements and javascript settings.
|
||||
*/
|
||||
function autocomplete_deluxe_element_process($element) {
|
||||
$element['#attached'] = array(
|
||||
'library' => array(array('system', 'ui.autocomplete'), array('system', 'ui.button')),
|
||||
'js' => array(drupal_get_path('module', 'autocomplete_deluxe') . '/autocomplete_deluxe.js'),
|
||||
'css' => array(drupal_get_path('module', 'autocomplete_deluxe') . '/autocomplete_deluxe.css'),
|
||||
);
|
||||
// Workaround for problems with jquery css in seven theme.
|
||||
if ($GLOBALS['theme'] == 'seven') {
|
||||
$element['#attached']['css'][] = drupal_get_path('module', 'autocomplete_deluxe') . '/autocomplete_deluxe.seven.css';
|
||||
}
|
||||
|
||||
$html_id = drupal_html_id('autocomplete-deluxe-input');
|
||||
|
||||
$element['#after_build'][] = 'autocomplete_deluxe_after_build';
|
||||
|
||||
// Set default options for multiple values.
|
||||
$element['#multiple'] = isset($element['#multiple']) ? $element['#multiple'] : FALSE;
|
||||
|
||||
$element['textfield'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => isset($element['#size']) ? $element['#size'] : '',
|
||||
'#attributes' => array('class' => array('autocomplete-deluxe-form'), 'id' => array($html_id)),
|
||||
'#default_value' => '',
|
||||
'#prefix' => '<div class="autocomplete-deluxe-container">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
$js_settings['autocomplete_deluxe'][$html_id] = array(
|
||||
'input_id' => $html_id,
|
||||
'multiple' => $element['#multiple'],
|
||||
'required' => $element['#required'],
|
||||
'limit' => isset($element['#limit']) ? $element['#limit'] : 10,
|
||||
'min_length' => isset($element['#min_length']) ? $element['#min_length'] : 0,
|
||||
'use_synonyms' => isset($element['#use_synonyms']) ? $element['#use_synonyms'] : 0,
|
||||
'delimiter' => isset($element['#delimiter']) ? $element['#delimiter'] : '',
|
||||
);
|
||||
|
||||
if (isset($element['#autocomplete_deluxe_path'])) {
|
||||
if (isset($element['#default_value'])) {
|
||||
// Split on the comma only if that comma has zero, or an even number of
|
||||
// quotes in ahead of it.
|
||||
// http://stackoverflow.com/questions/1757065/java-splitting-a-comma-separated-string-but-ignoring-commas-in-quotes
|
||||
$default_value = preg_replace('/,(?=([^\"]*\"[^\"]*\")*[^\"]*$)/i', '"" ""', $element['#default_value']);
|
||||
$default_value = '""' . $default_value . '""';
|
||||
}
|
||||
else {
|
||||
$default_value = '';
|
||||
}
|
||||
|
||||
if ($element['#multiple']) {
|
||||
$element['value_field'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#attributes' => array('class' => array('autocomplete-deluxe-value-field')),
|
||||
'#default_value' => $default_value,
|
||||
'#prefix' => '<div class="autocomplete-deluxe-value-container">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
$element['textfield']['#attributes']['style'] = array('display:none');
|
||||
}
|
||||
else {
|
||||
$element['textfield']['#default_value'] = isset($element['#default_value']) ? $element['#default_value'] : '';
|
||||
}
|
||||
|
||||
$js_settings['autocomplete_deluxe'][$html_id] += array(
|
||||
'type' => 'ajax',
|
||||
'uri' => $element['#autocomplete_deluxe_path'],
|
||||
);
|
||||
}
|
||||
else {
|
||||
// If there is no source (path or data), we don't want to add the js
|
||||
// settings and so the functions will be abborted.
|
||||
return $element;
|
||||
}
|
||||
$element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
|
||||
$element['#tree'] = TRUE;
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine the value for a autocomplete deluxe form
|
||||
* element.
|
||||
*/
|
||||
function autocomplete_deluxe_value(&$element, $input = FALSE, $form_state = NULL) {
|
||||
// This runs before child elements are processed, so we cannot calculate the
|
||||
// value here. But we have to make sure the value is an array, so the form
|
||||
// API is able to proccess the children to set their values in the array. Thus
|
||||
// once the form API has finished processing the element, the value is an
|
||||
// array containing the child element values. Then finally the after build
|
||||
// callback converts it back to the numeric value and sets that.
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* FAPI after build callback for the duration parameter type form.
|
||||
* Fixes up the form value by applying the multiplier.
|
||||
*/
|
||||
function autocomplete_deluxe_after_build($element, &$form_state) {
|
||||
// By default drupal sets the maxlength to 128 if the property isn't
|
||||
// specified, but since the limit isn't useful in some cases,
|
||||
// we unset the property.
|
||||
unset($element['textfield']['#maxlength']);
|
||||
|
||||
// Set the elements value from either the value field or text field input.
|
||||
$element['#value'] = isset($element['value_field']) ? $element['value_field']['#value'] : $element['textfield']['#value'];
|
||||
|
||||
if (isset($element['value_field'])) {
|
||||
$element['#value'] = trim($element['#value']);
|
||||
// Replace all double double quotes and space with a comma. This will allows
|
||||
// us to keep entries in double quotes.
|
||||
$element['#value'] = str_replace('"" ""', ',', $element['#value']);
|
||||
$element['#value'] = str_replace('"" ""', ',', $element['#value']);
|
||||
// Remove the double quotes at the beginning and the end from the first and
|
||||
// the last term.
|
||||
$element['#value'] = substr($element['#value'], 2, strlen($element['#value']) - 4);
|
||||
|
||||
unset($element['value_field']['#maxlength']);
|
||||
}
|
||||
|
||||
|
||||
form_set_value($element, $element['#value'], $form_state);
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*/
|
||||
function autocomplete_deluxe_element_info() {
|
||||
$types['autocomplete_deluxe'] = array(
|
||||
'#input' => TRUE,
|
||||
'#value_callback' => 'autocomplete_deluxe_value',
|
||||
'#pre_render' => array('form_pre_render_conditional_form_element'),
|
||||
'#process' => array('autocomplete_deluxe_element_process'),
|
||||
);
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function autocomplete_deluxe_menu() {
|
||||
$items['autocomplete_deluxe/taxonomy'] = array(
|
||||
'title' => 'Autocomplete deluxe taxonomy',
|
||||
'page callback' => 'taxonomy_autocomplete_deluxe',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
/**
|
||||
* JQuery UI style sheet fix for seven.
|
||||
*/
|
||||
|
||||
.ui-button {
|
||||
border: 1px solid #cccccc;
|
||||
background: #e6e6e6;
|
||||
}
|
||||
|
||||
.ui-state-hover,
|
||||
.ui-state-focus {
|
||||
border: 1px solid #bbbbbb;
|
||||
}
|
||||
|
||||
.ui-button.ui-state-active {
|
||||
border: 1px solid #777777;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Corner radius
|
||||
*/
|
||||
.ui-corner-tl {
|
||||
-moz-border-radius-topleft: 4px;
|
||||
-webkit-border-top-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-tr {
|
||||
-moz-border-radius-topright: 4px;
|
||||
-webkit-border-top-right-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-bl {
|
||||
-moz-border-radius-bottomleft: 4px;
|
||||
-webkit-border-bottom-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-br {
|
||||
-moz-border-radius-bottomright: 4px;
|
||||
-webkit-border-bottom-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-top {
|
||||
-moz-border-radius-topleft: 4px;
|
||||
-moz-border-radius-topright: 4px;
|
||||
-webkit-border-top-left-radius: 4px;
|
||||
-webkit-border-top-right-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-bottom {
|
||||
-moz-border-radius-bottomleft: 4px;
|
||||
-moz-border-radius-bottomright: 4px;
|
||||
-webkit-border-bottom-left-radius: 4px;
|
||||
-webkit-border-bottom-right-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-right {
|
||||
-moz-border-radius-bottomright: 4px;
|
||||
-moz-border-radius-topright: 4px;
|
||||
-webkit-border-bottom-right-radius: 4px;
|
||||
-webkit-border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-left {
|
||||
-moz-border-radius-bottomleft: 4px;
|
||||
-moz-border-radius-topleft: 4px;
|
||||
-webkit-border-bottom-left-radius: 4px;
|
||||
-webkit-border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.ui-corner-all {
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
sites/all/modules/contrib/fields/autocomplete_deluxe/x.gif
Normal file
BIN
sites/all/modules/contrib/fields/autocomplete_deluxe/x.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 498 B |
339
sites/all/modules/contrib/fields/cck_phone/LICENSE.txt
Normal file
339
sites/all/modules/contrib/fields/cck_phone/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
62
sites/all/modules/contrib/fields/cck_phone/README.int.txt
Normal file
62
sites/all/modules/contrib/fields/cck_phone/README.int.txt
Normal file
@@ -0,0 +1,62 @@
|
||||
About the International Phone Number format
|
||||
===========================================
|
||||
|
||||
These rules have been formulated off of the E.123 (for display) and
|
||||
E.164 (for input) specifications published by the ITU. In order to
|
||||
prevent ambiguity, we have chosen to restrict some of the stipulations
|
||||
these specifications give.
|
||||
|
||||
In summary, country calling codes are assigned by the ITU Telecommunication
|
||||
Standardization Sector in E.164. We take an international phone number to
|
||||
have the form +XX YYYYYYY where XX is the country code, and YYYYYYY to be
|
||||
the subscriber's number, possibly with intervening spaces. The maximum
|
||||
length for these phone numbers is 15.
|
||||
|
||||
Reference materials can be found here:
|
||||
- http://www.itu.int/rec/T-REC-E.123/en
|
||||
- http://www.itu.int/rec/T-REC-E.164/en
|
||||
|
||||
Modifications to E.123
|
||||
----------------------
|
||||
|
||||
7.1: The international prefix symbol "+" MUST prefix international
|
||||
phone numbers. All numbers missing this symbol will be assumed to be in
|
||||
the default country code.
|
||||
|
||||
When reformatting numbers to a standard format, the following conventions
|
||||
will be taken:
|
||||
|
||||
7.2: Parentheses will be normalized to spaces.
|
||||
|
||||
We do not support the multiple phone numbers as described by (7.4); users
|
||||
can always specify that multiple values are allowed if this is desired.
|
||||
The functionality specified by 7.5, 7.6 and 8 IS NOT implemented.
|
||||
|
||||
9.2 specifies that spacing SHALL OCCUR between the country code, the trunk
|
||||
code and the subscriber number. As trunk codes are omitted by convention,
|
||||
this means the only guaranteed separation will be between the country code
|
||||
and subscriber number. Our implementation MAY treat hyphens, spaces and
|
||||
parentheses as advisory indicators as to where spaces should be placed.
|
||||
However, +1 7329060489 will stay as it was specified, while +1 (732) 906-0489
|
||||
will be normalized to +1 732 906 0489. As a future feature, rules may
|
||||
be implemented for country codes specifying these conventions, however,
|
||||
I have deemed such functionality out of scope for now.
|
||||
|
||||
The Drupal task specifies that we should validate country codes, however,
|
||||
due to the highly volatile nature of these codes, the author does not
|
||||
believe that it is a good idea to maintain a list of valid country codes.
|
||||
Thus, we only validate that the country code is three or less digits.
|
||||
|
||||
Modifications to E.164
|
||||
----------------------
|
||||
|
||||
Our processing for NDD's will be similarly constrained. As per
|
||||
7.3.2, we will treat 0 as a valid trunk code for all countries.
|
||||
Other digits may be specified if the fall in the form of (X), where X is
|
||||
a single digit that is 7 or 8.
|
||||
|
||||
Postscript
|
||||
----------
|
||||
|
||||
Modifications to our implementation will occur as necessary by user bug
|
||||
reports.
|
||||
66
sites/all/modules/contrib/fields/cck_phone/README.txt
Normal file
66
sites/all/modules/contrib/fields/cck_phone/README.txt
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
Description
|
||||
-----------
|
||||
Another CCK module to provide a phone number field type.
|
||||
|
||||
Main differences cck_phone from Phone (CCK) phone.module are:
|
||||
- Single CCK widget instead of ever growing CCK widget per country
|
||||
- Supports all/multiple countries in one CCK field
|
||||
- Covers almost all country codes (239 on last count) out of the box, with generic phone number validation
|
||||
- Includes all countries codes or select your own list of countries
|
||||
- Custom country specific phone numbers validation & formatting
|
||||
- Custom country validation can be turned off, configurable per field
|
||||
- Better tel link support (RFC3966) or mobile support - iPhone, Android, iPad, Opera Mobile/Mini, etc.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
The cck_phone.module requires the content.module to be installed.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
To install, copy the cck_phone directory and all its contents to your modules directory.
|
||||
To enable this module, go to Administer > Modules, and enable Phone Number.
|
||||
|
||||
|
||||
Themable
|
||||
--------
|
||||
theme_phone_number($element)
|
||||
- FAPI theme for an individual phone number elements.
|
||||
|
||||
theme_phone_number_extension($extension = '')
|
||||
- Theme function for phone extension
|
||||
|
||||
theme_cck_phone_formatter_default($element)
|
||||
- Theme function for 'default' or global phone number field formatter.
|
||||
|
||||
theme_cck_phone_formatter_local($element)
|
||||
- Theme function for 'local' phone number field formatter.
|
||||
|
||||
theme_cck_phone_mobile_tel($element, $phone = '')
|
||||
- Theme function for mobile tel.
|
||||
|
||||
|
||||
Todo Tasks: (Contribution is welcome!)
|
||||
-----------
|
||||
- D7 port using Field API
|
||||
- migration option from phone.module
|
||||
- phone types (home, work, mobile, fax, etc) support
|
||||
- simpletest
|
||||
|
||||
Ongoing Tasks:
|
||||
--------------
|
||||
- add validation support to all country phone numbers
|
||||
- translation of the module
|
||||
|
||||
|
||||
Bugs/Features/Patches:
|
||||
----------------------
|
||||
If you want to report bugs, feature requests, or submit a patch, please do so at the project page on the Drupal web site.
|
||||
http://drupal.org/project/cck_phone
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
Initially sponsored by forDrupal.com
|
||||
20
sites/all/modules/contrib/fields/cck_phone/cck_phone.css
Normal file
20
sites/all/modules/contrib/fields/cck_phone/cck_phone.css
Normal file
@@ -0,0 +1,20 @@
|
||||
/* input field */
|
||||
.form-phone-number .form-item,
|
||||
.form-phone-number .form-item label {
|
||||
display: inline;
|
||||
}
|
||||
.form-phone-number .form-item label {
|
||||
margin-left: 1em;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
/* admin settings */
|
||||
.cck-phone-settings .form-checkboxes .form-item {
|
||||
float: left;
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.cck-phone-settings .cck-phone-default-country {
|
||||
background: #eee;
|
||||
font-weight: bold;
|
||||
}
|
||||
23
sites/all/modules/contrib/fields/cck_phone/cck_phone.info
Normal file
23
sites/all/modules/contrib/fields/cck_phone/cck_phone.info
Normal file
@@ -0,0 +1,23 @@
|
||||
name = Phone Number
|
||||
description = "The phone module allows administrators to define a field type for phone numbers."
|
||||
package = Fields
|
||||
dependencies[] = field
|
||||
core = 7.x
|
||||
|
||||
files[] = cck_phone.module
|
||||
files[] = includes/cck_phone_countrycodes.inc
|
||||
files[] = includes/cck_phone.token.inc
|
||||
files[] = includes/phone.au.inc
|
||||
files[] = includes/phone.ca.inc
|
||||
files[] = includes/phone.gb.inc
|
||||
files[] = includes/phone.hu.inc
|
||||
files[] = includes/phone.my.inc
|
||||
files[] = includes/phone.pl.inc
|
||||
files[] = includes/phone.us.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-03-02
|
||||
version = "7.x-1.x-dev"
|
||||
core = "7.x"
|
||||
project = "cck_phone"
|
||||
datestamp = "1330689918"
|
||||
|
||||
62
sites/all/modules/contrib/fields/cck_phone/cck_phone.install
Normal file
62
sites/all/modules/contrib/fields/cck_phone/cck_phone.install
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines phone number fields for CCK.
|
||||
* Installation file
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema().
|
||||
*/
|
||||
function cck_phone_field_schema($field) {
|
||||
return array(
|
||||
'columns' => array(
|
||||
'number' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 15,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'country_codes' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 2,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'extension' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 6,
|
||||
'not null' => FALSE,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function cck_phone_install() {
|
||||
drupal_set_message(st('Phone number module installed successfully.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function cck_phone_uninstall() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_enable().
|
||||
*
|
||||
* Notify content module when this module is enabled.
|
||||
*/
|
||||
function cck_phone_enable() {
|
||||
// TODO: Migration path for phone.module to cck_phone
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_disable().
|
||||
*
|
||||
* Notify content module when this module is disabled.
|
||||
*/
|
||||
function cck_phone_disable() {
|
||||
}
|
||||
100
sites/all/modules/contrib/fields/cck_phone/cck_phone.js
Normal file
100
sites/all/modules/contrib/fields/cck_phone/cck_phone.js
Normal file
@@ -0,0 +1,100 @@
|
||||
(function ($) {
|
||||
Drupal.PhoneNumber = Drupal.PhoneNumber || {};
|
||||
|
||||
/**
|
||||
* Filters checkboxes based on their label.
|
||||
* This code is shamelessly taken from checkbox_filter
|
||||
*/
|
||||
Drupal.PhoneNumber.filter = function() {
|
||||
var field = $(this);
|
||||
var checkboxes = field.parent().parent().find('.form-checkboxes .form-item');
|
||||
var found = false;
|
||||
var label = "";
|
||||
var option = null;
|
||||
for (var i = 0; i < checkboxes.length; i++) {
|
||||
option = checkboxes.eq(i);
|
||||
label = Drupal.PhoneNumber.trim(option.text());
|
||||
if (label.toUpperCase().indexOf(field.val().toUpperCase()) < 0) {
|
||||
option.hide();
|
||||
} else {
|
||||
option.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Trims whitespace from strings
|
||||
*/
|
||||
Drupal.PhoneNumber.trim = function(str) {
|
||||
var str = str.replace(/^\s\s*/, ''),
|
||||
ws = /\s/,
|
||||
i = str.length;
|
||||
while (ws.test(str.charAt(--i)));
|
||||
return str.slice(0, i + 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check/Uncheck all checkboxes
|
||||
*/
|
||||
Drupal.PhoneNumber.checkall = function(e) {
|
||||
var field = $(this);
|
||||
var checkboxes = $('.form-checkboxes .form-item:visible .form-checkbox', field.parent().parent());
|
||||
|
||||
var checked = (field.text() == Drupal.t('Select all'));
|
||||
if (checked) {
|
||||
checkboxes.attr('checked', true);
|
||||
field.text(Drupal.t('Deselect all'));
|
||||
}
|
||||
else {
|
||||
checkboxes.attr('checked', false);
|
||||
Drupal.PhoneNumber.checkDefault();
|
||||
field.text(Drupal.t('Select all'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Country selection should include default country code by default.
|
||||
*/
|
||||
Drupal.PhoneNumber.checkDefault = function(e) {
|
||||
var defaultCC = $('#edit-instance-settings-default-country').val();
|
||||
var span = $('<span class="default-cc"></span>').append(Drupal.t('Default'));
|
||||
|
||||
$('.cck-phone-settings .form-checkboxes').find('.form-checkbox').each(function() {
|
||||
if ($(this).val() == defaultCC) {
|
||||
$('.cck-phone-default-country')
|
||||
.removeClass('cck-phone-default-country')
|
||||
.find('span.default-cc').remove();
|
||||
|
||||
// TODO: check for "Enable default country code" only set the checkbox
|
||||
$(this)
|
||||
// .attr('checked', 'checked')
|
||||
.parents('.form-item:first')
|
||||
.addClass('cck-phone-default-country')
|
||||
.append(span);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach a filtering textfield to checkboxes.
|
||||
*/
|
||||
Drupal.behaviors.PhoneNumber = {
|
||||
attach: function(context) {
|
||||
// Ensure the new default country is checked
|
||||
$('#edit-instance-settings-default-country, .cck-phone-settings .form-checkboxes').bind('change', Drupal.PhoneNumber.checkDefault);
|
||||
$('#edit-instance-settings-default-country').trigger('change');
|
||||
$('form#field-ui-field-edit-form').submit(Drupal.PhoneNumber.checkDefault);
|
||||
|
||||
// Filter for countries
|
||||
var form = '<div class="form-item container-inline">'
|
||||
+ ' <label>' + Drupal.t('Filter') + ':</label> '
|
||||
+ ' <input class="cck-phone-filter form-text" type="text" size="30" />'
|
||||
+ ' <a class="cck-phone-check" style="margin-left: 1em;" href="javascript://">' + Drupal.t('Select all') + '</a>'
|
||||
+ '</div>';
|
||||
|
||||
$('.cck-phone-settings .form-checkboxes', context).before(form);
|
||||
$('input.cck-phone-filter').bind('keyup', Drupal.PhoneNumber.filter);
|
||||
$('a.cck-phone-check').bind('click', Drupal.PhoneNumber.checkall);
|
||||
}
|
||||
};
|
||||
})(jQuery);
|
||||
869
sites/all/modules/contrib/fields/cck_phone/cck_phone.module
Normal file
869
sites/all/modules/contrib/fields/cck_phone/cck_phone.module
Normal file
@@ -0,0 +1,869 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines phone number fields for CCK.
|
||||
* Provide some verifications on the phone numbers
|
||||
*/
|
||||
|
||||
define('CCK_PHONE_PHONE_MIN_LENGTH', 4); // Is there a phone number less than 4 digits?
|
||||
define('CCK_PHONE_PHONE_MAX_LENGTH', 15); // International standard 15 digits
|
||||
define('CCK_PHONE_EXTENSION_MAX_LENGTH', 6);
|
||||
define('CCK_PHONE_CC_MAX_LENGTH', 2);
|
||||
|
||||
// load country codes
|
||||
require_once dirname(__FILE__) . '/cck_phone_countrycodes.inc';
|
||||
|
||||
/**
|
||||
* Implements hook_init().
|
||||
* This hook is called on module initialization.
|
||||
*/
|
||||
function cck_phone_init() {
|
||||
// Token module support.
|
||||
if (module_exists('token')) {
|
||||
module_load_include('inc', 'cck_phone', 'cck_phone.token');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function cck_phone_theme() {
|
||||
return array(
|
||||
'cck_phone_phone_number' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'phone_number_extension' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
'cck_phone_formatter_global_phone_number' => array(
|
||||
'variables' => array('element' => NULL),
|
||||
),
|
||||
'cck_phone_formatter_local_phone_number' => array(
|
||||
'variables' => array('element' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_info().
|
||||
*/
|
||||
function cck_phone_field_info() {
|
||||
return array(
|
||||
'phone_number' => array(
|
||||
'label' => t('Phone number'),
|
||||
'description' => t('Store a number and country code in the database to assemble a phone number.'),
|
||||
'settings' => array('size' => CCK_PHONE_PHONE_MAX_LENGTH),
|
||||
'instance_settings' => array(
|
||||
'enable_default_country' => TRUE,
|
||||
'default_country' => NULL,
|
||||
'all_country_codes' => TRUE,
|
||||
'country_codes' => array('hide_single_cc' => FALSE, 'country_selection' => array()),
|
||||
'country_code_position' => 'after',
|
||||
'enable_country_level_validation' => TRUE,
|
||||
'enable_extension' => FALSE,
|
||||
),
|
||||
'default_widget' => 'phone_number',
|
||||
'default_formatter' => 'global_phone_number',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_instance_settings_form().
|
||||
*/
|
||||
function cck_phone_field_instance_settings_form($field, $instance) {
|
||||
drupal_add_css(drupal_get_path('module', 'cck_phone') . '/cck_phone.css');
|
||||
drupal_add_js(drupal_get_path('module', 'cck_phone') . '/cck_phone.js');
|
||||
|
||||
$defaults = field_info_instance_settings($field['type']);
|
||||
$settings = array_merge($defaults, $instance['settings']);
|
||||
|
||||
$form = array();
|
||||
$form['enable_default_country'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable default country code'),
|
||||
'#default_value' => $settings['enable_default_country'],
|
||||
'#description' => t('Check this to enable default country code below.'),
|
||||
);
|
||||
|
||||
$form['default_country'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Default country code'),
|
||||
'#default_value' => $settings['default_country'],
|
||||
'#options' => _cck_phone_cc_options(TRUE),
|
||||
'#description' => t('Item marked with * comes with country level phone number validation.'),
|
||||
'#states' => array(
|
||||
'invisible' => array(
|
||||
':input[name="instance[settings][enable_default_country]"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['all_country_codes'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Show all country codes.'),
|
||||
'#default_value' => $settings['all_country_codes'],
|
||||
'#description' => t('Uncheck this to select the country to be displayed.'),
|
||||
);
|
||||
// Country codes settings
|
||||
$form['country_codes'] = array(
|
||||
'#title' => 'Country selection',
|
||||
'#type' => 'fieldset',
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
'#attributes' => array('class' => array('cck-phone-settings')),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="instance[settings][all_country_codes]"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['country_codes']['hide_single_cc'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Hide when only one country code'),
|
||||
'#default_value' => $settings['country_codes']['hide_single_cc'],
|
||||
'#description' => t('By default when there is only one country code, it will show as a display-only form element. Check this to hide the country code.'),
|
||||
);
|
||||
|
||||
$form['country_codes']['country_selection'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => t('Select country codes to be included'),
|
||||
'#default_value' => isset($settings['country_codes']['country_selection']) && !empty($settings['country_codes']['country_selection']) ? $settings['country_codes']['country_selection'] : array($settings['default_country'] => $settings['default_country']),
|
||||
'#options' => _cck_phone_cc_options(TRUE),
|
||||
'#description' => t('Country marks with <em>*</em> has custom country code settings and/or validation.'),
|
||||
);
|
||||
|
||||
if (isset($settings['country_codes']['country_selection']) && !empty($settings['country_codes']['country_selection'])) {
|
||||
$form['country_codes']['country_selection']['#default_value'] = $settings['country_codes']['country_selection'];
|
||||
}
|
||||
elseif ($settings['enable_default_country']) {
|
||||
$form['country_codes']['country_selection']['#default_value'] = array($settings['default_country'] => $settings['default_country']);
|
||||
}
|
||||
|
||||
$form['country_code_position'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Country code position'),
|
||||
'#options' => array(
|
||||
'before' => t('Before phone number'),
|
||||
'after' => t('After phone number'),
|
||||
),
|
||||
'#default_value' => $settings['country_code_position'],
|
||||
'#description' => t('Select the position of the country code selection field relative to the phone number text field.'),
|
||||
);
|
||||
|
||||
$form['enable_country_level_validation'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable country level validation'),
|
||||
'#default_value' => $settings['enable_country_level_validation'],
|
||||
'#description' => t('Uncheck this to disable stringent country phone number validation.'),
|
||||
);
|
||||
|
||||
$form['enable_extension'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable phone extension support'),
|
||||
'#default_value' => $settings['enable_extension'],
|
||||
'#description' => t('Check this to enable phone number extension field.'),
|
||||
);
|
||||
|
||||
// Display country specific settings
|
||||
foreach (_cck_phone_custom_cc() as $cc) {
|
||||
$function = $cc . '_phone_field_settings';
|
||||
if (function_exists($function)) {
|
||||
$country_settings = $function($op, $field);
|
||||
if (isset($country_settings) && !empty($country_settings)) {
|
||||
$country_codes = cck_phone_countrycodes($cc);
|
||||
// Wrap with fieldset
|
||||
$wrapper = array(
|
||||
'#title' => t('%country specific settings', array('%country' => $country_codes['country'])),
|
||||
'#type' => 'fieldset',
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#attributes' => array('class' => 'cck-phone-settings cck-phone-settings-' . $cc),
|
||||
);
|
||||
$wrapper[] = $country_settings;
|
||||
array_push($form, $wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_validate().
|
||||
*/
|
||||
function cck_phone_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
|
||||
foreach ($items as $delta => $value) {
|
||||
_cck_phone_validate($items[$delta], $delta, $field, $instance, $langcode, $errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_presave().
|
||||
*/
|
||||
function cck_phone_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
foreach ($items as $delta => $value) {
|
||||
_cck_phone_sanitize($items[$delta], $delta, $field, $instance, $langcode);
|
||||
_cck_phone_process($items[$delta], $delta, $field, $instance, $langcode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_info().
|
||||
*/
|
||||
function cck_phone_field_formatter_info() {
|
||||
return array(
|
||||
'global_phone_number' => array(
|
||||
'label' => t('Global phone number (default)'),
|
||||
'field types' => array('phone_number'),
|
||||
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
|
||||
),
|
||||
'local_phone_number' => array(
|
||||
'label' => t('Local phone number'),
|
||||
'field types' => array('phone_number'),
|
||||
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_view().
|
||||
*/
|
||||
function cck_phone_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
|
||||
$element = array();
|
||||
$settings = $display['settings'];
|
||||
$formatter = $display['type'];
|
||||
|
||||
foreach ($items as $delta => $item) {
|
||||
$element[$delta] = array(
|
||||
'#markup' => theme('cck_phone_formatter_' . $formatter, $item),
|
||||
);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_is_empty().
|
||||
*/
|
||||
function cck_phone_field_is_empty($item, $field) {
|
||||
return empty($item['number']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for phone extension.
|
||||
*/
|
||||
function theme_phone_number_extension($element = '') {
|
||||
return t('<em> ext.</em> %extension', array('%extension' => $element['element']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for 'default' or global phone number field formatter.
|
||||
*/
|
||||
function theme_cck_phone_formatter_global_phone_number($element) {
|
||||
$phone = '';
|
||||
|
||||
// Display a global phone number with country code.
|
||||
if (!empty($element['number']) && !empty($element['country_codes'])) {
|
||||
// Call country default formatter if exist
|
||||
$custom_cc = _cck_phone_custom_cc();
|
||||
if (isset($custom_cc[$element['country_codes']])) {
|
||||
$function = $element['country_codes'] . '_formatter_default';
|
||||
if (function_exists($function)) {
|
||||
$phone = $function($element);
|
||||
}
|
||||
}
|
||||
|
||||
// Output a raw value if no custom formatter or formatter return empty
|
||||
if (empty($phone)) {
|
||||
$cc = cck_phone_countrycodes($element['country_codes']);
|
||||
$phone = $cc['code'] . '-' . $element['number'];
|
||||
}
|
||||
|
||||
// Extension
|
||||
if (!empty($element['extension'])) {
|
||||
$phone = $phone . theme('phone_number_extension', $element['extension']);
|
||||
}
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for 'local' phone number field formatter.
|
||||
*/
|
||||
function theme_cck_phone_formatter_local_phone_number($element) {
|
||||
$phone = '';
|
||||
|
||||
// Display a local phone number without country code.
|
||||
if (!empty($element['number'])) {
|
||||
// Call country local formatter if exist
|
||||
$custom_cc = _cck_phone_custom_cc();
|
||||
if (isset($custom_cc[$element['country_codes']])) {
|
||||
$function = $element['country_codes'] . '_formatter_local';
|
||||
if (function_exists($function)) {
|
||||
$phone = $function($element);
|
||||
}
|
||||
}
|
||||
|
||||
// Output a raw value if no custom formatter or formatter return empty
|
||||
if (empty($phone)) {
|
||||
$phone = $element['number'];
|
||||
}
|
||||
|
||||
// Extension
|
||||
if (!empty($element['extension'])) {
|
||||
$phone = $phone . theme('phone_number_extension', $element['extension']);
|
||||
}
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an array of country codes, for use in select or checkboxes form.
|
||||
*
|
||||
* @param boolean $show_custom
|
||||
* Mark item with '*' to indicate the country code has include file.
|
||||
* @param array $country_selection
|
||||
* Limit the list to the countries listed in this array.
|
||||
* @return string
|
||||
*/
|
||||
function _cck_phone_cc_options($show_custom = FALSE, $country_selection = array()) {
|
||||
$options = array();
|
||||
|
||||
if ($show_custom) {
|
||||
$custom_cc = _cck_phone_custom_cc();
|
||||
}
|
||||
|
||||
foreach (cck_phone_countrycodes() as $cc => $value) {
|
||||
$cc_name = $value['country'] . ' (' . $value['code'] . ')';
|
||||
|
||||
// faster using array key instead of in_array
|
||||
if ($show_custom && isset($custom_cc[$cc])) {
|
||||
$cc_name .= ' *';
|
||||
}
|
||||
|
||||
if (!empty($country_selection) && $country_selection[$cc] === 0) {
|
||||
continue;
|
||||
}
|
||||
$options[$cc] = check_plain($cc_name);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of country codes that has custom includes.
|
||||
*
|
||||
* @return
|
||||
* Array of country codes abbreviation or empty array if none exist.
|
||||
*/
|
||||
function _cck_phone_custom_cc() {
|
||||
static $countrycodes;
|
||||
|
||||
if (!isset($countrycodes)) {
|
||||
// load custom country codes phone number includes
|
||||
$path = drupal_get_path('module', 'cck_phone') . '/includes';
|
||||
// scan include phone numbers directory
|
||||
$files = file_scan_directory($path, '/^phone\..*\.inc$/');
|
||||
|
||||
$countrycodes = array();
|
||||
foreach ($files as $file) {
|
||||
module_load_include('inc', 'cck_phone', '/includes/' . $file->name);
|
||||
list ($dummy, $countrycode) = explode('.', $file->name);
|
||||
// faster using array key
|
||||
$countrycodes[$countrycode] = $countrycode;
|
||||
}
|
||||
}
|
||||
|
||||
return $countrycodes;
|
||||
}
|
||||
|
||||
function _cck_phone_valid_input($input) {
|
||||
// lenient checking, as long as don't have invalid phone number character
|
||||
$regex = '/^
|
||||
[\s.()-]* # optional separator
|
||||
(?: # }
|
||||
\d # } 4-15 digits number
|
||||
[\s.()-]* # } each followed by optional separator
|
||||
){' . CCK_PHONE_PHONE_MIN_LENGTH . ',' . CCK_PHONE_PHONE_MAX_LENGTH . '} # }
|
||||
$/x';
|
||||
|
||||
return preg_match($regex, $input);
|
||||
}
|
||||
|
||||
function _cck_phone_valid_cc_input($list, $cc) {
|
||||
if (isset($list[$cc]) && $list[$cc] == $cc) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
function _cck_phone_validate(&$item, $delta, $field, $instance, $langcode, &$errors) {
|
||||
if (isset($item['number'])) {
|
||||
$phone_input = trim($item['number']);
|
||||
}
|
||||
if (isset($item['country_codes'])) {
|
||||
$countrycode = trim($item['country_codes']);
|
||||
}
|
||||
$ext_input = '';
|
||||
$settings = $instance['settings'];
|
||||
|
||||
if ($settings['enable_extension']) {
|
||||
$ext_input = trim($item['extension']);
|
||||
}
|
||||
|
||||
if (isset($phone_input) && !empty($phone_input)) {
|
||||
|
||||
$error_params = array(
|
||||
'%phone_input' => check_plain($phone_input), // original phone input
|
||||
'%countrycode' => check_plain($countrycode),
|
||||
'%min_length' => CCK_PHONE_PHONE_MIN_LENGTH,
|
||||
'%max_length' => CCK_PHONE_PHONE_MAX_LENGTH,
|
||||
'%ext_input' => check_plain($ext_input),
|
||||
'%ext_max_length' => CCK_PHONE_EXTENSION_MAX_LENGTH,
|
||||
);
|
||||
|
||||
// Only allow digit, dash, space and bracket
|
||||
if (!_cck_phone_valid_input($phone_input, $ext_input)) {
|
||||
$error = t('The phone number must be between %min_length and %max_length digits in length.', $error_params);
|
||||
if ($settings['enable_extension'] && $ext_input != '') {
|
||||
$error .= '<br />' . t('The phone extension must be less than %ext_max_length digits in length.', $error_params);
|
||||
}
|
||||
|
||||
form_set_error($field['field_name'], $error);
|
||||
}
|
||||
else {
|
||||
if (!$settings['all_country_codes']) {
|
||||
if (!_cck_phone_valid_cc_input($settings['country_codes']['country_selection'], $countrycode)) {
|
||||
$error = t('Invalid country code "%countrycode" submitted.', $error_params);
|
||||
form_set_error($field['field_name'], $error);
|
||||
}
|
||||
}
|
||||
// Generic number validation
|
||||
if (!cck_phone_validate_number($countrycode, $phone_input, $ext_input)) {
|
||||
$error = t('The phone number must be between %min_length and %max_length digits in length.', $error_params);
|
||||
if ($field['enable_extension'] && $ext_input != '') {
|
||||
$error .= '<br />' . t('The phone extension must be less than %ext_max_length digits in length.', $error_params);
|
||||
}
|
||||
|
||||
form_set_error($field['field_name'], $error);
|
||||
}
|
||||
// Country level validation if enabled
|
||||
elseif ($settings['enable_country_level_validation']) {
|
||||
$custom_cc = _cck_phone_custom_cc();
|
||||
|
||||
if (isset($custom_cc[$countrycode])) {
|
||||
$validate_function = $countrycode . '_validate_number';
|
||||
|
||||
if (function_exists($validate_function)) {
|
||||
$error = '';
|
||||
if (!$validate_function($phone_input, $ext_input, $error)) {
|
||||
form_set_error($field['field_name'], t($error, $error_params));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _cck_phone_process(&$item, $delta = 0, $field, $instance, $langcode) {
|
||||
$settings = $instance['settings'];
|
||||
// Clean up the phone number.
|
||||
$item['number'] = cck_phone_clean_number($item['number']);
|
||||
if (isset($item['extension'])) {
|
||||
$item['extension'] = cck_phone_clean_number($item['extension']);
|
||||
}
|
||||
|
||||
// Don't save an invalid default value.
|
||||
if ((isset($instance['default_value']) && $item['number'] == $instance['default_value']) && (isset($settings['default_country']) && $item['country_codes'] == $settings['default_country'])) {
|
||||
if (!cck_phone_validate_number($item['country_codes'], $item['number'], $item['extension'])) {
|
||||
unset($item['number']);
|
||||
unset($item['country_codes']);
|
||||
unset($item['extension']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field according to field settings.
|
||||
*
|
||||
* @param $item
|
||||
* A single phone number item, usually containing number and country code.
|
||||
* @param $delta
|
||||
* The delta value if this field is one of multiple fields.
|
||||
* @param $field
|
||||
* The CCK field definition.
|
||||
* @param $node
|
||||
* The node containing this phone number.
|
||||
*/
|
||||
function _cck_phone_sanitize(&$item, $delta, $field, $instance, $langcode) {
|
||||
if (empty($item)) return;
|
||||
|
||||
$settings = $instance['settings'];
|
||||
|
||||
if (!empty($item['number'])) {
|
||||
$cc = $item['country_codes'];
|
||||
$item['number'] = cck_phone_clean_number($item['number']);
|
||||
|
||||
$custom_cc = _cck_phone_custom_cc();
|
||||
if (isset($custom_cc[$cc])) {
|
||||
$function = $cc . '_sanitize_number';
|
||||
|
||||
if (function_exists($function)) {
|
||||
$function($item['number']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($settings['enable_extension']) {
|
||||
$item['extension'] = cck_phone_clean_number($item['extension']);
|
||||
}
|
||||
else {
|
||||
unset($item['extension']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_info().
|
||||
*/
|
||||
function cck_phone_field_widget_info() {
|
||||
return array(
|
||||
'phone_number' => array(
|
||||
'label' => t('Phone number'),
|
||||
'field types' => array('phone_number'),
|
||||
'behaviors' => array(
|
||||
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
|
||||
'default value' => FIELD_BEHAVIOR_NONE,
|
||||
),
|
||||
'settings' => array(
|
||||
'size' => CCK_PHONE_PHONE_MAX_LENGTH,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_settings_form().
|
||||
*/
|
||||
function cck_phone_field_settings_form($field, $instance, $has_data) {
|
||||
$settings = $field['settings'];
|
||||
|
||||
$form = array();
|
||||
$form['size'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Size of phone number textfield'),
|
||||
'#default_value' => $settings['size'],
|
||||
'#element_validate' => array('_element_validate_integer_positive'),
|
||||
'#required' => TRUE,
|
||||
'#description' => t('International number is maximum 15 digits with additional country code, default is %length.', array('%length' => CCK_PHONE_PHONE_MAX_LENGTH)),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_form().
|
||||
*/
|
||||
function cck_phone_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
||||
// Retrieve any values set in $form_state, as will be the case during AJAX
|
||||
// rebuilds of this form.
|
||||
if (isset($form_state['values'][$field['field_name']][$langcode])) {
|
||||
$items = $form_state['values'][$field['field_name']][$langcode];
|
||||
unset($form_state['values'][$field['field_name']][$langcode]);
|
||||
}
|
||||
|
||||
foreach ($items as $delta => $item) {
|
||||
// Remove any items from being displayed that are not needed.
|
||||
if (!isset($item['number']) || $item['number'] == '') {
|
||||
unset($items[$delta]);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-index deltas after removing empty items.
|
||||
$items = array_values($items);
|
||||
|
||||
// Update order according to weight.
|
||||
$items = _field_sort_items($field, $items);
|
||||
|
||||
// Essentially we use the phone_number type, extended with some enhancements.
|
||||
$element_info = element_info('phone_number');
|
||||
|
||||
$element += array(
|
||||
'#type' => 'phone_number',
|
||||
'#default_value' => isset($items[$element['#delta']]) ? $items[$element['#delta']] : array(),
|
||||
'#process' => array_merge($element_info['#process'], array('cck_phone_field_widget_process')),
|
||||
);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements hook_field_widget_error().
|
||||
*/
|
||||
function cck_phone_field_widget_error($element, $error, $form, &$form_state) {
|
||||
form_error($element, $error['message'], $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* An element #process callback for the phone_number field type.
|
||||
*
|
||||
* Expands the phone_number type to include the extension and country codes.
|
||||
*/
|
||||
function cck_phone_field_widget_process($element, &$form_state, $form) {
|
||||
$item = $element['#value'];
|
||||
|
||||
$field = field_widget_field($element, $form_state);
|
||||
$instance = field_widget_instance($element, $form_state);
|
||||
$settings = $instance['settings'];
|
||||
|
||||
if ($settings['enable_extension']) {
|
||||
$element['extension'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#maxlength' => CCK_PHONE_EXTENSION_MAX_LENGTH,
|
||||
'#size' => CCK_PHONE_EXTENSION_MAX_LENGTH,
|
||||
'#title' => t('ext'),
|
||||
'#required' => FALSE,
|
||||
'#default_value' => isset($item['extension']) ? $item['extension'] : NULL,
|
||||
'#weight' => 2,
|
||||
);
|
||||
}
|
||||
|
||||
if ($settings['all_country_codes']) {
|
||||
$element['country_codes']['#options'] = _cck_phone_cc_options();
|
||||
}
|
||||
else {
|
||||
$element['country_codes']['#options'] = _cck_phone_cc_options(FALSE, $settings['country_codes']['country_selection']);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*/
|
||||
|
||||
function cck_phone_element_info() {
|
||||
$path = drupal_get_path('module', 'cck_phone');
|
||||
$types['phone_number'] = array(
|
||||
'#input' => TRUE,
|
||||
'#process' => array('cck_phone_phone_number_process'),
|
||||
'#element_validate' => array('cck_phone_phone_number_validate'),
|
||||
'#theme' => 'cck_phone_phone_number',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
'#attached' => array(
|
||||
'css' => array($path . '/cck_phone.css'),
|
||||
// 'js' => array($path . '/cck_phone.js'),
|
||||
),
|
||||
);
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an individual element.
|
||||
*/
|
||||
function cck_phone_phone_number_process($element, &$form_state, $form) {
|
||||
$item = $element['#value'];
|
||||
|
||||
$field = field_widget_field($element, $form_state);
|
||||
$instance = field_widget_instance($element, $form_state);
|
||||
$settings = $instance['settings'];
|
||||
|
||||
$element['number'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#maxlength' => $field['settings']['size'],
|
||||
'#size' => $field['settings']['size'],
|
||||
// '#title' => t('Number'),
|
||||
'#required' => ($element['#delta'] == 0 && $element['#required']) ? $element['#required'] : FALSE,
|
||||
'#default_value' => isset($item['number']) ? $item['number'] : NULL,
|
||||
'#attached' => array(
|
||||
'css' => array(
|
||||
drupal_get_path('module', 'cck_phone') . '/cck_phone.css',
|
||||
)
|
||||
),
|
||||
'#weight' => 0,
|
||||
);
|
||||
|
||||
// If only one country code, make it as hidden form item
|
||||
$country_list = array_count_values($settings['country_codes']['country_selection']);
|
||||
if ($country_list['0'] == count($settings['country_codes']['country_selection']) - 1) {
|
||||
foreach (array_keys($country_list) as $k => $v) {
|
||||
if ($v != '0') { // only one value other than '0'
|
||||
$cc = cck_phone_countrycodes($v);
|
||||
$element['country_codes'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $v,
|
||||
);
|
||||
if (!$settings['country_codes']['hide_single_cc']) {
|
||||
$element['country_codes_markup'] = array(
|
||||
'#type' => 'item',
|
||||
'#markup' => $value = $cc['country'] . ' (' . $cc['code'] . ')',
|
||||
'#weight' => ($settings['country_code_position'] == 'after' ? 1 : -1),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element['country_codes'] = array(
|
||||
'#type' => 'select',
|
||||
// '#title' => 'Country code',
|
||||
'#options' => _cck_phone_cc_options(),
|
||||
'#weight' => ($settings['country_code_position'] == 'after' ? 1 : -1),
|
||||
);
|
||||
}
|
||||
|
||||
if (!$element['#required']) {
|
||||
$element['country_codes']['#empty_option'] = t('- Select -');
|
||||
}
|
||||
if (isset($item['country_codes'])) {
|
||||
$element['country_codes']['#default_value'] = $item['country_codes'];
|
||||
}
|
||||
elseif ($settings['enable_default_country']) {
|
||||
$element['country_codes']['#default_value'] = $settings['default_country'];
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* An #element_validate callback for the phone_number element.
|
||||
*/
|
||||
function cck_phone_phone_number_validate(&$element, &$form_state) {
|
||||
$item = $element['#value'];
|
||||
$field = field_widget_field($element, $form_state);
|
||||
$instance = field_widget_instance($element, $form_state);
|
||||
$settings = $instance['settings'];
|
||||
|
||||
if (isset($item['number'])) {
|
||||
$phone_input = trim($item['number']);
|
||||
}
|
||||
if (isset($item['country_codes'])) {
|
||||
$countrycode = trim($item['country_codes']);
|
||||
}
|
||||
$ext_input = '';
|
||||
|
||||
if ($settings['enable_extension'] && isset($item['extension'])) {
|
||||
$ext_input = trim($item['extension']);
|
||||
}
|
||||
|
||||
if (isset($phone_input) && !empty($phone_input)) {
|
||||
if (empty($countrycode)) {
|
||||
form_set_error($field['field_name'], t('The phone number must be accompanied by a country code.'));
|
||||
}
|
||||
else {
|
||||
$error_params = array(
|
||||
'%phone_input' => check_plain($phone_input), // original phone input
|
||||
'%countrycode' => check_plain($countrycode),
|
||||
'%min_length' => CCK_PHONE_PHONE_MIN_LENGTH,
|
||||
'%max_length' => CCK_PHONE_PHONE_MAX_LENGTH,
|
||||
'%ext_input' => check_plain($ext_input),
|
||||
'%ext_max_length' => CCK_PHONE_EXTENSION_MAX_LENGTH,
|
||||
);
|
||||
|
||||
// Only allow digit, dash, space and bracket
|
||||
if (!_cck_phone_valid_input($phone_input, $ext_input)) {
|
||||
$error = t('The phone number must be between %min_length and %max_length digits in length.', $error_params);
|
||||
if ($settings['enable_extension'] && $ext_input != '') {
|
||||
$error .= '<br />' . t('The phone extension must be less than %ext_max_length digits in length.', $error_params);
|
||||
}
|
||||
|
||||
form_set_error($field['field_name'], $error);
|
||||
}
|
||||
else {
|
||||
if (!$settings['all_country_codes']) {
|
||||
if (!_cck_phone_valid_cc_input($settings['country_codes']['country_selection'], $countrycode)) {
|
||||
$error = t('Invalid country code "%countrycode" submitted.', $error_params);
|
||||
form_set_error($field['field_name'], $error);
|
||||
}
|
||||
}
|
||||
// Generic number validation
|
||||
if (!cck_phone_validate_number($countrycode, $phone_input, $ext_input)) {
|
||||
$error = t('The phone number must be between %min_length and %max_length digits in length.', $error_params);
|
||||
if ($settings['enable_extension'] && $ext_input != '') {
|
||||
$error .= '<br />' . t('The phone extension must be less than %ext_max_length digits in length.', $error_params);
|
||||
}
|
||||
|
||||
form_set_error($field['field_name'], $error);
|
||||
}
|
||||
// Country level validation if enabled
|
||||
elseif ($settings['enable_country_level_validation']) {
|
||||
$custom_cc = _cck_phone_custom_cc();
|
||||
|
||||
if (isset($custom_cc[$countrycode])) {
|
||||
$validate_function = $countrycode . '_validate_number';
|
||||
|
||||
if (function_exists($validate_function)) {
|
||||
$error = '';
|
||||
if (!$validate_function($phone_input, $ext_input, $error)) {
|
||||
form_set_error($field['field_name'], t($error, $error_params));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a phone number element.
|
||||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - element: A render element representing the file.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_cck_phone_phone_number($variables) {
|
||||
$element = $variables['element'];
|
||||
|
||||
// This wrapper is required to apply JS behaviors and CSS styling.
|
||||
$output = '';
|
||||
$output .= '<div class="form-phone-number">';
|
||||
$output .= drupal_render_children($element);
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip number of space, hash, dash, bracket, etc leaving digit only.
|
||||
*
|
||||
* @param string $number
|
||||
* @return string Returns digit only phone number.
|
||||
*/
|
||||
function cck_phone_clean_number($number) {
|
||||
// Remove none numeric characters
|
||||
$number = preg_replace('/[^0-9]/', '', $number);
|
||||
|
||||
return $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic validation for Phone Number.
|
||||
*
|
||||
* @param string $countrycode
|
||||
* @param string $number
|
||||
* @return boolean Returns boolean FALSE if the phone number is not valid.
|
||||
*/
|
||||
function cck_phone_validate_number($countrycode, $number, $ext = '') {
|
||||
// We don't want to worry about separators
|
||||
$number = cck_phone_clean_number($number);
|
||||
if ($number !== '' && drupal_strlen($number) > CCK_PHONE_PHONE_MAX_LENGTH) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$ext = cck_phone_clean_number($ext);
|
||||
if ($ext !== '' && drupal_strlen($ext) > CCK_PHONE_EXTENSION_MAX_LENGTH) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Token hook implementations. Included if token.module is installed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_token_list().
|
||||
*
|
||||
* Provide a user readable list of Phone Number tokens.
|
||||
*/
|
||||
function cck_phone_token_list($type = 'all') {
|
||||
if ($type == 'field' || $type == 'all') {
|
||||
$tokens = array();
|
||||
|
||||
$tokens['cck_phone']['number'] = t('Phone number');
|
||||
$tokens['cck_phone']['country_codes'] = t('Country code');
|
||||
$tokens['cck_phone']['extension'] = t('Extension');
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_token_values().
|
||||
*/
|
||||
function cck_phone_token_values($type, $object = NULL, $options = array()) {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'field' && isset($object[0]['number'])) {
|
||||
$item = $object[0];
|
||||
|
||||
$tokens['number'] = $item['number'];
|
||||
$tokens['country_codes'] = $item['country_codes'];
|
||||
$tokens['extension'] = isset($item['extension']) ? $item['extension'] : '';
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines country codes for Phone Number.
|
||||
* Provide country name and international codes per country codes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get all the country codes for supported countries.
|
||||
*
|
||||
* @param $cc
|
||||
* Optional, two character country code. If this is ommitted all country codes
|
||||
* will be returned.
|
||||
* @return
|
||||
* If no country code is provided an array keyed by country code, values are
|
||||
* arrays with a 'country' and 'code' values. If an invalid $cc is provided,
|
||||
* FALSE will be returned. If the country code is valid the country code for
|
||||
* that country will be returned.
|
||||
*/
|
||||
function cck_phone_countrycodes($cc = NULL) {
|
||||
// Alpha-2 codes from ISO 3166-1 http://en.wikipedia.org/wiki/ISO_3166-1
|
||||
// Country codes from http://en.wikipedia.org/wiki/Country_calling_code
|
||||
static $country_code;
|
||||
if (!isset($country_code)) {
|
||||
$country_code = array(
|
||||
'af' => array('country' => t('Afghanistan'), 'code' => '+93'),
|
||||
'al' => array('country' => t('Albania'), 'code' => '+355'),
|
||||
'dz' => array('country' => t('Algeria'), 'code' => '+213'),
|
||||
'as' => array('country' => t('American Samoa'), 'code' => '+1'),
|
||||
'ad' => array('country' => t('Andorra'), 'code' => '+376'),
|
||||
'ao' => array('country' => t('Angola'), 'code' => '+244'),
|
||||
'ai' => array('country' => t('Anguilla'), 'code' => '+1'),
|
||||
'ag' => array('country' => t('Antigua and Barbuda'), 'code' => '+1'),
|
||||
'ar' => array('country' => t('Argentina'), 'code' => '+54'),
|
||||
'am' => array('country' => t('Armenia'), 'code' => '+374'),
|
||||
'aw' => array('country' => t('Aruba'), 'code' => '+297'),
|
||||
'au' => array('country' => t('Australia'), 'code' => '+61'),
|
||||
'at' => array('country' => t('Austria'), 'code' => '+43'),
|
||||
'az' => array('country' => t('Azerbaijan'), 'code' => '+994'),
|
||||
'bs' => array('country' => t('Bahamas, The'), 'code' => '+1'),
|
||||
'bh' => array('country' => t('Bahrain'), 'code' => '+973'),
|
||||
'bd' => array('country' => t('Bangladesh'), 'code' => '+880'),
|
||||
'bb' => array('country' => t('Barbados'), 'code' => '+1'),
|
||||
'by' => array('country' => t('Belarus'), 'code' => '+375'),
|
||||
'be' => array('country' => t('Belgium'), 'code' => '+32'),
|
||||
'bz' => array('country' => t('Belize'), 'code' => '+501'),
|
||||
'bj' => array('country' => t('Benin'), 'code' => '+229'),
|
||||
'bm' => array('country' => t('Bermuda'), 'code' => '+1'),
|
||||
'bt' => array('country' => t('Bhutan'), 'code' => '+975'),
|
||||
'bo' => array('country' => t('Bolivia'), 'code' => '+591'),
|
||||
'ba' => array('country' => t('Bosnia and Herzegovina'), 'code' => '+387'),
|
||||
'bw' => array('country' => t('Botswana'), 'code' => '+267'),
|
||||
'br' => array('country' => t('Brazil'), 'code' => '+55'),
|
||||
'io' => array('country' => t('British Indian Ocean Territory'), 'code' => '+246'),
|
||||
'vg' => array('country' => t('British Virgin Islands'), 'code' => '+1'),
|
||||
'bn' => array('country' => t('Brunei'), 'code' => '+673'),
|
||||
'bg' => array('country' => t('Bulgaria'), 'code' => '+359'),
|
||||
'bf' => array('country' => t('Burkina Faso'), 'code' => '+226'),
|
||||
'bi' => array('country' => t('Burundi'), 'code' => '+257'),
|
||||
'kh' => array('country' => t('Cambodia'), 'code' => '+855'),
|
||||
'cm' => array('country' => t('Cameroon'), 'code' => '+237'),
|
||||
'ca' => array('country' => t('Canada'), 'code' => '+1'),
|
||||
'cv' => array('country' => t('Cape Verde'), 'code' => '+238'),
|
||||
'ky' => array('country' => t('Cayman Islands'), 'code' => '+1'),
|
||||
'cf' => array('country' => t('Central African Republic'), 'code' => '+236'),
|
||||
'td' => array('country' => t('Chad'), 'code' => '+235'),
|
||||
'cl' => array('country' => t('Chile'), 'code' => '+56'),
|
||||
'cn' => array('country' => t('China'), 'code' => '+86'),
|
||||
'cx' => array('country' => t('Christmas Island'), 'code' => '+61'),
|
||||
'cc' => array('country' => t('Cocos-Keeling Islands'), 'code' => '+61'),
|
||||
'co' => array('country' => t('Colombia'), 'code' => '+57'),
|
||||
'km' => array('country' => t('Comoros'), 'code' => '+269'),
|
||||
'cg' => array('country' => t('Congo, Republic of the'), 'code' => '+242'),
|
||||
'cd' => array('country' => t('Congo, Democratic Republic of'), 'code' => '+243'),
|
||||
'ck' => array('country' => t('Cook Islands'), 'code' => '+682'),
|
||||
'cr' => array('country' => t('Costa Rica'), 'code' => '+506'),
|
||||
'hr' => array('country' => t('Croatia'), 'code' => '+385'),
|
||||
'cu' => array('country' => t('Cuba'), 'code' => '+53'),
|
||||
'cy' => array('country' => t('Cyprus'), 'code' => '+357'),
|
||||
'cz' => array('country' => t('Czech Republic'), 'code' => '+420'),
|
||||
'dk' => array('country' => t('Denmark'), 'code' => '+45'),
|
||||
'dj' => array('country' => t('Djibouti'), 'code' => '+253'),
|
||||
'dm' => array('country' => t('Dominica'), 'code' => '+1'),
|
||||
'do' => array('country' => t('Dominican Republic'), 'code' => '+1'),
|
||||
'tp' => array('country' => t('East Timor'), 'code' => '+670'),
|
||||
'ec' => array('country' => t('Ecuador'), 'code' => '+593'),
|
||||
'eg' => array('country' => t('Egypt'), 'code' => '+20'),
|
||||
'sv' => array('country' => t('El Salvador'), 'code' => '+503'),
|
||||
'gq' => array('country' => t('Equatorial Guinea'), 'code' => '+240'),
|
||||
'er' => array('country' => t('Eritrea'), 'code' => '+291'),
|
||||
'ee' => array('country' => t('Estonia'), 'code' => '+372'),
|
||||
'et' => array('country' => t('Ethiopia'), 'code' => '+251'),
|
||||
'fk' => array('country' => t('Falkland Islands'), 'code' => '+500'),
|
||||
'fo' => array('country' => t('Faroe Islands'), 'code' => '+298'),
|
||||
'fj' => array('country' => t('Fiji'), 'code' => '+679'),
|
||||
'fi' => array('country' => t('Finland'), 'code' => '+358'),
|
||||
'fr' => array('country' => t('France'), 'code' => '+33'),
|
||||
'gf' => array('country' => t('French Guiana'), 'code' => '+594'),
|
||||
'pf' => array('country' => t('French Polynesia'), 'code' => '+689'),
|
||||
'ga' => array('country' => t('Gabon'), 'code' => '+241'),
|
||||
'gm' => array('country' => t('Gambia, The'), 'code' => '+220'),
|
||||
'ge' => array('country' => t('Georgia'), 'code' => '+995'),
|
||||
'de' => array('country' => t('Germany'), 'code' => '+49'),
|
||||
'gh' => array('country' => t('Ghana'), 'code' => '+233'),
|
||||
'gi' => array('country' => t('Gibraltar'), 'code' => '+350'),
|
||||
'gr' => array('country' => t('Greece'), 'code' => '+30'),
|
||||
'gl' => array('country' => t('Greenland'), 'code' => '+299'),
|
||||
'gd' => array('country' => t('Grenada'), 'code' => '+1'),
|
||||
'gp' => array('country' => t('Guadeloupe'), 'code' => '+590'),
|
||||
'gu' => array('country' => t('Guam'), 'code' => '+1'),
|
||||
'gt' => array('country' => t('Guatemala'), 'code' => '+502'),
|
||||
'gn' => array('country' => t('Guinea'), 'code' => '+224'),
|
||||
'gw' => array('country' => t('Guinea-Bissau'), 'code' => '+245'),
|
||||
'gy' => array('country' => t('Guyana'), 'code' => '+592'),
|
||||
'ht' => array('country' => t('Haiti'), 'code' => '+509'),
|
||||
'hn' => array('country' => t('Honduras'), 'code' => '+504'),
|
||||
'hk' => array('country' => t('Hong Kong'), 'code' => '+852'),
|
||||
'hu' => array('country' => t('Hungary'), 'code' => '+36'),
|
||||
'is' => array('country' => t('Iceland'), 'code' => '+354'),
|
||||
'in' => array('country' => t('India'), 'code' => '+91'),
|
||||
'id' => array('country' => t('Indonesia'), 'code' => '+62'),
|
||||
'ir' => array('country' => t('Iran'), 'code' => '+98'),
|
||||
'iq' => array('country' => t('Iraq'), 'code' => '+964'),
|
||||
'ie' => array('country' => t('Ireland'), 'code' => '+353'),
|
||||
'il' => array('country' => t('Israel'), 'code' => '+972'),
|
||||
'it' => array('country' => t('Italy'), 'code' => '+39'),
|
||||
'ci' => array('country' => t('Ivory Coast'), 'code' => '+225'),
|
||||
'jm' => array('country' => t('Jamaica'), 'code' => '+1'),
|
||||
'jp' => array('country' => t('Japan'), 'code' => '+81'),
|
||||
'jo' => array('country' => t('Jordan'), 'code' => '+962'),
|
||||
'kz' => array('country' => t('Kazakhstan'), 'code' => '+7'),
|
||||
'ke' => array('country' => t('Kenya'), 'code' => '+254'),
|
||||
'ki' => array('country' => t('Kiribati'), 'code' => '+686'),
|
||||
'kw' => array('country' => t('Kuwait'), 'code' => '+965'),
|
||||
'kg' => array('country' => t('Kyrgyzstan'), 'code' => '+996'),
|
||||
'la' => array('country' => t('Laos'), 'code' => '+856'),
|
||||
'lv' => array('country' => t('Latvia'), 'code' => '+371'),
|
||||
'lb' => array('country' => t('Lebanon'), 'code' => '+961'),
|
||||
'ls' => array('country' => t('Lesotho'), 'code' => '+266'),
|
||||
'lr' => array('country' => t('Liberia'), 'code' => '+231'),
|
||||
'ly' => array('country' => t('Libya'), 'code' => '+218'),
|
||||
'li' => array('country' => t('Liechtenstein'), 'code' => '+423'),
|
||||
'lt' => array('country' => t('Lithuania'), 'code' => '+370'),
|
||||
'lu' => array('country' => t('Luxembourg'), 'code' => '+352'),
|
||||
'mo' => array('country' => t('Macau'), 'code' => '+853'),
|
||||
'mk' => array('country' => t('Macedonia'), 'code' => '+389'),
|
||||
'mg' => array('country' => t('Madagascar'), 'code' => '+261'),
|
||||
'mw' => array('country' => t('Malawi'), 'code' => '+265'),
|
||||
'my' => array('country' => t('Malaysia'), 'code' => '+60'),
|
||||
'mv' => array('country' => t('Maldives'), 'code' => '+960'),
|
||||
'ml' => array('country' => t('Mali'), 'code' => '+223'),
|
||||
'mt' => array('country' => t('Malta'), 'code' => '+356'),
|
||||
'mh' => array('country' => t('Marshall Islands'), 'code' => '+692'),
|
||||
'mq' => array('country' => t('Martinique'), 'code' => '+596'),
|
||||
'mr' => array('country' => t('Mauritania'), 'code' => '+222'),
|
||||
'mu' => array('country' => t('Mauritius'), 'code' => '+230'),
|
||||
'yt' => array('country' => t('Mayotte'), 'code' => '+269'),
|
||||
'mx' => array('country' => t('Mexico'), 'code' => '+52'),
|
||||
'fm' => array('country' => t('Micronesia, Federated States of'), 'code' => '+691'),
|
||||
'md' => array('country' => t('Moldova'), 'code' => '+373'),
|
||||
'mc' => array('country' => t('Monaco'), 'code' => '+377'),
|
||||
'mn' => array('country' => t('Mongolia'), 'code' => '+976'),
|
||||
'me' => array('country' => t('Montenegro'), 'code' => '+382'),
|
||||
'ms' => array('country' => t('Montserrat'), 'code' => '+1'),
|
||||
'ma' => array('country' => t('Morocco'), 'code' => '+212'),
|
||||
'mz' => array('country' => t('Mozambique'), 'code' => '+258'),
|
||||
'mm' => array('country' => t('Myanmar'), 'code' => '+95'),
|
||||
'na' => array('country' => t('Namibia'), 'code' => '+264'),
|
||||
'nr' => array('country' => t('Nauru'), 'code' => '+674'),
|
||||
'np' => array('country' => t('Nepal'), 'code' => '+977'),
|
||||
'nl' => array('country' => t('Netherlands'), 'code' => '+31'),
|
||||
'an' => array('country' => t('Netherlands Antilles'), 'code' => '+599'),
|
||||
'nc' => array('country' => t('New Caledonia'), 'code' => '+687'),
|
||||
'nz' => array('country' => t('New Zealand'), 'code' => '+64'),
|
||||
'ni' => array('country' => t('Nicaragua'), 'code' => '+505'),
|
||||
'ne' => array('country' => t('Niger'), 'code' => '+227'),
|
||||
'ng' => array('country' => t('Nigeria'), 'code' => '+234'),
|
||||
'nu' => array('country' => t('Niue'), 'code' => '+683'),
|
||||
'nf' => array('country' => t('Norfolk Island'), 'code' => '+672'),
|
||||
'kp' => array('country' => t('North Korea'), 'code' => '+850'),
|
||||
'mp' => array('country' => t('Northern Mariana Islands'), 'code' => '+1'),
|
||||
'no' => array('country' => t('Norway'), 'code' => '+47'),
|
||||
'om' => array('country' => t('Oman'), 'code' => '+968'),
|
||||
'pk' => array('country' => t('Pakistan'), 'code' => '+92'),
|
||||
'pw' => array('country' => t('Palau'), 'code' => '+680'),
|
||||
'ps' => array('country' => t('Palestine'), 'code' => '+970'),
|
||||
'pa' => array('country' => t('Panama'), 'code' => '+507'),
|
||||
'pg' => array('country' => t('Papua New Guinea'), 'code' => '+675'),
|
||||
'py' => array('country' => t('Paraguay'), 'code' => '+595'),
|
||||
'pe' => array('country' => t('Peru'), 'code' => '+51'),
|
||||
'ph' => array('country' => t('Philippines'), 'code' => '+63'),
|
||||
'pl' => array('country' => t('Poland'), 'code' => '+48'),
|
||||
'pt' => array('country' => t('Portugal'), 'code' => '+351'),
|
||||
'pr' => array('country' => t('Puerto Rico'), 'code' => '+1'),
|
||||
'qa' => array('country' => t('Qatar'), 'code' => '+974'),
|
||||
'ro' => array('country' => t('Romania'), 'code' => '+40'),
|
||||
'ru' => array('country' => t('Russia'), 'code' => '+7'),
|
||||
'rw' => array('country' => t('Rwanda'), 'code' => '+250'),
|
||||
'sh' => array('country' => t('Saint Helena'), 'code' => '+290'),
|
||||
'kn' => array('country' => t('Saint Kitts and Nevis'), 'code' => '+1'),
|
||||
'lc' => array('country' => t('Saint Lucia'), 'code' => '+1'),
|
||||
'pm' => array('country' => t('Saint Pierre and Miquelon'), 'code' => '+508'),
|
||||
'vc' => array('country' => t('Saint Vincent and the Grenadines'), 'code' => '+1'),
|
||||
'ws' => array('country' => t('Samoa'), 'code' => '+1'),
|
||||
'sm' => array('country' => t('San Marino'), 'code' => '+378'),
|
||||
'st' => array('country' => t('Sao Tome and Principe'), 'code' => '+239'),
|
||||
'sa' => array('country' => t('Saudi Arabia'), 'code' => '+966'),
|
||||
'sn' => array('country' => t('Senegal'), 'code' => '+221'),
|
||||
'rs' => array('country' => t('Serbia'), 'code' => '+381'),
|
||||
'sc' => array('country' => t('Seychelles'), 'code' => '+248'),
|
||||
'sl' => array('country' => t('Sierra Leone'), 'code' => '+232'),
|
||||
'sg' => array('country' => t('Singapore'), 'code' => '+65'),
|
||||
'sk' => array('country' => t('Slovakia'), 'code' => '+421'),
|
||||
'si' => array('country' => t('Slovenia'), 'code' => '+386'),
|
||||
'sb' => array('country' => t('Solomon Islands'), 'code' => '+677'),
|
||||
'so' => array('country' => t('Somalia'), 'code' => '+252'),
|
||||
'za' => array('country' => t('South Africa'), 'code' => '+27'),
|
||||
'kr' => array('country' => t('South Korea'), 'code' => '+82'),
|
||||
'ss' => array('country' => t('South Sudan'), 'code' => '+211'),
|
||||
'es' => array('country' => t('Spain'), 'code' => '+34'),
|
||||
'lk' => array('country' => t('Sri Lanka'), 'code' => '+94'),
|
||||
'sd' => array('country' => t('Sudan'), 'code' => '+249'),
|
||||
'sr' => array('country' => t('Suriname'), 'code' => '+597'),
|
||||
'sz' => array('country' => t('Swaziland'), 'code' => '+268'),
|
||||
'se' => array('country' => t('Sweden'), 'code' => '+46'),
|
||||
'ch' => array('country' => t('Switzerland'), 'code' => '+41'),
|
||||
'sy' => array('country' => t('Syria'), 'code' => '+963'),
|
||||
'tw' => array('country' => t('Taiwan'), 'code' => '+886'),
|
||||
'tj' => array('country' => t('Tajikistan'), 'code' => '+992'),
|
||||
'tz' => array('country' => t('Tanzania'), 'code' => '+255'),
|
||||
'th' => array('country' => t('Thailand'), 'code' => '+66'),
|
||||
'tg' => array('country' => t('Togo'), 'code' => '+228'),
|
||||
'tk' => array('country' => t('Tokelau'), 'code' => '+690'),
|
||||
'to' => array('country' => t('Tonga'), 'code' => '+676'),
|
||||
'tt' => array('country' => t('Trinidad and Tobago'), 'code' => '+1'),
|
||||
'tn' => array('country' => t('Tunisia'), 'code' => '+216'),
|
||||
'tr' => array('country' => t('Turkey'), 'code' => '+90'),
|
||||
'tm' => array('country' => t('Turkmenistan'), 'code' => '+993'),
|
||||
'tc' => array('country' => t('Turks and Caicos Islands'), 'code' => '+1'),
|
||||
'tv' => array('country' => t('Tuvalu'), 'code' => '+688'),
|
||||
'ug' => array('country' => t('Uganda'), 'code' => '+256'),
|
||||
'ua' => array('country' => t('Ukraine'), 'code' => '+380'),
|
||||
'ae' => array('country' => t('United Arab Emirates'), 'code' => '+971'),
|
||||
'gb' => array('country' => t('United Kingdom'), 'code' => '+44'),
|
||||
'us' => array('country' => t('United States'), 'code' => '+1'),
|
||||
'uy' => array('country' => t('Uruguay'), 'code' => '+598'),
|
||||
'vi' => array('country' => t('US Virgin Islands'), 'code' => '+1'),
|
||||
'uz' => array('country' => t('Uzbekistan'), 'code' => '+998'),
|
||||
'vu' => array('country' => t('Vanuatu'), 'code' => '+678'),
|
||||
'va' => array('country' => t('Vatican City'), 'code' => '+39'),
|
||||
've' => array('country' => t('Venezuela'), 'code' => '+58'),
|
||||
'vn' => array('country' => t('Vietnam'), 'code' => '+84'),
|
||||
'wf' => array('country' => t('Wallis and Futuna'), 'code' => '+681'),
|
||||
'ye' => array('country' => t('Yemen'), 'code' => '+967'),
|
||||
'zm' => array('country' => t('Zambia'), 'code' => '+260'),
|
||||
'zw' => array('country' => t('Zimbabwe'), 'code' => '+263'),
|
||||
);
|
||||
}
|
||||
|
||||
if (is_null($cc)) {
|
||||
return $country_code;
|
||||
}
|
||||
elseif (isset($country_code[$cc])) {
|
||||
return $country_code[$cc];
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
165
sites/all/modules/contrib/fields/cck_phone/includes/API.php
Normal file
165
sites/all/modules/contrib/fields/cck_phone/includes/API.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Phone Number custom country API
|
||||
*
|
||||
* 'CC' will be used throughout this document to indicate country code
|
||||
* abbreviation. You should replace it with the correct country code
|
||||
* in the following functions name. For full list of country code
|
||||
* abbreviation, refer to the 2 alphabet list in the countries.txt.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Country field settings.
|
||||
* Country can provide additional field settings for the phone number
|
||||
* field as needed.
|
||||
*
|
||||
* @param $op
|
||||
* The operation to be performed. Possible values:
|
||||
* - "form": Display the field settings form.
|
||||
* - "validate": Check the field settings form for errors.
|
||||
* - "save": Declare which fields to save back to the database.
|
||||
* - "database columns": Declare the columns that content.module should create
|
||||
* and manage on behalf of the field. If the field module wishes to handle
|
||||
* its own database storage, this should be omitted.
|
||||
* - "filters": Declare the Views filters available for the field.
|
||||
* (this is used in CCK's default Views tables definition)
|
||||
* They always apply to the first column listed in the "database columns"
|
||||
* array.
|
||||
* @param $field
|
||||
* The field on which the operation is to be performed.
|
||||
* @return
|
||||
* This varies depending on the operation.
|
||||
* - "form": an array of form elements to add to
|
||||
* the settings page.
|
||||
* - "validate": no return value. Use form_set_error().
|
||||
* - "save": an array of names of form elements to
|
||||
* be saved in the database.
|
||||
* - "database columns": an array keyed by column name, with arrays of column
|
||||
* information as values. This column information must include "type", the
|
||||
* MySQL data type of the column, and may also include a "sortable" parameter
|
||||
* to indicate to views.module that the column contains ordered information.
|
||||
* TODO: Details of other information that can be passed to the database layer can
|
||||
* be found in the API for the Schema API.
|
||||
* - "filters": an array of 'filters' definitions as expected by views.module
|
||||
* (see Views Documentation).
|
||||
* When providing several filters, it is recommended to use the 'name'
|
||||
* attribute in order to let the user distinguish between them. If no 'name'
|
||||
* is specified for a filter, the key of the filter will be used instead.
|
||||
*/
|
||||
function CC_phone_field_settings($op, $field) {
|
||||
switch ($op) {
|
||||
// Country specific field settings
|
||||
case 'form':
|
||||
// ...
|
||||
return $form;
|
||||
|
||||
// Country specific field validation
|
||||
case 'validate':
|
||||
// ...
|
||||
break;
|
||||
|
||||
// Country specific field save
|
||||
case 'save':
|
||||
// ...
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate country level phone number.
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @param $ext
|
||||
* Digits only value.
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC (check_plain'ed)
|
||||
* - "%phone_input": the original number input by user (check_plain'ed)
|
||||
* - "%min_length": allowed minimum length of the phone number
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* - "%ext_input": the original extension input by user (check_plain'ed)
|
||||
* - "%ext_max_length": allowed maximum length of the phone extension
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function CC_validate_number($number, $ext = '', &$error) {
|
||||
// Don't need to check for extension because it has been checked by generic validation as all digits, unless has special format/requirements
|
||||
// your validation
|
||||
|
||||
if (FALSE) {
|
||||
// t() is no needed
|
||||
$error = '"%phone_input" is not a valid North American phone number, it should be a 10 digit number like "999 999 9999"';
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field for saving to DB.
|
||||
*
|
||||
* @param $number
|
||||
* A single phone number item.
|
||||
*/
|
||||
function CC_sanitize_number(&$number) {
|
||||
// your cleanup like removing trunk prefix
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC (check_plain'ed)
|
||||
* - "%phone_input": the original number input by user (check_plain'ed)
|
||||
* - "%min_length": allowed minimum length of the phone number
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* - "%ext_input": the original extension input by user (check_plain'ed)
|
||||
* - "%ext_max_length": allowed maximum length of the phone extension
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function CC_formatter_default($element) {
|
||||
$item = $element['#item'];
|
||||
|
||||
// Display a global phone number with country code.
|
||||
$cc = cck_phone_countrycodes($item['country_codes']);
|
||||
|
||||
// Format the phone number however you like, this is the default
|
||||
$phone = $cc['code'] . '-' . $item['number'];
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function CC_formatter_local($element) {
|
||||
// Display a local phone number without country code.
|
||||
// Format the phone number however you like, this is the default
|
||||
$phone = $element['#item']['number'];
|
||||
|
||||
return $phone;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
|
||||
File an issue if we miss any country codes.
|
||||
|
||||
Use the CC in the custom country code includes
|
||||
e.g.
|
||||
- file name: phone.CC.inc
|
||||
- function names: cck_phone_CC_settings_validate, cck_phone_CC_settings_save
|
||||
|
||||
CC Country name (+Code)
|
||||
--------------------------
|
||||
af - Afghanistan (+93)
|
||||
al - Albania (+355)
|
||||
dz - Algeria (+213)
|
||||
as - American Samoa (+1)
|
||||
ad - Andorra (+376)
|
||||
ao - Angola (+244)
|
||||
ai - Anguilla (+1)
|
||||
ag - Antigua and Barbuda (+1)
|
||||
ar - Argentina (+54)
|
||||
am - Armenia (+374)
|
||||
aw - Aruba (+297)
|
||||
au - Australia (+61)
|
||||
at - Austria (+43)
|
||||
az - Azerbaijan (+994)
|
||||
bs - Bahamas, The (+1)
|
||||
bh - Bahrain (+973)
|
||||
bd - Bangladesh (+880)
|
||||
bb - Barbados (+1)
|
||||
by - Belarus (+375)
|
||||
be - Belgium (+32)
|
||||
bz - Belize (+501)
|
||||
bj - Benin (+229)
|
||||
bm - Bermuda (+1)
|
||||
bt - Bhutan (+975)
|
||||
bo - Bolivia (+591)
|
||||
ba - Bosnia and Herzegovina (+387)
|
||||
bw - Botswana (+267)
|
||||
br - Brazil (+55)
|
||||
io - British Indian Ocean Territory (+246)
|
||||
vg - British Virgin Islands (+1)
|
||||
bn - Brunei (+673)
|
||||
bg - Bulgaria (+359)
|
||||
bf - Burkina Faso (+226)
|
||||
bi - Burundi (+257)
|
||||
kh - Cambodia (+855)
|
||||
cm - Cameroon (+237)
|
||||
ca - Canada (+1)
|
||||
cv - Cape Verde (+238)
|
||||
ky - Cayman Islands (+1)
|
||||
cf - Central African Republic (+236)
|
||||
td - Chad (+235)
|
||||
cl - Chile (+56)
|
||||
cn - China (+86)
|
||||
cx - Christmas Island (+61)
|
||||
cc - Cocos-Keeling Islands (+61)
|
||||
co - Colombia (+57)
|
||||
km - Comoros (+269)
|
||||
cg - Congo, Republic of the (+242)
|
||||
cd - Congo, Democratic Republic of (+243)
|
||||
ck - Cook Islands (+682)
|
||||
cr - Costa Rica (+506)
|
||||
hr - Croatia (+385)
|
||||
cu - Cuba (+53)
|
||||
cy - Cyprus (+357)
|
||||
cz - Czech Republic (+420)
|
||||
dk - Denmark (+45)
|
||||
dj - Djibouti (+253)
|
||||
dm - Dominica (+1)
|
||||
do - Dominican Republic (+1)
|
||||
tp - East Timor (+670)
|
||||
ec - Ecuador (+593)
|
||||
eg - Egypt (+20)
|
||||
sv - El Salvador (+503)
|
||||
gq - Equatorial Guinea (+240)
|
||||
er - Eritrea (+291)
|
||||
ee - Estonia (+372)
|
||||
et - Ethiopia (+251)
|
||||
fk - Falkland Islands (+500)
|
||||
fo - Faroe Islands (+298)
|
||||
fj - Fiji (+679)
|
||||
fi - Finland (+358)
|
||||
fr - France (+33)
|
||||
gf - French Guiana (+594)
|
||||
pf - French Polynesia (+689)
|
||||
ga - Gabon (+241)
|
||||
gm - Gambia, The (+220)
|
||||
ge - Georgia (+995)
|
||||
de - Germany (+49)
|
||||
gh - Ghana (+233)
|
||||
gi - Gibraltar (+350)
|
||||
gr - Greece (+30)
|
||||
gl - Greenland (+299)
|
||||
gd - Grenada (+1)
|
||||
gp - Guadeloupe (+590)
|
||||
gu - Guam (+1)
|
||||
gt - Guatemala (+502)
|
||||
gn - Guinea (+224)
|
||||
gw - Guinea-Bissau (+245)
|
||||
gy - Guyana (+592)
|
||||
ht - Haiti (+509)
|
||||
hn - Honduras (+504)
|
||||
hk - Hong Kong (+852)
|
||||
hu - Hungary (+36)
|
||||
is - Iceland (+354)
|
||||
in - India (+91)
|
||||
id - Indonesia (+62)
|
||||
ir - Iran (+98)
|
||||
iq - Iraq (+964)
|
||||
ie - Ireland (+353)
|
||||
il - Israel (+972)
|
||||
it - Italy (+39)
|
||||
ci - Ivory Coast (+225)
|
||||
jm - Jamaica (+1)
|
||||
jp - Japan (+81)
|
||||
jo - Jordan (+962)
|
||||
kz - Kazakhstan (+7)
|
||||
ke - Kenya (+254)
|
||||
ki - Kiribati (+686)
|
||||
kw - Kuwait (+965)
|
||||
kg - Kyrgyzstan (+996)
|
||||
la - Laos (+856)
|
||||
lv - Latvia (+371)
|
||||
lb - Lebanon (+961)
|
||||
ls - Lesotho (+266)
|
||||
lr - Liberia (+231)
|
||||
ly - Libya (+218)
|
||||
li - Liechtenstein (+423)
|
||||
lt - Lithuania (+370)
|
||||
lu - Luxembourg (+352)
|
||||
mo - Macau (+853)
|
||||
mk - Macedonia (+389)
|
||||
mg - Madagascar (+261)
|
||||
mw - Malawi (+265)
|
||||
my - Malaysia (+60)
|
||||
mv - Maldives (+960)
|
||||
ml - Mali (+223)
|
||||
mt - Malta (+356)
|
||||
mh - Marshall Islands (+692)
|
||||
mq - Martinique (+596)
|
||||
mr - Mauritania (+222)
|
||||
mu - Mauritius (+230)
|
||||
yt - Mayotte (+269)
|
||||
mx - Mexico (+52)
|
||||
fm - Micronesia, Federated States of (+691)
|
||||
md - Moldova (+373)
|
||||
mc - Monaco (+377)
|
||||
mn - Mongolia (+976)
|
||||
me - Montenegro (+382)
|
||||
ms - Montserrat (+1)
|
||||
ma - Morocco (+212)
|
||||
mz - Mozambique (+258)
|
||||
mm - Myanmar (+95)
|
||||
na - Namibia (+264)
|
||||
nr - Nauru (+674)
|
||||
np - Nepal (+977)
|
||||
nl - Netherlands (+31)
|
||||
an - Netherlands Antilles (+599)
|
||||
nc - New Caledonia (+687)
|
||||
nz - New Zealand (+64)
|
||||
ni - Nicaragua (+505)
|
||||
ne - Niger (+227)
|
||||
ng - Nigeria (+234)
|
||||
nu - Niue (+683)
|
||||
nf - Norfolk Island (+672)
|
||||
kp - North Korea (+850)
|
||||
mp - Northern Mariana Islands (+1)
|
||||
no - Norway (+47)
|
||||
om - Oman (+968)
|
||||
pk - Pakistan (+92)
|
||||
pw - Palau (+680)
|
||||
ps - Palestine (+970)
|
||||
pa - Panama (+507)
|
||||
pg - Papua New Guinea (+675)
|
||||
py - Paraguay (+595)
|
||||
pe - Peru (+51)
|
||||
ph - Philippines (+63)
|
||||
pl - Poland (+48)
|
||||
pt - Portugal (+351)
|
||||
pr - Puerto Rico (+1)
|
||||
qa - Qatar (+974)
|
||||
ro - Romania (+40)
|
||||
ru - Russia (+7)
|
||||
rw - Rwanda (+250)
|
||||
sh - Saint Helena (+290)
|
||||
kn - Saint Kitts and Nevis (+1)
|
||||
lc - Saint Lucia (+1)
|
||||
pm - Saint Pierre and Miquelon (+508)
|
||||
vc - Saint Vincent and the Grenadines (+1)
|
||||
ws - Samoa (+1)
|
||||
sm - San Marino (+378)
|
||||
st - Sao Tome and Principe (+239)
|
||||
sa - Saudi Arabia (+966)
|
||||
sn - Senegal (+221)
|
||||
rs - Serbia (+381)
|
||||
sc - Seychelles (+248)
|
||||
sl - Sierra Leone (+232)
|
||||
sg - Singapore (+65)
|
||||
sk - Slovakia (+421)
|
||||
si - Slovenia (+386)
|
||||
sb - Solomon Islands (+677)
|
||||
so - Somalia (+252)
|
||||
za - South Africa (+27)
|
||||
kr - South Korea (+82)
|
||||
ss - South Sudan (+211)
|
||||
es - Spain (+34)
|
||||
lk - Sri Lanka (+94)
|
||||
sd - Sudan (+249)
|
||||
sr - Suriname (+597)
|
||||
sz - Swaziland (+268)
|
||||
se - Sweden (+46)
|
||||
ch - Switzerland (+41)
|
||||
sy - Syria (+963)
|
||||
tw - Taiwan (+886)
|
||||
tj - Tajikistan (+992)
|
||||
tz - Tanzania (+255)
|
||||
th - Thailand (+66)
|
||||
tg - Togo (+228)
|
||||
tk - Tokelau (+690)
|
||||
to - Tonga (+676)
|
||||
tt - Trinidad and Tobago (+1)
|
||||
tn - Tunisia (+216)
|
||||
tr - Turkey (+90)
|
||||
tm - Turkmenistan (+993)
|
||||
tc - Turks and Caicos Islands (+1)
|
||||
tv - Tuvalu (+688)
|
||||
ug - Uganda (+256)
|
||||
ua - Ukraine (+380)
|
||||
ae - United Arab Emirates (+971)
|
||||
gb - United Kingdom (+44)
|
||||
us - United States (+1)
|
||||
uy - Uruguay (+598)
|
||||
vi - US Virgin Islands (+1)
|
||||
uz - Uzbekistan (+998)
|
||||
vu - Vanuatu (+678)
|
||||
va - Vatican City (+39)
|
||||
ve - Venezuela (+58)
|
||||
vn - Vietnam (+84)
|
||||
wf - Wallis and Futuna (+681)
|
||||
ye - Yemen (+967)
|
||||
zm - Zambia (+260)
|
||||
zw - Zimbabwe (+263)
|
||||
173
sites/all/modules/contrib/fields/cck_phone/includes/phone.au.inc
Normal file
173
sites/all/modules/contrib/fields/cck_phone/includes/phone.au.inc
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for Australia phone numbers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Patterns generated from Telecommunications Numbering Plan 1997
|
||||
* http://www.comlaw.gov.au/comlaw/management.nsf/lookupindexpagesbyid/IP200506356?OpenDocument
|
||||
*/
|
||||
function _cck_phone_au_number_patterns() {
|
||||
$valid_patterns = array(
|
||||
// Geographic numbers (10 digits) - Central East Region (NSW, ACT, Northern VIC).
|
||||
'/^02[4,6-9][0-9]{7}$/',
|
||||
'/^023[3,8][0-9]{6}$/',
|
||||
'/^025[0-3,5-9][0-9]{6}$/',
|
||||
|
||||
// Geographic numbers (10 digits) - South East Region (TAS, Southern NSW, VIC).
|
||||
'/^03[5,7-9][0-9]{7}$/',
|
||||
'/^034[0-5,7-9][0-9]{6}$/',
|
||||
'/^036[1-5,7][0-9]{6}$/',
|
||||
|
||||
// Geographic numbers (10 digits) - North East Region (QLD).
|
||||
'/^07[2-4][0-9]{7}$/',
|
||||
'/^075[2-7][0-9]{6}$/',
|
||||
'/^0776[0-9]{6}$/',
|
||||
|
||||
// Geographic numbers (10 digits) - Central and West Region (WA, SA, NT and Western NSW).
|
||||
'/^08[7-9][0-9]{7}$/',
|
||||
'/^085[1-4][0-9]{6}$/',
|
||||
'/^086[0-8][0-9]{6}$/',
|
||||
|
||||
// Mobile numbers (10 digits).
|
||||
'/^04[0-9]{8}$/',
|
||||
|
||||
// Local rate special numbers (10 digits).
|
||||
'/^130[0-9]{7}$/',
|
||||
|
||||
// Local rate special numbers (6 digits).
|
||||
'/^13[1-3,5-9][0-9]{3}$/',
|
||||
'/^134[0-4,6-9][0-9]{2}$/',
|
||||
|
||||
// Free phone numbers (10 digits).
|
||||
'/^180[0-1][0-9]{6}$/',
|
||||
|
||||
// Satelite telephone numbers (10 digits).
|
||||
'/^014[1-3,5,7][0-9]{6}$/',
|
||||
|
||||
// Satelite telephone numbers (9 digits).
|
||||
'/^014[0,4,6,8-9][0-9]{5}$/',
|
||||
'/^015[0-9]{6}$/',
|
||||
'/^017[1,2,8,9][0-9]{5}$/',
|
||||
'/^018[0-9]{6}$/',
|
||||
);
|
||||
|
||||
$invalid_patterns = array(
|
||||
// Invalid geographic phone numbers.
|
||||
'/^0[2,3,7]5550[0-9]{4}$/',
|
||||
);
|
||||
|
||||
$format_search_patterns = array(
|
||||
// Geographic numbers (10 digits).
|
||||
'/^(0)([2,3,7,8])([0-9]{4})([0-9]{4})$/',
|
||||
|
||||
// Mobile numbers (10 digits).
|
||||
'/^(0)(4[0-9]{2})([0-9]{3})([0-9]{3})$/',
|
||||
|
||||
// 1300 numbers, 1800 numbers (10 digits).
|
||||
'/^(1[3,8][0-9]{2})([0-9]{3})([0-9]{3})$/',
|
||||
|
||||
// 13 numbers (6 digits).
|
||||
'/^(13)([0-9]{2})([0-9]{2})$/',
|
||||
|
||||
// Satelite telephone numbers (10 digits).
|
||||
'/^(0)(14)([0-9])([0-9]{3})([0-9]{3})$/',
|
||||
|
||||
// Satelite telephone numbers (9 digits).
|
||||
'/^(0)(1[4,5,7,8])([0-9]{3})([0-9]{3})$/',
|
||||
);
|
||||
|
||||
$format_replace_patterns = array(
|
||||
// Geographic numbers (10 digits).
|
||||
'($1$2) $3 $4',
|
||||
|
||||
// Mobile numbers (10 digits).
|
||||
'$1$2 $3 $4',
|
||||
|
||||
// 1300 numbers, 1800 numbers (10 digits).
|
||||
'$1 $2 $3',
|
||||
|
||||
// 13 numbers (6 digits).
|
||||
'$1 $2 $3',
|
||||
|
||||
// Satelite telephone numbers (10 digits).
|
||||
'$1$2 $3 $4 $5',
|
||||
|
||||
// Satelite telephone numbers (9 digits).
|
||||
'$1$2 $3 $4',
|
||||
);
|
||||
|
||||
$format_replace_patterns_international = array(
|
||||
// Geographic numbers (10 digits).
|
||||
'$2 $3 $4',
|
||||
|
||||
// Mobile numbers (10 digits).
|
||||
'$2 $3 $4',
|
||||
|
||||
// 1300 numbers, 1800 numbers (10 digits).
|
||||
'$1 $2 $3',
|
||||
|
||||
// 13 numbers (6 digits).
|
||||
'$1 $2 $3',
|
||||
|
||||
// Satelite telephone numbers (10 digits).
|
||||
'$2 $3 $4 $5',
|
||||
|
||||
// Satelite telephone numbers (9 digits).
|
||||
'$2 $3 $4',
|
||||
);
|
||||
|
||||
return array($valid_patterns, $invalid_patterns, $format_search_patterns, $format_replace_patterns, $format_replace_patterns_international);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that $number is a valid Australian phone number.
|
||||
*/
|
||||
function au_validate_number($number, $ext = '', &$error) {
|
||||
// Don't need to check for extension because it has been checked by generic validation as all digits, unless has special format/requirements
|
||||
// We don't want to worry about separators
|
||||
$number = cck_phone_clean_number($number);
|
||||
|
||||
if (empty($number)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
list($valid_patterns, $invalid_patterns, $format_search_patterns, $format_replace_patterns, $format_replace_patterns_international) = _cck_phone_au_number_patterns();
|
||||
|
||||
$invalid_number = preg_replace($invalid_patterns, '', $number);
|
||||
$correct_number = preg_replace($valid_patterns, '', $number);
|
||||
|
||||
if (empty($invalid_number)) {
|
||||
$error = 'The phone number you have entered is classified as unusable by the Australian telecommunications authority.';
|
||||
return FALSE;
|
||||
}
|
||||
elseif (!empty($correct_number)) {
|
||||
$error = 'You have not entered a valid australian phone number. Please enter a 10 digit phone number including the area code, but not including the 61 international prefix. Valid 1800, 1300, and 13 numbers are accepted, as are satilite and AMPS numbers.';
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for Australian phone number.
|
||||
*/
|
||||
function au_formatter_default($element) {
|
||||
// Display a global phone number with country code.
|
||||
$cc = cck_phone_countrycodes($element['country_codes']);
|
||||
|
||||
list($valid_patterns, $invalid_patterns, $format_search_patterns, $format_replace_patterns, $format_replace_patterns_international) = _cck_phone_au_number_patterns();
|
||||
|
||||
return $cc['code'] .' '. preg_replace($format_search_patterns, $format_replace_patterns_international, $element['number']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local formatter for local Australian phone number.
|
||||
*/
|
||||
function au_formatter_local($element) {
|
||||
list($valid_patterns, $invalid_patterns, $format_search_patterns, $format_replace_patterns, $format_replace_patterns_international) = _cck_phone_au_number_patterns();
|
||||
|
||||
return preg_replace($format_search_patterns, $format_replace_patterns, $element['number']);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for Canada phone numbers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Verifies that $number is a valid ten-digit North American phone number.
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @param $ext
|
||||
* Digits only value.
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function ca_validate_number($number, $ext = '', &$error) {
|
||||
return us_validate_number($number, $ext = '', $error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field for saving to DB.
|
||||
*
|
||||
* @param $number
|
||||
* A single phone number item.
|
||||
*/
|
||||
function ca_sanitize_number(&$number) {
|
||||
us_sanitize_number($number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function ca_formatter_default($element) {
|
||||
return us_formatter_default($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function ca_formatter_local($element) {
|
||||
return us_formatter_local($element);
|
||||
}
|
||||
127
sites/all/modules/contrib/fields/cck_phone/includes/phone.gb.inc
Normal file
127
sites/all/modules/contrib/fields/cck_phone/includes/phone.gb.inc
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for United Kingdom phone numbers.
|
||||
*/
|
||||
|
||||
function _uk_phone_rules() {
|
||||
// TODO: more detailed check by area codes
|
||||
return '/^
|
||||
0*(2[03489])(\d{4})(\d{4}) # 02x [eight-digit local number]
|
||||
|
|
||||
0*(11[3-8])(\d{3})(\d{4}) # 011x [seven-digit local number]
|
||||
|
|
||||
0*(1[2-9]1)(\d{3})(\d{4}) # 01x1 [seven-digit local number]
|
||||
|
|
||||
0*(1[2-9][0|2-9]\d)(\d{5,6}) # 01xxx [mostly six-digit local numbers] (but not 01x1 codes)
|
||||
$/x';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate country level phone number.
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @param $ext
|
||||
* Digits only value.
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function gb_validate_number($number, $ext = '', &$error) {
|
||||
// We don't want to worry about separators
|
||||
$number = cck_phone_clean_number($number);
|
||||
|
||||
if (preg_match(_uk_phone_rules(), $number)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// t() is not needed
|
||||
$error = '"%phone_input" is not a valid United Kingdom phone number, it should be a 10 digit number like "99 9999 9999", with optional leading "0"';
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field for saving to DB.
|
||||
*
|
||||
* @param $number
|
||||
* A single phone number item.
|
||||
*/
|
||||
function gb_sanitize_number(&$number) {
|
||||
// Remove trunk prefix '0'
|
||||
$number = preg_replace('/^([0]*)/', '', $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function gb_formatter_default($element) {
|
||||
// Display a global phone number with country code.
|
||||
$phone = '';
|
||||
$number = $element['number'];
|
||||
if ($number) {
|
||||
$cc = cck_phone_countrycodes($element['country_codes']);
|
||||
if (preg_match(_uk_phone_rules(), $number, $matches)) {
|
||||
// output as +44 AA BBBB CCCC, +44 AAA BBB CCCC or +44 AAAA BBB CCC
|
||||
array_shift($matches);
|
||||
$phone = $cc['code'] . ' ' . implode(' ', $matches);
|
||||
}
|
||||
else {
|
||||
$phone = "$cc[code] $number";
|
||||
}
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function gb_formatter_local($element) {
|
||||
// Display a local phone number without country code.
|
||||
$phone = '';
|
||||
$number = $element['number'];
|
||||
if ($number) {
|
||||
if (preg_match(_uk_phone_rules(), $number, $matches)) {
|
||||
// output as 0AA BBBB CCCC, 0AAA BBB CCCC or 0AAAA BBB CCC
|
||||
array_shift($matches);
|
||||
$phone = '0' . implode(' ', $matches);
|
||||
}
|
||||
else {
|
||||
$phone = "0$number";
|
||||
}
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
165
sites/all/modules/contrib/fields/cck_phone/includes/phone.hu.inc
Normal file
165
sites/all/modules/contrib/fields/cck_phone/includes/phone.hu.inc
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for Hungarian phone numbers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Verifies and mage parts from $number
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @return boolean
|
||||
* Array
|
||||
* if array['error'] is present, the validation fails
|
||||
* else ['area'] for area number
|
||||
* ['first'] ['second'] for the AA/BBB-CCC numbers
|
||||
* ['first'] ['second'] ['third'] for the A(A)/BBB-CC-DD numbers
|
||||
*/
|
||||
function hu_parts($number) {
|
||||
/**
|
||||
* Because Hungary an telephone numbers are both in open and closed number region, the area code length may be vary. If the area code is 1, 7 more digits follow it.
|
||||
* If the area code is 20/30/70, also 7 more digits.
|
||||
* If any other 2 digits are code is appear, we want 6 more digits.
|
||||
*
|
||||
* So complecated, I know :)
|
||||
*
|
||||
*/
|
||||
|
||||
$result = array();
|
||||
// Last 9 digits
|
||||
$n = drupal_substr($number, -9);
|
||||
|
||||
if ($n === FALSE || (drupal_substr($n, 0, 1) != 2 && drupal_substr($n, 0, 1) != 3 && drupal_substr($n, 0, 1) != 7)) {
|
||||
// No 9 digit, check for 8 digit
|
||||
if (drupal_substr($number, -8) === FALSE) {
|
||||
// No 8 digit, too short for valid telephone number
|
||||
$result['error'] = '"%phone_input" is not a valid Hungarian phone number, it should be a 9 digit number like "20/123-45-67" or a 8 digit number like "23/123-456"';
|
||||
}
|
||||
else {
|
||||
$n = drupal_substr($number, -8);
|
||||
// It is 8 digits
|
||||
if (drupal_substr($n, 0, 1) == 1) {
|
||||
// A number from Budapest
|
||||
$result['area'] = drupal_substr($n, 0, 1);
|
||||
$result['first'] = drupal_substr($n, 1, 3);
|
||||
$result['second'] = drupal_substr($n, 4, 2);
|
||||
$result['third'] = drupal_substr($n, 6, 2);
|
||||
}
|
||||
else {
|
||||
// A number from countryside
|
||||
$result['area'] = drupal_substr($n, 0, 2);
|
||||
$result['first'] = drupal_substr($n, 2, 3);
|
||||
$result['second'] = drupal_substr($n, 5, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Cell phone number
|
||||
$result['area'] = drupal_substr($n, 0, 2);
|
||||
$result['first'] = drupal_substr($n, 2, 3);
|
||||
$result['second'] = drupal_substr($n, 5, 2);
|
||||
$result['third'] = drupal_substr($n, 7, 2);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that $number is a valid nine digit Hungarian phone number.
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @param $ext
|
||||
* Digits only value.
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function hu_validate_number($number, $ext = '', &$error) {
|
||||
// Don't need to check for extension because it has been checked by generic validation as all digits, unless has special format/requirements
|
||||
// We don't want to worry about separators
|
||||
|
||||
$number = cck_phone_clean_number($number);
|
||||
|
||||
$result = hu_parts($number);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
// t() is no needed
|
||||
$error = $result['error'];
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field for saving to DB.
|
||||
*
|
||||
* @param $number
|
||||
* A single phone number item.
|
||||
*/
|
||||
function hu_sanitize_number(&$number) {
|
||||
// Remove prefix '36' or '+36'
|
||||
|
||||
$number = preg_replace('/^(?:\+?36|06*)/', '', $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['country_codes']: alpha-2 country code
|
||||
* $element['number']: phone number
|
||||
* $element['extension']: ext
|
||||
* @return boolean
|
||||
* STRING The formatted number
|
||||
*/
|
||||
function hu_formatter_default($element) {
|
||||
$number = $element['number'];
|
||||
$ext = $element['extension'];
|
||||
|
||||
$result = hu_parts($number);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
return $number . ($ext ? '/' . $ext : '');
|
||||
}
|
||||
|
||||
// output as +36 (AA) BBB CCDD/ext or +36 (AA) BBB CCC/ext
|
||||
$phone = '+36 (' . $result['area'] . ') ' . $result['first'] . ' ' . $result['second'] . $result['third'];
|
||||
|
||||
return $phone . ($ext ? '/' . $ext : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['country_codes']: alpha-2 country code
|
||||
* $element['number']: phone number
|
||||
* $element['extension']: ext
|
||||
* @return boolean
|
||||
* STRING The formatted number
|
||||
*/
|
||||
function hu_formatter_local($element) {
|
||||
$number = $element['number'];
|
||||
$ext = $element['extension'];
|
||||
|
||||
$result = hu_parts($number);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
return $number . ($ext ? '/' . $ext : '');
|
||||
}
|
||||
|
||||
// output as AA/BBB-CC-DD or AA/BBB-CCC
|
||||
$phone = $result['area'] . '/' . $result['first'] . '-' . $result['second'] . (isset($result['third']) ? '-' . $result['third'] : '');
|
||||
|
||||
return $phone . ($ext ? '/' . $ext : '');
|
||||
}
|
||||
178
sites/all/modules/contrib/fields/cck_phone/includes/phone.my.inc
Normal file
178
sites/all/modules/contrib/fields/cck_phone/includes/phone.my.inc
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for Malaysia phone numbers.
|
||||
*/
|
||||
|
||||
function _my_phone_rules() {
|
||||
$rules = array();
|
||||
|
||||
// rule: 'area code, min length, max length'
|
||||
// Geographic land line number
|
||||
$rules[] = array("2", 7); // Domestic access code to Singapore
|
||||
$rules[] = array("3", 8); // Selangor & Federal Territories of Kuala Lumpur & Putrajaya
|
||||
$rules[] = array("4", 7); // Kedah, Penang & Perlis
|
||||
$rules[] = array("5", 7); // Perak & Cameron Highlands (Pahang)
|
||||
$rules[] = array("6", 7); // Melaka, Negeri Sembilan & Muar (Johor)
|
||||
$rules[] = array("7", 7); // Johor (except Muar)
|
||||
$rules[] = array("80", 6); // Domestic access code to Brunei (East Malaysia only)
|
||||
// $rules[] = array("81", 6); // reserved
|
||||
$rules[] = array("82", 6); // Kuching (Sarawak)
|
||||
$rules[] = array("83", 6); // Sri Aman (Sarawak)
|
||||
$rules[] = array("84", 6); // Sarikei, Bintangor, Sibu, Kanowit, Song, & Kapit (Sarawak)
|
||||
$rules[] = array("85", 6); // Lawas, Limbang, Miri (Sarawak)
|
||||
$rules[] = array("86", 6); // Bintulu, Belaga (Sarawak)
|
||||
$rules[] = array("87", 6); // Inner District (Sabah) & Federal Territory of Labuan
|
||||
$rules[] = array("88", 6); // Kota Kinabalu, Kudat (Sabah)
|
||||
$rules[] = array("89", 6); // Lahad Datu, Sandakan, Tawau (Sabah)
|
||||
$rules[] = array("9", 7); // Kelantan, Pahang (except Cameron Highlands) & Terengganu
|
||||
|
||||
// Mobile number structure
|
||||
$rules[] = array("10", 7);
|
||||
$rules[] = array("11", 7);
|
||||
$rules[] = array("12", 7);
|
||||
$rules[] = array("13", 7);
|
||||
$rules[] = array("14", 7);
|
||||
$rules[] = array("15", 7);
|
||||
$rules[] = array("16", 7);
|
||||
$rules[] = array("17", 7);
|
||||
$rules[] = array("18", 7);
|
||||
$rules[] = array("19", 7);
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that $number is a valid Malaysia phone number.
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @param $ext
|
||||
* Digits only value.
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function my_validate_number($number, $ext = '', &$error) {
|
||||
// We don't want to worry about separators
|
||||
$number = cck_phone_clean_number($number);
|
||||
|
||||
foreach (_my_phone_rules() as $rule) {
|
||||
// define regular expression
|
||||
$regex = '/^
|
||||
([0]*) # an optional 0
|
||||
(' . $rule[0] . ') # area code
|
||||
\d{' . $rule[1] . '} # local number within length $rule[1] & $rule[2]
|
||||
$/x';
|
||||
|
||||
$result = preg_match($regex, $number, $matches);
|
||||
|
||||
if ($result) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// t() is no needed
|
||||
$error = '"%phone_input" is not a valid Malaysia phone number, it should be a 9-10 digit number like "03-2222 2222", "0" is optional and will be removed.';
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field for saving to DB.
|
||||
*
|
||||
* @param $number
|
||||
* A single phone number item.
|
||||
*/
|
||||
function my_sanitize_number(&$number) {
|
||||
// Remove trunk prefix '0'
|
||||
|
||||
$number = preg_replace('/^([0]*)/', '', $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function my_formatter_default($element) {
|
||||
$phone = '';
|
||||
|
||||
// Display a global phone number with country code.
|
||||
$cc = cck_phone_countrycodes($element['country_codes']);
|
||||
|
||||
// Format the phone number however you like, this is the default
|
||||
foreach (_my_phone_rules() as $rule) {
|
||||
// define regular expression
|
||||
$regex = '/^
|
||||
(' . $rule[0] . ') # area code
|
||||
(\d{3,4})
|
||||
(\d{4})
|
||||
$/x';
|
||||
|
||||
$result = preg_match($regex, $element['number'], $matches);
|
||||
|
||||
if ($result) {
|
||||
// output as +60A-BBB CCCC or +60A-BBBB CCCC
|
||||
$phone = $cc['code'] . $matches[1] . '-' . $matches[2] . ' ' . $matches[3];
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['#item']['country_codes']: alpha-2 country code
|
||||
* $element['#item']['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function my_formatter_local($element) {
|
||||
// Display a local phone number without country code.
|
||||
$phone = $element['number'];
|
||||
|
||||
foreach (_my_phone_rules() as $rule) {
|
||||
// define regular expression
|
||||
$regex = '/^
|
||||
(' . $rule[0] . ') # area code
|
||||
(\d{3,4})
|
||||
(\d{4})
|
||||
$/x';
|
||||
|
||||
$result = preg_match($regex, $phone, $matches);
|
||||
|
||||
if ($result) {
|
||||
// output as 0A-BBB CCCC or 0A-BBBB CCCC
|
||||
$phone = '0' . $matches[1] . '-' . $matches[2] . ' ' . $matches[3];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for Polish phone numbers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Polish phone number regex helper.
|
||||
*/
|
||||
function _pl_regex() {
|
||||
return '/^
|
||||
([1-9]\d) # 2-digit area code
|
||||
([1-9]\d{2}) # 3-digit phone prefix (cannot start with 0)
|
||||
(\d{4})
|
||||
$/x';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that $number is a valid 9-digit Polish phone number.
|
||||
*/
|
||||
function pl_validate_number($number, $ext = '', &$error) {
|
||||
$number = cck_phone_clean_number($number);
|
||||
$regex = _pl_regex();
|
||||
|
||||
$result = preg_match($regex, $number, $matches);
|
||||
|
||||
if ($result) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
$error = '"%phone_input" is not a valid Polish phone number, it should be a 9-digit
|
||||
number like "99 999 99 99".';
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for formatting output.
|
||||
* Output as +48 (AA) BBB CCCC
|
||||
*/
|
||||
function _pl_formatter($element) {
|
||||
$phone = '';
|
||||
|
||||
$regex = _pl_regex();
|
||||
|
||||
$result = preg_match($regex, $element['number'], $matches);
|
||||
|
||||
if ($result) {
|
||||
$phone = '(' . $matches[1] . ') ' . $matches[2] . ' ' . $matches[3];
|
||||
}
|
||||
return $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*/
|
||||
function pl_formatter_default($element) {
|
||||
$cc = cck_phone_countrycodes($element['country_codes']);
|
||||
$number = _pl_formatter($element);
|
||||
return $cc['code'] . ' ' . $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*/
|
||||
function pl_formatter_local($element) {
|
||||
return _pl_formatter($element);
|
||||
}
|
||||
139
sites/all/modules/contrib/fields/cck_phone/includes/phone.us.inc
Normal file
139
sites/all/modules/contrib/fields/cck_phone/includes/phone.us.inc
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CCK Field for North American phone numbers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Verifies that $number is a valid ten-digit North American phone number.
|
||||
*
|
||||
* @param $number
|
||||
* Digits only value.
|
||||
* @param $ext
|
||||
* Digits only value.
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function us_validate_number($number, $ext = '', &$error) {
|
||||
// Don't need to check for extension because it has been checked by generic validation as all digits, unless has special format/requirements
|
||||
// We don't want to worry about separators
|
||||
$number = cck_phone_clean_number($number);
|
||||
|
||||
// define regular expression
|
||||
$regex = '/^
|
||||
([1]*) # an optional 1
|
||||
[2-9][0-8]\d # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
|
||||
[2-9]\d{2} # 3-digit prefix (cannot start with 0 or 1)
|
||||
\d{4} # 4-digit line number
|
||||
$/x';
|
||||
|
||||
$result = preg_match($regex, $number, $matches);
|
||||
|
||||
if ($result && $matches[1] == '') {
|
||||
return TRUE;
|
||||
}
|
||||
elseif ($result && $matches[1] == '1') {
|
||||
// t() is no needed
|
||||
$error = 'Please enter a 10 digit North American phone number like "999 999 9999", without the country code "1" or "+1"';
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
// t() is no needed
|
||||
$error = '"%phone_input" is not a valid North American phone number, it should be a 10 digit number like "999 999 9999"';
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup user-entered values for a phone number field for saving to DB.
|
||||
*
|
||||
* @param $number
|
||||
* A single phone number item.
|
||||
*/
|
||||
function us_sanitize_number(&$number) {
|
||||
// Remove prefix '1'
|
||||
|
||||
$number = preg_replace('/^([1]*)/', '', $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default formatter for international phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['country_codes']: alpha-2 country code
|
||||
* $element['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function us_formatter_default($element) {
|
||||
$phone = '';
|
||||
|
||||
// Display a global phone number with country code.
|
||||
$cc = cck_phone_countrycodes($element['country_codes']);
|
||||
|
||||
// Format the phone number however you like, this is the default
|
||||
// define regular expression
|
||||
$regex = '/^
|
||||
([2-9][0-8]\d) # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
|
||||
([2-9]\d{2}) # 3-digit prefix (cannot start with 0 or 1)
|
||||
(\d{4}) # 4-digit line number
|
||||
/x';
|
||||
|
||||
$result = preg_match($regex, $element['number'], $matches);
|
||||
|
||||
if ($result) {
|
||||
// output as +1 (AAA) BBB-CCCC
|
||||
$phone = $cc['code'] . ' (' . $matches[1] . ') ' . $matches[2] . '-' . $matches[3];
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local formatter for local phone number.
|
||||
*
|
||||
* @param $element
|
||||
* $element['country_codes']: alpha-2 country code
|
||||
* $element['number']: phone number
|
||||
* @param $error
|
||||
* The error message to shown to user.
|
||||
* Available parameters to use in the error message are
|
||||
* - "%countrycode": the alpha-2 CC
|
||||
* - "%phone_input": the original number input by user (could be invalid)
|
||||
* - "%max_length": allowed maximum length of the phone number
|
||||
* @return boolean
|
||||
* TRUE if it is a valid phone number for that country, FALSE otherwise.
|
||||
*/
|
||||
function us_formatter_local($element) {
|
||||
$phone = '';
|
||||
|
||||
// Display a local phone number without country code.
|
||||
$regex = '/^
|
||||
([2-9][0-8]\d) # area code (Allowed range of [2-9] for the first digit, [0-8] for the second, and [0-9] for the third digit)
|
||||
([2-9]\d{2}) # 3-digit prefix (cannot start with 0 or 1)
|
||||
(\d{4}) # 4-digit line number
|
||||
/x';
|
||||
|
||||
$result = preg_match($regex, $element['number'], $matches);
|
||||
|
||||
if ($result) {
|
||||
// output as (AAA) BBB CCCC
|
||||
$phone = '(' . $matches[1] . ') ' . $matches[2] . '-' . $matches[3];
|
||||
}
|
||||
|
||||
return $phone;
|
||||
}
|
||||
339
sites/all/modules/contrib/fields/computed_field/LICENSE.txt
Normal file
339
sites/all/modules/contrib/fields/computed_field/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
@@ -0,0 +1,13 @@
|
||||
name = Computed Field
|
||||
description = Defines a field type that allows values to be "computed" via PHP code.
|
||||
core = 7.x
|
||||
dependencies[] = field
|
||||
package = Fields
|
||||
files[]=computed_field.install
|
||||
files[]=computed_field.module
|
||||
; Information added by drupal.org packaging script on 2012-02-02
|
||||
version = "7.x-1.0-beta1"
|
||||
core = "7.x"
|
||||
project = "computed_field"
|
||||
datestamp = "1328217338"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the computed field module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements of hook_field_schema().
|
||||
*/
|
||||
function computed_field_field_schema($field) {
|
||||
if ($field['type'] == 'computed') {
|
||||
$settings = $field['settings'];
|
||||
|
||||
if ($settings['store']) {
|
||||
$columns = array('value' => array());
|
||||
|
||||
// Hardcoded 'longtext' settings
|
||||
if ($settings['database']['data_type'] == 'longtext') {
|
||||
$columns['value']['type'] = 'text';
|
||||
$columns['value']['size'] = 'big';
|
||||
}
|
||||
else {
|
||||
$columns['value']['type'] = isset($settings['database']['data_type']) ? $settings['database']['data_type'] : 'varchar';
|
||||
}
|
||||
// 'text' and 'varchar' fields get length settings
|
||||
if ($settings['database']['data_type'] == 'text' || $settings['database']['data_type'] == 'varchar') {
|
||||
$columns['value']['length'] = isset($settings['database']['data_length']) ? $settings['database']['data_length'] : 32;
|
||||
}
|
||||
// 'int' and 'float' fields get size settings
|
||||
if ($settings['database']['data_type'] == 'int' || $settings['database']['data_type'] == 'float') {
|
||||
$columns['value']['size'] = isset($settings['database']['data_size']) ? $settings['database']['data_size'] : 'normal';
|
||||
}
|
||||
// 'decimal' fields get precision and scale settings
|
||||
if ($settings['database']['data_type'] == 'numeric') {
|
||||
$columns['value']['precision'] = isset($settings['database']['data_precision']) ? $settings['database']['data_precision'] : 10;
|
||||
$columns['value']['scale'] = isset($settings['database']['data_scale']) ? $settings['database']['data_scale'] : 2;
|
||||
}
|
||||
// Add 'not null' settings
|
||||
$columns['value']['not null'] = isset($settings['database']['data_not_NULL']) ? $settings['database']['data_not_NULL'] : TRUE;
|
||||
// Add default values if set
|
||||
if ($settings['database']['data_default'] != '') {
|
||||
$columns['value']['default'] = $settings['database']['data_default'];
|
||||
}
|
||||
// Add a simple index on the data if requested (except 'text' fields)
|
||||
if ($settings['database']['data_index'] && $columns['value']['type'] != 'text') {
|
||||
$indexes = array('value' => array('value'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($columns) && isset($indexes)) {
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
'indexes' => $indexes,
|
||||
);
|
||||
}
|
||||
elseif (isset($columns)) {
|
||||
return array(
|
||||
'columns' => $columns,
|
||||
);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements field hook_field_info().
|
||||
*/
|
||||
function computed_field_field_info() {
|
||||
return array(
|
||||
'computed' => array(
|
||||
'label' => t('Computed'),
|
||||
'description' => t('Create field data via PHP code.'),
|
||||
'settings' => array(
|
||||
'code' => '$entity_field[0][\'value\'] = "";',
|
||||
'display_format' => '$display_output = $entity_field_item[\'value\'];',
|
||||
'store' => 1,
|
||||
'database' => array(
|
||||
'data_type' => 'varchar',
|
||||
'data_length' => 32,
|
||||
'data_size' => 'normal',
|
||||
'data_precision' => 10,
|
||||
'data_scale' => 2,
|
||||
'data_not_NULL' => FALSE,
|
||||
'data_default' => NULL,
|
||||
'data_index' => FALSE,
|
||||
),
|
||||
),
|
||||
'default_widget' => 'computed',
|
||||
'default_formatter' => 'computed_field_plain',
|
||||
// If we followed the core convention of separate fields for each data
|
||||
// type we could make Entity API happy by just setting a property_type.
|
||||
// Instead we have to use our own callback to determine the type then
|
||||
// rerun theirs to setup the rest of the field properties.
|
||||
'property_callbacks' => array('computed_field_entity_property_callback'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to setup Entity API's field properties.
|
||||
*/
|
||||
function computed_field_entity_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
|
||||
$property_types = array(
|
||||
'int' => 'integer',
|
||||
'float' => 'decimal', 'numeric' => 'decimal',
|
||||
'varchar' => 'text', 'text' => 'text', 'longtext' => 'text',
|
||||
);
|
||||
if (isset($field['columns']['value']) && isset($property_types[$field['columns']['value']['type']])) {
|
||||
// Entity API's defaults are pretty good so set the property_type and let
|
||||
// them do the work for us.
|
||||
$field_type['property_type'] = $property_types[$field['columns']['value']['type']];
|
||||
entity_metadata_field_default_property_callback($info, $entity_type, $field, $instance, $field_type);
|
||||
// The only thing is that a setter doesn't make sense, so let's disable it.
|
||||
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
|
||||
unset($property['setter callback']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements of hook_field_settings_form().
|
||||
*/
|
||||
function computed_field_field_settings_form($field, $instance, $has_data) {
|
||||
$form = array();
|
||||
$compute_func = 'computed_field_' . $field['field_name'] . '_compute';
|
||||
$display_func = 'computed_field_' . $field['field_name'] . '_display';
|
||||
$settings = $field['settings'];
|
||||
|
||||
$form['#element_validate'] = array('computed_field_field_settings_form_validate');
|
||||
|
||||
$form['code'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 15,
|
||||
'#title' => t('Computed Code (PHP)'),
|
||||
'#description' => t('The variables available to your code include: <code>@fields</code>. To set the value of the field, set <code>@entity_field</code>. For multi-value computed fields continue with <code>@entity_field_multi</code>. Here\'s a simple example which sets the computed field\'s value to the value of the sum of the number fields (<code>@field_a</code> and <code>@field_b</code>) in a node entity:<p><code>@example</code> The first pop fetches the last (or only) item from the field while the second pop fetches its <code>[\'value\']</code> contents (assuming it\'s the only key that\'s set).<p>Alternately, this code can be supplied by your own custom function named: <code>@compute_func(&$entity_field, $entity_type, $entity, $field, $instance, $langcode, $items)</code>',
|
||||
array('@fields' => '&$entity_field, $entity_type, $entity, $field, $instance, $langcode, and $items',
|
||||
'@entity_field' => '$entity_field[0][\'value\']',
|
||||
'@entity_field_multi' => '$entity_field[1][\'value\']',
|
||||
'@field_a' => 'field_a',
|
||||
'@field_b' => 'field_b',
|
||||
'@example' => '$entity_field[0][\'value\'] = array_pop(array_pop(field_get_items($entity_type, $entity, \'field_a\'))) + array_pop(array_pop(field_get_items($entity_type, $entity, \'field_b\')));',
|
||||
'@compute_func' => $compute_func)),
|
||||
'#default_value' => !empty($settings['code']) ? $settings['code'] : '$entity_field[0][\'value\'] = "";',
|
||||
'#access' => !function_exists($compute_func),
|
||||
);
|
||||
if (function_exists($compute_func)) {
|
||||
$form['compute_func'] = array(
|
||||
'#type' => 'item',
|
||||
'#markup' => t('<strong>This field is COMPUTED using <code>@compute_func()</code>.</strong>', array('@compute_func' => $compute_func)),
|
||||
);
|
||||
}
|
||||
$form['display_format'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Display Code (PHP)'),
|
||||
'#description' => t('This code should assign a string to the <code>@display_output</code> variable, which will be printed when the field is displayed. The raw computed value of the field is in <code>@value</code>. <strong>Note:</strong> this code has no effect if you use the "Raw computed value" display formatter.<p> Alternately, this code can be supplied by your own custom function named: <code>@display_func($field, $entity_field_item, $entity_lang, $langcode)</code>. Return the value to be displayed. Original value is in $entity_field_item[\'value\'].',
|
||||
array('@display_output' => '$display_output',
|
||||
'@value' => '$entity_field_item[\'value\']',
|
||||
'@display_func' => $display_func)),
|
||||
'#default_value' => !empty($settings['display_format']) ? $settings['display_format'] : '$display_output = $entity_field_item[\'value\'];',
|
||||
'#access' => !function_exists($display_func),
|
||||
);
|
||||
if (function_exists($display_func)) {
|
||||
$form['display_func'] = array(
|
||||
'#type' => 'item',
|
||||
'#markup' => t('<strong>This field is DISPLAYED using <code>@display_func()</code>.</strong>', array('@display_func' => $display_func)),
|
||||
);
|
||||
}
|
||||
$form['store'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Store value in the database'),
|
||||
'#description' => t('The value will be stored in the database with the settings below. As a result, it will only be recalculated when the entity is updated. This option is required when accessing the field through Views.'),
|
||||
'#default_value' => is_numeric($settings['store']) ? $settings['store'] : 1 ,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database'] = array('#type' => 'fieldset', '#title' => t('Database Storage Settings'));
|
||||
|
||||
if ($has_data) {
|
||||
$form['database']['warning'] = array(
|
||||
'#type' => 'item',
|
||||
'#markup' => t('<strong>**This field currently has stored data, so modifications to its DB settings are not allowed.**</strong>'),
|
||||
);
|
||||
}
|
||||
$form['database']['data_type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Data Type'),
|
||||
'#description' => t('The SQL datatype to store this field in.'),
|
||||
'#default_value' => !empty($settings['database']['data_type']) ? $settings['database']['data_type'] : 'varchar',
|
||||
'#options' => array('varchar' => 'varchar', 'text' => 'text', 'longtext' => 'longtext', 'int' => 'int', 'float' => 'float', 'numeric' => 'decimal'),
|
||||
'#required' => FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_length'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Data Length (varchar/text)'),
|
||||
'#description' => t('<strong>Only</strong> valid for <strong>varchar</strong> or <strong>text</strong> fields. The length of the field stored in the database.'),
|
||||
'#default_value' => !empty($settings['database']['data_length']) ? $settings['database']['data_length'] : 32,
|
||||
'#required' => FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_size'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Data Size (int/float)'),
|
||||
'#description' => t('<strong>Only</strong> valid for <strong>int</strong> or <strong>float</strong> fields. The size of the field stored in the database.'),
|
||||
'#default_value' => !empty($settings['database']['data_size']) ? $settings['database']['data_size'] : 'normal',
|
||||
'#options' => array('tiny' => 'tiny', 'small' => 'small', 'medium' => 'medium', 'normal' => 'normal', 'big' => 'big'),
|
||||
'#required' => FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_precision'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Decimal Precision (decimal)'),
|
||||
'#description' => t('<strong>Only</strong> valid for <strong>decimal</strong> fields. The total number of digits to store in the database, including those to the right of the decimal.'),
|
||||
'#options' => drupal_map_assoc(range(10, 32)),
|
||||
'#default_value' => !empty($settings['database']['data_precision']) ? $settings['database']['data_precision'] : 10,
|
||||
'#required' => FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_scale'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Decimal Scale (decimal)'),
|
||||
'#description' => t('<strong>Only</strong> valid for <strong>decimal</strong> fields. The number of digits to the right of the decimal. '),
|
||||
'#options' => drupal_map_assoc(range(0, 10)),
|
||||
'#default_value' => !empty($settings['database']['data_scale']) ? $settings['database']['data_scale'] : 2,
|
||||
'#required' => FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_default'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Default Value'),
|
||||
'#default_value' => $settings['database']['data_default'],
|
||||
'#required' => FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_not_NULL'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Not NULL'),
|
||||
'#default_value' => is_numeric($settings['database']['data_not_NULL']) ? $settings['database']['data_not_NULL'] : FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['database']['data_index'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Index computed values in the database (Does not apply to text or longtext fields.)'),
|
||||
'#default_value' => is_numeric($settings['database']['data_index']) ? $settings['database']['data_index'] : FALSE,
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the #element_validate callback for computed_field_field_settings_form().
|
||||
*/
|
||||
function computed_field_field_settings_form_validate($element, &$form_state) {
|
||||
$settings = $form_state['values']['field']['settings'];
|
||||
if ($settings['store']) {
|
||||
if (empty($settings['database']['data_type'])) {
|
||||
form_set_error('field][settings][data_type', t('To store this field in the database, please specify a data type.'));
|
||||
}
|
||||
if (($settings['database']['data_type'] == 'text' || $settings['database']['data_type'] == 'varchar') && empty($settings['database']['data_length'])) {
|
||||
form_set_error('field][settings][database][data_length', t('To store this field in the database, please specify the data length.'));
|
||||
}
|
||||
if (($settings['database']['data_type'] == 'int' || $settings['database']['data_type'] == 'float') && (!empty($settings['database']['data_default']) && !is_numeric($settings['database']['data_default']))) {
|
||||
form_set_error('field][settings][database][data_default', t('Your default value should be numeric given your data type.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_load().
|
||||
*/
|
||||
function computed_field_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
|
||||
$settings = $field['settings'];
|
||||
// Compute field values on load if they aren't stored in the database
|
||||
if (!$settings['store']) {
|
||||
foreach ($entities as $etid => $entity) {
|
||||
_computed_field_compute_value($entity_type, $entity, $field, $instances, $langcode, $items[$etid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_prepare_view().
|
||||
*/
|
||||
function computed_field_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
|
||||
// Compute field values in case user is "previewing" an entity
|
||||
foreach ($entities as $etid => $entity) {
|
||||
if (isset($entity->op) && $entity->op == 'Preview') {
|
||||
_computed_field_compute_value($entity_type, $entity, $field, $instances, $langcode, $items[$etid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_insert().
|
||||
*/
|
||||
function computed_field_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
_computed_field_compute_value($entity_type, $entity, $field, $instance, $langcode, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_update().
|
||||
*/
|
||||
function computed_field_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
_computed_field_compute_value($entity_type, $entity, $field, $instance, $langcode, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_widget_info().
|
||||
*/
|
||||
function computed_field_field_widget_info() {
|
||||
return array(
|
||||
'computed' => array(
|
||||
'label' => t('Computed'),
|
||||
'field types' => array('computed'),
|
||||
'behaviors' => array(
|
||||
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
|
||||
'default value' => FIELD_BEHAVIOR_NONE,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_widget_form().
|
||||
*/
|
||||
|
||||
function computed_field_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
||||
|
||||
// If there are no items yet, add a null item value to avoid
|
||||
// preview errors when selecting a different language
|
||||
if (empty($items)) $items[0]['value'] = NULL;
|
||||
|
||||
foreach ($items as $item_delta => $item) {
|
||||
$element[$item_delta]['value'] = array(
|
||||
'#type' => 'value',
|
||||
'#tree' => TRUE,
|
||||
'#default_value' => isset($item['value']) ? $item['value'] : NULL,
|
||||
);
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_info().
|
||||
*/
|
||||
function computed_field_field_formatter_info() {
|
||||
return array(
|
||||
'computed_field_unsanitized' => array(
|
||||
'label' => t('Unsanitized'),
|
||||
'field types' => array('computed'),
|
||||
),
|
||||
'computed_field_plain' => array(
|
||||
'label' => t('Plain text'),
|
||||
'field types' => array('computed'),
|
||||
),
|
||||
'computed_field_markup' => array(
|
||||
'label' => t('Filtered markup'),
|
||||
'field types' => array('computed'),
|
||||
),
|
||||
'computed_field_computed_value' => array(
|
||||
'label' => t('Raw value, no display code'),
|
||||
'field types' => array('computed'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_view().
|
||||
*/
|
||||
function computed_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
|
||||
$element = array();
|
||||
|
||||
// Special case formatter that returns the raw computed values without any display code processing
|
||||
if ($display['type'] == "computed_field_computed_value") {
|
||||
foreach ($items as $delta => $item) {
|
||||
if (!isset($entity_field_item['value'])) $entity_field_item['value'] = NULL;
|
||||
$element[$delta] = array('#markup' => $item['value']);
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
// Other display formatters which run through display code processing
|
||||
// Check if the value is to be formatted by a display function outside the DB
|
||||
$display_func = 'computed_field_' . $field['field_name'] . '_display';
|
||||
if (function_exists($display_func)) $display_in_code = TRUE;
|
||||
else $display_in_code = FALSE;
|
||||
|
||||
// Loop the items to display
|
||||
foreach ($items as $delta => $item) {
|
||||
|
||||
// For "some" backwards compatibility
|
||||
$entity_field_item = $item;
|
||||
|
||||
// Setup a variable with the entity language if available
|
||||
if (isset($entity->language)) $entity_lang = $entity->language;
|
||||
else $entity_lang = LANGUAGE_NONE;
|
||||
|
||||
// If there are value "holes" in the field array let's set the value to NULL
|
||||
// to avoid undefined index errors in typical PHP display code
|
||||
if (!isset($entity_field_item['value'])) $entity_field_item['value'] = NULL;
|
||||
|
||||
// Execute the display code
|
||||
$display_output = NULL;
|
||||
if ($display_in_code) {
|
||||
$display_output = $display_func($field, $entity_field_item, $entity_lang, $langcode);
|
||||
}
|
||||
else {
|
||||
eval($field['settings']['display_format']);
|
||||
}
|
||||
|
||||
// Output the formatted display item
|
||||
switch ($display['type']) {
|
||||
case 'computed_field_unsanitized':
|
||||
$element[$delta] = array('#markup' => $display_output);
|
||||
break;
|
||||
case 'computed_field_plain':
|
||||
$element[$delta] = array('#markup' => check_plain($display_output));
|
||||
break;
|
||||
case 'computed_field_markup':
|
||||
$element[$delta] = array('#markup' => check_markup($display_output));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements field hook_field_is_empty().
|
||||
*/
|
||||
function computed_field_field_is_empty($item, $field) {
|
||||
$data_type = $field['settings']['database']['data_type'];
|
||||
if ($data_type == 'int' || $data_type == 'float') {
|
||||
return !is_numeric($item['value']);
|
||||
}
|
||||
return empty($item['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_info().
|
||||
*/
|
||||
function computed_field_token_info() {
|
||||
$types['computed'] = array(
|
||||
'name' => t("Computed"),
|
||||
'description' => t("Tokens related to Computed fields."),
|
||||
'needs-data' => 'node',
|
||||
);
|
||||
$fields = field_info_fields();
|
||||
$node = array();
|
||||
$computed = array();
|
||||
foreach ($fields as $field_name => $field) {
|
||||
if ($field['module'] == "computed_field") {
|
||||
$node[str_replace('_', '-', $field_name)] = array(
|
||||
'name' => t("Computed: %field_name", array('%field_name' => $field_name)),
|
||||
'description' => t("Computed field %field_name value.", array('%field_name' => $field_name)),
|
||||
'type' => 'computed',
|
||||
);
|
||||
$computed['rawvalue'] = array(
|
||||
'name' => t("Raw computed value"),
|
||||
'description' => t("Computed field %field_name raw value.", array('%field_name' => $field_name)),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!empty($computed)) {
|
||||
return array(
|
||||
'types' => $types,
|
||||
'tokens' => array('node' => $node, 'computed' => $computed),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_tokens().
|
||||
*/
|
||||
function computed_field_tokens($type, $tokens, array $data = array(), array $options = array()) {
|
||||
$computed_fields = array();
|
||||
$replacements = array();
|
||||
$sanitize = !empty($options['sanitize']);
|
||||
$lang = isset($options['language']->language) ? $options['language']->language : LANGUAGE_NONE;
|
||||
$fields = field_info_fields();
|
||||
foreach ($fields as $field_name => $field) {
|
||||
if ($field['module'] == "computed_field") {
|
||||
$computed_fields[] = str_replace('_', '-', $field_name);
|
||||
}
|
||||
}
|
||||
foreach ($tokens as $name => $original) {
|
||||
// For normal display output
|
||||
if (in_array($name, $computed_fields)) {
|
||||
$field_name = str_replace('-', '_', $name);
|
||||
$entity_field_item = $data[$type]->{$field_name}[$lang][0];
|
||||
$field = $fields[$field_name];
|
||||
// Check if the value is to be formatted by a display function outside the DB
|
||||
$display_func = 'computed_field_' . $field_name . '_display';
|
||||
if (function_exists($display_func)) {
|
||||
$display_output = $display_func($field, $entity_field_item);
|
||||
}
|
||||
else {
|
||||
eval($field['settings']['display_format']);
|
||||
}
|
||||
$replacements[$original] = $sanitize ? check_plain($display_output) : $display_output;
|
||||
}
|
||||
// For raw value output
|
||||
elseif (in_array(str_replace(':rawvalue', '', $name), $computed_fields)) {
|
||||
$field_name = str_replace('-', '_', str_replace(':rawvalue', '', $name));
|
||||
$replacements[$original] = $sanitize ? check_plain($data[$type]->{$field_name}[$lang][0]['value']) : $data[$type]->{$field_name}[$lang][0]['value'];
|
||||
}
|
||||
}
|
||||
return $replacements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private function to compute the fields value.
|
||||
*/
|
||||
function _computed_field_compute_value($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
$settings = $field['settings'];
|
||||
|
||||
// Setup a variable with the field values
|
||||
$entity_field =& $items;
|
||||
|
||||
// Setup a variable with the entity language if available
|
||||
if (isset($entity->language)) $entity_lang = $entity->language;
|
||||
else $entity_lang = LANGUAGE_NONE;
|
||||
|
||||
// Allow the value to be computed from code not stored in DB
|
||||
$compute_func = 'computed_field_' . $field['field_name'] . '_compute';
|
||||
if (function_exists($compute_func)) {
|
||||
$compute_func($entity_field, $entity_type, $entity, $field, $instance, $langcode, $items);
|
||||
}
|
||||
else {
|
||||
if (isset($settings['code'])) {
|
||||
eval($settings['code']);
|
||||
}
|
||||
}
|
||||
}
|
||||
339
sites/all/modules/contrib/fields/content_taxonomy/LICENSE.txt
Normal file
339
sites/all/modules/contrib/fields/content_taxonomy/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
21
sites/all/modules/contrib/fields/content_taxonomy/README.txt
Normal file
21
sites/all/modules/contrib/fields/content_taxonomy/README.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
Content Taxonomy:
|
||||
*****************
|
||||
|
||||
Migration from D6 to D7:
|
||||
|
||||
- backup your DB
|
||||
- run the core upgrade path
|
||||
- download and install the Content Migrate (CCK) module
|
||||
- download and install the Content Taxonomy Migrate module
|
||||
- goto Structure > Migrate and select your fields to upgrade
|
||||
- clear caches
|
||||
- check if the data is available or rollback
|
||||
|
||||
note: the content taxonomy module allows you to select the parent term, but all other advanced settings of content taxonomy will be lost.
|
||||
|
||||
|
||||
Author:
|
||||
-------
|
||||
Matthias Hutterer
|
||||
mh86@drupal.org
|
||||
m_hutterer@hotmail.com
|
||||
@@ -0,0 +1,16 @@
|
||||
name = Content Taxonomy
|
||||
description = Extends the Taxonomy Reference Fields
|
||||
|
||||
core = 7.x
|
||||
package = Fields
|
||||
|
||||
dependencies[] = taxonomy
|
||||
|
||||
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-02-13
|
||||
version = "7.x-1.0-beta2"
|
||||
core = "7.x"
|
||||
project = "content_taxonomy"
|
||||
datestamp = "1360767812"
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_form_ID_alter().
|
||||
*/
|
||||
function content_taxonomy_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
|
||||
$field = $form['#field'];
|
||||
$instance = $form['#instance'];
|
||||
|
||||
// Add parent selector to term reference fields,
|
||||
// except to the autocomplete widget, as it ignores the parent setting.
|
||||
if ($field['type'] == 'taxonomy_term_reference'
|
||||
&& !($instance['widget']['type'] == 'taxonomy_autocomplete' || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy')) {
|
||||
|
||||
// add parent form.
|
||||
foreach ($field['settings']['allowed_values'] as $delta => $tree) {
|
||||
$options[0] = '---';
|
||||
// todo this might break with huge vocs
|
||||
$voc = taxonomy_vocabulary_machine_name_load($tree['vocabulary']);
|
||||
foreach (taxonomy_get_tree($voc->vid) as $term) {
|
||||
$options[$term->tid] = str_repeat('- ', $term->depth) . $term->name;
|
||||
}
|
||||
|
||||
$form['field']['settings']['allowed_values'][$delta]['parent'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Parent'),
|
||||
'#options' => $options,
|
||||
'#default_value' => isset($tree['parent']) ? $tree['parent'] : 0,
|
||||
);
|
||||
|
||||
$form['field']['settings']['allowed_values'][$delta]['depth'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Tree depth'),
|
||||
'#default_value' => isset($tree['depth']) ? $tree['depth'] : '',
|
||||
'#description' => t('Set the depth of the tree. Leave empty to load all terms.'),
|
||||
'#element_validate' => array('_element_validate_integer_positive'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add opt group setting.
|
||||
if ($field['type'] == 'taxonomy_term_reference' && $instance['widget']['type'] == 'options_select') {
|
||||
$form['instance']['widget']['settings']['content_taxonomy_opt_groups'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Render parent terms as opt-groups'),
|
||||
'#default_value' => isset($instance['widget']['settings']['content_taxonomy_opt_groups']) ? $instance['widget']['settings']['content_taxonomy_opt_groups'] : FALSE,
|
||||
'#description' => t('This option only works if you have a 2-level hierarchy in your vocabulary. Then the parents in the first level get opt-groups and the child terms will be selectable.'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_info_alter().
|
||||
*/
|
||||
function content_taxonomy_field_info_alter(&$info) {
|
||||
// Use own options callback for handling additional configuration options.
|
||||
$info['taxonomy_term_reference']['settings']['options_list_callback'] = 'content_taxonomy_allowed_values';
|
||||
|
||||
// Add depth option.
|
||||
foreach ($info['taxonomy_term_reference']['settings']['allowed_values'] as $key => $values) {
|
||||
$info['taxonomy_term_reference']['settings']['allowed_values'][$key]['depth'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of valid terms for a taxonomy field.
|
||||
* Extends taxonomy_allowed_values() with the tree depth option.
|
||||
*
|
||||
* @param $field
|
||||
* The field definition.
|
||||
* @return
|
||||
* The array of valid terms for this field, keyed by term id.
|
||||
*/
|
||||
function content_taxonomy_allowed_values($field) {
|
||||
$options = array();
|
||||
foreach ($field['settings']['allowed_values'] as $tree) {
|
||||
if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
|
||||
$max_depth = (isset($tree['depth']) && !empty($tree['depth'])) ? $tree['depth'] : NULL;
|
||||
if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'], $max_depth)) {
|
||||
foreach ($terms as $term) {
|
||||
$options[$term->tid] = str_repeat('- ', $term->depth) . $term->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_info_alter().
|
||||
*/
|
||||
function content_taxonomy_field_widget_info_alter(&$info) {
|
||||
if (isset($info['options_select']['settings'])) {
|
||||
$info['options_select']['settings'] += array(
|
||||
'content_taxonomy_opt_groups' => FALSE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_form_alter().
|
||||
*/
|
||||
function content_taxonomy_field_widget_form_alter(&$element, &$form_state, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
|
||||
if (!empty($instance['widget']['settings']['content_taxonomy_opt_groups'])) {
|
||||
$options = content_taxonomy_allowed_values_opt_groups($field);
|
||||
if (isset($element['#options']['_none'])) {
|
||||
$options = array('_none' => $element['#options']['_none']) + $options;
|
||||
}
|
||||
$element['#options'] = $options;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for generating opt groups.
|
||||
*
|
||||
* Similar to content_taxonomy_allowed_values(), but unfortunately we cannot
|
||||
* directly change content_taxonomy_allowed_values() as it only has the field
|
||||
* variable and opt groups are settings on the instance level. Still, this is
|
||||
* not a big performance issue, as taxonomy_get_tree statically caches some
|
||||
* data.
|
||||
*/
|
||||
function content_taxonomy_allowed_values_opt_groups($field) {
|
||||
$options = array();
|
||||
foreach ($field['settings']['allowed_values'] as $tree) {
|
||||
if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
|
||||
if ($terms = taxonomy_get_tree($vocabulary->vid, 0, 2)) {
|
||||
$current_group_term = NULL;
|
||||
foreach ($terms as $term) {
|
||||
if ($term->depth == 0) {
|
||||
$current_group_term = $term;
|
||||
}
|
||||
elseif ($term->depth == 1 && !is_null($current_group_term)) {
|
||||
$options[$current_group_term->name][$term->tid] = $term->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
name = Content Taxonomy Autocomplete
|
||||
description = Extends the Taxonomy Autocomplete Widget
|
||||
|
||||
core = 7.x
|
||||
package = Fields
|
||||
|
||||
dependencies[] = content_taxonomy
|
||||
|
||||
files[] = includes/content_taxonomy_autocomplete_moderated_terms.inc
|
||||
|
||||
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-02-13
|
||||
version = "7.x-1.0-beta2"
|
||||
core = "7.x"
|
||||
project = "content_taxonomy"
|
||||
datestamp = "1360767812"
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_info_alter().
|
||||
*/
|
||||
function content_taxonomy_autocomplete_field_widget_info_alter(&$info) {
|
||||
// Add a setting for validating new terms.
|
||||
$ct_settings = array(
|
||||
'content_taxonomy_autocomplete_new_terms' => 'allow',
|
||||
);
|
||||
$info['taxonomy_autocomplete']['settings'] += $ct_settings;
|
||||
|
||||
// Add this to the autocomplete deluxe as well, if enabled.
|
||||
if (isset($info['autocomplete_deluxe_taxonomy']['settings'])) {
|
||||
$info['autocomplete_deluxe_taxonomy']['settings'] += $ct_settings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_ID_alter().
|
||||
*/
|
||||
function content_taxonomy_autocomplete_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
|
||||
$field = $form['#field'];
|
||||
$instance = $form['#instance'];
|
||||
if ($instance['widget']['type'] == 'taxonomy_autocomplete' || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy') {
|
||||
// Add a setting form for validating new terms.
|
||||
$options = array(
|
||||
'allow' => t('Allow and insert new terms'),
|
||||
'moderate' => t('Allow new terms and insert them into a separate vocabulary'),
|
||||
'deny' => t('Deny any new terms'),
|
||||
);
|
||||
$form['instance']['widget']['settings']['content_taxonomy_autocomplete_new_terms'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Autocomplete settings'),
|
||||
'#options' => $options,
|
||||
'#default_value' => isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms']) ? $instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'] : 'allow',
|
||||
'#description' => t('If option 2 is selected, re-save this settings form and afterwards select a second vocabulary for new terms in the field settings. In case the Autocomplete Deluxe widget is used, new terms can be hidden from the suggestion list.'),
|
||||
);
|
||||
}
|
||||
|
||||
// Show form for second vocabulary.
|
||||
if (isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms']) && $instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'] == 'moderate') {
|
||||
// Initialize settings, if not set.
|
||||
if (!isset($field['settings']['allowed_values'][1])) {
|
||||
$field['settings']['allowed_values'][1] = array(
|
||||
'vocabulary' => $field['settings']['allowed_values'][0]['vocabulary'],
|
||||
'parent' => 0,
|
||||
);
|
||||
}
|
||||
$vocabularies = taxonomy_get_vocabularies();
|
||||
$options = array();
|
||||
$options[''] = '---';
|
||||
foreach ($vocabularies as $vocabulary) {
|
||||
$options[$vocabulary->machine_name] = $vocabulary->name;
|
||||
}
|
||||
$form['field']['settings']['allowed_values'][1]['vocabulary'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Vocabulary for new terms'),
|
||||
'#default_value' => isset($field['settings']['allowed_values'][1]['vocabulary']) ? $field['settings']['allowed_values'][1]['vocabulary'] : '',
|
||||
'#options' => $options,
|
||||
'#description' => t('New terms form autocompletes will be inserted in this vocabulary.'),
|
||||
//'#disabled' => $has_data, //todo
|
||||
);
|
||||
$form['field']['settings']['allowed_values'][1]['parent'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $field['settings']['allowed_values'][1]['parent'],
|
||||
);
|
||||
if($instance['widget']['type'] == 'autocomplete_deluxe_taxonomy') {
|
||||
// todo: should this setting be added field_info_alter?
|
||||
$form['field']['settings']['allowed_values'][1]['content_taxonomy_ignore_in_suggestions'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Ignore vocabulary above for suggested terms.'),
|
||||
'#default_value' => isset($field['settings']['allowed_values'][1]['content_taxonomy_ignore_in_suggestions']) ? $field['settings']['allowed_values'][1]['content_taxonomy_ignore_in_suggestions'] : FALSE,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_attach_form().
|
||||
*/
|
||||
function content_taxonomy_autocomplete_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
|
||||
// Add validation function to taxonomy_autocompletes, if necessary.
|
||||
$instances = field_info_instances($form['#entity_type'], $form['#bundle']);
|
||||
foreach ($instances as $instance) {
|
||||
if (($instance['widget']['type'] == 'taxonomy_autocomplete' || $instance['widget']['type'] == 'autocomplete_deluxe_taxonomy')
|
||||
&& isset($form[$instance['field_name']])
|
||||
&& isset($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'])) {
|
||||
|
||||
// Use the language that is used in this form (which doesn't necessarily
|
||||
// be the default language in $langcode).
|
||||
$lang_key = $form[$instance['field_name']]['#language'];
|
||||
if ($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'] == 'moderate') {
|
||||
$form[$instance['field_name']][$lang_key]['#element_validate'][] = 'content_taxonomy_autocomplete_validate_moderate_new_terms';
|
||||
}
|
||||
else if ($instance['widget']['settings']['content_taxonomy_autocomplete_new_terms'] == 'deny') {
|
||||
$form[$instance['field_name']][$lang_key]['#element_validate'][] = 'content_taxonomy_autocomplete_validate_deny_new_terms';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form element validate handler for taxonomy term autocomplete element, which denies any new terms.
|
||||
*/
|
||||
function content_taxonomy_autocomplete_validate_deny_new_terms($element, &$form_state, $form) {
|
||||
$values = $form_state['values'];
|
||||
foreach ($element['#array_parents'] as $parent) {
|
||||
$values = $values[$parent];
|
||||
}
|
||||
foreach ($values as $delta => $value) {
|
||||
if ($value['tid'] == 'autocreate') {
|
||||
form_error($element, t('%name: new terms are not allowed. Please choose from the given list.', array('%name' => $element['#title'])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form element validate handler for taxonomy term autocomplete element, which inserts new terms into a separate voc.
|
||||
*/
|
||||
function content_taxonomy_autocomplete_validate_moderate_new_terms($element, &$form_state) {
|
||||
// taxonomy_field_validate() is invoked before.
|
||||
// Reset vocabulary id for new terms.
|
||||
$field = field_widget_field($element, $form_state);
|
||||
$values =& $form_state['values'];
|
||||
foreach ($element['#array_parents'] as $parent) {
|
||||
$values =& $values[$parent];
|
||||
}
|
||||
if (isset($field['settings']['allowed_values'][1])) {
|
||||
if ($voc2 = taxonomy_vocabulary_machine_name_load($field['settings']['allowed_values'][1]['vocabulary'])) {
|
||||
foreach ($values as $delta => $value) {
|
||||
if ($value['tid'] == 'autocreate') {
|
||||
$values[$delta]['vid'] = $voc2->vid;
|
||||
$values[$delta]['vocabulary_machine_name'] = $voc2->machine_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_query_TAG_alter().
|
||||
*/
|
||||
function content_taxonomy_autocomplete_query_autocomplete_deluxe_taxonomy_autocomplete_alter(QueryAlterableInterface $query) {
|
||||
$field = field_info_field($query->getMetaData('field_name'));
|
||||
if (isset($field['settings']['allowed_values'][1]) && isset($field['settings']['allowed_values'][1]['content_taxonomy_ignore_in_suggestions']) && $field['settings']['allowed_values'][1]['content_taxonomy_ignore_in_suggestions']) {
|
||||
if ($voc1 = taxonomy_vocabulary_machine_name_load($field['settings']['allowed_values'][0]['vocabulary'])) {
|
||||
$query->condition('t.vid', $voc1->vid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_search_api_processor_info().
|
||||
*/
|
||||
function content_taxonomy_autocomplete_search_api_processor_info() {
|
||||
$callbacks['content_taxonomy_autocomplete_moderated_terms'] = array(
|
||||
'name' => t('Content Taxonomy Autocomplete Moderated Terms Filter'),
|
||||
'description' => t('Filters terms from autocompletes that belong to the moderated vocabulary.'),
|
||||
'class' => 'ContentTaxonomyAutocompleteModeratedTermsSearchAPIProcessor',
|
||||
);
|
||||
return $callbacks;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
name = Content Taxonomy Migrate
|
||||
description = Migration from Content Taxonomy to Term Reference Fields
|
||||
|
||||
core = 7.x
|
||||
package = Fields
|
||||
|
||||
dependencies[] = taxonomy
|
||||
dependencies[] = content_migrate
|
||||
|
||||
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-02-13
|
||||
version = "7.x-1.0-beta2"
|
||||
core = "7.x"
|
||||
project = "content_taxonomy"
|
||||
datestamp = "1360767812"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
function content_taxonomy_migrate_content_migrate_field_alter(&$field_value, $instance_value) {
|
||||
if ($field_value['type'] == 'content_taxonomy') {
|
||||
$field_value['type'] = 'taxonomy_term_reference';
|
||||
$field_value['module'] = 'taxonomy';
|
||||
|
||||
// transform field settings
|
||||
$old_settings = $field_value['settings'];
|
||||
$vocabulary = taxonomy_vocabulary_load($old_settings['vid']);
|
||||
$field_value['settings'] = array();
|
||||
$field_value['settings']['allowed_values'] = array();
|
||||
$field_value['settings']['allowed_values'][0]['vocabulary'] = $vocabulary->machine_name;
|
||||
$field_value['settings']['allowed_values'][0]['parent'] = $old_settings['parent'];
|
||||
}
|
||||
}
|
||||
|
||||
function content_taxonomy_migrate_content_migrate_instance_alter(&$instance_value, $field_value) {
|
||||
if ($instance_value['widget_type'] == "content_taxonomy_autocomplete") {
|
||||
$instance_value['widget_type'] = 'taxonomy_autocomplete';
|
||||
$instance_value['widget']['type'] = 'taxonomy_autocomplete';
|
||||
$instance_value['widget']['module'] = 'taxonomy';
|
||||
}
|
||||
else if ($instance_value['widget_type'] == "content_taxonomy_options" || $instance_value['widget_type'] == "content_taxonomy_tree") {
|
||||
$instance_value['widget_type'] = 'options_buttons';
|
||||
$instance_value['widget']['type'] = 'options_buttons';
|
||||
$instance_value['widget']['module'] = 'options';
|
||||
}
|
||||
else if ($instance_value['widget_type'] == "content_taxonomy_select" || $instance_value['widget_type'] == 'content_taxonomy_hs') {
|
||||
$instance_value['widget_type'] = 'options_select';
|
||||
$instance_value['widget']['type'] = 'options_select';
|
||||
$instance_value['widget']['module'] = 'options';
|
||||
}
|
||||
|
||||
// fix formatter
|
||||
foreach ($instance_value['display'] as $context => $settings) {
|
||||
if ($instance_value['display'][$context]['type'] == 'default') {
|
||||
$instance_value['display'][$context]['type'] = 'taxonomy_term_reference_plain';
|
||||
}
|
||||
else if ($instance_value['display'][$context]['type'] == 'link') {
|
||||
$instance_value['display'][$context]['type'] = 'taxonomy_term_reference_link';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function content_taxonomy_migrate_content_migrate_data_record_alter(&$record, $field) {
|
||||
// fill the taxonomy_index
|
||||
if ($field['type'] == 'taxonomy_term_reference') {
|
||||
if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $record['entity_type'] == 'node') {
|
||||
if (isset($record[$field['field_name'] . "_tid"]) && $record[$field['field_name'] . "_tid"]) {
|
||||
$entity = node_load($record['entity_id']);
|
||||
db_delete('taxonomy_index')->condition('nid', $entity->nid)->condition('tid', $record[$field['field_name'] . "_tid"])->execute();
|
||||
$query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created', ));
|
||||
$query->values(array(
|
||||
'nid' => $entity->nid,
|
||||
'tid' => $record[$field['field_name'] . "_tid"],
|
||||
'sticky' => $entity->sticky,
|
||||
'created' => $entity->created,
|
||||
));
|
||||
$query->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Search API Processor that filters out terms from moderated vocabularies.
|
||||
*/
|
||||
class ContentTaxonomyAutocompleteModeratedTermsSearchAPIProcessor extends SearchApiAbstractProcessor {
|
||||
|
||||
/**
|
||||
* Confiuration callback.
|
||||
*
|
||||
* Only allow users to select taxonomy fields.
|
||||
*/
|
||||
public function configurationForm() {
|
||||
$form = parent::configurationForm();
|
||||
$form['fields']['#options'] = $this->filterTaxonomyFieldsOptions($form['fields']['#options']);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Postprocess items while indexing and filter out the moderated terms.
|
||||
*/
|
||||
public function preprocessIndexItems(array &$items) {
|
||||
$fields = $this->getTaxonomyFields($this->options['fields']);
|
||||
foreach ($items as &$item) {
|
||||
foreach ($fields as $search_api_property_name => $field) {
|
||||
if (isset($item[$search_api_property_name])) {
|
||||
$this->processTaxonomyField($item[$search_api_property_name]['value'], $item[$search_api_property_name]['type'], $field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a single field on a single item and does the actual filtering.
|
||||
*
|
||||
* As such a field can be nested, recursions are used until we reach the top
|
||||
* level.
|
||||
*/
|
||||
protected function processTaxonomyField(&$value, &$type, $field) {
|
||||
if (!isset($value) || $value === '') {
|
||||
return;
|
||||
}
|
||||
if (substr($type, 0, 10) == 'list<list<') {
|
||||
$inner_type = $t1 = substr($type, 5, -1);
|
||||
foreach ($value as &$v) {
|
||||
$t1 = $inner_type;
|
||||
$this->processTaxonomyField($v, $t1, $field);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $v) {
|
||||
if ($this->fieldValueIsModerated($v, $field)) {
|
||||
unset($value[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($this->fieldValueIsModerated($value, $field)) {
|
||||
$value = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the given term id is from moderated vocabulary.
|
||||
*
|
||||
* @param $value
|
||||
* The term id.
|
||||
* @param $field
|
||||
* The according field API field.
|
||||
*/
|
||||
private function fieldValueIsModerated($value, $field) {
|
||||
$allowed_voc = $field['settings']['allowed_values'][0]['vocabulary'];
|
||||
$term = taxonomy_term_load($value);
|
||||
if ($term && $term->vocabulary_machine_name == $allowed_voc) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that filters the configuration field options for taxonomy
|
||||
* fields.
|
||||
*/
|
||||
private function filterTaxonomyFieldsOptions($options) {
|
||||
$taxonomy_fields = array();
|
||||
foreach ($options as $search_api_property_name => $label) {
|
||||
if ($this->getTaxonomyField($search_api_property_name)) {
|
||||
$taxonomy_fields[$search_api_property_name] = $label;
|
||||
}
|
||||
}
|
||||
return $taxonomy_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the taxonomy fields for the given search API
|
||||
* property names.
|
||||
*/
|
||||
private function getTaxonomyFields($search_api_properties) {
|
||||
$taxonomy_fields = array();
|
||||
foreach ($search_api_properties as $search_api_property_name => $label) {
|
||||
if ($field = $this->getTaxonomyField($search_api_property_name)) {
|
||||
$taxonomy_fields[$search_api_property_name] = $field;
|
||||
}
|
||||
}
|
||||
return $taxonomy_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that extracts the taxonomy field from a search API property
|
||||
* name.
|
||||
*/
|
||||
private function getTaxonomyField($search_api_property_name) {
|
||||
$parts = explode(':', $search_api_property_name);
|
||||
foreach ($parts as $part) {
|
||||
if (substr($part, 0, 6) == 'field_') {
|
||||
$field = field_info_field($part);
|
||||
if ($field && isset($field['type']) && $field['type'] == "taxonomy_term_reference") {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
616
sites/all/modules/contrib/fields/date/CHANGELOG.txt
Normal file
616
sites/all/modules/contrib/fields/date/CHANGELOG.txt
Normal file
@@ -0,0 +1,616 @@
|
||||
Date Module 7.x
|
||||
=================
|
||||
|
||||
===================
|
||||
Version 7.x-2.x-dev
|
||||
===================
|
||||
|
||||
======================
|
||||
Version 7.x-2.6
|
||||
======================
|
||||
|
||||
- Issue #1423364 by catmat, Add file and path to hook_context_plugins().
|
||||
- Issue #1713248, Remove incorrect use of date_popup() function in previous commit.
|
||||
- Issue #1143680 by kristiaanvandeneynde, Make Date Popup widget able to accept custom settings.
|
||||
- Issue #1596546 by applicity_sam, Make sure incorrect month name creates validation error.
|
||||
- Issue #1432702, Fix some miscellaneous problems with date example dates and formats.
|
||||
- Issue #1512464 by Liam Moreland, Allow for undefined formatter in Date upgrade handling.
|
||||
- Issue #1659638 by bojanz, Hide install message if Drupal is not installed (i.e. in install profiles).
|
||||
- Issue #1605158 by covenantd, Be sure value2 is initiated in Date Context handler.
|
||||
- Issue #1355256 by barraponto develCuy and KarenS, set default value for date text widget increment to 1, and update existing fields.
|
||||
- Issue #1561306 by Cyberwolf, Date pager replacement was not working correctly when used with multiple dates.
|
||||
- Issue #1541740 by hass, Make Date requirements more easily translatable.
|
||||
- Issue #1543524 by iamEAP, Add update hook to remove the D6 date_timezone field from users.
|
||||
- Issue #1603640 by bevan, Don't return anything for empty date interval.
|
||||
- Issue #1235508, Make sure that ISO strings with '00' in the month and/or day don't create dates for the previous month and day.
|
||||
- Issue #1289270 by pdrake: Fixed date arguments and filters do not work with relationships.
|
||||
- Issue #895760 by Reinette: Added RFC2447 option 'STATUS' to date_api_ical().inc.
|
||||
- Issue #606658 by johnmunro and KarenS, Make sure ical import processes multi-day all-day events correctly.
|
||||
- Issue #1408216 follow up, Need to be sure that NULL is the default state for the sql functions.
|
||||
- Issue #1540410, Update the Date Tools calendar creation wizard to use the new calendar path.
|
||||
|
||||
======================
|
||||
Version 7.x-2.5
|
||||
======================
|
||||
|
||||
- Fix nasty errors on views that have no row indexes, like the frontage view.
|
||||
|
||||
======================
|
||||
Version 7.x-2.4
|
||||
======================
|
||||
|
||||
- Issue #1534342 by bass, Make name of clean pager option easier to translate.
|
||||
- Add a hook to alter the default date for a Date argument.
|
||||
- Issue #1531904, Make sure that multiple value dates that have the delta set only display the selected value.
|
||||
- Revert Issue #1266688 by fago, This change broke Entity token support.
|
||||
|
||||
======================
|
||||
Version 7.x-2.3
|
||||
======================
|
||||
|
||||
- Issue #1444804, Remove html placeholder on text widget.
|
||||
- Issue #1286230, Clean up date pager documentation, it contains deprecated information.
|
||||
- Issue #1469020, Make sure page not found is working right for dates outside the specified range.
|
||||
- Issue #1111626, Fix some problems caused by passing in a date string with an offset.
|
||||
- Issue #1477860, Avoid undefined index errors in date_views_select_validate().
|
||||
- Issue #1469038, Add some clarity to the BYDAY description options and make sure a valid value is selected.
|
||||
- Issue #1405364 by snufkin, Add display options to format_interval to match Views interval options.
|
||||
- Issue #1266688 by linclark, Add microdata support to Date metadata.
|
||||
- Issue #1509434 by casey, Add timezone info in hook_field_presave() instead of hook_field_insert() and hook_field_update().
|
||||
- Issue #1509012, Fix fatal error when viewing repeat tab.
|
||||
- Issue #1037174 by dealancer, More work to allow ajax to work on other widgets.
|
||||
- Issue #1473592 by zabelc, Make sure migrated date with missing end date still gets imported correctly.
|
||||
- Issue #1442718 by jastraat and bones, Make sure show end date checkbox does not display when end date is empty.
|
||||
- Issue #1504556, Fix invalid access permission name in Date API configuration menu.
|
||||
- Issue #1484458, Vega timepicker code was incorrectly computing the default date because of the wrong format for the value passed to it.
|
||||
- Issue #1459668, Add back Remove date_field_get_sql_handler() function temporarily since Signup module is still using it. Mark it deprecated.
|
||||
- Issue #1478296, Display longer abbreviations for day names in date repeat widget so they can be translated.
|
||||
- Issue #1488662 by martin.heidegger, Make error message more easily translatable.
|
||||
- Issue #1478848 by onelittleant, Don't set default values on new translation entities.
|
||||
- Issue #1360672, Fix limit format code to remove leftover non-ascii text as well as leftover ascii text.
|
||||
- Issue #1464280 by geerlingguy Georgique and dealancer: Fix notice when using exposed between filter.
|
||||
- Issue #1484640 by onelittleant, Some entities may not have base tables.
|
||||
- Issue #1472966, Get rid of notice that appears for entities without repeats.
|
||||
- Move pager css around. Some code in Calendar and Date API belongs in Date Views.
|
||||
- Fix Date Popup default format which was ending up using 24 hour time no matter what format was used for short format.
|
||||
- Remove outdated _repeat widget name from Date Tools.
|
||||
- Date Tools is defaulting to creating a calendar even if Calendar module is not enabled.
|
||||
- Issue #1472148 by arlinsandbulte: wvega jQuery time-picker doesn't show scrollbar.
|
||||
- Issue #1392128 by kidrobot, tim.plunkett, willvincent: Fixed Repeats tab shows on nodes with non-repeating dates.
|
||||
- Issue #1452882 by coredumperror: Fixed Date Migrate Example doesn't deregister it's migration when disabled.
|
||||
- Issue #1452408 by reglogge: Fixed Trailing dots are removed from date formats even if they are needed for the format.
|
||||
- Issue #1285260 by Steven Jones: Fixed 'Starting from' display option.
|
||||
- Issue #1467244 by bluetegu: Fixed Recurring Sunday errors.
|
||||
- Issue #1442718, Empty default values were getting populated by the code that tried to fix default values on hidden fields.
|
||||
- Make sure date_handler->placeholders gets initialized even for queries that don't execute so the pager won't throw an exception if the value is missing.
|
||||
|
||||
======================
|
||||
Version 7.x-2.2
|
||||
======================
|
||||
|
||||
NOTES:
|
||||
The iCal templates were removed and moved to the new Date iCal module (http://drupal.org/project/date_ical).
|
||||
|
||||
- Issue #1423364 by emptyvoid, Move Date context plugin into its own file.
|
||||
- Issue #1447372 by yched, Memory friendlier version of date_repeat_field_bundles().
|
||||
- Issue #1447140 by tim.plunkett: Remove iCal-related theme functions/files.
|
||||
- Issue #1284170 by benjifisher, Lots of cleanup of the iCal export and its template to be sure all day items are exported correctly.
|
||||
- Issue #1346424, The calendar title got left out of the latest ical template changes.
|
||||
- Add more information to the date_views_base_tables() function about why we can't use the entity type from views_fetch_data().
|
||||
- Additional handling is needed so that revisions are handled correctly in Views.
|
||||
- Remove date_field_get_sql_handler() function which isn't being used anywhere.
|
||||
- Rework the Date Views hooks that queue up the right fields and base tables so they work better across all types of entities.
|
||||
- Fix the hooks for file tables, it is file_managed, not files.
|
||||
- Add a helper function to map entity types to Views base tables to make it easier to know what type of entity is being used on a view.
|
||||
- Add status information to Date help screen, hide the non-working change tab on the Date Tools screen, and remove some code that goes to the calendar module from Date Tools.
|
||||
|
||||
======================
|
||||
Version 7.x-2.1
|
||||
======================
|
||||
|
||||
- Issue #1437242 by zerbash, Remove extraneous leading slashes in module_load_include().
|
||||
- Issue #1436722 by hefox: Fixed Undefined variable $form_set_error() used as function.
|
||||
- Issue #1250626 by G<>bor Hojtsy, B-Prod, hefox: Added start date and end date labels.
|
||||
- Issue #1253482, Make sure $argument->is_default gets reset by the Date pager when altering results.
|
||||
- Adjust Date Tools to work with changes to use Views templates to create calendars.
|
||||
- Issue #1398584 by dhalbert and , Make sure groupby times is initialized.
|
||||
- Issue #1394248, Make sure all date parts are selected when using an exposed select filter.
|
||||
- Issue #1425774 by sgabe, Fix error in exposed filter, array_filter() -- first argument should be an array in date_select_input_date().
|
||||
- Issue #1432992 by bart.hanssens, Fix typo in php documentation.
|
||||
- Issue #323852 by tim.plunkett and arlinsandbulte, Dropdowns shouldn't include a blank option when required.
|
||||
- Issue #323852, Validation was broken for unlimited value select widgets with required dates, they were incorrectly getting their end dates cleared out.
|
||||
- Issue #1424656 by tim.plunkett, Unify signature and alters of #process callbacks.
|
||||
- Issue #1408014 by dasjo, We no longer need the $error_element value to display errors properly, second follow-up.
|
||||
- Issue #1299030 by Vincent B: Ensure that 'To Date' is properly marked when required.
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-rc2
|
||||
======================
|
||||
|
||||
New Features/Major Changes
|
||||
|
||||
- Issue #1358790 by tim.plunkett and redndahead, Store date objects in field_load to speed up processing, with a field setting option to control it.
|
||||
|
||||
Bugfixes
|
||||
|
||||
- Issue #1423598, Found a way to flag items that are new so we know when to add default values.
|
||||
- Made some fixes to find and test the right entities when checking whether to use default values. More work is needed.
|
||||
- Issue #1422600, Make sure end date cannot cause validation errors when show end date checkbox is not checked.
|
||||
- Issue #1417872, Remove code to compute missing date parts from empty values now that the new validation prevents that from working.
|
||||
- Issue #1417872, Make sure empty year field is validated in the same way other date parts are validated.
|
||||
- Alter date field test to test with a complete end date instead of using empty elements.
|
||||
- Fix broken logic in repeat additions.
|
||||
- Fix test broken by date repeat clean up.
|
||||
- Issue #1419106 by hanoii: Added more info to hook_date_text_process_alter().
|
||||
- Issue #1209026, When date validation fails, Date Popup value is getting cleared.
|
||||
- Issue #1017216 by tim.plunkett, arlinsandbulte: Added custom date format without time shows 'all day'.
|
||||
- Issue #1408014 by dasjo, We no longer need the $error_element value to display errors properly.
|
||||
- Issue #554546 by master-of-magic: Fix Timezone list translation
|
||||
- Issue #1411038 by jhodgdon: Fixed Date formatting is not obeying granularity.
|
||||
- Issue #1359464, Make sure that default values on hidden elements have the same construct as loaded values to avoid errors.
|
||||
- Issue #1399744 by tim.plunkett, Rework the way filter groups are used to be sure the Date filter group does not clobber the Views filter group.
|
||||
- Issue #1411862, Move the date_views_fields() function into date_view.module to be sure it is always available.
|
||||
- Issue #1380350, Rework SQL query handling to pass in a comparison date for computing offsets to better handle dates affected by DST adjustments.
|
||||
- Issue #1359464, Temporary fix for broken handling of repeating dates on users with a TODO to figure out where it's coming from.
|
||||
- Issue #1404494 by byrond, Make sure hidden formatters don't get switched to date_default in update hook.
|
||||
- Issue #1386012, Order weekdays in Date Repeat form to match the site first day of week settings.
|
||||
- Issue #1376476 by pbfleetwood, Add commas to default formatting of week and day headers.
|
||||
- Issue #1408430, Views pagination with exposed, unset, filters, results in invalid default values. Treat them as empty input.
|
||||
- Issue #1408996, Exposed Date Popup widget with time not correctly initialized.
|
||||
- Issue #1271726, Text widgets in exposed filters used with pagers produce unexpected results.
|
||||
- Issue #1096000, Custom date formats not working right.
|
||||
- Issue #1405364, Format interval settings were getting overridden by missing break.
|
||||
- Issue #1387890, Make sure disabled fields are shown and retain their original values.
|
||||
- Issue #1402232 by timplunkett, Switch 'Implementation of' to 'Implements'
|
||||
- Issue #1402236 by timplunkett, All functions should be prefixed with your module name to avoid name clashes
|
||||
- Issue #1402238 by timplumkett, Remove references to CCK
|
||||
- Issue #1011624, Filters and arguments were not always using the right base table to select field options, causing 'column missing' errors.
|
||||
- Issue #1397822, Fix 'Undefined index: field' error on line 207 of date_views_filter_handler_simple.inc.
|
||||
- Issue #1396536, Repeating fields weren't getting created with Devel Generate because of the change in widgets. Add new hooks so Date Repeat Field can add the repeats.
|
||||
- Issue #1397126 follow-up by arlinsandbulte, Fix broken tests.
|
||||
- Issue #1397158, The default value for the end date was using the wrong timezone setting.
|
||||
- Issue #1392128 by kidrobot and tim.plunkett, Don't show repeat tab unless the date is repeating.
|
||||
- Issue #1397126, Add Date API section to administration menu and consolidate Date Popup and Date Tools settings there.
|
||||
- Follow up to Issue #1302052 by benjifisher, More clean up of ical line endings.
|
||||
- Issue #1388174 by travist, Remove redundant use of date_default_timezone().
|
||||
- Issue #1388586 by Moloc, Don't use check_plain() on system messages with links.
|
||||
- Issue #1302052 by benjifisher, penguin25, and helmo, Fix linespace ending problems in ical files.
|
||||
- Issue #1357216, The Date Views field list was including the Date Views filter itself, creating errors about missing node.date_filter values.
|
||||
- Issue #1259870, Reinstate the test for a missing date argument for the pager.
|
||||
- The new option to hide the add_delta for simple fields needs to be adjusted to work right where there is no field.
|
||||
- Tweak the all day formula to check for 59:59 even for items that use increments, to help fix problems when the calendar creates all day values.
|
||||
- Our test for whether this is a Date argument or filter needs to include a check that the field was actually processed by Date Views. Some dates are not.
|
||||
- Revert the change to 7.8. It breaks the modules page.
|
||||
- Issue #1379172 by deviantpixel, Note that the Date Repeat form uses a function that was re-named in 7.8.
|
||||
- Store the locale format in a static cache to avoid re-computing it dozens of times on calendar views.
|
||||
- Sheesh. Fix syntax error in api.date.php.
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-rc1
|
||||
======================
|
||||
|
||||
Notes:
|
||||
The Date Browser has been removed. Please use the Date Pager instead. If you have existing views using the Date
|
||||
Browser the navigation will just disappear from them. If you add a Date Pager to the view you should get it back.
|
||||
Then delete the Date Browser attachment from the view, since it doesn't do anything any more.
|
||||
|
||||
The UNTIL date was not getting included in repeating results and that is now fixed. This is an API change of sorts
|
||||
for anyone who worked around the issue by setting it ahead.
|
||||
|
||||
The All Day checkbox and All Day themes were moved into a separate module, using new hooks added to the date
|
||||
processing. This module should serve as an example of how other modules can inject functionality into date fields.
|
||||
|
||||
A new module has been added for integrating the Date Repeat API into date fields. Some of this code has been
|
||||
moved into the new module, more of it will be moved later as I figure out how to unwind it from the base
|
||||
processing. An update hook has been added to enable this module by default for existing sites. If you don't
|
||||
use Repeating dates you can disable it.
|
||||
|
||||
New Features/Major Changes
|
||||
|
||||
- Issue #1229378 by ksenzee, Sync the end date with the start date on new dates using select widgets.
|
||||
- Issue #1236216, Move the repeating date integration out of the Date module and into a separate, Date Repeat Field module.
|
||||
- Issue #874322, The All Day functionality has been moved into a separate module and hooks were added to make it easier for other modules to inject steps into date processing.
|
||||
- Issue #1267046, Include the UNTIL date in repeating results..
|
||||
- Issue #1354606 by temaruk, Rework the repeating date UI to make it more user-friendly.
|
||||
- Issue #1362654, Remove Advanced Help integration, it needs a total rewrite.
|
||||
- Issue #1357362, Remove Date Browser, use Date Pager instead.
|
||||
- Issue #1354606, Make sure COUNT option without UNTIL date can be handled correctly by repeating date computations.
|
||||
|
||||
Bugfixes
|
||||
|
||||
- Fix to new default date handling, the default date has to set a date in the database timezone, not the display timezone.
|
||||
- Issue #1245106 by G<>bor Hojtsy, Hide the option to add the delta into the view for single value fields.
|
||||
- Issue #1370876, Make sure new Date All Day code does not try to set the popup values if Date Popup is disabled.
|
||||
- Issue #874322, Add back the date_field_all_day() function to avoid breaking other modules that are using it.
|
||||
- Fix Date text placeholder to display a formatted date instead of a format. Follow up to Date repeat UI changes.
|
||||
- Issue #1248520 by fearlsgroove, Use attribute selector on all day and end day checkboxes.
|
||||
- Issue #952446 and #1031690, Select dates with only year and month were not working.
|
||||
- Issue #1292152 by pfrenssen, Remove debug functions.
|
||||
- Issue #1338976 by Josh Benner, Adjust iCal unwrap to allow for leading spaces, per standard.
|
||||
- Issue #1352486 by d.novikov, Rework date SQL formatting for Microsoft SQL.
|
||||
- Issue #1266536, Keep timezone adjustments from altering the values for repeating date EXCEPTIONS and ADDITIONS.
|
||||
- Issue #1353488, Some repeating date calculations using PHP 5.3.6+ were not computing correctly.
|
||||
- Issue #1364026, Fix link to documentation, also move help to Date API module.
|
||||
- Issue #1276270, Fix fatal error when using repeat date on user.
|
||||
- Issue #1362758, Add empty file for the date_plugin_display_attachment.inc file that was removed, to avoid fatal errors if it is missing on a site that formerly used it.
|
||||
- Issue #1363460, Make sure widget dates do not end up with the current date when they should be empty.
|
||||
- Issue #1353488, Attempt to fix problem using date_date_set() in PHP 5.3.6+.
|
||||
- Date Migrate tests needed some fixes to conform to latest code.
|
||||
- Issue #1353790, Hide missing index notice if the value in the Date Popup does not match the expected value, it will still get trapped as a validation error.
|
||||
- Issue #1353790, Make sure Date Popup properly translates the default value if it includes month or day names.
|
||||
- Issue #1217796, Make sure that All Day formatting works correctly even if the All Day label is empty.
|
||||
- The repeat description was lost by a recent change to the theme that sent the element through the theme twice.
|
||||
- Remove date_get_nested_elements() function. Not being used and I don't want other code to start expecting it.
|
||||
- Issue #1266144, The end date should get set to blank if it is optional and matches the start date, but only if it is not populated by default values.
|
||||
- Issue #1349510, Make sure default values get populated before processing so they still get set on hidden fields.
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-alpha5
|
||||
======================
|
||||
|
||||
Notes:
|
||||
The date repeat widgets have been removed to keep users from trying to change repeating dates into non-repeating dates.
|
||||
There are now just three widgets, Date Select, Date Text, and Date Popup. Whether or not a date is a repeating date
|
||||
is now controlled by a field setting.
|
||||
|
||||
New Features/UX Changes/API Changes
|
||||
|
||||
- Issue #1304056 by DamienMcKenna, Add option to date_difference to indicate direction of difference.
|
||||
- Issue #1238660, Add custom format option for the date format used in summary arguments.
|
||||
- Issue #1038482 by somanyfish, iCal import failing due to colon instead of semi-colon
|
||||
- Issue #1252952 by eosrei: Make "all day" checkbox configurable on a per field instance basis.
|
||||
- Issue #1266144 by arlinsandbulte: Clarify Default End Date Setting
|
||||
- Issue #1261478 by stevector and KarenS, Reconfigure the back/next buttons into item lists so Views ajax pager works right.
|
||||
- Issue #1262960, Add a new module to work with the Context module to set a condition based on the value of a date field.
|
||||
- Issue #1216878, Re-introduce 'repeat' as a field setting rather than a widget type so people can't try to switch back and forth between repeating and non-repeating dates. Eliminate repeat widgets.
|
||||
|
||||
Bugfixes
|
||||
|
||||
- Issue #1280658 and follow up to Issue #1238660 by KarenS and tockliasteroid, Rework the format control over the summary title and apply it to the title() callback.
|
||||
- Issue #1276622 by ArtistConk, Make sure Except date contains no default value.
|
||||
- Issue #1153766 by fago, More work on the entity property setters and getters.
|
||||
- Issue #1331214, Make sure Date Migrate properly handles empty date values.
|
||||
- Issue #1285224, Make sure Date Migrate works for importing repeating dates now that widgets have changed.
|
||||
- Issue #1162290, Make sure date for example formats avoids confusing short and long month names.
|
||||
- Re-organize handling of custom date formats.
|
||||
- Issue #1122038, Make sure empty values are not passed to Views to be themed for repeating dates.
|
||||
- Issue #1101284 by pfournier, Expand regex for Month names to catch more possible variations.
|
||||
- Issue #1343406 by slashrsm, add back the caching of the views fields list.
|
||||
- Issue #1302374 by miro_dietiker, Account for an inconsistency in core handling of non-existant date formats.
|
||||
- Issue #1344014 by James Sharpe, Get rid of 'Repeats every 0 days' description.
|
||||
- Issue #1302212, Change the way default dates using custom code are created.
|
||||
- Issue #1292898, Check for all day checkbox in the basic date element validation so empty time for newly added elements still passes validation.
|
||||
- Issue #1252952 follow up, Move checkbox setting to the same spot where time is set, and don't show option on dates without time.
|
||||
- Issue #1335818 by joelpitter, Don't create a date for empty values in the date getters and setters.
|
||||
- Issue #1271726, Keep default_value out of exposed form so it won't show up in pager.
|
||||
- Issue #1017866, Fix miscellaneous problems where filter/argument incorrectly do timezone adjustment.
|
||||
- Issue #1103032, Attempt to add setters to date entity metadata so Rules can use them.
|
||||
- Issue #1153766, Adapt metadata functions to the pattern in the current Entity code, add $info to the getters.
|
||||
- Issue #1278876 by basicmagic.net, Typo in date.css
|
||||
- Issue #752550 by Fonant, Week number gets printed twice
|
||||
- Issue #1052586 by jpsolero, Problem with Date API when using Calendar with argument set to "Week" granularity and "current date" default argument
|
||||
- Issue #1266144, End date same as start date default not being respected.
|
||||
- Issue #1239934 by casey, Fix javascript exception in date_year_range.js.
|
||||
- Issue #1310558, Don't show extra label on exposed date filter.
|
||||
- Fix bug in Date Popup that still uses the current date when the default date is empty.
|
||||
- Issue #1335578 by aaronbauman, Make it possible to pass in +/- 1000 years to years back/forward.
|
||||
- Issue #1292516 by mcarbone, Fix Uninitialized string offset in Date Migrate.
|
||||
- Issue #1084980 by jwilson3, Set default value for $granularity to be array in date_formatter_format.
|
||||
- Issue #1227350 by grendzy, Summary view should not be calling date_forbid().
|
||||
- Issue #1286570, Fix undefined index error caused by using a remember value without checking if it exists.
|
||||
- Issue #1337440 by phoenix, Fix syntax error in vcalendar tpl file.
|
||||
- Issue #1103032, Add plain date formatter and set it to be the default token formatter.
|
||||
- Issue #1177684 by tim.plunket, Fix typo in last commit.
|
||||
- Issue #1177684, Wrong translation of short month name.
|
||||
- Issue #1201342 by colinlee and alexprv, Comment out SQLSVR timezone adjustment until it gets fixed properly.
|
||||
- Issue #1308274 by sneyerst, SQL Server DATEPART function cannot accept composed datetime formats.
|
||||
- Issue #1308266 by sneyerst, Fix arithmetic overflow in SQLSVR.
|
||||
- Issue #1333104 by tim.plunkett, Check that $field['settings'] exists in date_is_repeat_field().
|
||||
- Error message for years back and forward doesn't match new labels, should be Starting year and Ending year.
|
||||
- Issue #1179715, Switch drupal_array_get_nested_value() to use 'values' instead of 'input', where it makes sense, and simplify some of this code.
|
||||
- Issue #1179715, Create a helper function for testing hidden/disabled dates and test each date element and validator to skip processing in that case.
|
||||
- Issue #1179715, When hidden by #access=FALSE, repeating date fields were getting removed and not replaced.
|
||||
- Issue #1179715, By pass date repeat widget processing and validation when element is hidden from user.
|
||||
- Issue #1179715, Don't do timezone adjustments in the widget, wait for #process so we can skip it when the date field has been hidden by #access.
|
||||
- Issue #1338194, Logic for creating end date wasn't taking into account the possibility that a field might have no value2.
|
||||
- Issue #1179715, Default value callback for the timezone widget was not returning an array.
|
||||
- Issue #1179716, Remove value_callback for date_repeat and date_combo forms, the default behavior works fine.
|
||||
- Issue #1178716 by das-peter, Use drupal_array_get_nested_value() in Date Repeat instead of trying to find it manually.
|
||||
- Issue #1178716 by das-peter and KarenS, Tweak the date repeat widget to identify empty input when used on nodes with translation.
|
||||
- Issue #1178716 by das-peter and KarenS, Fix date repeat form values that are not arrays when hidden on a node that has translation.
|
||||
- Issue #1178176 by das-peter, Fix date_combo_value_callback to return NULL to avoid data lost on untranslatable dates used with Entity Translation.
|
||||
- Date Context module was making incorrect assumptions about the $language of the field.
|
||||
- Issue #1237974, Schema module wants the datetime column to be lower case.
|
||||
- Issue #1233084, fix a few places that were wrapping $instance['label'] with t().
|
||||
- Issue #1188380 by Xen and jherencia, use #title instead of field['label'] in date display because that has the i18n translation.
|
||||
- Issue #1330768 by das-peter, remove whitespace.
|
||||
- Tweak date_pager_url to allow a way to create non-absolute urls.
|
||||
- Make sure deleted displays won't create errors in Views by returning FALSE in date_forbid() if there is no date argument.
|
||||
- Issue #1257830, Beef up the logic when creating the date repeat tabs to work for more kinds of entities.
|
||||
- Issue #1260962, Repeating date fields should save the date even if there is no repeat information.
|
||||
- Issue #1241836 by kzoli, Fix undefined cardinality indexes.
|
||||
- Issue #1233722, Fix undefined index notice in pager when other filters are used.
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-alpha4
|
||||
======================
|
||||
|
||||
Notes to themers:
|
||||
|
||||
Previous versions put dates with both From and To dates into a fieldset and other dates were not.
|
||||
The new code adds additional floating elements that are hard to contain, so now all dates are
|
||||
enclosed in fieldsets in the node form. There are also new elements on the form, an optional
|
||||
checkbox for hiding/showing the To date and an optional checkbox for hiding/showing time.
|
||||
Previously dates on the node form had 'From date' and 'To date' labels above them, this
|
||||
has been changed to remove those labels, using the Google calendar date entry screen
|
||||
as a model. This simplifies the node form and dates take up less space. A light grey border
|
||||
has been added around each collection of dates (the From date and the To date). The display
|
||||
of labels above the date parts (year, month, day, date, time, etc) is controlled in the
|
||||
field settings. Previous versions did not always honor those settings, this one does.
|
||||
|
||||
New Features/UX Improvements
|
||||
|
||||
- Issue #1249724 by KarenS, G<>bor Hojtsy, David_Rothstein, Improve usability of date and time input configuration.
|
||||
- Issue #1250784 by David_Rothstein, Add user-friendly labels for start and end date values in Views.
|
||||
- Issue #742146, Add option to remove X-WR-CALNAME if VEVENT is not a feed.
|
||||
- Add option to change method from PUBLISH to REQUEST in VCALENDAR.
|
||||
- Issue #334435, Add a theme function for the 'Date' and 'Time' labels in the Popup widget.
|
||||
- Issue #1239956 by David_Rothstein, Change the default separation between from and to dates to use 'to' instead of a hyphen.
|
||||
- Issue #1240628 by David_Rothstein, Make the date increment default to 15 instead of 1.
|
||||
- Issue #1249724 by David_Rothstein: Improve usability of date and time input configuration
|
||||
- Issue #1177198 by tim.plunkett: Allow CTools to process #dependency for date elements.
|
||||
- Issue #1245562 by David_Rothstein, Rename the default date display format to something friendlier
|
||||
- Issue #1239934 by David_Rothstein and G<>bor Hojtsy, Reuse the "years back and forward" dropdown widget on the Views filter settings page.
|
||||
- Issue #1239228 by G<>bor Hojtsy, Date Views filter form UI improvements, clarify the way absolute and relative dates work.
|
||||
- Issue #233047 by ksenzee and David_Rothstein, Add the Vegas jQuery timepicker as a new time selector option.
|
||||
- Issue #1145976 by tim.plunkett and KarenS, Add 'is date' identifier to all date handlers.
|
||||
- Issue #1234140 by arlinsundbulte, Change terminology in user-facing text from 'From/To Date' to 'Start/End Date'.
|
||||
- Issue #1233948 by KarenS, Add 'All Day' checkbox to hide/show the time parts of the date form. If All day is chosen, any time is replaced with 00:00:00 when the form is submitted.
|
||||
- Issue #1233612 by KarenS, Add 'Collect end date' checkbox for dates with optional end dates to hide/show the end date.
|
||||
- Issue #821200 by scor and KarenS, Add RDF support to the date field.
|
||||
- Issue #1211744 by EclipseGC and KarenS, Add a Date pager plugin that is designed to add paging in conjunction with a Date argument.
|
||||
- Issue #1180612 by mikeryan, Add support for Migrate module.
|
||||
- Issue #1198320 by ksenzee, David_Rothstein, Noyz: Make UI improvements to field settings page.
|
||||
- Issue #1215738 by ksenzee, Make granularity settings checkboxes horizontal.
|
||||
- Issue #1215686 by ksenzee, Change name of date field types to be more intuitive.
|
||||
- Issue #1216996 by ksenzee, Change the years back/forward setting into two drop down boxes.
|
||||
- Issue #1222468 by ksenzee, Hide timezone options when using granularity without time.
|
||||
- Issue #1229388 by ksenzee, Hide formatter from/to choices on fields without multiple values.
|
||||
|
||||
Removed deprecated functions
|
||||
|
||||
- Removed date_handler_fields(), only applicable to D6 code.
|
||||
- Removed date_views_real_url() and date_views_page_url(), used by older calendar version.
|
||||
- Remove unused date_handler_field_multiple.
|
||||
|
||||
Tests
|
||||
|
||||
- Issue #1251592 by David_Rothstein, Set reasonable default values if date formats have not been configured, and add tests for that.
|
||||
- Issue #1242764 Add tests for every possible combination of field type, timezone handling, and granularity.
|
||||
- More work on tests, add a foreach loop to run through all field_type/widget_type combinations.
|
||||
- Rework tests to use a base class rather than copying the same functions everywhere.
|
||||
- Issue #1209408 Make sure date_repeat_calc() returns empty array for FREQ=NONE and INTERVAL=0, also add a test for that.
|
||||
- Issue #1161006 by justinrandall, Add tests to check that dates that should have time but do not are correctly caught in validation.
|
||||
|
||||
Bugfixes
|
||||
|
||||
- Issue #1256406 by q0rban, use variable_get() in hook_requirments().
|
||||
- Follow up to Issue #1145976, Make sure 'is date' only gets applied to the date values, not delta, timezone, etc.
|
||||
- Issue #1238364, Make sure the Date pager doesn't throw errors if the default date is missing.
|
||||
- Issue #1246416, Add info to the Date Popup README.txt about how to download the WVega timepicker.
|
||||
- Issue #1253230, Package name of Date Migrate was different than the other Date components.
|
||||
- Issue #1251592, Add installation message and system requirements warnings about missing system date settings.
|
||||
- Issue #1250784, Don't save psuedo field settings created by the new UI in the field itself.
|
||||
- Issue #1239228 by David_Rothstein, Always add Date Views css to View UI edit forms.
|
||||
- Issue #1254540 by David_Rothstein, Move borders off of the wrappers so they don't appear when the dates inside them are hidden.
|
||||
- Issue #1253248 by David_Rothstein, Move RDF attributes handling to preprocess function.
|
||||
- Issue #1087798 by anj, Fix X-WR-CALNAME in VCALENDAR.
|
||||
- Issue #1254582 Repeat additions need to be adjusted to use the same time as the original date.
|
||||
- Move vcalendar and vevent templates from Date Views to Date API modules.
|
||||
- Follow up to Issue #1250344, We don't need extra space when there is a description, only when there is not.
|
||||
- Issue #1239228 by G<>bor Hojtsy, More tweaks to filter css.
|
||||
- Issue #1244924 by G<>bor Hojtsy, Minor text improvements in date filter configuration
|
||||
- Issue #1245556 by David_Rothstein, Date granularity description incorrectly implies that it affects the date attributes that are displayed
|
||||
- Issue #1247444 by G<>bor Hojtsy, Give a little breathing space to the date year range "other" field
|
||||
- Issue #1250344 by jessebeach, Fix padding around date fields by adding clearfix class.
|
||||
- Issue #1249116 by yched, Fix various glitches with D6 migration code.
|
||||
- Issue #1243022 by fmosca and KarenS, Make sure all_day #states visibility is only set when there is a value for all_day.
|
||||
- Issue #1236192 by loganfsmyth, Make sure #date_label_position has a default value in the Date Popup module.
|
||||
- Issue #1246416, Test whether libraries_get_path() returns a valid path before using it.
|
||||
- Issue #1235994, Don't display 'All Day' when using a format that has no time.
|
||||
- Issue #1245690 by mikeryan, Migration plugin missing seconds from date formats
|
||||
- Issue #1229406 by David Rothstein, G<>bor Hojtsy, and tim.plunkett Fix broken timepicker in Chrome and Safari.
|
||||
- Issue #1239412 by keithm, Fix validation error when #access is false.
|
||||
- Issue #1232522, Don't alter field_ui_field_edit form except on date fields.
|
||||
- Issue #1243842, Make sure the All Day and Show End Date flags work correctly in unlimited value fields that use ajax.
|
||||
- Follow up to Issue #1239956, Fix tests broken by change in date separator.
|
||||
- Issue #1241576, Fix date combo validation for all-day dates so they don't fail validation because the format is unexpected.
|
||||
- Take the guesswork out of examining Date info for Views, add is_field flag.
|
||||
- Follow up to Issue #874322, Date popup field needs to accept date without time for the all day flag to work.
|
||||
- Follow up to Issue #1130814, It looks like the modification is not needed in date_repeat_set_month_day and date_repeat_set_year_day.
|
||||
- Issue #1160132 by seanbfuller and KarenS, Exposed filter widgets were not displaying the default values.
|
||||
- Adjust the way widgets are styled in Views exposed filters after the latest style changes for form elements.
|
||||
- Issue #1234114 by arlinsandbulte, Add more space between checkboxes.
|
||||
- Issue #1234090, Fix undefined variable 'all_day'.
|
||||
- Issue #1232570 by dboulet, Remove some unneeded duplication of core clearfix and other css cleanup.
|
||||
- Issue #1232614 by dboulet, Date css should not be setting font family.
|
||||
- Timezone and Date Popup weren't obeying the settings for displaying the date part label.
|
||||
- Issue #1130814 by cdracars, mikeryan, mayobutter, Fix date_modify difference between PHP 5.3.5 and 5.3.6 so both work to compute repeating dates.
|
||||
- Issue #1017866 by KarenS and Jason89s, Make sure views argument and filter don't do timezone adjustment for dates that don't have time.
|
||||
- Issue #1204988 by paulsheldrake, Remove IE6 code from datepicker CSS.
|
||||
- Issue #1231864 by Damien McKenna, Clean up line endings in vevent and vcalendar tpl files.
|
||||
- Issue #1231382 by dboulet, Clean up date css, code style fixes.
|
||||
- Date repeat additions and exceptions need to be reworked into full, timezone-adjusted, datetime values when passing them to FAPI as default values.
|
||||
- Issue #1223034 by c4rl, Make sure repeating date additions and exceptions work correctly when there is more than one repeating date in the same form.
|
||||
- Issue #1229362, Date Popup module needs date_is_date() function, which should not require Date module. Move that to Date API.
|
||||
- Issue #1227208 by ksenzee, Minor text changes.
|
||||
- Issue #1094408, Change method of identifying Field module filters, using the name of the group is not robust enough.
|
||||
- Issue #1227264 by gapa, Fix wrong class in date-pager.tpl.php.
|
||||
- Issue #1207540, Summary grouping won't work right unless the formula alias doesn't match an actual field value.
|
||||
- Issue #1227350 Summary query still needs the formula, add it back.
|
||||
- Fix 'variables cannot be passed by reference' notice on repeats page.
|
||||
- Issue #1222736 Fix export errors caused when previous export fix of using export plugins got broken by changes in Views.
|
||||
- Issue #1077490 Fix notices about missing #date_flexible.
|
||||
- Move the 'top' date pager to below the header instead of below attachment_before so you can add header text above it.
|
||||
- The value for variable_get('date_first_day') should default to zero to match core default.
|
||||
- Issue #1147620 by KarenS with an assist from tim.plunkett, Fix the query so it will locate dates that span days or months by checking the intersection of the date range and the query range. Also add an option to the argument so you can do a simple query for either the from or to date when checking the whole range isn't the right solution.
|
||||
- Issue #307274 by ksenzee, Fix broken validation for absolute value in years back/forward.
|
||||
- Issue #1173374 by fietserwin, Remove translation of the jQuery datepicker day and month names, now handled by core.
|
||||
- Issue #1192020 by tim.plunkett: Fixed date granularity is too fragile in date_field_all_day().
|
||||
- Issue #1110012 Remove 'parent' items from Views plugins, no longer needed? See if this fixes the issue.
|
||||
- Issue #1183892, Initialize $identifier in date_views_filter_handler_simple.
|
||||
- Issue #1103290 by stickywes and ingaro, Change postgres 'FMYYYY-FMMM-FMDDTFMHH:FMMI:FMSS' to 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS'.
|
||||
- Issue #1186528 by jox, Make date field combo label translatable.
|
||||
- Issue #1123186 by KingJoshi, Fix misnamed date_part_hour_prefix in hook_theme().
|
||||
- Issue #1032942 by fietserwin, Rename date popup functions that are getting picked up by theme('date').
|
||||
- Issue #1206756 More tweaks to the validation changes. They were blocking zero times and causing some test failures.
|
||||
- Issue #1197352 Don't display language about from and to dates when there is no todate.
|
||||
- Issue #1201288 by rafa0961, fix broken references to SQLSERVER.
|
||||
- More work on cleaning up validation, add in some ideas from fearlsgrove about checking the granularity of the input array against the expected granularity.
|
||||
- Issue #1161006 Dates that should have time but do not were not correctly caught in validation.
|
||||
- Get rid of overlapping formatter functionality. There should be a default formatter with the option to choose a date format as a setting, not a formatter for each format. This was a leftover from the D6 functionality.
|
||||
- Issue #1159404 by mikeryan, Fix incorrect call to parse an rrule in date_repeat_build_dates().
|
||||
- Issue #1160656 by jjs, Replace missing break in date_api.sql.inc that breaks PostgreSQL.
|
||||
- Issue #1150454, Fix undefined index notices for repeat_collapsed value.
|
||||
- Issue #1150462, Put length limit on content type names created by Date Tools so block delta won't overflow the allowed size.
|
||||
- Issue #1136734, When migrating date format data from D6 to D7, don't try to overwrite existing custom values.
|
||||
- Issue #1161042 by Ollie222, Date filters using time were inconsistently formatted.
|
||||
- Issue #1130884, Bad logic in 'between' filter SQL, should always join with AND.
|
||||
- Issue #1139418 by ankur, Bad logic in week argument SQL, should always join with AND.
|
||||
- Issue #1118356, Disabling the Timepicker was having no effect.
|
||||
- Issue #408770 by vkareh, Make sure dates with #access = FALSE get passed through date_combo_element_process().
|
||||
- Issue #1037174 by das-peter, add ajax support to date popup.
|
||||
- Issue #1160614 by joelstein, Make sure date repeat rule gets split correctly no matter which line endings were used.
|
||||
- Issue #1110708 by mr.baileys, Fix problem combining date filter with other exposed filters.
|
||||
- Switch some references to $node to use $entity instead.
|
||||
- Issue #1112206, add a dummy field to the date navigation bar query to keep it from trying to create invalid sql.
|
||||
- Issue #1112206, $this->view->query->clear_fields() is still need for date_browser to keep Views from trying to use missing field values.
|
||||
- Date browser only works with date_argument, should work with any argument derived from date.
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-alpha3
|
||||
======================
|
||||
|
||||
- Issue #1138700, missed a couple references to the construct() function.
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-alpha2
|
||||
======================
|
||||
|
||||
- Follow up to Issue #1103290, constructor was not set up correctly and did not get triggered, so none of the date handlers had a db_type.
|
||||
- Issue #1138622, preliminary pass at adding support for SQL Server.
|
||||
- Issue #1136618 by ksenzee, Fix broken hide/show capability for date filter values.
|
||||
- Issue #1059078 Add preliminary support for SQLite dates.
|
||||
- Issue #1103290 by kevintheday, Use db_driver() to determine database engine.
|
||||
- The 'now' values got broken again somewhere along the line. Now we need to switch the ISO format used by our SQL queries back to the datetime format the widgets use.
|
||||
- Looks like Views changed ['expose']['operator'] to ['expose']['operator_id'].
|
||||
- Issue #1115770, Make sure filters values are switched back to ISO format so time comparisons work correctly.
|
||||
- Issue #1132916 by znerol, Fix a couple more usages of date_default_timezone_name().
|
||||
- Issue #1131308 Don't try to do timzone conversion when there is no localzone for a field.
|
||||
- Issue #1093222 Fix broken function to remove calendar views.
|
||||
- Issue #820670 Add update to move D6 date format data to D7 data.
|
||||
- Issue 1074344 Fix problem with date select widget that keeps resetting pm back to am.
|
||||
- Issue #1001186 Make sure that a 2 digit year is flagged as an error.
|
||||
- Issue #1117420 by threewestwinds, Make timepicker formats more useful.
|
||||
- Issue #1126408 by thekevinday, Add more sql formats to date api.
|
||||
- Issue #1129326 by robertom, add missing value to element in date_combo.
|
||||
- Issue #998220 by jamsilver and yched, fix handling of validation in date_combo. This also fixes errors when using a date in Profile 2 and Field Collections.
|
||||
- Issue #1022592 by andypost and tim.plunkett optimize hook_form_alter into hook_form FORMID_alter.
|
||||
- Issue 1021424 by joostvdl and wiizzard, fix context in translations to use core values.
|
||||
- Remove extra fields from the Date field. I think the filter and argument now get the right tables joined in without that. We still need the extra fields on calendar, but now we will only add them in the calendar view.
|
||||
- Fix some notices in vcalendar theme.
|
||||
- Fix the mini calendar querystring.
|
||||
- Fix logic for day argument formula.
|
||||
- Fix logic for week argument formula.
|
||||
- Issue #1086582 by bojanz, summary options are in a different place now, fix the method of removing the summary option on multiple-date arguments.
|
||||
- Views renamed 'wildcard' to 'exception'.
|
||||
- Apparently the handler->argument value is not always populated.
|
||||
- Fix fallback value for date_group.
|
||||
- Issue #1103032 by tim.plunkett, Remove token integration code until Token module is fixed.
|
||||
- Now that there is no group of 'Fields' we need different tests to tell if this is a field filter.
|
||||
- Views changed the group name of fields from 'Fields' to 'Content'. Blech, broke everything.
|
||||
- Fix potential error if handler is broken.
|
||||
- Remove reference to a function that no longer exists in Views.
|
||||
- Issue #1116962 by jpontani, mordonez: Parse Error - date_views_fields.inc on line 119.
|
||||
- Fix the logic for year and month only dates.
|
||||
- Add helper function to test if handler is a date handler.
|
||||
- Fix broken handling when creating dates from timestamps.
|
||||
- Set some defaults for dates without month or day.
|
||||
- Issue ##1094408 by Boobaa: Date field not showing up in views arguments in localized site
|
||||
- Issue #1018412 by omerida: get_class() called without object.
|
||||
- There were some problems when creating a year-only date using the select filter caused by trying to create a date with zeros in the month and day. Fix the date building logic to force a valid month and day into them.
|
||||
- Complex filters were not using the date handler of the individual fields.
|
||||
- Issue #1100934, Replace deprecated date_array() function.
|
||||
- #1096246 Date argument also was not applying the group method in the right place in the query, causing that method to be applied to all filters.
|
||||
- Missed a couple places when re-naming the get_value() function in the filter.
|
||||
- Fix more notices.
|
||||
- #1096246 Date filter was not apply the group method in the right place in the query, causing that method to be applied to all filters.
|
||||
- Fix undefined index notice.
|
||||
- Remove non-used function.
|
||||
- Issue #1082654 by arlinsandbulte: Remove master branch files and explain in readme.txt
|
||||
- Issue #906622 by bfroehle, Start cleanup of Date token code.
|
||||
- Fix typo in form processing.
|
||||
- Clean up the admin summary for the date filter.
|
||||
- Fix another use of get_value() in the filter.
|
||||
- Fix some strict errors in the views filter.
|
||||
- #1094408 by Boobaa: Date field not showing up in views arguments in localized site
|
||||
- #1041428, by tim.plunkett: Fix logic errors in 'All Day' computations.
|
||||
- #1054458: Move date_increment_round() function into Date API module so it is always available.
|
||||
- #745074, by rsevero: Don't test for valid timezone-adjusted date for dates that don't use time.
|
||||
- #1076992: The timezone element never got completely updated to D7.
|
||||
- #1013662 by developer-x: Remove check for start and end date - this prevented multiday-all day events from showing 'All Day'
|
||||
|
||||
======================
|
||||
Version 7.x-2.0-alpha1
|
||||
======================
|
||||
|
||||
- #1082658: Saving the options as arrays breaks other things. Add a custom export plugin instead.
|
||||
- #1082658, Views options need to be declared as arrays or they are not saved in the export in Views 3.
|
||||
- #1075896 Break out the code into the simple argument and a complex argument that combines date fields.
|
||||
- #1075890 Break out the code into the simple filter and a complex filter that combines date fields.
|
||||
|
||||
======================
|
||||
Version 7.x-1.0-dev
|
||||
======================
|
||||
|
||||
Abandoned the 7.x-1.x branch.
|
||||
|
||||
Start a new 7.x-2.x branch that will contain a complete re-work of the Views handling.
|
||||
|
||||
The 7.x-2.x branch will totally re-work and simplify the Views filters. These changes may/will
|
||||
break some views and will require that you check views that use the date filter or
|
||||
argument to be sure they are still configured correctly.
|
||||
|
||||
There is a new date_filter_handler_simple for an individual date field that simplifies
|
||||
the Views handling by using most of the core Views field handling but adds in the
|
||||
possibility to set a default date using options like 'now', along with a choice of a
|
||||
month/day/year drop-down selector or popup calendar selector.
|
||||
|
||||
The date_filter_handler is an extension of the simple handler that allows you to combine
|
||||
multiple dates into a single filter so that you can control all of them with the same
|
||||
filter widget, allowing you to either 'OR' or 'AND' them together.
|
||||
|
||||
The arguments will be rewritten in the same way, with a simple argument handler for
|
||||
individual dates and another handler that extends that to control multiple dates with
|
||||
a single argument.
|
||||
|
||||
- Add some error trapping in case the parent dateObject is unable to make a date out of a string to avoid showing the user errors.
|
||||
- #1027752 by B-Prod and dboulet, Fix missing table join on argument summary view.
|
||||
- #1047412 by das-peter - Using date filter in February causes "The day is invalid" error.
|
||||
- #1014162 Now that the datefield processing expands to date & time, the form_value is corrupted.
|
||||
- Changes to the data migration code to work with latest iteration of Content Migrate.
|
||||
|
||||
======================
|
||||
Version 7.x-1.0-alpha2
|
||||
======================
|
||||
|
||||
- Views made lots of changes to field handling just before the new release, which broke lots of things here.
|
||||
- Adding some work-arounds to get things working again and waiting until the dust settles on how the new core fields will be handled in Views before doing much more with the Views integration. These changes should get things working with latest Views release.
|
||||
|
||||
======================
|
||||
Version 7.x-1.0-alpha1
|
||||
======================
|
||||
|
||||
- Initial release, probably still buggy.
|
||||
- Remove Date PHP4, no longer needed because PHP4 is not supported any more.
|
||||
- Remove Date Timezone, now handled by core.
|
||||
47
sites/all/modules/contrib/fields/date/INSTALL.txt
Normal file
47
sites/all/modules/contrib/fields/date/INSTALL.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
================================================================================
|
||||
Date API Installation instructions:
|
||||
================================================================================
|
||||
1) If you have an earlier version of the Date module on your system, empty the
|
||||
date folder out completely. The files in later versions have different names
|
||||
and are located in different places.
|
||||
|
||||
2) Download the whole package of files from http://drupal.org/project/date.
|
||||
|
||||
3) Upload the date files to the modules directory. The package includes files
|
||||
needed by the Date API, and optional modules to to create date fields.
|
||||
|
||||
4) Go to admin/modules and enable the needed modules from the Date/Time group.
|
||||
|
||||
You should end up with a structure like:
|
||||
|
||||
/drupal/sites/all/modules/date/date.info
|
||||
/drupal/sites/all/modules/date/date.install
|
||||
/drupal/sites/all/modules/date/date.module
|
||||
...
|
||||
|
||||
/drupal/sites/all/modules/date/date_api/date_api.info
|
||||
/drupal/sites/all/modules/date/date_api/date_api.install
|
||||
/drupal/sites/all/modules/date/date_api/date_api.module
|
||||
...
|
||||
|
||||
================================================================================
|
||||
Install Date Fields:
|
||||
================================================================================
|
||||
|
||||
1) The date field type is included in the Date files at
|
||||
http://drupal.org/project/date.
|
||||
|
||||
2) Go to admin/modules and enable the Date module. Be sure that the Date API
|
||||
module, the Date Timezone module, and the core Field module are also enabled.
|
||||
|
||||
3) Go to admin/structure/types to view content types and edit a content type.
|
||||
|
||||
4) Make sure the default timezone name has been set at
|
||||
admin/config/regional/settings.
|
||||
|
||||
5) While viewing a content type, select the option to add a new field from the
|
||||
tabs at the top of the page. Several options for date fields will be visible.
|
||||
|
||||
================================================================================
|
||||
More documentation is available at http://drupal.org/node/92460.
|
||||
================================================================================
|
||||
339
sites/all/modules/contrib/fields/date/LICENSE.txt
Normal file
339
sites/all/modules/contrib/fields/date/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
223
sites/all/modules/contrib/fields/date/README.txt
Normal file
223
sites/all/modules/contrib/fields/date/README.txt
Normal file
@@ -0,0 +1,223 @@
|
||||
INFORMATION FOR DEVELOPERS
|
||||
|
||||
Once the Date API is installed, all functions in the API are available to be
|
||||
used anywhere by any module.
|
||||
|
||||
The API uses the PHP 5.2 date functions to create and manipulate dates.
|
||||
|
||||
Example, the following will create a date for the local value in one
|
||||
timezone, adjust it to a different timezone, then return the offset in seconds
|
||||
in the new timezone for the input date; The offset will be adjusted for both
|
||||
the timezone difference and daylight savings time, if necessary:
|
||||
|
||||
$date = date_create('2007-03-11 02:00:00', timezone_open('America/Chicago'));
|
||||
$chicago_time = date_format($date, 'Y-m-d H:i');
|
||||
|
||||
print 'At '. $chicago_time .' in Chicago, the timezone offset in seconds
|
||||
was '. date_offset_get($date);
|
||||
|
||||
date_timezone_set($date, timezone_open('Europe/Berlin');
|
||||
$berlin_time = date_format($date, 'Y-m-d H:i');
|
||||
|
||||
print 'It was '. $berlin_time .' in Berlin when it
|
||||
was '. $chicago_time .' in Chicago.';
|
||||
print 'At that time in Berlin, the timezone offset in seconds was
|
||||
'. date_offset_get($date);
|
||||
|
||||
A helper class is available, new DateObject($string, $timezone, $format), where
|
||||
$string is a unixtimestamp, an ISO date, or a string like YYYY-MM-DD HH:MM:SS,
|
||||
$timezone is the name of the timezone this date is in, and $format is the format
|
||||
of date it is (DATE_FORMAT_UNIX, DATE_FORMAT_ISO, or DATE_FORMAT_DATETIME). It
|
||||
creates and return a date object set to the right date and timezone.
|
||||
|
||||
Simpletest tests for these functions are included in the package.
|
||||
|
||||
Available functions include the following (more documentation is provided in
|
||||
the files):
|
||||
|
||||
============================================================================
|
||||
Preconfigured arrays
|
||||
============================================================================
|
||||
Both translated and untranslated values are available. The
|
||||
date_week_days_ordered() function will shift an array of week day names so it
|
||||
starts with the site's first day of the week, otherwise the weekday names start
|
||||
with Sunday as the first value, which is the expected order for many php and sql
|
||||
functions.
|
||||
|
||||
date_month_names();
|
||||
date_month_names_abbr();
|
||||
date_month_names_untranslated();
|
||||
date_week_days();
|
||||
date_week_days_abbr();
|
||||
date_week_days_untranslated();
|
||||
date_week_days_ordered();
|
||||
date_years();
|
||||
date_hours();
|
||||
date_minutes();
|
||||
date_seconds();
|
||||
date_timezone_names();
|
||||
date_ampm();
|
||||
|
||||
============================================================================
|
||||
Miscellaneous date manipulation functions
|
||||
============================================================================
|
||||
Pre-defined constants and functions that will handle pre-1970 and post-2038
|
||||
dates in both PHP 4 and PHP 5, in any OS. Dates can be converted from one
|
||||
type to another and date parts can be extracted from any date type.
|
||||
|
||||
DATE_DATETIME
|
||||
DATE_ISO
|
||||
DATE_UNIX
|
||||
DATE_ARRAY
|
||||
DATE_OBJECT
|
||||
DATE_ICAL
|
||||
|
||||
date_convert()
|
||||
date_is_valid();
|
||||
date_part_is_valid();
|
||||
date_part_extract();
|
||||
|
||||
============================================================================
|
||||
Date calculation and navigation
|
||||
============================================================================
|
||||
date_difference() will find the time difference between any two days, measured
|
||||
in seconds, minutes, hours, days, months, weeks, or years.
|
||||
|
||||
date_days_in_month();
|
||||
date_days_in_year();
|
||||
date_weeks_in_year();
|
||||
date_last_day_of_month();
|
||||
date_day_of_week();
|
||||
date_day_of_week_name();
|
||||
date_difference();
|
||||
|
||||
============================================================================
|
||||
Date regex and format helpers
|
||||
============================================================================
|
||||
Pre-defined constants, an array of date format strings and their
|
||||
equivalent regex strings.
|
||||
|
||||
DATE_REGEX_LOOSE is a very loose regex that will pull date parts out
|
||||
of an ISO date with or without separators, using either 'T' or a space
|
||||
to separate date and time, and with or without time.
|
||||
|
||||
date_format_date() is similar to format_date(), except it takes a
|
||||
date object instead of a timestamp as the first parameter.
|
||||
|
||||
DATE_FORMAT_ISO
|
||||
DATE_FORMAT_DATETIME
|
||||
DATE_FORMAT_UNIX
|
||||
DATE_FORMAT_ICAL
|
||||
|
||||
DATE_REGEX_ISO
|
||||
DATE_REGEX_DATETIME
|
||||
DATE_REGEX_LOOSE
|
||||
|
||||
date_format_date();
|
||||
date_short_formats();
|
||||
date_medium_formats();
|
||||
date_long_formats();
|
||||
date_format_patterns();
|
||||
|
||||
============================================================================
|
||||
Standardized ical parser and creator
|
||||
============================================================================
|
||||
The iCal parser is found in date_api_ical.inc, which is not included by default.
|
||||
Include that file if you want to use these functions:
|
||||
|
||||
Complete rewrite of ical imports to parse vevents, vlocations, valarms,
|
||||
and all kinds of timezone options and repeat rules for ical imports.
|
||||
The function now sticks to parsing the ical into an array that can be used
|
||||
in various ways. It no longer trys to convert timezones while parsing,
|
||||
instead a date_ical_date_format() function is provided that can be used to
|
||||
convert from the ical timezone to whatever timezone is desired in the
|
||||
results. Repeat rules are parsed into an array which other modules can
|
||||
manipulate however they like to create additional events from the results.
|
||||
|
||||
date_ical_export();
|
||||
date_ical_import();
|
||||
date_ical_date_format();
|
||||
|
||||
============================================================================
|
||||
Helpers for portable date SQL
|
||||
============================================================================
|
||||
The SQL functions are found in date_api_sql.inc, which is not included by
|
||||
default. Include that file if you want to use these functions:
|
||||
|
||||
date_sql();
|
||||
date_server_zone_adj();
|
||||
date_sql_concat();
|
||||
date_sql_pad();
|
||||
|
||||
============================================================================
|
||||
Date forms and validators
|
||||
============================================================================
|
||||
Reusable, configurable, self-validating FAPI date elements are found in
|
||||
date_api_elements.inc, which is not included by default. Include it
|
||||
if you want to use these elements. To use them, create a form element
|
||||
and set the '#type' to one of the following:
|
||||
|
||||
date_select
|
||||
The date_select element will create a collection of form elements, with a
|
||||
separate select or textfield for each date part. The whole collection will
|
||||
get reformatted back into a date value of the requested type during validation.
|
||||
|
||||
date_text
|
||||
The date_text element will create a textfield that can contain a whole
|
||||
date or any part of a date as text. The user input value will be re-formatted
|
||||
back into a date value of the requested type during validation.
|
||||
|
||||
date_timezone
|
||||
The date_timezone element will create a drop-down selector to pick a
|
||||
timezone name.
|
||||
|
||||
The custom date elements require a few other pieces of information to work
|
||||
correctly, like #date_format and #date_type. See the internal documentation
|
||||
for more information.
|
||||
|
||||
============================================================================
|
||||
Date Popup Module
|
||||
============================================================================
|
||||
|
||||
A new module is included in the package that will enable a popup jQuery
|
||||
calendar date picker and timepicker in date and time fields.
|
||||
|
||||
It is implemented as a custom form element, so set '#type' to 'date_popup'
|
||||
to use this element. See the internal documentation for more information.
|
||||
|
||||
============================================================================
|
||||
Date Repeat API
|
||||
============================================================================
|
||||
|
||||
An API for repeating dates is available if installed. It can be used by
|
||||
other modules to create a form element that will allow users to select
|
||||
repeat rules and store those selections in an iCal RRULE string, and a
|
||||
calculation function that will parse the RRULE and return an array of dates
|
||||
that match those rules. The API is implemented in the Date module as a
|
||||
new date widget if the Date Repeat API is installed.
|
||||
|
||||
============================================================================
|
||||
RDF Integration
|
||||
============================================================================
|
||||
|
||||
To make RDF easier to use, the base date themes (date_display_single and
|
||||
date_display_range) have been expanded so they pass attributes and
|
||||
RDF mappings for the field, if any, to the theme. If RDF is installed
|
||||
and no other mappings are provided, the theme adds RDF information
|
||||
to mark both the Start and End dates as 'xsd:dateTime' datatypes with the
|
||||
property of 'dc:date'. This occurs in the theme preprocess layer, in
|
||||
particular via the functions template_preprocess_date_display_single() and
|
||||
template_preprocess_date_display_range().
|
||||
|
||||
To mark these as events instead, you could install the schemaorg
|
||||
module, which will load the schema.org vocabulary. The mark the content type
|
||||
that contains events as an 'Event', using the UI exposed by that
|
||||
module and set the event start date field with the 'dateStart'
|
||||
property and tag other fields in the content type with the appropriate
|
||||
property types. The Date module theme will wrap the start and end
|
||||
date output with appropriate markup.
|
||||
|
||||
If the result is not quite what you need, you should be able to implement your
|
||||
own theme preprocess functions, e.g. MYTHEME_preprocess_date_display_single()
|
||||
or MYTHEME_preprocess_date_display_range() and alter the attributes to use the
|
||||
values you want.
|
||||
529
sites/all/modules/contrib/fields/date/date.api.php
Normal file
529
sites/all/modules/contrib/fields/date/date.api.php
Normal file
@@ -0,0 +1,529 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the Date module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Alter the default value for a date argument.
|
||||
*
|
||||
* @param object $argument
|
||||
* The argument object.
|
||||
* @param string $value
|
||||
* The default value created by the argument handler.
|
||||
*/
|
||||
function hook_date_default_argument_alter(&$argument, &$value) {
|
||||
$style_options = $style_options = $argument->view->display_handler->get_option('style_options');
|
||||
if (!empty($style_options['track_date'])) {
|
||||
$default_date = date_now();
|
||||
$value = $default_date->format($argument->arg_format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the entity before formatting it.
|
||||
*
|
||||
* @param object $entity
|
||||
* The entity object being viewed.
|
||||
* @param array $variables
|
||||
* The variables passed to the formatter.
|
||||
* - entity: The $entity object.
|
||||
* - entity_type: The $entity_type.
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - langcode: The $langcode.
|
||||
* - items: The $items array.
|
||||
* - display: The $display array.
|
||||
* - dates: The processed dates array, empty at this point.
|
||||
* - attributes: The attributes array, empty at this point.
|
||||
* - rdf_mapping: The RDF mapping array.
|
||||
* - add_rdf: If module_exists('rdf').
|
||||
*/
|
||||
function hook_date_formatter_pre_view_alter(&$entity, &$variables) {
|
||||
if (!empty($entity->view)) {
|
||||
$field = $variables['field'];
|
||||
$date_id = 'date_id_' . $field['field_name'];
|
||||
$date_delta = 'date_delta_' . $field['field_name'];
|
||||
$date_item = $entity->view->result[$entity->view->row_index];
|
||||
if (!empty($date_item->$date_id)) {
|
||||
$entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the dates array created by date_formatter_process().
|
||||
*
|
||||
* @param array $dates
|
||||
* The $dates array created by the Date module.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - format: The string $format.
|
||||
* - entity_type: The $entity_type.
|
||||
* - entity: The $entity object.
|
||||
* - langcode: The string $langcode.
|
||||
* - item: The $item array.
|
||||
* - display: The $display array.
|
||||
*/
|
||||
function hook_date_formatter_dates_alter(&$dates, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$format = $context['format'];
|
||||
$entity_type = $context['entity_type'];
|
||||
$entity = $context['entity'];
|
||||
$date1 = $dates['value']['local']['object'];
|
||||
$date2 = $dates['value2']['local']['object'];
|
||||
|
||||
$is_all_day = date_all_day_field($field, $instance, $date1, $date2);
|
||||
|
||||
$all_day1 = '';
|
||||
$all_day2 = '';
|
||||
if ($format != 'format_interval' && $is_all_day) {
|
||||
$all_day1 = theme('date_all_day', array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'which' => 'date1',
|
||||
'date1' => $date1,
|
||||
'date2' => $date2,
|
||||
'format' => $format,
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity));
|
||||
$all_day2 = theme('date_all_day', array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'which' => 'date2',
|
||||
'date1' => $date1,
|
||||
'date2' => $date2,
|
||||
'format' => $format,
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity));
|
||||
$dates['value']['formatted_time'] = theme('date_all_day_label');
|
||||
$dates['value2']['formatted_time'] = theme('date_all_day_label');
|
||||
$dates['value']['formatted'] = $all_day1;
|
||||
$dates['value2']['formatted'] = $all_day2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_text element before the rest of the validation is run.
|
||||
*
|
||||
* @param array $element
|
||||
* The $element array.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $input
|
||||
* The array of input values to be validated.
|
||||
*/
|
||||
function hook_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
// Let Date module massage the format for all day values so they will pass
|
||||
// validation. The All day flag, if used, actually exists on the parent
|
||||
// element.
|
||||
date_all_day_value($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_select element before the rest of the validation is run.
|
||||
*
|
||||
* @param array $element
|
||||
* The $element array.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $input
|
||||
* The array of input values to be validated.
|
||||
*/
|
||||
function hook_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
// Let Date module massage the format for all day values so they will pass
|
||||
// validation. The All day flag, if used, actually exists on the parent
|
||||
// element.
|
||||
date_all_day_value($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_popup element before the rest of the validation is run.
|
||||
*
|
||||
* @param array $element
|
||||
* The $element array.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $input
|
||||
* The array of input values to be validated.
|
||||
*/
|
||||
function hook_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
// Let Date module massage the format for all day values so they will pass
|
||||
// validation. The All day flag, if used, actually exists on the parent
|
||||
// element.
|
||||
date_all_day_value($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_combo element before the rest of the validation is run.
|
||||
*
|
||||
* @param array $element
|
||||
* The $element array.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - item: The $item array.
|
||||
*
|
||||
* @see date_combo_element_process()
|
||||
*/
|
||||
function hook_date_combo_pre_validate_alter(&$element, &$form_state, $context) {
|
||||
if (!empty($context['item']['all_day'])) {
|
||||
|
||||
$field = $context['field'];
|
||||
|
||||
// If we have an all day flag on this date and the time is empty, change the
|
||||
// format to match the input value so we don't get validation errors.
|
||||
$element['#date_is_all_day'] = TRUE;
|
||||
$element['value']['#date_format'] = date_part_format('date', $element['value']['#date_format']);
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$element['value2']['#date_format'] = date_part_format('date', $element['value2']['#date_format']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the local start date objects created by the date_combo validation.
|
||||
*
|
||||
* This is called before the objects are converted back to the database timezone
|
||||
* and stored.
|
||||
*
|
||||
* @param object $date
|
||||
* The $date object.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - item: The $item array.
|
||||
* - element: The $element array.
|
||||
*/
|
||||
function hook_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {
|
||||
// If this is an 'All day' value, set the time to midnight.
|
||||
if (!empty($context['element']['#date_is_all_day'])) {
|
||||
$date->setTime(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the local end date objects created by the date_combo validation.
|
||||
*
|
||||
* This is called before the objects are converted back to the database timezone
|
||||
* and stored.
|
||||
*
|
||||
* @param object $date
|
||||
* The $date object.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - item: The $item array.
|
||||
* - element: The $element array.
|
||||
*/
|
||||
function hook_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
|
||||
// If this is an 'All day' value, set the time to midnight.
|
||||
if (!empty($context['element']['#date_is_all_day'])) {
|
||||
$date->setTime(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_text widget element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the date_text element.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - form: Nested array of form elements that comprise the form.
|
||||
*
|
||||
* @see date_text_element_process()
|
||||
*/
|
||||
function hook_date_text_process_alter(&$element, &$form_state, $context) {
|
||||
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
|
||||
if ($all_day_id != '') {
|
||||
// All Day handling on text dates works only if the user leaves the time out
|
||||
// of the input value. There is no element to hide or show.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_select widget element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the date_select element.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - form: Nested array of form elements that comprise the form.
|
||||
*
|
||||
* @see date_select_element_process()
|
||||
*/
|
||||
function hook_date_select_process_alter(&$element, &$form_state, $context) {
|
||||
// Hide or show the element in reaction to the all_day status for the element.
|
||||
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
|
||||
if ($all_day_id != '') {
|
||||
foreach (array('hour', 'minute', 'second', 'ampm') as $field) {
|
||||
if (array_key_exists($field, $element)) {
|
||||
$element[$field]['#states'] = array(
|
||||
'visible' => array(
|
||||
'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_popup widget element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the date_popup element.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - form: Nested array of form elements that comprise the form.
|
||||
*
|
||||
* @see date_popup_element_process()
|
||||
*/
|
||||
function hook_date_popup_process_alter(&$element, &$form_state, $context) {
|
||||
// Hide or show the element in reaction to the all_day status for the element.
|
||||
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
|
||||
if ($all_day_id != '' && array_key_exists('time', $element)) {
|
||||
$element['time']['#states'] = array(
|
||||
'visible' => array(
|
||||
'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_combo element after the Date module is finished with it.
|
||||
*
|
||||
* @param array $element
|
||||
* The $element array.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - form: Nested array of form elements that comprise the form.
|
||||
*/
|
||||
function hook_date_combo_process_alter(&$element, &$form_state, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$field_name = $element['#field_name'];
|
||||
$delta = $element['#delta'];
|
||||
|
||||
// Add a date repeat form element, if needed.
|
||||
// We delayed until this point so we don't bother adding it to hidden fields.
|
||||
if (date_is_repeat_field($field, $instance)) {
|
||||
$item = $element['#value'];
|
||||
$element['rrule'] = array(
|
||||
'#type' => 'date_repeat_rrule',
|
||||
'#theme_wrappers' => array('date_repeat_rrule'),
|
||||
'#default_value' => isset($item['rrule']) ? $item['rrule'] : '',
|
||||
'#date_timezone' => $element['#date_timezone'],
|
||||
'#date_format' => date_limit_format(date_input_format($element, $field, $instance), $field['settings']['granularity']),
|
||||
'#date_text_parts' => (array) $instance['widget']['settings']['text_parts'],
|
||||
'#date_increment' => $instance['widget']['settings']['increment'],
|
||||
'#date_year_range' => $instance['widget']['settings']['year_range'],
|
||||
'#date_label_position' => $instance['widget']['settings']['label_position'],
|
||||
'#prev_value' => isset($item['value']) ? $item['value'] : '',
|
||||
'#prev_value2' => isset($item['value2']) ? $item['value2'] : '',
|
||||
'#prev_rrule' => isset($item['rrule']) ? $item['rrule'] : '',
|
||||
'#date_repeat_widget' => str_replace('_repeat', '', $instance['widget']['type']),
|
||||
'#date_repeat_collapsed' => $instance['widget']['settings']['repeat_collapsed'],
|
||||
'#date_flexible' => 0,
|
||||
'#weight' => $instance['widget']['weight'] + .4,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_timezone widget element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the date_select element.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - form: Nested array of form elements that comprise the form.
|
||||
*
|
||||
* @see date_timezone_element_process()
|
||||
*/
|
||||
function hook_date_timezone_process_alter(&$element, &$form_state, $context) {
|
||||
// @todo.
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the date_year_range widget element.
|
||||
*
|
||||
* @param array $element
|
||||
* An associative array containing the properties of the date_select element.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - form: Nested array of form elements that comprise the form.
|
||||
*
|
||||
* @see date_year_range_element_process()
|
||||
*/
|
||||
function hook_date_year_range_process_alter(&$element, &$form_state, $context) {
|
||||
// @todo.
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a date field settings form.
|
||||
*
|
||||
* @param array $form
|
||||
* Nested array of form elements that comprise the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - has_data: The value of $has_data.
|
||||
*
|
||||
* @see hook_field_settings_form()
|
||||
*/
|
||||
function hook_date_field_settings_form_alter(&$form, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$has_data = $context['has_data'];
|
||||
|
||||
$form['repeat'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Repeating date'),
|
||||
'#default_value' => $field['settings']['repeat'],
|
||||
'#options' => array(0 => t('No'), 1 => t('Yes')),
|
||||
'#attributes' => array('class' => array('container-inline')),
|
||||
'#description' => t("Repeating dates use an 'Unlimited' number of values. Instead of the 'Add more' button, they include a form to select when and how often the date should repeat."),
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a date field instance settings form.
|
||||
*
|
||||
* @param array $form
|
||||
* Nested array of form elements that comprise the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
*
|
||||
* @see hook_field_instance_settings_form()
|
||||
*/
|
||||
function hook_date_field_instance_settings_form_alter(&$form, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$form['new_setting'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => '',
|
||||
'#title' => t('My new setting'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a date field widget settings form.
|
||||
*
|
||||
* @param array $form
|
||||
* Nested array of form elements that comprise the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
*
|
||||
* @see hook_field_widget_settings_form()
|
||||
*/
|
||||
function hook_date_field_widget_settings_form_alter(&$form, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$form['new_setting'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => '',
|
||||
'#title' => t('My new setting'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a date field formatter settings form.
|
||||
*
|
||||
* @param array $form
|
||||
* Nested array of form elements that comprise the form.
|
||||
* @param array $form_state
|
||||
* A keyed array containing the current state of the form.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - view_mode: The formatter view mode.
|
||||
*
|
||||
* @see hook_field_formatter_settings_form()
|
||||
*/
|
||||
function hook_date_field_formatter_settings_form_alter(&$form, &$form_state, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$view_mode = $context['view_mode'];
|
||||
$display = $instance['display'][$view_mode];
|
||||
$formatter = $display['type'];
|
||||
if ($formatter == 'date_default') {
|
||||
$form['show_repeat_rule'] = array(
|
||||
'#title' => t('Repeat rule:'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
'show' => t('Show repeat rule'),
|
||||
'hide' => t('Hide repeat rule')),
|
||||
'#default_value' => $settings['show_repeat_rule'],
|
||||
'#access' => $field['settings']['repeat'],
|
||||
'#weight' => 5,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter a date field formatter settings summary.
|
||||
*
|
||||
* @param array $summary
|
||||
* An array of strings to be concatenated into a short summary of the
|
||||
* formatter settings.
|
||||
* @param array $context
|
||||
* An associative array containing the following keys:
|
||||
* - field: The $field array.
|
||||
* - instance: The $instance array.
|
||||
* - view_mode: The formatter view mode.
|
||||
*
|
||||
* @see hook_field_formatter_settings_summary()
|
||||
*/
|
||||
function hook_date_field_formatter_settings_summary_alter(&$summary, $context) {
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$view_mode = $context['view_mode'];
|
||||
$display = $instance['display'][$view_mode];
|
||||
$formatter = $display['type'];
|
||||
$settings = $display['settings'];
|
||||
if (isset($settings['show_repeat_rule']) && !empty($field['settings']['repeat'])) {
|
||||
if ($settings['show_repeat_rule'] == 'show') {
|
||||
$summary[] = t('Show repeat rule');
|
||||
}
|
||||
else {
|
||||
$summary[] = t('Hide repeat rule');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Date Devel Generate code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_devel_generate().
|
||||
*
|
||||
* Included only when needed.
|
||||
*/
|
||||
function date_devel_generate($entity, $field, $instance, $bundle) {
|
||||
|
||||
$entity_field = array();
|
||||
if (isset($instance['widget']['settings']['year_range'])) {
|
||||
$split = explode(':', $instance['widget']['settings']['year_range']);
|
||||
$back = str_replace('-', '', $split[0]);
|
||||
$forward = str_replace('+', '', $split[1]);
|
||||
}
|
||||
else {
|
||||
$back = 2;
|
||||
$forward = 2;
|
||||
}
|
||||
// Pick a random year within the time range,
|
||||
// and a random second within that year.
|
||||
$year = date_format(date_now(), 'Y') - $back + mt_rand(0, ($forward + $back));
|
||||
$start = new DateObject($year . '-01-01 00:00:00', date_get_timezone_db($field['settings']['tz_handling']));
|
||||
$leap = date_format($start, 'L');
|
||||
$max_days = $leap ? 366 : 365;
|
||||
$seconds = mt_rand(0, ($max_days * 86400));
|
||||
date_modify($start, "+$seconds seconds");
|
||||
$increment = $instance['widget']['settings']['increment'];
|
||||
date_increment_round($start, $increment);
|
||||
|
||||
// Modify End date by 1 hour to 3 days, shorter for repeating dates
|
||||
// longer for others.
|
||||
$start2 = clone($start);
|
||||
$max = !empty($field['settings']['repeat']) ? 720 : 4320;
|
||||
$max = 240;
|
||||
date_modify($start2, '+' . mt_rand(60, $max) . ' minutes');
|
||||
date_increment_round($start2, $increment);
|
||||
|
||||
if ($field['settings']['tz_handling'] == 'date') {
|
||||
// Choose a random timezone.
|
||||
// Not all keys exist, so we have to check.
|
||||
$timezones = array_keys(date_timezone_names(TRUE));
|
||||
$key = mt_rand(0, count($timezones) - 1);
|
||||
if (!array_key_exists($key, $timezones)) {
|
||||
$timezone = date_default_timezone();
|
||||
}
|
||||
else {
|
||||
$timezone = $timezones[$key];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$timezone = date_get_timezone($field['settings']['tz_handling']);
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'date':
|
||||
$format = DATE_FORMAT_ISO;
|
||||
break;
|
||||
case 'datestamp':
|
||||
$format = DATE_FORMAT_UNIX;
|
||||
break;
|
||||
case 'datetime':
|
||||
$format = DATE_FORMAT_DATETIME;
|
||||
break;
|
||||
}
|
||||
$entity_field['value'] = date_format($start, $format);
|
||||
if ($field['settings']['todate']) {
|
||||
$entity_field['value2'] = date_format($start2, $format);
|
||||
}
|
||||
date_timezone_set($start, timezone_open($timezone));
|
||||
$entity_field['timezone'] = $timezone;
|
||||
$entity_field['offset'] = date_offset_get($start);
|
||||
date_timezone_set($start2, timezone_open($timezone));
|
||||
$entity_field['offset2'] = date_offset_get($start2);
|
||||
return $entity_field;
|
||||
|
||||
}
|
||||
537
sites/all/modules/contrib/fields/date/date.field.inc
Normal file
537
sites/all/modules/contrib/fields/date/date.field.inc
Normal file
@@ -0,0 +1,537 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Field hooks to implement a date field.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_info().
|
||||
*/
|
||||
function date_field_formatter_info() {
|
||||
$formatters = array(
|
||||
'date_default' => array(
|
||||
'label' => t('Date and time'),
|
||||
'field types' => array('date', 'datestamp', 'datetime'),
|
||||
'settings' => array(
|
||||
'format_type' => 'long',
|
||||
'multiple_number' => '',
|
||||
'multiple_from' => '',
|
||||
'multiple_to' => '',
|
||||
'fromto' => 'both',
|
||||
),
|
||||
),
|
||||
'format_interval' => array(
|
||||
'label' => t('Time ago'),
|
||||
'field types' => array('date', 'datestamp', 'datetime'),
|
||||
'settings' => array(
|
||||
'interval' => 2,
|
||||
'interval_display' => 'time ago',
|
||||
),
|
||||
),
|
||||
'date_plain' => array(
|
||||
'label' => t('Plain'),
|
||||
'field types' => array('date', 'datestamp', 'datetime'),
|
||||
),
|
||||
);
|
||||
return $formatters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_settings_form().
|
||||
*/
|
||||
function date_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$formatter = $display['type'];
|
||||
module_load_include('inc', 'date', 'date_admin');
|
||||
switch ($formatter) {
|
||||
case 'format_interval':
|
||||
$form = date_interval_formatter_settings_form($field, $instance, $view_mode, $form, $form_state);
|
||||
break;
|
||||
default:
|
||||
$form = date_default_formatter_settings_form($field, $instance, $view_mode, $form, $form_state);
|
||||
break;
|
||||
}
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'view_mode' => $view_mode,
|
||||
);
|
||||
drupal_alter('date_field_formatter_settings_form', $form, $form_state, $context);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_settings_summary().
|
||||
*/
|
||||
function date_field_formatter_settings_summary($field, $instance, $view_mode) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$formatter = $display['type'];
|
||||
module_load_include('inc', 'date', 'date_admin');
|
||||
switch ($formatter) {
|
||||
case 'format_interval':
|
||||
$summary = date_interval_formatter_settings_summary($field, $instance, $view_mode);
|
||||
break;
|
||||
default:
|
||||
$summary = date_default_formatter_settings_summary($field, $instance, $view_mode);
|
||||
break;
|
||||
}
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'view_mode' => $view_mode,
|
||||
);
|
||||
drupal_alter('date_field_formatter_settings_summary', $summary, $context);
|
||||
|
||||
return implode('<br />', $summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_formatter_view().
|
||||
*
|
||||
* Useful values:
|
||||
*
|
||||
* $entity->date_id
|
||||
* If set, this will show only an individual date on a field with
|
||||
* multiple dates. The value should be a string that contains
|
||||
* the following values, separated with periods:
|
||||
* - module name of the module adding the item
|
||||
* - node nid
|
||||
* - field name
|
||||
* - delta value of the field to be displayed
|
||||
* - other information the module's custom theme might need
|
||||
*
|
||||
* Used by the calendar module and available for other uses.
|
||||
* example: 'date:217:field_date:3:test'
|
||||
*
|
||||
* $entity->date_repeat_show
|
||||
* If true, tells the theme to show all the computed values
|
||||
* of a repeating date. If not true or not set, only the
|
||||
* start date and the repeat rule will be displayed.
|
||||
*/
|
||||
function date_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
|
||||
$element = array();
|
||||
$settings = $display['settings'];
|
||||
$formatter = $display['type'];
|
||||
$variables = array(
|
||||
'entity' => $entity,
|
||||
'entity_type' => $entity_type,
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'langcode' => $langcode,
|
||||
'items' => $items,
|
||||
'display' => $display,
|
||||
'dates' => array(),
|
||||
'attributes' => array(),
|
||||
'rdf_mapping' => array(),
|
||||
'add_rdf' => module_exists('rdf'),
|
||||
);
|
||||
|
||||
// If there is an RDf mapping for this date field, pass it down to the theme.
|
||||
$rdf_mapping = array();
|
||||
if (!empty($entity->rdf_mapping) && function_exists('rdf_rdfa_attributes')) {
|
||||
if (!empty($entity->rdf_mapping[$field['field_name']])) {
|
||||
$variables['rdf_mapping'] = $rdf_mapping = $entity->rdf_mapping[$field['field_name']];
|
||||
}
|
||||
}
|
||||
|
||||
// Give other modules a chance to prepare the entity before formatting it.
|
||||
drupal_alter('date_formatter_pre_view', $entity, $variables);
|
||||
|
||||
// See if we are only supposed to display a selected
|
||||
// item from multiple value date fields.
|
||||
$selected_deltas = array();
|
||||
if (!empty($entity->date_id)) {
|
||||
foreach ((array) $entity->date_id as $key => $id) {
|
||||
list($module, $nid, $field_name, $selected_delta, $other) = explode('.', $id . '.');
|
||||
if ($field_name == $field['field_name']) {
|
||||
$selected_deltas[] = $selected_delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch ($display['type']) {
|
||||
case 'date_plain':
|
||||
foreach ($items as $delta => $item) {
|
||||
if (!empty($entity->date_id) && !in_array($delta, $selected_deltas)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (empty($item['value2']) || $item['value'] == $item['value2']) {
|
||||
$element[$delta] = array('#markup' => $item['value']);
|
||||
}
|
||||
else {
|
||||
$element[$delta] = array('#markup' => t('!start-date to !end-date', array('!start-date' => $item['value'], '!end-date' => $item['value2'])));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'format_interval':
|
||||
foreach ($items as $delta => $item) {
|
||||
if (!empty($entity->date_id) && !in_array($delta, $selected_deltas)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
$variables['delta'] = $delta;
|
||||
$variables['item'] = $item;
|
||||
$variables['dates'] = date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
|
||||
$variables['attributes'] = !empty($rdf_mapping) ? rdf_rdfa_attributes($rdf_mapping, $item['value']) : array();
|
||||
$element[$delta] = array('#markup' => theme('date_display_interval', $variables));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
foreach ($items as $delta => $item) {
|
||||
if (!empty($entity->date_id) && !in_array($delta, $selected_deltas)) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
$variables['delta'] = $delta;
|
||||
$variables['item'] = $item;
|
||||
$variables['dates'] = date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
|
||||
$variables['attributes'] = !empty($rdf_mapping) ? rdf_rdfa_attributes($rdf_mapping, $item['value']) : array();
|
||||
$output = theme('date_display_combination', $variables);
|
||||
if (!empty($output)) {
|
||||
$element[$delta] = array('#markup' => $output);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_is_empty().
|
||||
*/
|
||||
function date_field_is_empty($item, $field) {
|
||||
// Sometimes a $item is a date object.
|
||||
// Coming from repeating dates. Why??
|
||||
if (!is_array($item)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (empty($item['value'])) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif ($field['settings']['todate'] == 'required' && empty($item['value2'])) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_info().
|
||||
*/
|
||||
function date_field_info() {
|
||||
$settings = array(
|
||||
'settings' => array(
|
||||
'todate' => '',
|
||||
'granularity' => drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute')),
|
||||
'tz_handling' => 'site',
|
||||
'timezone_db' => 'UTC',
|
||||
),
|
||||
'instance_settings' => array(
|
||||
'default_value' => 'now',
|
||||
'default_value_code' => '',
|
||||
'default_value2' => 'same',
|
||||
'default_value_code2' => '',
|
||||
),
|
||||
// Integrate with the Entity Metadata module.
|
||||
'property_type' => 'date',
|
||||
'property_callbacks' => array('date_entity_metadata_property_info_alter'),
|
||||
);
|
||||
return array(
|
||||
'datetime' => array(
|
||||
'label' => 'Date',
|
||||
'description' => t('Store a date in the database as a datetime field, recommended for complete dates and times that may need timezone conversion.'),
|
||||
'default_widget' => 'date_select',
|
||||
'default_formatter' => 'date_default',
|
||||
'default_token_formatter' => 'date_plain',
|
||||
) + $settings,
|
||||
'date' => array(
|
||||
'label' => 'Date (ISO format)',
|
||||
'description' => t('Store a date in the database as an ISO date, recommended for historical or partial dates.'),
|
||||
'default_widget' => 'date_select',
|
||||
'default_formatter' => 'date_default',
|
||||
'default_token_formatter' => 'date_plain',
|
||||
) + $settings,
|
||||
'datestamp' => array(
|
||||
'label' => 'Date (Unix timestamp)',
|
||||
'description' => t('Store a date in the database as a timestamp, deprecated format to support legacy data.'),
|
||||
'default_widget' => 'date_select',
|
||||
'default_formatter' => 'date_default',
|
||||
'default_token_formatter' => 'date_plain',
|
||||
) + $settings,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_info().
|
||||
*/
|
||||
function date_field_widget_info() {
|
||||
$settings = array(
|
||||
'settings' => array(
|
||||
'input_format' => date_default_format('date_select'),
|
||||
'input_format_custom' => '',
|
||||
'increment' => 15,
|
||||
'text_parts' => array(),
|
||||
'year_range' => '-3:+3',
|
||||
'label_position' => 'above',
|
||||
),
|
||||
'behaviors' => array(
|
||||
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
|
||||
'default value' => FIELD_BEHAVIOR_NONE,
|
||||
),
|
||||
);
|
||||
|
||||
$info = array(
|
||||
'date_select' => array(
|
||||
'label' => t('Select list'),
|
||||
'field types' => array('date', 'datestamp', 'datetime'),
|
||||
) + $settings,
|
||||
'date_text' => array(
|
||||
'label' => t('Text field'),
|
||||
'field types' => array('date', 'datestamp', 'datetime'),
|
||||
) + $settings,
|
||||
);
|
||||
|
||||
if (module_exists('date_popup')) {
|
||||
$info['date_popup'] = array(
|
||||
'label' => t('Pop-up calendar'),
|
||||
'field types' => array('date', 'datestamp', 'datetime'),
|
||||
) + $settings;
|
||||
}
|
||||
|
||||
// The date text widget should use an increment of 1.
|
||||
$info['date_text']['increment'] = 1;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_load().
|
||||
*/
|
||||
function date_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
|
||||
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$db_format = date_type_format($field['type']);
|
||||
$process = date_process_values($field);
|
||||
foreach ($entities as $id => $entity) {
|
||||
foreach ($items[$id] as $delta => &$item) {
|
||||
// If the file does not exist, mark the entire item as empty.
|
||||
if (is_array($item)) {
|
||||
$timezone = isset($item['timezone']) ? $item['timezone'] : '';
|
||||
$item['timezone'] = date_get_timezone($field['settings']['tz_handling'], $timezone);
|
||||
$item['timezone_db'] = $timezone_db;
|
||||
$item['date_type'] = $field['type'];
|
||||
if (!empty($field['settings']['cache_enabled']) && ($delta < $field['settings']['cache_count'] || $field['settings']['cache_count'] == 0)) {
|
||||
foreach ($process as $processed) {
|
||||
if (!empty($item[$processed])) {
|
||||
$date = new DateObject($item[$processed], $item['timezone_db'], $db_format);
|
||||
$date->limitGranularity($field['settings']['granularity']);
|
||||
$item['db'][$processed] = $date;
|
||||
}
|
||||
}
|
||||
if (!empty($item['db']['value']) && empty($item['db']['value2'])) {
|
||||
$item['db']['value2'] = $item['db']['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_validate().
|
||||
*/
|
||||
function date_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
|
||||
$field_name = $field['field_name'];
|
||||
$flexible = 0;
|
||||
|
||||
// Don't try to validate if there were any errors before this point
|
||||
// since the element won't have been munged back into a date.
|
||||
if (!form_get_errors()) {
|
||||
foreach ($items as $delta => $item) {
|
||||
if (is_array($item) && isset($item['value'])) {
|
||||
$process = date_process_values($field, $instance);
|
||||
$date1 = new DateObject($item['value'], $item['timezone'], date_type_format($field['type']));
|
||||
if (count($process) == 1 || (empty($item['value2']) && $item['value2'] !== 0)) {
|
||||
$date2 = clone($date1);
|
||||
}
|
||||
else {
|
||||
$date2 = new DateObject($item['value2'], $item['timezone'], date_type_format($field['type']));
|
||||
}
|
||||
$valid1 = $date1->validGranularity($field['settings']['granularity'], $flexible);
|
||||
$valid2 = $date2->validGranularity($field['settings']['granularity'], $flexible);
|
||||
|
||||
foreach ($process as $processed) {
|
||||
if ($processed == 'value' && $field['settings']['todate'] && !$valid1 && $valid2) {
|
||||
$errors[$field['field_name']][$langcode][$delta][] = array(
|
||||
'error' => 'value',
|
||||
'message' => t("A 'Start date' date is required for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])),
|
||||
);
|
||||
}
|
||||
if ($processed == 'value2' && $field['settings']['todate'] == 'required' && ($instance['required'] && $valid1 && !$valid2)) {
|
||||
$errors[$field['field_name']][$langcode][$delta][] = array(
|
||||
'error' => 'value2',
|
||||
'message' => t("An 'End date' is required for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_insert().
|
||||
*/
|
||||
function date_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
$field_name = $field['field_name'];
|
||||
|
||||
if (empty($items)) {
|
||||
return;
|
||||
}
|
||||
// Add some information needed to interpret token values.
|
||||
$values = $items;
|
||||
foreach ($values as $delta => $item) {
|
||||
$timezone = isset($item['timezone']) ? $item['timezone'] : '';
|
||||
if (is_array($item)) {
|
||||
$items[$delta]['timezone'] = date_get_timezone($field['settings']['tz_handling'], $timezone);
|
||||
$items[$delta]['timezone_db'] = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$items[$delta]['date_type'] = $field['type'];
|
||||
}
|
||||
}
|
||||
$entity->{$field['field_name']}[$langcode] = $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_insert().
|
||||
*/
|
||||
function date_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
$context = array(
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity,
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'langcode' => $langcode,
|
||||
);
|
||||
drupal_alter('date_field_insert', $items, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_update().
|
||||
*/
|
||||
function date_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
||||
$context = array(
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity,
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'langcode' => $langcode,
|
||||
);
|
||||
drupal_alter('date_field_update', $items, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_instance_settings_form().
|
||||
*
|
||||
* Wrapper functions for date administration, included only when processing
|
||||
* field settings.
|
||||
*/
|
||||
function date_field_instance_settings_form($field, $instance) {
|
||||
module_load_include('inc', 'date', 'date_admin');
|
||||
return _date_field_instance_settings_form($field, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_settings_form().
|
||||
*/
|
||||
function date_field_widget_settings_form($field, $instance) {
|
||||
module_load_include('inc', 'date', 'date_admin');
|
||||
return _date_field_widget_settings_form($field, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_settings_form().
|
||||
*/
|
||||
function date_field_settings_form($field, $instance, $has_data) {
|
||||
module_load_include('inc', 'date', 'date_admin');
|
||||
return _date_field_settings_form($field, $instance, $has_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_content_migrate_field_alter().
|
||||
*
|
||||
* Use this to tweak the conversion of field settings from the D6 style to the
|
||||
* D7 style for specific situations not handled by basic conversion, as when
|
||||
* field types or settings are changed.
|
||||
*
|
||||
* $field_value['widget_type'] is available to see what widget type was
|
||||
* originally used.
|
||||
*/
|
||||
function date_content_migrate_field_alter(&$field_value, $instance_value) {
|
||||
switch ($field_value['module']) {
|
||||
case 'date':
|
||||
// Those settings do not exist anymore, or have been moved to the instance
|
||||
// level.
|
||||
unset($field_value['settings']['default_format']);
|
||||
unset($field_value['settings']['repeat_collapsed']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_content_migrate_instance_alter().
|
||||
*
|
||||
* Use this to tweak the conversion of instance or widget settings from the D6
|
||||
* style to the D7 style for specific situations not handled by basic
|
||||
* conversion, as when formatter or widget names or settings are changed.
|
||||
*/
|
||||
function date_content_migrate_instance_alter(&$instance_value, $field_value) {
|
||||
switch ($instance_value['widget']['module']) {
|
||||
case 'date':
|
||||
|
||||
// Some settings have been moved from field to instance.
|
||||
$instance_value['widget']['settings']['repeat_collapsed'] = $field_value['settings']['repeat_collapsed'];
|
||||
|
||||
// Some settings were moved from widget settings to instance settings.
|
||||
$instance_value['settings']['default_value'] = $instance_value['default_value'];
|
||||
unset($instance_value['default_value']);
|
||||
$instance_value['settings']['default_value_code'] = $instance_value['widget']['settings']['default_value_code'];
|
||||
unset($instance_value['widget']['settings']['default_value_code']);
|
||||
$instance_value['settings']['default_value2'] = $instance_value['widget']['settings']['default_value2'];
|
||||
unset($instance_value['widget']['settings']['default_value2']);
|
||||
$instance_value['settings']['default_value_code2'] = $instance_value['widget']['settings']['default_value_code2'];
|
||||
unset($instance_value['widget']['settings']['default_value_code2']);
|
||||
|
||||
// We need to retrieve formatter settings from the variables and store
|
||||
// them in the instance.
|
||||
foreach ($instance_value['display'] as $context => &$display) {
|
||||
if ($display['type'] != 'format_interval') {
|
||||
$old_settings = date_old_formatter_get_settings($instance_value['field_name'], $instance_value['bundle'], $context);
|
||||
$display['settings'] = array_merge($display['settings'], $old_settings);
|
||||
// If the formatter was the 'default', then use the old
|
||||
// 'default_format' field property.
|
||||
$format = ($display['type'] == 'default') ? $field_value['settings']['default_format'] : $display['type'];
|
||||
$display['settings']['format_type'] = $format;
|
||||
$display['type'] = 'date_default';
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an array of old formatter settings.
|
||||
*/
|
||||
function date_old_formatter_get_settings($field_name, $type_name, $context) {
|
||||
$options = array();
|
||||
$value = 'date:' . $type_name . ':' . $context . ':' . $field_name;
|
||||
$options['show_repeat_rule'] = variable_get($value . '_show_repeat_rule', 'show');
|
||||
$options['multiple_number'] = variable_get($value . '_multiple_number', '');
|
||||
$options['multiple_from'] = variable_get($value . '_multiple_from', '');
|
||||
$options['multiple_to'] = variable_get($value . '_multiple_to', '');
|
||||
$options['fromto'] = variable_get($value . '_fromto', 'both');
|
||||
return $options;
|
||||
}
|
||||
18
sites/all/modules/contrib/fields/date/date.info
Normal file
18
sites/all/modules/contrib/fields/date/date.info
Normal file
@@ -0,0 +1,18 @@
|
||||
name = Date
|
||||
description = Makes date/time fields available.
|
||||
dependencies[] = date_api
|
||||
package = Date/Time
|
||||
core = 7.x
|
||||
php = 5.2
|
||||
files[] = tests/date_api.test
|
||||
files[] = tests/date.test
|
||||
files[] = tests/date_field.test
|
||||
files[] = tests/date_validation.test
|
||||
files[] = tests/date_timezone.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-08-13
|
||||
version = "7.x-2.6"
|
||||
core = "7.x"
|
||||
project = "date"
|
||||
datestamp = "1344850024"
|
||||
|
||||
194
sites/all/modules/contrib/fields/date/date.install
Normal file
194
sites/all/modules/contrib/fields/date/date.install
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the Date module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_field_schema().
|
||||
*/
|
||||
function date_field_schema($field) {
|
||||
$db_columns = array();
|
||||
switch ($field['type']) {
|
||||
case 'datestamp':
|
||||
$db_columns['value'] = array(
|
||||
'type' => 'int',
|
||||
'not null' => FALSE,
|
||||
'sortable' => TRUE,
|
||||
'views' => TRUE,
|
||||
);
|
||||
break;
|
||||
case 'datetime':
|
||||
$db_columns['value'] = array(
|
||||
'type' => 'datetime',
|
||||
'mysql_type' => 'datetime',
|
||||
'pgsql_type' => 'timestamp without time zone',
|
||||
'sqlite_type' => 'varchar',
|
||||
'sqlsrv_type' => 'smalldatetime',
|
||||
'not null' => FALSE,
|
||||
'sortable' => TRUE,
|
||||
'views' => TRUE,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$db_columns['value'] = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 20,
|
||||
'not null' => FALSE,
|
||||
'sortable' => TRUE,
|
||||
'views' => TRUE,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// If a second date is needed for 'End date', make a copy of the first one.
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$db_columns['value2'] = $db_columns['value'];
|
||||
|
||||
// We don't want Field API to create additional columns, just the first.
|
||||
// We modify them our own way in views data.
|
||||
$db_columns['value2']['views'] = FALSE;
|
||||
}
|
||||
// Timezone and offset columns are used only if date-specific dates are used.
|
||||
if (isset($field['settings']['tz_handling']) && $field['settings']['tz_handling'] == 'date') {
|
||||
$db_columns['timezone'] = array(
|
||||
'type' => 'varchar',
|
||||
'length' => 50,
|
||||
'not null' => FALSE,
|
||||
'sortable' => TRUE,
|
||||
'views' => FALSE,
|
||||
);
|
||||
$db_columns['offset'] = array(
|
||||
'type' => 'int',
|
||||
'not null' => FALSE,
|
||||
'sortable' => TRUE,
|
||||
'views' => FALSE,
|
||||
);
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$db_columns['offset2'] = array('type' => 'int', 'not null' => FALSE, 'sortable' => TRUE, 'views' => FALSE);
|
||||
}
|
||||
}
|
||||
if (isset($field['settings']['repeat']) && $field['settings']['repeat'] == 1) {
|
||||
$db_columns['rrule'] = array(
|
||||
'type' => 'text',
|
||||
'not null' => FALSE,
|
||||
'sortable' => FALSE,
|
||||
'views' => FALSE,
|
||||
);
|
||||
}
|
||||
return array('columns' => $db_columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function date_update_last_removed() {
|
||||
return 6005;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rid of the individual formatters for each format type,
|
||||
* these are now settings in the default formatter.
|
||||
*/
|
||||
function date_update_7000() {
|
||||
$instances = field_info_instances();
|
||||
foreach ($instances as $entity_type => $entities) {
|
||||
foreach ($entities as $bundle => $fields) {
|
||||
foreach ($fields as $field_name => $instance) {
|
||||
if (in_array($instance['widget']['type'], array('date_popup'))) {
|
||||
$changed = FALSE;
|
||||
foreach ($instance['display'] as $context => $display) {
|
||||
if ($display['type'] != 'date_default' && $display['type'] != 'date_interval' && $display['type'] != 'hidden') {
|
||||
$instance['display'][$context]['type'] = 'date_default';
|
||||
$instance['display'][$context]['settings']['format_type'] = str_replace('date_', '', $display['type']);
|
||||
$changed = TRUE;
|
||||
}
|
||||
}
|
||||
if ($changed) {
|
||||
field_update_instance($instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rid of the separate widgets for repeating dates. The code now handles
|
||||
* repeating dates correctly using the regular widgets.
|
||||
*/
|
||||
function date_update_7001() {
|
||||
$query = db_select('field_config_instance', 'fci', array('fetch' => PDO::FETCH_ASSOC));
|
||||
$query->join('field_config', 'fc', 'fc.id = fci.field_id');
|
||||
$query->fields('fci');
|
||||
$query->condition(db_or()->condition('fc.type', 'date')->condition('fc.type', 'datestamp')->condition('fc.type', 'datetime'));
|
||||
$results = $query->execute();
|
||||
|
||||
foreach ($results as $record) {
|
||||
$instance = unserialize($record['data']);
|
||||
if (in_array($instance['widget']['type'], array('date_popup_repeat', 'date_text_repeat', 'date_select_repeat'))) {
|
||||
$instance['widget']['type'] = str_replace('_repeat', '', $instance['widget']['type']);
|
||||
db_update('field_config_instance')
|
||||
->fields(array(
|
||||
'data' => serialize($instance),
|
||||
))
|
||||
->condition('field_name', $record['field_name'])
|
||||
->condition('entity_type', $record['entity_type'])
|
||||
->condition('bundle', $record['bundle'])
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
field_cache_clear();
|
||||
drupal_set_message(t('The widgets for repeating dates have changed. Please check the Display Fields page for each content type that has repeating date fields and confirm that the right widget has been selected.'), 'warning');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a notification about the new Date All Day module, and enable it.
|
||||
*/
|
||||
function date_update_7002() {
|
||||
drupal_set_message(t("The <em>All Day</em> functionality has been moved into a separate module. This new module provides the option to add an <em>All Day</em> checkbox to toggle time on and off for date fields. It also contains the theme that displays the <em>All Day</em> text on fields that have no time. For consistency with prior code, it has been automatically enabled. If you don't want the <em>All Day</em> functionality you can disable this module."));
|
||||
module_enable(array('date_all_day'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a notification about the new Date Repeat Field module, and enable it.
|
||||
*/
|
||||
function date_update_7003() {
|
||||
drupal_set_message(t("The <em>Date Repeat</em> integration for Date fields is being moved into a separate module. For consistency with prior code, it has been automatically enabled if the Date Repeat API module is enabled. If you don't use <em>Date Repeat</em> functionality in your fields, you can disable this module."));
|
||||
if (module_exists('date_repeat')) {
|
||||
module_enable(array('date_repeat_field'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Date text widgets should always use an increment of 1.
|
||||
*/
|
||||
function date_update_7004() {
|
||||
|
||||
// Select date fields.
|
||||
$query = db_select('field_config_instance', 'fci', array('fetch' => PDO::FETCH_ASSOC));
|
||||
$query->join('field_config', 'fc', 'fc.id = fci.field_id');
|
||||
$query->fields('fci');
|
||||
$query->condition(db_or()->condition('fc.type', 'date')->condition('fc.type', 'datestamp')->condition('fc.type', 'datetime'));
|
||||
$results = $query->execute();
|
||||
|
||||
// Find the ones that use the date_text widget.
|
||||
foreach ($results as $record) {
|
||||
$instance = unserialize($record['data']);
|
||||
if (in_array($instance['widget']['type'], array('date_text'))) {
|
||||
$instance['widget']['settings']['increment'] = 1;
|
||||
db_update('field_config_instance')
|
||||
->fields(array(
|
||||
'data' => serialize($instance),
|
||||
))
|
||||
->condition('field_name', $record['field_name'])
|
||||
->condition('entity_type', $record['entity_type'])
|
||||
->condition('bundle', $record['bundle'])
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
field_cache_clear();
|
||||
drupal_set_message(t('Date text widgets have been updated to use an increment of 1.'));
|
||||
}
|
||||
|
||||
159
sites/all/modules/contrib/fields/date/date.js
Normal file
159
sites/all/modules/contrib/fields/date/date.js
Normal file
@@ -0,0 +1,159 @@
|
||||
(function ($) {
|
||||
|
||||
|
||||
Drupal.behaviors.dateSelect = {};
|
||||
|
||||
Drupal.behaviors.dateSelect.attach = function (context, settings) {
|
||||
var $widget = $('.form-type-date-select').parents('fieldset').once('date');
|
||||
var i;
|
||||
for (i = 0; i < $widget.length; i++) {
|
||||
new Drupal.date.EndDateHandler($widget[i]);
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.date = Drupal.date || {};
|
||||
|
||||
/**
|
||||
* Constructor for the EndDateHandler object.
|
||||
*
|
||||
* The EndDateHandler is responsible for synchronizing a date select widget's
|
||||
* end date with its start date. This behavior lasts until the user
|
||||
* interacts with the end date widget.
|
||||
*
|
||||
* @param widget
|
||||
* The fieldset DOM element containing the from and to dates.
|
||||
*/
|
||||
Drupal.date.EndDateHandler = function (widget) {
|
||||
this.$widget = $(widget);
|
||||
this.$start = this.$widget.find('.form-type-date-select[class$=value]');
|
||||
this.$end = this.$widget.find('.form-type-date-select[class$=value2]');
|
||||
if (this.$end.length == 0) {
|
||||
return;
|
||||
}
|
||||
this.initializeSelects();
|
||||
// Only act on date fields where the end date is completely blank or already
|
||||
// the same as the start date. Otherwise, we do not want to override whatever
|
||||
// the default value was.
|
||||
if (this.endDateIsBlank() || this.endDateIsSame()) {
|
||||
this.bindClickHandlers();
|
||||
// Start out with identical start and end dates.
|
||||
this.syncEndDate();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Store all the select dropdowns in an array on the object, for later use.
|
||||
*/
|
||||
Drupal.date.EndDateHandler.prototype.initializeSelects = function () {
|
||||
var $starts = this.$start.find('select');
|
||||
var $end, $start, endId, i, id;
|
||||
this.selects = {};
|
||||
for (i = 0; i < $starts.length; i++) {
|
||||
$start = $($starts[i]);
|
||||
id = $start.attr('id');
|
||||
endId = id.replace('-value-', '-value2-');
|
||||
$end = $('#' + endId);
|
||||
this.selects[id] = {
|
||||
'id': id,
|
||||
'start': $start,
|
||||
'end': $end
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if all dropdowns in the end date widget are blank.
|
||||
*/
|
||||
Drupal.date.EndDateHandler.prototype.endDateIsBlank = function () {
|
||||
var id;
|
||||
for (id in this.selects) {
|
||||
if (this.selects.hasOwnProperty(id)) {
|
||||
if (this.selects[id].end.val() != '') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the end date widget has the same value as the start date.
|
||||
*/
|
||||
Drupal.date.EndDateHandler.prototype.endDateIsSame = function () {
|
||||
var id;
|
||||
for (id in this.selects) {
|
||||
if (this.selects.hasOwnProperty(id)) {
|
||||
if (this.selects[id].end.val() != this.selects[id].start.val()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a click handler to each of the start date's select dropdowns.
|
||||
*/
|
||||
Drupal.date.EndDateHandler.prototype.bindClickHandlers = function () {
|
||||
var id;
|
||||
for (id in this.selects) {
|
||||
if (this.selects.hasOwnProperty(id)) {
|
||||
this.selects[id].start.bind('click.endDateHandler', this.startClickHandler.bind(this));
|
||||
this.selects[id].end.bind('focus', this.endFocusHandler.bind(this));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Click event handler for each of the start date's select dropdowns.
|
||||
*/
|
||||
Drupal.date.EndDateHandler.prototype.startClickHandler = function (event) {
|
||||
this.syncEndDate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Focus event handler for each of the end date's select dropdowns.
|
||||
*/
|
||||
Drupal.date.EndDateHandler.prototype.endFocusHandler = function (event) {
|
||||
var id;
|
||||
for (id in this.selects) {
|
||||
if (this.selects.hasOwnProperty(id)) {
|
||||
this.selects[id].start.unbind('click.endDateHandler');
|
||||
}
|
||||
}
|
||||
$(event.target).unbind('focus', this.endFocusHandler);
|
||||
};
|
||||
|
||||
Drupal.date.EndDateHandler.prototype.syncEndDate = function () {
|
||||
var id;
|
||||
for (id in this.selects) {
|
||||
if (this.selects.hasOwnProperty(id)) {
|
||||
this.selects[id].end.val(this.selects[id].start.val());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}(jQuery));
|
||||
|
||||
/**
|
||||
* Function.prototype.bind polyfill for older browsers.
|
||||
* https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
|
||||
*/
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (oThis) {
|
||||
if (typeof this !== "function") // closest thing possible to the ECMAScript 5 internal IsCallable function
|
||||
throw new TypeError("Function.prototype.bind - what is trying to be fBound is not callable");
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function () {},
|
||||
fBound = function () {
|
||||
return fToBind.apply(this instanceof fNOP ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
fNOP.prototype = this.prototype;
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
743
sites/all/modules/contrib/fields/date/date.module
Normal file
743
sites/all/modules/contrib/fields/date/date.module
Normal file
@@ -0,0 +1,743 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines date/time field types.
|
||||
*/
|
||||
|
||||
module_load_include('theme', 'date', 'date');
|
||||
module_load_include('inc', 'date', 'date.field');
|
||||
module_load_include('inc', 'date', 'date_elements');
|
||||
|
||||
/**
|
||||
* Helper function to figure out the bundle name for an entity.
|
||||
*/
|
||||
function date_get_entity_bundle($entity_type, $entity) {
|
||||
switch ($entity_type) {
|
||||
case 'field_collection_item':
|
||||
$bundle = $entity->field_name;
|
||||
break;
|
||||
default:
|
||||
$bundle = field_extract_bundle($entity_type, $entity);
|
||||
break;
|
||||
}
|
||||
// If there is no bundle name, field_info() uses the entity name as the bundle
|
||||
// name in its arrays.
|
||||
if (empty($bundle)) {
|
||||
$bundle = $entity_type;
|
||||
}
|
||||
return $bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default date format for the given field widget.
|
||||
*/
|
||||
function date_default_format($type) {
|
||||
// Example input formats must show all possible date parts, so add seconds.
|
||||
$default_format = str_replace('i', 'i:s', variable_get('date_format_short', 'm/d/Y - H:i'));
|
||||
return $default_format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function around each of the widget types for creating a date object.
|
||||
*/
|
||||
function date_input_date($field, $instance, $element, $input) {
|
||||
switch ($instance['widget']['type']) {
|
||||
case 'date_text':
|
||||
$function = 'date_text_input_date';
|
||||
break;
|
||||
case 'date_popup':
|
||||
$function = 'date_popup_input_date';
|
||||
break;
|
||||
default:
|
||||
$function = 'date_select_input_date';
|
||||
}
|
||||
return $function($element, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function date_theme() {
|
||||
$path = drupal_get_path('module', 'date');
|
||||
module_load_include('theme', 'date', 'date');
|
||||
|
||||
$base = array(
|
||||
'file' => 'date.theme',
|
||||
'path' => "$path",
|
||||
);
|
||||
$themes = array(
|
||||
'date_combo' => $base + array('render element' => 'element'),
|
||||
'date_text_parts' => $base + array('render element' => 'element'),
|
||||
'date' => $base + array('render element' => 'element'),
|
||||
'date_display_single' => $base + array(
|
||||
'variables' => array(
|
||||
'date' => NULL,
|
||||
'timezone' => NULL,
|
||||
'dates' => NULL,
|
||||
'attributes' => array(),
|
||||
'rdf_mapping' => NULL,
|
||||
'add_rdf' => NULL,
|
||||
),
|
||||
),
|
||||
'date_display_range' => $base + array(
|
||||
'variables' => array(
|
||||
'date1' => NULL,
|
||||
'date2' => NULL,
|
||||
'timezone' => NULL,
|
||||
'dates' => NULL,
|
||||
// HTML attributes that will be applied to both the start and end dates
|
||||
// (unless overridden).
|
||||
'attributes' => array(),
|
||||
// HTML attributes that will be applied to the start date only.
|
||||
'attributes_start' => array(),
|
||||
// HTML attributes that will be applied to the end date only.
|
||||
'attributes_end' => array(),
|
||||
'rdf_mapping' => NULL,
|
||||
'add_rdf' => NULL,
|
||||
)),
|
||||
'date_display_combination' => $base + array(
|
||||
'variables' => array(
|
||||
'entity_type' => NULL,
|
||||
'entity' => NULL,
|
||||
'field' => NULL,
|
||||
'instance' => NULL,
|
||||
'langcode' => NULL,
|
||||
'item' => NULL,
|
||||
'delta' => NULL,
|
||||
'display' => NULL,
|
||||
'dates' => NULL,
|
||||
'attributes' => array(),
|
||||
'rdf_mapping' => NULL,
|
||||
'add_rdf' => NULL,
|
||||
),
|
||||
),
|
||||
'date_display_interval' => $base + array(
|
||||
'variables' => array(
|
||||
'entity_type' => NULL,
|
||||
'entity' => NULL,
|
||||
'field' => NULL,
|
||||
'instance' => NULL,
|
||||
'langcode' => NULL,
|
||||
'item' => NULL,
|
||||
'delta' => NULL,
|
||||
'display' => NULL,
|
||||
'dates' => NULL,
|
||||
'attributes' => array(),
|
||||
'rdf_mapping' => NULL,
|
||||
'add_rdf' => NULL,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*
|
||||
* date_combo will create a 'start' and optional 'end' date, along with
|
||||
* an optional 'timezone' column for date-specific timezones. Each
|
||||
* 'start' and 'end' date will be constructed from date_select or date_text.
|
||||
*/
|
||||
function date_element_info() {
|
||||
$type = array();
|
||||
$type['date_combo'] = array(
|
||||
'#input' => TRUE,
|
||||
'#delta' => 0,
|
||||
'#columns' => array('value', 'value2', 'timezone', 'offset', 'offset2'),
|
||||
'#process' => array('date_combo_element_process'),
|
||||
'#element_validate' => array('date_combo_validate'),
|
||||
'#theme_wrappers' => array('date_combo'),
|
||||
);
|
||||
if (module_exists('ctools')) {
|
||||
$type['date_combo']['#pre_render'] = array('ctools_dependent_pre_render');
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating formatted date arrays from a formatter.
|
||||
*
|
||||
* Use the Date API to get an object representation of a date field.
|
||||
*
|
||||
* @param string $formatter
|
||||
* The date formatter.
|
||||
* @param string $entity_type
|
||||
* The entity_type for the instance
|
||||
* @param object $entity
|
||||
* The entity object.
|
||||
* @param array $field
|
||||
* The field info array.
|
||||
* @param array $instance
|
||||
* The field instance array.
|
||||
* @param string $langcode
|
||||
* The language code used by this field.
|
||||
* @param array $item
|
||||
* An entity field item, like $entity->myfield[0].
|
||||
* @param array $display
|
||||
* The instance display settings.
|
||||
*
|
||||
* @return array
|
||||
* An array that holds the Start and End date objects.
|
||||
* Each date object looks like:
|
||||
* date [value] => array (
|
||||
* [db] => array ( // the value stored in the database
|
||||
* [object] => the datetime object
|
||||
* [datetime] => 2007-02-15 20:00:00
|
||||
* )
|
||||
* [local] => array ( // the local representation of that value
|
||||
* [object] => the datetime object
|
||||
* [datetime] => 2007-02-15 14:00:00
|
||||
* [timezone] => US/Central
|
||||
* [offset] => -21600
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
function date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display) {
|
||||
$dates = array();
|
||||
$timezone = date_default_timezone();
|
||||
if (empty($timezone)) {
|
||||
return $dates;
|
||||
}
|
||||
|
||||
$granularity = date_granularity($field);
|
||||
$settings = $display['settings'];
|
||||
$field_name = $field['field_name'];
|
||||
$format = date_formatter_format($formatter, $settings, $granularity, $langcode);
|
||||
$timezone = isset($item['timezone']) ? $item['timezone'] : '';
|
||||
$timezone = date_get_timezone($field['settings']['tz_handling'], $timezone);
|
||||
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$db_format = date_type_format($field['type']);
|
||||
$process = date_process_values($field);
|
||||
foreach ($process as $processed) {
|
||||
if (empty($item[$processed])) {
|
||||
$dates[$processed] = NULL;
|
||||
}
|
||||
else {
|
||||
// Create a date object with a GMT timezone from the database value.
|
||||
$dates[$processed] = array();
|
||||
|
||||
// Check to see if this date was already created by date_field_load().
|
||||
if (isset($item['db'][$processed])) {
|
||||
$date = $item['db'][$processed];
|
||||
}
|
||||
else {
|
||||
$date = new DateObject($item[$processed], $timezone_db, $db_format);
|
||||
$date->limitGranularity($field['settings']['granularity']);
|
||||
}
|
||||
|
||||
$dates[$processed]['db']['object'] = $date;
|
||||
$dates[$processed]['db']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
|
||||
|
||||
date_timezone_set($date, timezone_open($timezone));
|
||||
$dates[$processed]['local']['object'] = $date;
|
||||
$dates[$processed]['local']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
|
||||
$dates[$processed]['local']['timezone'] = $timezone;
|
||||
$dates[$processed]['local']['offset'] = date_offset_get($date);
|
||||
|
||||
// Format the date, special casing the 'interval' format which doesn't
|
||||
// need to be processed.
|
||||
$dates[$processed]['formatted'] = '';
|
||||
$dates[$processed]['formatted_iso'] = date_format_date($date, 'custom', 'c');
|
||||
if (is_object($date)) {
|
||||
if ($format == 'format_interval') {
|
||||
$dates[$processed]['interval'] = date_format_interval($date);
|
||||
}
|
||||
elseif ($format == 'format_calendar_day') {
|
||||
$dates[$processed]['calendar_day'] = date_format_calendar_day($date);
|
||||
}
|
||||
elseif ($format == 'U') {
|
||||
$dates[$processed]['formatted'] = date_format_date($date, 'custom', $format);
|
||||
$dates[$processed]['formatted_date'] = date_format_date($date, 'custom', $format);
|
||||
$dates[$processed]['formatted_time'] = '';
|
||||
$dates[$processed]['formatted_timezone'] = '';
|
||||
}
|
||||
elseif (!empty($format)) {
|
||||
$dates[$processed]['formatted'] = date_format_date($date, 'custom', $format);
|
||||
$dates[$processed]['formatted_date'] = date_format_date($date, 'custom', date_limit_format($format, array('year', 'month', 'day')));
|
||||
$dates[$processed]['formatted_time'] = date_format_date($date, 'custom', date_limit_format($format, array('hour', 'minute', 'second')));
|
||||
$dates[$processed]['formatted_timezone'] = date_format_date($date, 'custom', date_limit_format($format, array('timezone')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($dates['value2'])) {
|
||||
$dates['value2'] = $dates['value'];
|
||||
}
|
||||
|
||||
// Allow other modules to alter the date values.
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'format' => $format,
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity,
|
||||
'langcode' => $langcode,
|
||||
'item' => $item,
|
||||
'display' => $display,
|
||||
);
|
||||
drupal_alter('date_formatter_dates', $dates, $context);
|
||||
|
||||
$dates['format'] = $format;
|
||||
return $dates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the granularity for a field.
|
||||
*
|
||||
* $field['settings']['granularity'] will contain an array like
|
||||
* ('hour' => 'hour', 'month' => 0) where the values turned on return their own
|
||||
* names and the values turned off return a zero need to reconfigure this into
|
||||
* simple array of the turned on values
|
||||
*
|
||||
* @param array $field
|
||||
* The field array.
|
||||
*/
|
||||
function date_granularity($field) {
|
||||
if (!is_array($field) || !is_array($field['settings']['granularity'])) {
|
||||
$field['settings']['granularity'] = drupal_map_assoc(array('year', 'month', 'day'));
|
||||
}
|
||||
return array_values(array_filter($field['settings']['granularity']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create an array of the date values in a
|
||||
* field that need to be processed.
|
||||
*/
|
||||
function date_process_values($field) {
|
||||
return $field['settings']['todate'] ? array('value', 'value2') : array('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter() for field_ui_field_edit_form().
|
||||
*/
|
||||
function date_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
|
||||
$field = $form['#field'];
|
||||
$instance = $form['#instance'];
|
||||
|
||||
if (!in_array($field['type'], array('date', 'datetime', 'datestamp'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reorganize the instance settings and widget settings sections into a more
|
||||
// intuitive combined fieldset.
|
||||
$form['instance']['defaults'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('More settings and values'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
);
|
||||
$form['instance']['date_format'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Date entry'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
$form['instance']['default_values'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Default values'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
$form['instance']['years_back_and_forward'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Starting and ending year'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
$form['instance']['#pre_render'][] = 'date_field_ui_field_edit_form_pre_render';
|
||||
}
|
||||
|
||||
/**
|
||||
* Rearrange form elements into fieldsets for presentation only.
|
||||
*/
|
||||
function date_field_ui_field_edit_form_pre_render($form) {
|
||||
foreach ($form as $name => $element) {
|
||||
if (is_array($element) && isset($element['#fieldset'])) {
|
||||
$fieldset = $element['#fieldset'];
|
||||
$form[$fieldset][$name] = $element;
|
||||
unset($form[$name]);
|
||||
}
|
||||
}
|
||||
foreach (array('date_format', 'default_values', 'years_back_and_forward') as $name) {
|
||||
if (element_children($form[$name])) {
|
||||
// Force the items in the fieldset to be resorted now that the instance
|
||||
// and widget settings are combined.
|
||||
$form[$name]['#sorted'] = FALSE;
|
||||
$form['defaults'][$name] = $form[$name];
|
||||
}
|
||||
unset($form[$name]);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_error().
|
||||
*/
|
||||
function date_field_widget_error($element, $error, $form, &$form_state) {
|
||||
form_error($element[$error['error']], $error['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a date format string from formatter settings.
|
||||
*/
|
||||
function date_formatter_format($formatter, $settings, $granularity = array(), $langcode = NULL) {
|
||||
$format_type = !empty($settings['format_type']) ? $settings['format_type'] : 'format_interval';
|
||||
|
||||
switch ($formatter) {
|
||||
case 'format_interval':
|
||||
return 'format_interval';
|
||||
break;
|
||||
case 'date_plain':
|
||||
return 'date_plain';
|
||||
break;
|
||||
default:
|
||||
$format = date_format_type_format($format_type, $langcode);
|
||||
break;
|
||||
}
|
||||
|
||||
// A selected format might include timezone information.
|
||||
array_push($granularity, 'timezone');
|
||||
return date_limit_format($format, $granularity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the right format for a format type.
|
||||
* Checks for locale-based format first.
|
||||
*/
|
||||
function date_format_type_format($format_type, $langcode = NULL) {
|
||||
$static = &drupal_static(__FUNCTION__);
|
||||
if (!isset($static[$langcode][$format_type])) {
|
||||
$format = system_date_format_locale($langcode, $format_type);
|
||||
|
||||
// If locale enabled and $format_type inexistent in {date_format_locale}
|
||||
// we receive (due to inconsistency of core api) an array of all (other)
|
||||
// formats available for $langcode in locale table.
|
||||
// However there's no guarantee that the key $format_type exists.
|
||||
// See http://drupal.org/node/1302358.
|
||||
if (!is_string($format)) {
|
||||
// If the configuration page at admin/config/regional/date-time was
|
||||
// never saved, the default core date format variables
|
||||
// ('date_format_short', 'date_format_medium', and 'date_format_long')
|
||||
// will not be stored in the database, so we have to define their
|
||||
// expected defaults here.
|
||||
switch ($format_type) {
|
||||
case 'short':
|
||||
$default = 'm/d/Y - H:i';
|
||||
break;
|
||||
case 'long':
|
||||
$default = 'l, F j, Y - H:i';
|
||||
break;
|
||||
// If it's not one of the core date types and isn't stored in the
|
||||
// database, we'll fall back on using the same default format as the
|
||||
// 'medium' type.
|
||||
case 'medium':
|
||||
default:
|
||||
// @todo: If a non-core module provides a date type and does not
|
||||
// variable_set() a default for it, the default assumed here may
|
||||
// not be correct (since the default format used by 'medium' may
|
||||
// not even be one of the allowed formats for the date type in
|
||||
// question). To fix this properly, we should really call
|
||||
// system_get_date_formats($format_type) and take the first
|
||||
// format from that list as the default. However, this function
|
||||
// is called often (on many different page requests), so calling
|
||||
// system_get_date_formats() from here would be a performance hit
|
||||
// since that function writes several records to the database
|
||||
// during each page request that calls it.
|
||||
$default = 'D, m/d/Y - H:i';
|
||||
break;
|
||||
}
|
||||
$format = variable_get('date_format_' . $format_type, $default);
|
||||
}
|
||||
$static[$langcode][$format_type] = $format;
|
||||
}
|
||||
return $static[$langcode][$format_type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to adapt entity date fields to formatter settings.
|
||||
*/
|
||||
function date_prepare_entity($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display) {
|
||||
// If there are options to limit multiple values,
|
||||
// alter the entity values to match.
|
||||
$field_name = $field['field_name'];
|
||||
$options = $display['settings'];
|
||||
$max_count = $options['multiple_number'];
|
||||
|
||||
// If no results should be shown, empty the values and return.
|
||||
if (is_numeric($max_count) && $max_count == 0) {
|
||||
$entity->{$field_name} = array();
|
||||
return $entity;
|
||||
}
|
||||
|
||||
// Otherwise removed values that should not be displayed.
|
||||
if (!empty($options['multiple_from']) || !empty($options['multiple_to']) || !empty($max_count)) {
|
||||
$format = date_type_format($field['type']);
|
||||
include_once drupal_get_path('module', 'date_api') . '/date_api_sql.inc';
|
||||
$date_handler = new date_sql_handler($field);
|
||||
$arg0 = !empty($options['multiple_from']) ? $date_handler->arg_replace($options['multiple_from']) : variable_get('date_min_year', 100) . '-01-01T00:00:00';
|
||||
$arg1 = !empty($options['multiple_to']) ? $date_handler->arg_replace($options['multiple_to']) : variable_get('date_max_year', 4000) . '-12-31T23:59:59';
|
||||
if (!empty($arg0) && !empty($arg1)) {
|
||||
$arg = $arg0 . '--' . $arg1;
|
||||
}
|
||||
elseif (!empty($arg0)) {
|
||||
$arg = $arg0;
|
||||
}
|
||||
elseif (!empty($arg1)) {
|
||||
$arg = $arg1;
|
||||
}
|
||||
if (!empty($arg)) {
|
||||
$range = $date_handler->arg_range($arg);
|
||||
$start = date_format($range[0], $format);
|
||||
$end = date_format($range[1], $format);
|
||||
// Empty out values we don't want to see.
|
||||
$count = 0;
|
||||
foreach ($entity->{$field_name}[$langcode] as $delta => $value) {
|
||||
if (!empty($entity->date_repeat_show_all)) {
|
||||
break;
|
||||
}
|
||||
elseif ((!empty($max_count) && is_numeric($max_count) && $count >= $max_count) ||
|
||||
(!empty($value['value']) && $value['value'] < $start) ||
|
||||
(!empty($value['value2']) && $value['value2'] > $end)) {
|
||||
unset($entity->{$field_name}[$langcode][$delta]);
|
||||
}
|
||||
else {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to alter the property info of date fields.
|
||||
*
|
||||
* @see date_field_info()
|
||||
*/
|
||||
function date_entity_metadata_property_info_alter(&$info, $entity_type, $field, $instance, $field_type) {
|
||||
$name = $field['field_name'];
|
||||
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
|
||||
|
||||
if ($field['type'] != 'datestamp' || $field['settings']['timezone_db'] != 'UTC') {
|
||||
// Add a getter callback to convert the date into the right format.
|
||||
$property['getter callback'] = 'date_entity_metadata_field_getter';
|
||||
$property['setter callback'] = 'date_entity_metadata_field_setter';
|
||||
unset($property['query callback']);
|
||||
}
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
// Define a simple data structure containing both dates.
|
||||
$property['type'] = ($field['cardinality'] != 1) ? 'list<struct>' : 'struct';
|
||||
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
|
||||
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
|
||||
$property['property info'] = array(
|
||||
'value' => array(
|
||||
'type' => 'date',
|
||||
'label' => t('Start date'),
|
||||
'getter callback' => 'date_entity_metadata_struct_getter',
|
||||
'setter callback' => 'date_entity_metadata_struct_setter',
|
||||
// The getter and setter callbacks for 'value' and 'value2'
|
||||
// will not provide the field name as $name, we'll add it to $info.
|
||||
'field_name' => $field['field_name'],
|
||||
),
|
||||
'value2' => array(
|
||||
'type' => 'date',
|
||||
'label' => t('End date'),
|
||||
'getter callback' => 'date_entity_metadata_struct_getter',
|
||||
'setter callback' => 'date_entity_metadata_struct_setter',
|
||||
// The getter and setter callbacks for 'value' and 'value2'
|
||||
// will not provide the field name as $name, we'll add it to $info.
|
||||
'field_name' => $field['field_name'],
|
||||
),
|
||||
'duration' => array(
|
||||
'type' => 'duration',
|
||||
'label' => t('Duration'),
|
||||
'desription' => t('The duration of the time period given by the dates.'),
|
||||
'getter callback' => 'date_entity_metadata_duration_getter',
|
||||
// No setter callback for duration.
|
||||
// The getter callback for duration will not provide the field name
|
||||
// as $name, we'll add it to $info.
|
||||
'field_name' => $field['field_name'],
|
||||
),
|
||||
);
|
||||
unset($property['query callback']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter callback to return date values as datestamp in UTC from the field.
|
||||
*/
|
||||
function date_entity_metadata_field_getter($entity, array $options, $name, $entity_type, &$context) {
|
||||
$return = entity_metadata_field_verbatim_get($entity, $options, $name, $entity_type, $context);
|
||||
$items = ($context['field']['cardinality'] == 1) ? array($return) : $return;
|
||||
foreach ($items as $key => $item) {
|
||||
$items[$key] = date_entity_metadata_struct_getter($item, $options, 'value', 'struct', $context);
|
||||
}
|
||||
return ($context['field']['cardinality'] == 1) ? $items[0] : $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter callback to return date values as datestamp in UTC.
|
||||
*/
|
||||
function date_entity_metadata_struct_getter($item, array $options, $name, $type, $info) {
|
||||
$value = trim($item[$name]);
|
||||
if (empty($value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$timezone_db = !empty($item['timezone_db']) ? $item['timezone_db'] : 'UTC';
|
||||
$date = new DateObject($value, $timezone_db);
|
||||
return !empty($date) ? date_format_date($date, 'custom', 'U') : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter callback to return the duration of the time period given by the dates.
|
||||
*/
|
||||
function date_entity_metadata_duration_getter($item, array $options, $name, $type, $info) {
|
||||
$value = date_entity_metadata_struct_getter($item, $options, 'value', 'struct', $info);
|
||||
$value2 = date_entity_metadata_struct_getter($item, $options, 'value2', 'struct', $info);
|
||||
if ($value && $value2) {
|
||||
return $value2 - $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for setting field property values.
|
||||
*
|
||||
* Based on entity_metadata_field_property_set(), the original property setter,
|
||||
* adapted to transform non-timestamp date values to timestamps.
|
||||
*/
|
||||
function date_entity_metadata_field_setter(&$entity, $name, $value, $langcode, $entity_type, $info) {
|
||||
$field = field_info_field($name);
|
||||
if (!isset($langcode)) {
|
||||
// Try to figure out the default language used by the entity.
|
||||
// @todo: Update once http://drupal.org/node/1260640 has been fixed.
|
||||
$langcode = isset($entity->language) ? $entity->language : LANGUAGE_NONE;
|
||||
}
|
||||
$values = $field['cardinality'] == 1 ? array($value) : (array) $value;
|
||||
|
||||
$items = array();
|
||||
foreach ($values as $delta => $value) {
|
||||
// Make use of the struct setter to convert the date back to a timestamp.
|
||||
$info['field_name'] = $name;
|
||||
date_entity_metadata_struct_setter($items[$delta], 'value', $value, $langcode, 'struct', $info);
|
||||
}
|
||||
$entity->{$name}[$langcode] = $items;
|
||||
// Empty the static field language cache, so the field system picks up any
|
||||
// possible new languages.
|
||||
drupal_static_reset('field_language');
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for setting an individual field value if a to-date may be there too.
|
||||
* Based on entity_property_verbatim_set().
|
||||
*
|
||||
* The passed in unix timestamp (UTC) is converted to the right value and
|
||||
* format dependent on the field.
|
||||
*
|
||||
* $name is either 'value' or 'value2'.
|
||||
*/
|
||||
function date_entity_metadata_struct_setter(&$item, $name, $value, $langcode, $type, $info) {
|
||||
if (!isset($value)) {
|
||||
$item[$name] = NULL;
|
||||
}
|
||||
else {
|
||||
$field = field_info_field($info['field_name']);
|
||||
$format = date_type_format($field['type']);
|
||||
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
|
||||
$date = new DateObject($value, 'UTC');
|
||||
if ($timezone_db != 'UTC') {
|
||||
date_timezone_set($date, timezone_open($timezone_db));
|
||||
}
|
||||
$item[$name] = $date->format($format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate functionality of what is now date_all_day_field() in
|
||||
* the Date All Day module. Copy left here to avoid breaking other
|
||||
* modules that use this function.
|
||||
*
|
||||
* DEPRECATED!, will be removed at some time in the future.
|
||||
*/
|
||||
function date_field_all_day($field, $instance, $date1, $date2 = NULL) {
|
||||
if (empty($date1) || !is_object($date1)) {
|
||||
return FALSE;
|
||||
}
|
||||
elseif (!date_has_time($field['settings']['granularity'])) {
|
||||
return TRUE;
|
||||
}
|
||||
if (empty($date2)) {
|
||||
$date2 = $date1;
|
||||
}
|
||||
|
||||
$granularity = date_granularity_precision($field['settings']['granularity']);
|
||||
$increment = isset($instance['widget']['settings']['increment']) ? $instance['widget']['settings']['increment'] : 1;
|
||||
return date_is_all_day(date_format($date1, DATE_FORMAT_DATETIME), date_format($date2, DATE_FORMAT_DATETIME), $granularity, $increment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Date API SQL handler for the given date field.
|
||||
*
|
||||
* The handler will be set up to make the correct timezone adjustments
|
||||
* for the field settings.
|
||||
*
|
||||
* @param array $field
|
||||
* The $field array.
|
||||
* @param string $compare_tz
|
||||
* The timezone used for comparison values in the SQL.
|
||||
*
|
||||
* DEPRECATED!, will be removed at some time in the future.
|
||||
*/
|
||||
function date_field_get_sql_handler($field, $compare_tz = NULL) {
|
||||
module_load_include('inc', 'date_api', 'date_api_sql');
|
||||
|
||||
$db_info = date_api_database_info($field);
|
||||
|
||||
// Create a DateAPI SQL handler class for this field type.
|
||||
$handler = new date_sql_handler($field['type']);
|
||||
|
||||
// If this date field stores a timezone in the DB, tell the handler about it.
|
||||
if ($field['settings']['tz_handling'] == 'date') {
|
||||
$handler->db_timezone_field = $db_info['columns']['timezone']['column'];
|
||||
}
|
||||
else {
|
||||
$handler->db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
}
|
||||
|
||||
if (empty($compare_tz)) {
|
||||
$compare_tz = date_get_timezone($field['settings']['tz_handling']);
|
||||
}
|
||||
$handler->local_timezone = $compare_tz;
|
||||
|
||||
// Now that the handler is properly initialized, force the DB
|
||||
// to use UTC so no timezone conversions get added to things like
|
||||
// NOW() or FROM_UNIXTIME().
|
||||
$handler->set_db_timezone();
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_properties_alter().
|
||||
*
|
||||
* Alters the widget properties of a field instance before it gets displayed.
|
||||
* Used here to flag new entities so we can later tell if they need default values.
|
||||
*/
|
||||
function date_field_widget_properties_alter(&$widget, $context) {
|
||||
if (in_array($widget['type'], array('date_select', 'date_text', 'date_popup'))) {
|
||||
$entity_type = $context['entity_type'];
|
||||
$entity = $context['entity'];
|
||||
$info = entity_get_info($entity_type);
|
||||
$id = $info['entity keys']['id'];
|
||||
$widget['is_new']= FALSE;
|
||||
if (empty($entity->$id)) {
|
||||
$widget['is_new'] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
355
sites/all/modules/contrib/fields/date/date.theme
Normal file
355
sites/all/modules/contrib/fields/date/date.theme
Normal file
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Theme functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup themeable
|
||||
* @{
|
||||
*
|
||||
* Formatter themes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns HTML for a date element formatted as a Start/End combination.
|
||||
*
|
||||
* $entity->date_id
|
||||
* If set, this will show only an individual date on a field with
|
||||
* multiple dates. The value should be a string that contains
|
||||
* the following values, separated with periods:
|
||||
* - module name of the module adding the item
|
||||
* - node nid
|
||||
* - field name
|
||||
* - delta value of the field to be displayed
|
||||
* - other information the module's custom theme might need
|
||||
*
|
||||
* Used by the calendar module and available for other uses.
|
||||
* example: 'date.217.field_date.3.test'
|
||||
*
|
||||
* $entity->date_repeat_show
|
||||
* If true, tells the theme to show all the computed values of a repeating
|
||||
* date. If not true or not set, only the start date and the repeat rule
|
||||
* will be displayed.
|
||||
*
|
||||
* $dates['format']
|
||||
* The format string used on these dates
|
||||
* $dates['value']['local']['object']
|
||||
* The local date object for the Start date
|
||||
* $dates['value2']['local']['object']
|
||||
* The local date object for the End date
|
||||
* $dates['value']['local']['datetime']
|
||||
* The datetime value of the Start date database (GMT) value
|
||||
* $dates['value2']['local']['datetime']
|
||||
* The datetime value of the End date database (GMT) value
|
||||
* $dates['value']['formatted']
|
||||
* Formatted Start date, i.e. 'February 15, 2007 2:00 pm';
|
||||
* $dates['value']['formatted_date']
|
||||
* Only the date part of the formatted Start date
|
||||
* $dates['value']['formatted_time']
|
||||
* Only the time part of the formatted Start date
|
||||
* $dates['value2']['formatted']
|
||||
* Formatted End date, i.e. 'February 15, 2007 6:00 pm';
|
||||
* $dates['value2']['formatted_date']
|
||||
* Only the date part of the formatted End date
|
||||
* $dates['value2']['formatted_time']
|
||||
* Only the time part of the formatted End date
|
||||
*/
|
||||
function theme_date_display_combination($variables) {
|
||||
static $repeating_ids = array();
|
||||
|
||||
$entity_type = $variables['entity_type'];
|
||||
$entity = $variables['entity'];
|
||||
$field = $variables['field'];
|
||||
$instance = $variables['instance'];
|
||||
$langcode = $variables['langcode'];
|
||||
$item = $variables['item'];
|
||||
$delta = $variables['delta'];
|
||||
$display = $variables['display'];
|
||||
$field_name = $field['field_name'];
|
||||
$formatter = $display['type'];
|
||||
$options = $display['settings'];
|
||||
$dates = $variables['dates'];
|
||||
$attributes = $variables['attributes'];
|
||||
$rdf_mapping = $variables['rdf_mapping'];
|
||||
$add_rdf = $variables['add_rdf'];
|
||||
$precision = date_granularity_precision($field['settings']['granularity']);
|
||||
|
||||
$output = '';
|
||||
|
||||
// If date_id is set for this field and delta doesn't match, don't display it.
|
||||
if (!empty($entity->date_id)) {
|
||||
foreach ((array) $entity->date_id as $key => $id) {
|
||||
list($module, $nid, $field_name, $item_delta, $other) = explode('.', $id . '.');
|
||||
if ($field_name == $field['field_name'] && isset($delta) && $item_delta != $delta) {
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the formatter settings to see if the repeat rule should be displayed.
|
||||
// Show it only with the first multiple value date.
|
||||
list($id) = entity_extract_ids($entity_type, $entity);
|
||||
if (!in_array($id, $repeating_ids) && module_exists('date_repeat_field') && !empty($item['rrule']) && $options['show_repeat_rule'] == 'show') {
|
||||
$repeat_vars = array(
|
||||
'field' => $field,
|
||||
'item' => $item,
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity,
|
||||
);
|
||||
$output .= theme('date_repeat_display', $repeat_vars);
|
||||
$repeating_ids[] = $id;
|
||||
}
|
||||
|
||||
// If this is a full node or a pseudo node created by grouping multiple
|
||||
// values, see exactly which values are supposed to be visible.
|
||||
if (isset($entity->$field_name)) {
|
||||
$entity = date_prepare_entity($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
|
||||
// Did the current value get removed by formatter settings?
|
||||
if (empty($entity->{$field_name}[$langcode][$delta])) {
|
||||
return $output;
|
||||
}
|
||||
// Adjust the $element values to match the changes.
|
||||
$element['#entity'] = $entity;
|
||||
}
|
||||
|
||||
switch ($options['fromto']) {
|
||||
case 'value':
|
||||
$date1 = $dates['value']['formatted'];
|
||||
$date2 = $date1;
|
||||
break;
|
||||
case 'value2':
|
||||
$date2 = $dates['value2']['formatted'];
|
||||
$date1 = $date2;
|
||||
break;
|
||||
default:
|
||||
$date1 = $dates['value']['formatted'];
|
||||
$date2 = $dates['value2']['formatted'];
|
||||
break;
|
||||
}
|
||||
|
||||
// Pull the timezone, if any, out of the formatted result and tack it back on
|
||||
// at the end, if it is in the current formatted date.
|
||||
$timezone = $dates['value']['formatted_timezone'];
|
||||
if ($timezone) {
|
||||
$timezone = ' ' . $timezone;
|
||||
}
|
||||
$date1 = str_replace($timezone, '', $date1);
|
||||
$date2 = str_replace($timezone, '', $date2);
|
||||
$time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
|
||||
$time1 = preg_replace('([\)\]]$)', '', $time1);
|
||||
$time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
|
||||
$time2 = preg_replace('([\)\]]$)', '', $time2);
|
||||
|
||||
// A date with a granularity of 'hour' has a time string that is an integer
|
||||
// value. We can't use that to replace time strings in formatted dates.
|
||||
$has_time_string = date_has_time($field['settings']['granularity']);
|
||||
if ($precision == 'hour') {
|
||||
$has_time_string = FALSE;
|
||||
}
|
||||
|
||||
// No date values, display nothing.
|
||||
if (empty($date1) && empty($date2)) {
|
||||
$output .= '';
|
||||
}
|
||||
// Start and End dates match or there is no End date, display a complete
|
||||
// single date.
|
||||
elseif ($date1 == $date2 || empty($date2)) {
|
||||
$output .= theme('date_display_single', array(
|
||||
'date' => $date1,
|
||||
'timezone' => $timezone,
|
||||
'attributes' => $attributes,
|
||||
'rdf_mapping' => $rdf_mapping,
|
||||
'add_rdf' => $add_rdf,
|
||||
'dates' => $dates,
|
||||
));
|
||||
}
|
||||
// Same day, different times, don't repeat the date but show both Start and
|
||||
// End times. We can NOT do this if the replacement value is an integer
|
||||
// instead of a time string.
|
||||
elseif ($has_time_string && $dates['value']['formatted_date'] == $dates['value2']['formatted_date']) {
|
||||
// Replace the original time with the start/end time in the formatted start
|
||||
// date. Make sure that parentheses or brackets wrapping the time will be
|
||||
// retained in the final result.
|
||||
$time = theme('date_display_range', array(
|
||||
'date1' => $time1,
|
||||
'date2' => $time2,
|
||||
'timezone' => $timezone,
|
||||
'attributes' => $attributes,
|
||||
'rdf_mapping' => $rdf_mapping,
|
||||
'add_rdf' => $add_rdf,
|
||||
'dates' => $dates,
|
||||
));
|
||||
$replaced = str_replace($time1, $time, $date1);
|
||||
$output .= theme('date_display_single', array(
|
||||
'date' => $replaced,
|
||||
'timezone' => $timezone,
|
||||
'attributes' => array(),
|
||||
'rdf_mapping' => array(),
|
||||
'add_rdf' => FALSE,
|
||||
'dates' => $dates,
|
||||
));
|
||||
}
|
||||
// Different days, display both in their entirety.
|
||||
else {
|
||||
$output .= theme('date_display_range', array(
|
||||
'date1' => $date1,
|
||||
'date2' => $date2,
|
||||
'timezone' => $timezone,
|
||||
'attributes' => $attributes,
|
||||
'rdf_mapping' => $rdf_mapping,
|
||||
'add_rdf' => $add_rdf,
|
||||
'dates' => $dates,
|
||||
));
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template preprocess function for displaying a single date.
|
||||
*/
|
||||
function template_preprocess_date_display_single(&$variables) {
|
||||
if ($variables['add_rdf']) {
|
||||
// Pass along the rdf mapping for this field, if any. Add some default rdf
|
||||
// attributes that will be used if not overridden by attributes passed in.
|
||||
$rdf_mapping = $variables['rdf_mapping'];
|
||||
$base_attributes = array(
|
||||
'property' => array('dc:date'),
|
||||
'datatype' => 'xsd:dateTime',
|
||||
'content' => $variables['dates']['value']['formatted_iso'],
|
||||
);
|
||||
$variables['attributes'] = $variables['attributes'] + $base_attributes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date element formatted as a single date.
|
||||
*/
|
||||
function theme_date_display_single($variables) {
|
||||
$date = $variables['date'];
|
||||
$timezone = $variables['timezone'];
|
||||
$attributes = $variables['attributes'];
|
||||
|
||||
// Wrap the result with the attributes.
|
||||
return '<span class="date-display-single"' . drupal_attributes($attributes) . '>' . $date . $timezone . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Template preprocess function for displaying a range of dates.
|
||||
*/
|
||||
function template_preprocess_date_display_range(&$variables) {
|
||||
// Merge in the shared attributes for themes to use.
|
||||
$variables['attributes_start'] += $variables['attributes'];
|
||||
$variables['attributes_end'] += $variables['attributes'];
|
||||
|
||||
if ($variables['add_rdf']) {
|
||||
// Pass along the rdf mapping for this field, if any. Add some default rdf
|
||||
// attributes that will be used if not overridden by attributes passed in.
|
||||
$rdf_mapping = $variables['rdf_mapping'];
|
||||
$dates = $variables['dates'];
|
||||
$base_attributes = array(
|
||||
'property' => array('dc:date'),
|
||||
'datatype' => 'xsd:dateTime',
|
||||
'content' => $dates['value']['formatted_iso'],
|
||||
);
|
||||
$variables['attributes_start'] += $base_attributes;
|
||||
$variables['attributes_end'] += $base_attributes;
|
||||
$variables['attributes_end']['content'] = $dates['value2']['formatted_iso'];
|
||||
foreach ($variables['attributes_end']['property'] as $delta => $property) {
|
||||
$variables['attributes_end']['property'][$delta] = str_replace('start', 'end', $property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date element formatted as a range.
|
||||
*/
|
||||
function theme_date_display_range($variables) {
|
||||
$date1 = $variables['date1'];
|
||||
$date2 = $variables['date2'];
|
||||
$timezone = $variables['timezone'];
|
||||
$attributes_start = $variables['attributes_start'];
|
||||
$attributes_end = $variables['attributes_end'];
|
||||
|
||||
// Wrap the result with the attributes.
|
||||
return t('!start-date to !end-date', array(
|
||||
'!start-date' => '<span class="date-display-start"' . drupal_attributes($attributes_start) . '>' . $date1 . '</span>',
|
||||
'!end-date' => '<span class="date-display-end"' . drupal_attributes($attributes_end) . '>' . $date2 . $timezone . '</span>',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date element formatted as an interval.
|
||||
*/
|
||||
function theme_date_display_interval($variables) {
|
||||
$entity = $variables['entity'];
|
||||
$options = $variables['display']['settings'];
|
||||
$dates = $variables['dates'];
|
||||
$attributes = $variables['attributes'];
|
||||
|
||||
// Get the formatter settings, either the default settings for this node type
|
||||
// or the View settings stored in $entity->date_info.
|
||||
if (!empty($entity->date_info) && !empty($entity->date_info->formatter_settings)) {
|
||||
$options = $entity->date_info->formatter_settings;
|
||||
}
|
||||
|
||||
$time_ago_vars = array(
|
||||
'start_date' => $dates['value']['local']['object'],
|
||||
'end_date' => $dates['value2']['local']['object'],
|
||||
'interval' => $options['interval'],
|
||||
'interval_display' => $options['interval_display'],
|
||||
);
|
||||
|
||||
if ($return = theme('date_time_ago', $time_ago_vars)) {
|
||||
return '<span class="date-display-interval"' . drupal_attributes($attributes) . ">$return</span>";
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a start/end date combination on form.
|
||||
*/
|
||||
function theme_date_combo($variables) {
|
||||
$element = $variables['element'];
|
||||
$field = field_info_field($element['#field_name']);
|
||||
$instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
|
||||
|
||||
// Group start/end items together in fieldset.
|
||||
$fieldset = array(
|
||||
'#title' => t($element['#title']) . ' ' . ($element['#delta'] > 0 ? intval($element['#delta'] + 1) : ''),
|
||||
'#value' => '',
|
||||
'#description' => !empty($element['#fieldset_description']) ? $element['#fieldset_description'] : '',
|
||||
'#attributes' => array(),
|
||||
'#children' => $element['#children'],
|
||||
);
|
||||
return theme('fieldset', array('element' => $fieldset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for the text/select options for date parts in a table.
|
||||
*/
|
||||
function theme_date_text_parts($variables) {
|
||||
$element = $variables['element'];
|
||||
$rows = array();
|
||||
foreach (date_granularity_names() as $key => $part) {
|
||||
if ($element[$key]['#type'] == 'hidden') {
|
||||
$rows[] = drupal_render($element[$key]);
|
||||
}
|
||||
else {
|
||||
$rows[] = array($part, drupal_render($element[$key][0]), drupal_render($element[$key][1]));
|
||||
}
|
||||
}
|
||||
if ($element['year']['#type'] == 'hidden') {
|
||||
return implode($rows) . drupal_render_children($element);
|
||||
}
|
||||
else {
|
||||
$header = array(t('Date part'), t('Select list'), t('Text field'));
|
||||
return theme('table', array('header' => $header, 'rows' => $rows)) . drupal_render_children($element);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} End of addtogroup themeable */
|
||||
72
sites/all/modules/contrib/fields/date/date.tokens.inc
Normal file
72
sites/all/modules/contrib/fields/date/date.tokens.inc
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Token module integration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_info().
|
||||
*/
|
||||
function date_token_info() {
|
||||
// All date types can share the same date value type.
|
||||
$info['types']['date-field-value'] = array(
|
||||
'name' => t('Date field values'),
|
||||
'description' => t('Tokens related to date field values.'),
|
||||
'needs-data' => 'date-field-value',
|
||||
'field-value' => TRUE,
|
||||
);
|
||||
// Provide two tokens: 'date' (the date or start-date), and 'end-date'.
|
||||
$info['tokens']['date-field-value']['date'] = array(
|
||||
'name' => t('Date'),
|
||||
'description' => t('The date value.'),
|
||||
'type' => 'date',
|
||||
);
|
||||
$info['tokens']['date-field-value']['to-date'] = array(
|
||||
'name' => t('End Date'),
|
||||
'description' => t('The End date value.'),
|
||||
'type' => 'date',
|
||||
);
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_tokens().
|
||||
*/
|
||||
function date_tokens($type, $tokens, array $data = array(), array $options = array()) {
|
||||
$replacements = array();
|
||||
$language_code = isset($options['language']) ? $options['language']->language : NULL;
|
||||
|
||||
if (($type == 'date-field-value') && !empty($data['item'])) {
|
||||
$item = $data['item'];
|
||||
|
||||
// Create tokens for the field "Date" or "Start date".
|
||||
if (($date_tokens = token_find_with_prefix($tokens, 'date')) && !empty($item['value'])) {
|
||||
// Load the Start date and convert to a unix timestamp.
|
||||
$date = new DateObject($item['value'], $item['timezone_db'], date_type_format($item['date_type']));
|
||||
if (!empty($date) && $item['timezone_db'] != $item['timezone']) {
|
||||
date_timezone_set($date, timezone_open($item['timezone']));
|
||||
}
|
||||
$timestamp = !empty($date) ? date_format_date($date, 'custom', 'U') : '';
|
||||
// Generate the token replacements, using the date token type provided
|
||||
// by system.module.
|
||||
$replacements += token_generate('date', $date_tokens, array('date' => $timestamp), $options);
|
||||
}
|
||||
|
||||
// Create tokens for the field "End date".
|
||||
if (($date_tokens = token_find_with_prefix($tokens, 'end-date')) && !empty($item['value2'])) {
|
||||
// Load the to date and convert to a unix timestamp.
|
||||
$date = new DateObject($item['value2'], $item['timezone_db'], date_type_format($item['date_type']));
|
||||
if (!empty($date) && $item['timezone_db'] != $item['timezone']) {
|
||||
date_timezone_set($date, timezone_open($item['timezone']));
|
||||
}
|
||||
$timestamp = !empty($date) ? date_format_date($date, 'custom', 'U') : '';
|
||||
// Generate the token replacements, using the date token type provided
|
||||
// by system.module.
|
||||
$replacements += token_generate('date', $date_tokens, array('date' => $timestamp), $options);
|
||||
}
|
||||
}
|
||||
|
||||
return $replacements;
|
||||
}
|
||||
605
sites/all/modules/contrib/fields/date/date_admin.inc
Normal file
605
sites/all/modules/contrib/fields/date/date_admin.inc
Normal file
@@ -0,0 +1,605 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Date administration code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Settings for the default formatter.
|
||||
*/
|
||||
function date_default_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$settings = $display['settings'];
|
||||
$formatter = $display['type'];
|
||||
$form = array();
|
||||
|
||||
$form['format_type'] = array(
|
||||
'#title' => t('Choose how users view dates and times:'),
|
||||
'#type' => 'select',
|
||||
'#options' => date_format_type_options(),
|
||||
'#default_value' => $settings['format_type'],
|
||||
'#description' => t('To add or edit options, visit <a href="@date-time-page">Date and time settings</a>.', array('@date-time-page' => url('admin/config/regional/date-time'))),
|
||||
'#weight' => 0,
|
||||
);
|
||||
|
||||
$form['fromto'] = array(
|
||||
'#title' => t('Display:'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
'both' => t('Both Start and End dates'),
|
||||
'value' => t('Start date only'),
|
||||
'value2' => t('End date only'),
|
||||
),
|
||||
'#access' => $field['settings']['todate'],
|
||||
'#default_value' => $settings['fromto'],
|
||||
'#weight' => 1,
|
||||
);
|
||||
|
||||
// Make the string translatable by keeping it as a whole rather than
|
||||
// translating prefix and suffix separately.
|
||||
list($prefix, $suffix) = explode('@count', t('Show @count value(s)'));
|
||||
$form['multiple_number'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Multiple values:'),
|
||||
'#size' => 5,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $settings['multiple_number'],
|
||||
'#weight' => 2,
|
||||
'#access' => ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($field['cardinality'] > 1),
|
||||
'#description' => t('Identify a specific number of values to display, or leave blank to show all values.'),
|
||||
);
|
||||
|
||||
list($prefix, $suffix) = explode('@isodate', t('starting from @isodate'));
|
||||
$form['multiple_from'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 15,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $settings['multiple_from'],
|
||||
'#weight' => 3,
|
||||
'#access' => ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($field['cardinality'] > 1),
|
||||
);
|
||||
|
||||
list($prefix, $suffix) = explode('@isodate', t('ending with @isodate'));
|
||||
$form['multiple_to'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 15,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $settings['multiple_to'],
|
||||
'#weight' => 4,
|
||||
'#access' => ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($field['cardinality'] > 1),
|
||||
'#description' => t('Identify specific start and/or end dates in the format YYYY-MM-DDTHH:MM:SS, or leave blank for all available dates.'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings for the interval formatter.
|
||||
*/
|
||||
function date_interval_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$settings = $display['settings'];
|
||||
$form = array();
|
||||
$form['interval'] = array(
|
||||
'#title' => t('Interval'),
|
||||
'#description' => t("How many time units should be shown in the 'time ago' string."),
|
||||
'#type' => 'select',
|
||||
'#options' => drupal_map_assoc(range(1, 6)),
|
||||
'#default_value' => $settings['interval'],
|
||||
'#weight' => 0,
|
||||
);
|
||||
// Uses the same options used by Views format_interval.
|
||||
$options = array(
|
||||
'raw time ago' => t('Time ago'),
|
||||
'time ago' => t('Time ago (with "ago" appended)'),
|
||||
'raw time hence' => t('Time hence'),
|
||||
'time hence' => t('Time hence (with "hence" appended)'),
|
||||
'raw time span' => t('Time span (future dates have "-" prepended)'),
|
||||
'inverse time span' => t('Time span (past dates have "-" prepended)'),
|
||||
'time span' => t('Time span (with "ago/hence" appended)'),
|
||||
);
|
||||
$form['interval_display'] = array(
|
||||
'#title' => t('Display'),
|
||||
'#description' => t("How to display the time ago or time hence for this field."),
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
'#default_value' => $settings['interval_display'],
|
||||
'#weight' => 0,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings summary for the default formatter.
|
||||
*/
|
||||
function date_default_formatter_settings_summary($field, $instance, $view_mode) {
|
||||
$display = $instance['display'][$view_mode];
|
||||
$settings = $display['settings'];
|
||||
$formatter = $display['type'];
|
||||
$format_types = date_format_type_options();
|
||||
$summary = array();
|
||||
$format = FALSE;
|
||||
switch ($formatter) {
|
||||
case 'date_plain':
|
||||
$format = t('Plain');
|
||||
break;
|
||||
case 'format_interval':
|
||||
$format = t('Interval');
|
||||
break;
|
||||
default:
|
||||
if (!empty($format_types[$settings['format_type']])) {
|
||||
$format = $format_types[$settings['format_type']];
|
||||
}
|
||||
}
|
||||
if ($format) {
|
||||
$summary[] = t('Display dates using the @format format', array('@format' => $format));
|
||||
}
|
||||
else {
|
||||
$summary[] = t('Display dates using the default format because the specified format (@format) is not defined', array('@format' => $settings['format_type']));
|
||||
}
|
||||
|
||||
if (array_key_exists('fromto', $settings) && $field['settings']['todate']) {
|
||||
$options = array(
|
||||
'both' => t('Display both Start and End dates'),
|
||||
'value' => t('Display Start date only'),
|
||||
'value2' => t('Display End date only'),
|
||||
);
|
||||
$summary[] = $options[$settings['fromto']];
|
||||
}
|
||||
|
||||
if (array_key_exists('multiple_number', $settings) && !empty($field['cardinality'])) {
|
||||
$summary[] = t('Show @count value(s) starting with @date1, ending with @date2', array(
|
||||
'@count' => !empty($settings['multiple_number']) ? $settings['multiple_number'] : t('all'),
|
||||
'@date1' => !empty($settings['multiple_from']) ? $settings['multiple_from'] : t('earliest'),
|
||||
'@date2' => !empty($settings['multiple_to']) ? $settings['multiple_to'] : t('latest'),
|
||||
));
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings summary for the interval formatter.
|
||||
*
|
||||
* @TODO Add settings later.
|
||||
*/
|
||||
function date_interval_formatter_settings_summary($field, $instance, $view_mode) {
|
||||
$summary = array();
|
||||
$display = $instance['display'][$view_mode];
|
||||
$settings = $display['settings'];
|
||||
$formatter = $display['type'];
|
||||
$summary[] = t('Display time ago, showing @interval units.', array('@interval' => $settings['interval']));
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for date_field_instance_settings_form().
|
||||
*
|
||||
* @see date_field_instance_settings_form_validate()
|
||||
*/
|
||||
function _date_field_instance_settings_form($field, $instance) {
|
||||
$widget = $instance['widget'];
|
||||
$settings = $instance['settings'];
|
||||
$widget_settings = $instance['widget']['settings'];
|
||||
|
||||
$form['default_value'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Default date'),
|
||||
'#default_value' => $settings['default_value'],
|
||||
'#options' => array('blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
|
||||
'#weight' => 1,
|
||||
'#fieldset' => 'default_values',
|
||||
);
|
||||
|
||||
$description = t("Describe a time by reference to the current day, like '+90 days' (90 days from the day the field is created) or '+1 Saturday' (the next Saturday). See !strtotime for more details.", array('!strtotime' => l(t('strtotime'), 'http://www.php.net/manual/en/function.strtotime.php')));
|
||||
$form['default_value_code'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Relative default value'),
|
||||
'#description' => $description,
|
||||
'#default_value' => $settings['default_value_code'],
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="instance[settings][default_value]"]' => array('value' => 'strtotime')),
|
||||
),
|
||||
'#weight' => 1.1,
|
||||
'#fieldset' => 'default_values',
|
||||
);
|
||||
$form['default_value2'] = array(
|
||||
'#type' => !empty($field['settings']['todate']) ? 'select' : 'hidden',
|
||||
'#title' => t('Default end date'),
|
||||
'#default_value' => $settings['default_value2'],
|
||||
'#options' => array('same' => t('Same as Default date'), 'blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
|
||||
'#weight' => 2,
|
||||
'#fieldset' => 'default_values',
|
||||
);
|
||||
$form['default_value_code2'] = array(
|
||||
'#type' => !empty($field['settings']['todate']) ? 'textfield' : 'hidden',
|
||||
'#title' => t('Relative default value for end date'),
|
||||
'#description' => $description,
|
||||
'#default_value' => $settings['default_value_code2'],
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="instance[settings][default_value2]"]' => array('value' => 'strtotime')),
|
||||
),
|
||||
'#weight' => 2.1,
|
||||
'#fieldset' => 'default_values',
|
||||
);
|
||||
|
||||
$form['#element_validate'] = array('date_field_instance_settings_form_validate');
|
||||
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
);
|
||||
drupal_alter('date_field_instance_settings_form', $form, $context);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for _date_field_instance_settings_form().
|
||||
*/
|
||||
function date_field_instance_settings_form_validate(&$form, &$form_state) {
|
||||
$settings = $form_state['values']['instance']['settings'];
|
||||
|
||||
if ($settings['default_value'] == 'strtotime') {
|
||||
$is_strtotime = @strtotime($settings['default_value_code']);
|
||||
if (!$is_strtotime) {
|
||||
form_set_error('instance][settings][default_value_code', t('The Strtotime default value is invalid.'));
|
||||
}
|
||||
}
|
||||
if (isset($settings['default_value2']) && $settings['default_value2'] == 'strtotime') {
|
||||
$is_strtotime = @strtotime($settings['default_value_code2']);
|
||||
if (!$is_strtotime) {
|
||||
form_set_error('instance][settings][default_value_code2', t('The Strtotime default value for the End Date is invalid.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for date_field_widget_settings_form().
|
||||
*
|
||||
* @see date_field_widget_settings_form_validate()
|
||||
*/
|
||||
function _date_field_widget_settings_form($field, $instance) {
|
||||
$widget = $instance['widget'];
|
||||
$settings = $widget['settings'];
|
||||
|
||||
$form = array(
|
||||
'#element_validate' => array('date_field_widget_settings_form_validate'),
|
||||
);
|
||||
|
||||
$options = array();
|
||||
if ($widget['type'] == 'date_popup' && module_exists('date_popup')) {
|
||||
$formats = date_popup_formats();
|
||||
}
|
||||
else {
|
||||
// Example input formats must show all possible date parts, so add seconds.
|
||||
$formats = str_replace('i', 'i:s', array_keys(system_get_date_formats('short')));
|
||||
$formats = drupal_map_assoc($formats);
|
||||
}
|
||||
$now = date_example_date();
|
||||
foreach ($formats as $f) {
|
||||
$options[$f] = date_format_date($now, 'custom', $f);
|
||||
}
|
||||
$form['input_format'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Date entry options'),
|
||||
'#default_value' => $settings['input_format'],
|
||||
'#options' => $options,
|
||||
'#description' => t('Control the order and format of the options users see.'),
|
||||
'#weight' => 3,
|
||||
'#fieldset' => 'date_format',
|
||||
);
|
||||
// Only a limited set of formats is available for the Date Popup module.
|
||||
if ($widget['type'] != 'date_popup') {
|
||||
$form['input_format']['#options']['custom'] = t('Custom format');
|
||||
$form['input_format_custom'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Custom input format'),
|
||||
'#default_value' => $settings['input_format_custom'],
|
||||
'#description' => t("Override the input format selected above. Define a php date format string like 'm-d-Y H:i' (see <a href=\"@link\">http://php.net/date</a> for more details).", array('@link' => 'http://php.net/date')),
|
||||
'#weight' => 5,
|
||||
'#fieldset' => 'date_format',
|
||||
'#attributes' => array('class' => array('indent')),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="instance[widget][settings][input_format]"]' => array('value' => 'custom'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['input_format_custom'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => '',
|
||||
);
|
||||
}
|
||||
|
||||
if (in_array($widget['type'], array('date_select', 'date_popup'))) {
|
||||
$form['year_range'] = array(
|
||||
'#type' => 'date_year_range',
|
||||
'#default_value' => $settings['year_range'],
|
||||
'#fieldset' => 'date_format',
|
||||
'#weight' => 6,
|
||||
);
|
||||
$form['increment'] = array(
|
||||
'#type' => 'select', '#title' => t('Time increments'),
|
||||
'#default_value' => $settings['increment'],
|
||||
'#options' => array(
|
||||
1 => t('1 minute'),
|
||||
5 => t('5 minute'),
|
||||
10 => t('10 minute'),
|
||||
15 => t('15 minute'),
|
||||
30 => t('30 minute')),
|
||||
'#weight' => 7,
|
||||
'#fieldset' => 'date_format',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['year_range'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $settings['year_range'],
|
||||
);
|
||||
$form['increment'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $settings['increment'],
|
||||
);
|
||||
}
|
||||
|
||||
$form['label_position'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $settings['label_position'],
|
||||
);
|
||||
$form['text_parts'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $settings['text_parts'],
|
||||
);
|
||||
$form['advanced'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Advanced settings'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#fieldset' => 'date_format',
|
||||
'#weight' => 9,
|
||||
);
|
||||
if (in_array($widget['type'], array('date_select'))) {
|
||||
$options = array('above' => t('Above'), 'within' => t('Within'), 'none' => t('None'));
|
||||
$description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'Within' inserts the label as the first option in the select list and in blank textfields. 'None' doesn't label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
|
||||
}
|
||||
else {
|
||||
$options = array('above' => t('Above'), 'none' => t('None'));
|
||||
$description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'None' doesn't label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
|
||||
}
|
||||
$form['advanced']['label_position'] = array(
|
||||
'#type' => 'radios',
|
||||
'#options' => $options,
|
||||
'#default_value' => $settings['label_position'],
|
||||
'#title' => t('Position of date part labels'),
|
||||
'#description' => $description,
|
||||
);
|
||||
$form['advanced']['text_parts'] = array(
|
||||
'#theme' => $widget['type'] == 'date_select' ? 'date_text_parts' : '',
|
||||
);
|
||||
$text_parts = (array) $settings['text_parts'];
|
||||
foreach (date_granularity_names() as $key => $value) {
|
||||
if ($widget['type'] == 'date_select') {
|
||||
$form['advanced']['text_parts'][$key] = array(
|
||||
'#type' => 'radios',
|
||||
'#default_value' => in_array($key, $text_parts) ? 1 : 0,
|
||||
'#options' => array(0 => '', 1 => ''),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['advanced']['text_parts'][$key] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => (int) in_array($key, (array) $settings['text_parts']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
);
|
||||
drupal_alter('date_field_widget_settings_form', $form, $context);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for _date_field_widget_settings_form().
|
||||
*/
|
||||
function date_field_widget_settings_form_validate(&$form, &$form_state) {
|
||||
// The widget settings are in the wrong place in the form because of #tree on
|
||||
// the top level.
|
||||
$settings = $form_state['values']['instance']['widget']['settings'];
|
||||
$settings = array_merge($settings, $settings['advanced']);
|
||||
unset($settings['advanced']);
|
||||
form_set_value(array('#parents' => array('instance', 'widget', 'settings')), $settings, $form_state);
|
||||
|
||||
$widget = &$form_state['values']['instance']['widget'];
|
||||
// Munge the table display for text parts back into an array of text parts.
|
||||
if (is_array($widget['settings']['text_parts'])) {
|
||||
form_set_value($form['text_parts'], array_keys(array_filter($widget['settings']['text_parts'])), $form_state);
|
||||
}
|
||||
|
||||
if ($widget['settings']['input_format'] === 'custom' && empty($widget['settings']['input_format_custom'])) {
|
||||
form_set_error('instance][widget][settings][input_format_custom', t('Please enter a custom date format, or choose one of the preset formats.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for date_field_settings_form().
|
||||
*
|
||||
* @see date_field_settings_validate()
|
||||
*/
|
||||
function _date_field_settings_form($field, $instance, $has_data) {
|
||||
$settings = $field['settings'];
|
||||
|
||||
$form = array(
|
||||
'#element_validate' => array('date_field_settings_validate'),
|
||||
);
|
||||
|
||||
// Make sure granularity is in the right format and has no empty values.
|
||||
if (!empty($settings['granularity']) && is_array($settings['granularity'])) {
|
||||
$granularity = array_filter($settings['granularity']);
|
||||
}
|
||||
$tz_handling = $settings['tz_handling'];
|
||||
|
||||
$description = t('Select the date attributes to collect and store.');
|
||||
$options = date_granularity_names();
|
||||
$checkbox_year = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => check_plain($options['year']),
|
||||
'#value' => 'year',
|
||||
'#return_value' => 'year',
|
||||
'#disabled' => TRUE,
|
||||
);
|
||||
unset($options['year']);
|
||||
$form['granularity'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => t('Date attributes to collect'),
|
||||
'#default_value' => $granularity,
|
||||
'#options' => $options,
|
||||
'#attributes' => array('class' => array('container-inline')),
|
||||
'#description' => $description,
|
||||
'#disabled' => $has_data,
|
||||
'year' => $checkbox_year,
|
||||
);
|
||||
|
||||
$description = t('End dates are used to collect duration. E.g., allow an event to start on September 15, and end on September 16.');
|
||||
$form['enddate_get'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Collect an end date'),
|
||||
'#description' => $description,
|
||||
'#default_value' => (empty($settings['todate']) ? FALSE : TRUE),
|
||||
'#disabled' => $has_data,
|
||||
);
|
||||
$form['enddate_required'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Required'),
|
||||
'#default_value' => ((isset($settings['todate']) && $settings['todate'] === 'required') ? TRUE : FALSE),
|
||||
'#disabled' => $has_data,
|
||||
'#states' => array(
|
||||
'invisible' => array(
|
||||
'input[name="field[settings][enddate_get]"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$description = t('Select the timezone handling method for this date field.');
|
||||
$form['tz_handling'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Time zone handling'),
|
||||
'#default_value' => $tz_handling,
|
||||
'#options' => date_timezone_handling_options(),
|
||||
'#description' => $description,
|
||||
'#disabled' => $has_data,
|
||||
'#attached' => array(
|
||||
'js' => array(drupal_get_path('module', 'date') . '/date_admin.js'),
|
||||
),
|
||||
);
|
||||
// Force this value to hidden because we don't want to allow it to be changed
|
||||
// right now, but allow it to be a variable if needed.
|
||||
$form['timezone_db'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => date_get_timezone_db($tz_handling),
|
||||
);
|
||||
|
||||
$form['cache_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Cache dates'),
|
||||
'#description' => t('Date objects can be created and cached as date fields are loaded rather than when they are displayed to improve performance.'),
|
||||
'#default_value' => !empty($settings['cache_enabled']),
|
||||
'#weight' => 10,
|
||||
);
|
||||
$form['cache_count'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Maximum dates per field'),
|
||||
'#default_value' => (isset($settings['cache_count'])) ? $settings['cache_count'] : 4,
|
||||
'#description' => t("If set to '0', all date values on every entity will be cached. Note that caching every date on fields that may have a large number of multiple or repeating values may create a significant performance penalty when the cache is cleared. The suggested setting for multiple value and repeating fields is no more than 4 values per field."),
|
||||
'#size' => 3,
|
||||
'#weight' => 11,
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
'input[name="field[settings][cache_enabled]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'has_data' => $has_data,
|
||||
);
|
||||
drupal_alter('date_field_settings_form', $form, $context);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation handler for _date_field_settings_form().
|
||||
*/
|
||||
function date_field_settings_validate(&$form, &$form_state) {
|
||||
$field = &$form_state['values']['field'];
|
||||
|
||||
if ($field['settings']['tz_handling'] == 'none') {
|
||||
form_set_value($form['timezone_db'], '', $form_state);
|
||||
}
|
||||
else {
|
||||
form_set_value($form['timezone_db'], date_get_timezone_db($field['settings']['tz_handling']), $form_state);
|
||||
}
|
||||
|
||||
if ($field['settings']['tz_handling'] != 'none' && !in_array('hour', array_filter($field['settings']['granularity']))) {
|
||||
form_set_error('field[settings][tz_handling]', t('Dates without hours granularity must not use any timezone handling.'));
|
||||
}
|
||||
|
||||
// Extract the correct 'todate' value out of the two end date checkboxes.
|
||||
if ($field['settings']['enddate_get']) {
|
||||
if ($field['settings']['enddate_required']) {
|
||||
$field['settings']['todate'] = 'required';
|
||||
}
|
||||
else {
|
||||
$field['settings']['todate'] = 'optional';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$field['settings']['todate'] = '';
|
||||
}
|
||||
|
||||
// Don't save the pseudo values created in the UI.
|
||||
unset($field['settings']['enddate_get'], $field['settings']['enddate_required']);
|
||||
|
||||
if (!empty($field['settings']['cache_enabled'])) {
|
||||
if (!is_numeric($field['settings']['cache_count'])) {
|
||||
form_set_error('field[settings][cache_count]', t('The number of cache values must be a number.'));
|
||||
}
|
||||
elseif ($field['settings']['cache_count'] < 0) {
|
||||
form_set_error('field[settings][cache_count]', t('The number of cache values must be a number 0 or greater.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timezone handling options.
|
||||
*
|
||||
* The 'none' option will do no timezone conversions and will store and display
|
||||
* dates exactly as entered useful in locales or situations where timezone
|
||||
* conversions are not working reliably, for dates with no times, for historical
|
||||
* dates where timezones are irrelevant, or anytime conversion is unnecessary or
|
||||
* undesirable.
|
||||
*/
|
||||
function date_timezone_handling_options() {
|
||||
return array(
|
||||
'site' => t("Site's time zone"),
|
||||
'date' => t("Date's time zone"),
|
||||
'user' => t("User's time zone"),
|
||||
'utc' => 'UTC',
|
||||
'none' => t('No time zone conversion'),
|
||||
);
|
||||
}
|
||||
81
sites/all/modules/contrib/fields/date/date_admin.js
Normal file
81
sites/all/modules/contrib/fields/date/date_admin.js
Normal file
@@ -0,0 +1,81 @@
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.dateAdmin = {};
|
||||
|
||||
Drupal.behaviors.dateAdmin.attach = function (context, settings) {
|
||||
// Remove timezone handling options for fields without hours granularity.
|
||||
var $hour = $('#edit-field-settings-granularity-hour').once('date-admin');
|
||||
if ($hour.length) {
|
||||
new Drupal.dateAdmin.TimezoneHandler($hour);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Drupal.dateAdmin = {};
|
||||
|
||||
/**
|
||||
* Constructor for the TimezoneHandler object.
|
||||
*
|
||||
* This object is responsible for showing the timezone handling options dropdown
|
||||
* when the user has chosen to collect hours as part of the date field, and
|
||||
* hiding it otherwise.
|
||||
*/
|
||||
Drupal.dateAdmin.TimezoneHandler = function ($checkbox) {
|
||||
this.$checkbox = $checkbox;
|
||||
this.$dropdown = $('#edit-field-settings-tz-handling');
|
||||
this.$timezoneDiv = $('.form-item-field-settings-tz-handling');
|
||||
// Store the initial value of the timezone handling dropdown.
|
||||
this.storeTimezoneHandling();
|
||||
// Toggle the timezone handling section when the user clicks the "Hour"
|
||||
// checkbox.
|
||||
this.$checkbox.bind('click', $.proxy(this.clickHandler, this));
|
||||
// Trigger the click handler so that if the checkbox is unchecked on initial
|
||||
// page load, the timezone handling section will be hidden.
|
||||
this.clickHandler();
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler triggered when the user clicks the "Hour" checkbox.
|
||||
*/
|
||||
Drupal.dateAdmin.TimezoneHandler.prototype.clickHandler = function () {
|
||||
if (this.$checkbox.is(':checked')) {
|
||||
this.restoreTimezoneHandlingOptions();
|
||||
}
|
||||
else {
|
||||
this.hideTimezoneHandlingOptions();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the timezone handling options section of the form.
|
||||
*/
|
||||
Drupal.dateAdmin.TimezoneHandler.prototype.hideTimezoneHandlingOptions = function () {
|
||||
this.storeTimezoneHandling();
|
||||
this.$dropdown.val('none');
|
||||
this.$timezoneDiv.hide();
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the timezone handling options section of the form.
|
||||
*/
|
||||
Drupal.dateAdmin.TimezoneHandler.prototype.restoreTimezoneHandlingOptions = function () {
|
||||
var val = this.getTimezoneHandling();
|
||||
this.$dropdown.val(val);
|
||||
this.$timezoneDiv.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Store the current value of the timezone handling dropdown.
|
||||
*/
|
||||
Drupal.dateAdmin.TimezoneHandler.prototype.storeTimezoneHandling = function () {
|
||||
this._timezoneHandling = this.$dropdown.val();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the stored value of the timezone handling dropdown.
|
||||
*/
|
||||
Drupal.dateAdmin.TimezoneHandler.prototype.getTimezoneHandling = function () {
|
||||
return this._timezoneHandling;
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,9 @@
|
||||
Date All Day
|
||||
|
||||
This module provides the option to add an 'All Day' checkbox to toggle time on
|
||||
and off for date fields. It also contains the theme that displays the 'All Day'
|
||||
text on fields that have no time.
|
||||
|
||||
Additionally, this module serves as an example of how other modules can inject
|
||||
new functionality into date fields using various hooks provided by Date and by
|
||||
the Field API.
|
||||
@@ -0,0 +1,13 @@
|
||||
name = Date All Day
|
||||
description = Adds 'All Day' functionality to date fields, including an 'All Day' theme and 'All Day' checkboxes for the Date select and Date popup widgets.
|
||||
dependencies[] = date_api
|
||||
dependencies[] = date
|
||||
package = Date/Time
|
||||
core = 7.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-08-13
|
||||
version = "7.x-2.6"
|
||||
core = "7.x"
|
||||
project = "date"
|
||||
datestamp = "1344850024"
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Adds All Day functionality to the Date field.
|
||||
*
|
||||
* This module implements a number of hooks in the Date field and
|
||||
* Date api element processing and to add an All Day checkbox to
|
||||
* date widgets, and also adds an All Day theme and
|
||||
* All Day information to the formatting.
|
||||
*
|
||||
* Keep in mind that the process hooks are fired from the top down,
|
||||
* first date_combo, then the date_select or date_popup.
|
||||
*
|
||||
* Validation fires from the bottom up, first date_select and
|
||||
* date_popup, then date_combo.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function date_all_day_theme() {
|
||||
$themes = array(
|
||||
'date_all_day' => array(
|
||||
'variables' => array(
|
||||
'field' => NULL,
|
||||
'instance' => NULL,
|
||||
'which' => NULL,
|
||||
'date1' => NULL,
|
||||
'date2' => NULL,
|
||||
'format' => NULL,
|
||||
'entity_type' => NULL,
|
||||
'entity' => NULL,
|
||||
'view' => NULL
|
||||
)
|
||||
),
|
||||
'date_all_day_label' => array(
|
||||
'variables' => array()
|
||||
),
|
||||
);
|
||||
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_formatter_dates_alter().
|
||||
*
|
||||
* This allows us to alter the $dates array created
|
||||
* by date_formatter_process.
|
||||
*/
|
||||
function date_all_day_date_formatter_dates_alter(&$dates, $context) {
|
||||
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
$format = $context['format'];
|
||||
$entity_type = $context['entity_type'];
|
||||
$entity = $context['entity'];
|
||||
$date1 = $dates['value']['local']['object'];
|
||||
$date2 = $dates['value2']['local']['object'];
|
||||
|
||||
$is_all_day = date_all_day_field($field, $instance, $date1, $date2);
|
||||
|
||||
$all_day1 = '';
|
||||
$all_day2 = '';
|
||||
if ($format != 'format_interval' && $is_all_day) {
|
||||
$all_day1 = theme('date_all_day', array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'which' => 'date1',
|
||||
'date1' => $date1,
|
||||
'date2' => $date2,
|
||||
'format' => $format,
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity));
|
||||
$all_day2 = theme('date_all_day', array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'which' => 'date2',
|
||||
'date1' => $date1,
|
||||
'date2' => $date2,
|
||||
'format' => $format,
|
||||
'entity_type' => $entity_type,
|
||||
'entity' => $entity));
|
||||
$dates['value']['formatted_time'] = theme('date_all_day_label');
|
||||
$dates['value2']['formatted_time'] = theme('date_all_day_label');
|
||||
$dates['value']['formatted'] = $all_day1;
|
||||
$dates['value2']['formatted'] = $all_day2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust start/end date format to account for 'all day' .
|
||||
*
|
||||
* @param array $field, the field definition for this date field.
|
||||
* @param string $which, which value to return, 'date1' or 'date2' .
|
||||
* @param object $date1, a date/time object for the 'start' date.
|
||||
* @param object $date2, a date/time object for the 'end' date.
|
||||
* @param string $format
|
||||
* @param object $entity, the node this date comes from (may be incomplete, always contains nid).
|
||||
* @param object $view, the view this node comes from, if applicable.
|
||||
* @return formatted date.
|
||||
*/
|
||||
function theme_date_all_day($vars) {
|
||||
$field = $vars['field'];
|
||||
$instance = $vars['instance'];
|
||||
$which = $vars['which'];
|
||||
$date1 = $vars['date1'];
|
||||
$date2 = $vars['date2'];
|
||||
$format = $vars['format'];
|
||||
$entity = $vars['entity'];
|
||||
$view = !empty($vars['view']) ? $vars['view'] : NULL;
|
||||
|
||||
if (empty($date1) || !is_object($date1) || $format == 'format_interval') {
|
||||
return;
|
||||
}
|
||||
if (empty($date2)) {
|
||||
$date2 = $date1;
|
||||
}
|
||||
|
||||
$suffix = '';
|
||||
if (!date_has_time($field['settings']['granularity'])) {
|
||||
$format = date_limit_format($format, array('year', 'month', 'day'));
|
||||
}
|
||||
else {
|
||||
$format_granularity = date_format_order($format);
|
||||
$format_has_time = FALSE;
|
||||
if (in_array('hour', $format_granularity)) {
|
||||
$format_has_time = TRUE;
|
||||
}
|
||||
$all_day = date_all_day_field($field, $instance, $date1, $date2);
|
||||
if ($all_day && $format_has_time) {
|
||||
$format = date_limit_format($format, array('year', 'month', 'day'));
|
||||
$suffix = ' ' . theme('date_all_day_label');
|
||||
}
|
||||
}
|
||||
|
||||
return trim(date_format_date($$which, 'custom', $format) . $suffix);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme the way an 'all day' label will look.
|
||||
*/
|
||||
function theme_date_all_day_label() {
|
||||
return '(' . t('All day', array(), array('context' => 'datetime')) .')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a Start/End date combination qualify as 'All day'.
|
||||
*
|
||||
* @param array $field, the field definition for this date field.
|
||||
* @param object $date1, a date/time object for the 'Start' date.
|
||||
* @param object $date2, a date/time object for the 'End' date.
|
||||
* @return TRUE or FALSE.
|
||||
*/
|
||||
function date_all_day_field($field, $instance, $date1, $date2 = NULL) {
|
||||
if (empty($date1) || !is_object($date1)) {
|
||||
return FALSE;
|
||||
}
|
||||
elseif (!date_has_time($field['settings']['granularity'])) {
|
||||
return TRUE;
|
||||
}
|
||||
if (empty($date2)) {
|
||||
$date2 = $date1;
|
||||
}
|
||||
|
||||
$granularity = date_granularity_precision($field['settings']['granularity']);
|
||||
$increment = isset($instance['widget']['settings']['increment']) ? $instance['widget']['settings']['increment'] : 1;
|
||||
return date_is_all_day(date_format($date1, DATE_FORMAT_DATETIME), date_format($date2, DATE_FORMAT_DATETIME), $granularity, $increment);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_combo_process_alter().
|
||||
*
|
||||
* This hook lets us make changes to the date_combo element.
|
||||
*/
|
||||
function date_all_day_date_combo_process_alter(&$element, &$form_state, $context) {
|
||||
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
|
||||
// Add the all_day checkbox to the combo element.
|
||||
if (!empty($instance['widget']['settings']['display_all_day'])) {
|
||||
|
||||
$parents = $element['#parents'];
|
||||
$first_parent = array_shift($parents);
|
||||
$all_day_id = $first_parent . '[' . implode('][', $parents) . '][all_day]';;
|
||||
foreach (array('value', 'value2') as $key) {
|
||||
if (array_key_exists($key, $element)) {
|
||||
$element[$key]['#date_all_day_id'] = $all_day_id;
|
||||
}
|
||||
}
|
||||
|
||||
$from = $element['#default_value']['value'];
|
||||
$to = !empty($element['#default_value']['value2']) ? $element['#default_value']['value2'] : $element['#default_value']['value'];
|
||||
$date_is_all_day = date_is_all_day($from, $to);
|
||||
$all_day = !empty($form_state['values']['all_day']) || $date_is_all_day;
|
||||
$element['all_day'] = array(
|
||||
'#title' => t('All Day'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $all_day,
|
||||
'#weight' => -21,
|
||||
'#prefix' => '<div class="date-float">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
}
|
||||
|
||||
// Set all_day to 0 for all other date fields.
|
||||
else {
|
||||
$form['all_day']['#type'] = 'hidden';
|
||||
$form['all_day']['#value'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_date_text_process_alter().
|
||||
*
|
||||
* This hook lets us make changes to the date_select widget.
|
||||
*/
|
||||
function date_all_day_date_text_process_alter(&$element, &$form_state, $context) {
|
||||
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
|
||||
if ($all_day_id != '') {
|
||||
// All Day handling on text dates works only if the user leaves the time out of the input value.
|
||||
// There is no element to hide or show.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_select_process_alter().
|
||||
*
|
||||
* This hook lets us make changes to the date_select widget.
|
||||
*/
|
||||
function date_all_day_date_select_process_alter(&$element, &$form_state, $context) {
|
||||
|
||||
// Hide or show this element in reaction to the all_day status for this element.
|
||||
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
|
||||
if ($all_day_id != '') {
|
||||
foreach(array('hour', 'minute', 'second', 'ampm') as $field) {
|
||||
if (array_key_exists($field, $element)) {
|
||||
$element[$field]['#states'] = array(
|
||||
'visible' => array(
|
||||
'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_popup_process_alter().
|
||||
*
|
||||
* This hook lets us make changes to the date_popup element.
|
||||
*/
|
||||
function date_all_day_date_popup_process_alter(&$element, &$form_state, $context) {
|
||||
|
||||
// Hide or show this element in reaction to the all_day status for this element.
|
||||
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
|
||||
if ($all_day_id != '' && array_key_exists('time', $element)) {
|
||||
$element['time']['#states'] = array(
|
||||
'visible' => array(
|
||||
'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_select_pre_validate_alter().
|
||||
*
|
||||
* This hook lets us alter the element or the form_state before the rest
|
||||
* of the date_select validation gets fired.
|
||||
*/
|
||||
function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
// Let Date module massage the format for all day values so they will pass validation.
|
||||
// The All day flag, if used, actually exists on the parent element.
|
||||
date_all_day_value($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_select_pre_validate_alter().
|
||||
*
|
||||
* This hook lets us alter the element or the form_state before the rest
|
||||
* of the date_select validation gets fired.
|
||||
*/
|
||||
function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
// Let Date module massage the format for all day values so they will pass validation.
|
||||
// The All day flag, if used, actually exists on the parent element.
|
||||
date_all_day_value($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_select_pre_validate_alter().
|
||||
*
|
||||
* This hook lets us alter the element or the form_state before the rest
|
||||
* of the date_popup validation gets fired.
|
||||
*/
|
||||
function date_all_day_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
// Let Date module massage the format for all day values so they will pass validation.
|
||||
// The All day flag, if used, actually exists on the parent element.
|
||||
date_all_day_value($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to check if the all day flag is set on the parent of an
|
||||
* element, and adjust the date_format accordingly so the missing time will
|
||||
* not cause validation errors.
|
||||
*/
|
||||
function date_all_day_value(&$element, $form_state) {
|
||||
if (!empty($element['#date_all_day_id'])) {
|
||||
$parents = $element['#parents'];
|
||||
array_pop($parents);
|
||||
$parent_element = drupal_array_get_nested_value($form_state['values'], $parents);
|
||||
if (!empty($parent_element) && !empty($parent_element['all_day'])) {
|
||||
$element['#date_format'] = date_part_format('date', $element['#date_format']);
|
||||
return $parent_element['all_day'];
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_combo_pre_validate_alter().
|
||||
*
|
||||
* This hook lets us alter the element or the form_state before the rest
|
||||
* of the date_combo validation gets fired.
|
||||
*/
|
||||
function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $context) {
|
||||
|
||||
if (!empty($context['item']['all_day'])) {
|
||||
|
||||
$field = $context['field'];
|
||||
|
||||
// If we have an all day flag on this date and the time is empty,
|
||||
// change the format to match the input value so we don't get validation errors.
|
||||
$element['#date_is_all_day'] = TRUE;
|
||||
$element['value']['#date_format'] = date_part_format('date', $element['value']['#date_format']);
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$element['value2']['#date_format'] = date_part_format('date', $element['value2']['#date_format']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_combo_validate_date_start_alter().
|
||||
*
|
||||
* This hook lets us alter the local date objects created by the date_combo validation
|
||||
* before they are converted back to the database timezone and stored.
|
||||
*/
|
||||
function date_all_day_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {
|
||||
|
||||
// If this is an 'All day' value, set the time to midnight.
|
||||
if (!empty($context['element']['#date_is_all_day'])) {
|
||||
$date->setTime(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_combo_validate_date_end_alter().
|
||||
*
|
||||
* This hook lets us alter the local date objects created by the date_combo validation
|
||||
* before they are converted back to the database timezone and stored.
|
||||
*/
|
||||
function date_all_day_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
|
||||
|
||||
// If this is an 'All day' value, set the time to midnight.
|
||||
if (!empty($context['element']['#date_is_all_day'])) {
|
||||
$date->setTime(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_field_widget_info_alter().
|
||||
*
|
||||
* This Field API hook lets us add a new setting to the widgets.
|
||||
*/
|
||||
function date_all_day_field_widget_info_alter(&$info) {
|
||||
// Add a setting to a widget type.
|
||||
$info['date_select']['settings'] += array(
|
||||
'display_all_day' => 0,
|
||||
);
|
||||
$info['date_text']['settings'] += array(
|
||||
'display_all_day' => 0,
|
||||
);
|
||||
if (module_exists('date_popup')) {
|
||||
$info['date_popup']['settings'] += array(
|
||||
'display_all_day' => 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_field_widget_settings_form_alter().
|
||||
*
|
||||
* This hook lets us alter the field settings form by adding a place
|
||||
* to set the value added above.
|
||||
*/
|
||||
function date_all_day_date_field_widget_settings_form_alter(&$form, $context) {
|
||||
|
||||
$field = $context['field'];
|
||||
$instance = $context['instance'];
|
||||
|
||||
$settings = $instance['widget']['settings'];
|
||||
|
||||
$form['display_all_day'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Display all day checkbox'),
|
||||
'#default_value' => $settings['display_all_day'],
|
||||
'#description' => t("Determines whether to display the 'All Day' checkbox to the user."),
|
||||
'#weight' => 8,
|
||||
'#fieldset' => 'date_format',
|
||||
);
|
||||
|
||||
// Hide the option to use the all day checkbox for dates with no time.
|
||||
if (!date_has_time($field['settings']['granularity'])) {
|
||||
$form['display_all_day']['#type'] = 'hidden';
|
||||
$form['display_all_day']['#value'] = 0;
|
||||
}
|
||||
}
|
||||
27
sites/all/modules/contrib/fields/date/date_api/date-rtl.css
Normal file
27
sites/all/modules/contrib/fields/date/date_api/date-rtl.css
Normal file
@@ -0,0 +1,27 @@
|
||||
.container-inline-date > .form-item {
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.container-inline-date .form-item .form-item {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.container-inline-date .form-item input,
|
||||
.container-inline-date .form-item select,
|
||||
.container-inline-date .form-item option {
|
||||
margin-left: 5px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.container-inline-date .date-spacer {
|
||||
margin-left: 0;
|
||||
margin-right: -5px;
|
||||
}
|
||||
|
||||
.form-type-date-select .form-type-select[class$=hour] {
|
||||
margin-right: .75em;
|
||||
}
|
||||
|
||||
#edit-field-settings-granularity .form-type-checkbox {
|
||||
margin-left: .6em;
|
||||
}
|
||||
188
sites/all/modules/contrib/fields/date/date_api/date.css
Normal file
188
sites/all/modules/contrib/fields/date/date_api/date.css
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file
|
||||
* Main stylesheet for Date module.
|
||||
*/
|
||||
|
||||
/* Force start/end dates to float using inline-block, where it works, otherwise inline. */
|
||||
.container-inline-date {
|
||||
clear: both;
|
||||
}
|
||||
.container-inline-date .form-item {
|
||||
float: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container-inline-date > .form-item {
|
||||
display: inline-block;
|
||||
margin-right: 0.5em; /* LTR */
|
||||
margin-bottom: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.container-inline-date .form-item .form-item {
|
||||
float: left; /* LTR */
|
||||
}
|
||||
.container-inline-date .form-item,
|
||||
.container-inline-date .form-item input {
|
||||
width: auto;
|
||||
}
|
||||
.container-inline-date .description {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.container-inline-date .form-item input,
|
||||
.container-inline-date .form-item select,
|
||||
.container-inline-date .form-item option {
|
||||
margin-right: 5px; /* LTR */
|
||||
}
|
||||
|
||||
.container-inline-date .date-spacer {
|
||||
margin-left: -5px; /* LTR */
|
||||
}
|
||||
|
||||
.views-right-60 .container-inline-date div {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container-inline-date .date-timezone .form-item {
|
||||
clear: both;
|
||||
float: none;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* The exposed Views form doesn't need some of these styles */
|
||||
.container-inline-date .date-padding {
|
||||
padding: 10px;
|
||||
float: left;
|
||||
}
|
||||
.views-exposed-form .container-inline-date .date-padding {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Fixes for date popup css so it will behave in Drupal */
|
||||
#calendar_div,
|
||||
#calendar_div td,
|
||||
#calendar_div th {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#calendar_div,
|
||||
.calendar_control,
|
||||
.calendar_links,
|
||||
.calendar_header,
|
||||
.calendar {
|
||||
border-collapse: separate;
|
||||
margin: 0;
|
||||
width: 185px;
|
||||
}
|
||||
|
||||
.calendar td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* formatting for start/end dates in nodes and views */
|
||||
span.date-display-single {
|
||||
}
|
||||
span.date-display-start {
|
||||
}
|
||||
span.date-display-end {
|
||||
}
|
||||
|
||||
.date-prefix-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.date-clear {
|
||||
clear: both;
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.date-no-float {
|
||||
clear: both;
|
||||
float: none;
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.date-float {
|
||||
clear: none;
|
||||
float: left;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Add space between date option checkboxes ('All day' & 'Collect End Date') */
|
||||
.date-float .form-type-checkbox{
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
/* Add space between the date and time portions of the date_select widget. */
|
||||
.form-type-date-select .form-type-select[class$=hour] {
|
||||
margin-left: .75em; /* LTR */
|
||||
}
|
||||
|
||||
.date-container .date-format-delete {
|
||||
float: left;
|
||||
margin-top: 1.8em;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
.date-container .date-format-name {
|
||||
float: left;
|
||||
}
|
||||
.date-container .date-format-type {
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.date-container .select-container {
|
||||
clear: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* Calendar day css */
|
||||
div.date-calendar-day {
|
||||
background: #F3F3F3;
|
||||
border-top: 1px solid #EEE;
|
||||
border-left: 1px solid #EEE;
|
||||
border-right: 1px solid #BBB;
|
||||
border-bottom: 1px solid #BBB;
|
||||
color: #999;
|
||||
float: left;
|
||||
line-height: 1;
|
||||
margin: 6px 10px 0 0;
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
div.date-calendar-day span {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
div.date-calendar-day span.month {
|
||||
background-color: #B5BEBE;
|
||||
color: white;
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
div.date-calendar-day span.day {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.date-calendar-day span.year {
|
||||
font-size: .9em;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* Admin styling */
|
||||
.form-item.form-item-instance-widget-settings-input-format-custom,
|
||||
.form-item.form-item-field-settings-enddate-required {
|
||||
margin-left: 1.3em;
|
||||
}
|
||||
|
||||
#edit-field-settings-granularity .form-type-checkbox {
|
||||
margin-right: .6em; /* LTR */
|
||||
}
|
||||
|
||||
.date-year-range-select {
|
||||
margin-right: 1em;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Administrative page callbacks for the date_api module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create replacement values for deprecated timezone names.
|
||||
*/
|
||||
function _date_timezone_replacement($old) {
|
||||
$replace = array(
|
||||
'Brazil/Acre' => 'America/Rio_Branco',
|
||||
'Brazil/DeNoronha' => 'America/Noronha',
|
||||
'Brazil/East' => 'America/Recife',
|
||||
'Brazil/West' => 'America/Manaus',
|
||||
'Canada/Atlantic' => 'America/Halifax',
|
||||
'Canada/Central' => 'America/Winnipeg',
|
||||
'Canada/East-Saskatchewan' => 'America/Regina',
|
||||
'Canada/Eastern' => 'America/Toronto',
|
||||
'Canada/Mountain' => 'America/Edmonton',
|
||||
'Canada/Newfoundland' => 'America/St_Johns',
|
||||
'Canada/Pacific' => 'America/Vancouver',
|
||||
'Canada/Saskatchewan' => 'America/Regina',
|
||||
'Canada/Yukon' => 'America/Whitehorse',
|
||||
'CET' => 'Europe/Berlin',
|
||||
'Chile/Continental' => 'America/Santiago',
|
||||
'Chile/EasterIsland' => 'Pacific/Easter',
|
||||
'CST6CDT' => 'America/Chicago',
|
||||
'Cuba' => 'America/Havana',
|
||||
'EET' => 'Europe/Bucharest',
|
||||
'Egypt' => 'Africa/Cairo',
|
||||
'Eire' => 'Europe/Belfast',
|
||||
'EST' => 'America/New_York',
|
||||
'EST5EDT' => 'America/New_York',
|
||||
'GB' => 'Europe/London',
|
||||
'GB-Eire' => 'Europe/Belfast',
|
||||
'Etc/GMT' => 'UTC',
|
||||
'Etc/GMT+0' => 'UTC',
|
||||
'Etc/GMT+1' => 'UTC',
|
||||
'Etc/GMT+10' => 'UTC',
|
||||
'Etc/GMT+11' => 'UTC',
|
||||
'Etc/GMT+12' => 'UTC',
|
||||
'Etc/GMT+2' => 'UTC',
|
||||
'Etc/GMT+3' => 'UTC',
|
||||
'Etc/GMT+4' => 'UTC',
|
||||
'Etc/GMT+5' => 'UTC',
|
||||
'Etc/GMT+6' => 'UTC',
|
||||
'Etc/GMT+7' => 'UTC',
|
||||
'Etc/GMT+8' => 'UTC',
|
||||
'Etc/GMT+9' => 'UTC',
|
||||
'Etc/GMT-0' => 'UTC',
|
||||
'Etc/GMT-1' => 'UTC',
|
||||
'Etc/GMT-10' => 'UTC',
|
||||
'Etc/GMT-11' => 'UTC',
|
||||
'Etc/GMT-12' => 'UTC',
|
||||
'Etc/GMT-13' => 'UTC',
|
||||
'Etc/GMT-14' => 'UTC',
|
||||
'Etc/GMT-2' => 'UTC',
|
||||
'Etc/GMT-3' => 'UTC',
|
||||
'Etc/GMT-4' => 'UTC',
|
||||
'Etc/GMT-5' => 'UTC',
|
||||
'Etc/GMT-6' => 'UTC',
|
||||
'Etc/GMT-7' => 'UTC',
|
||||
'Etc/GMT-8' => 'UTC',
|
||||
'Etc/GMT-9' => 'UTC',
|
||||
'Etc/GMT0' => 'UTC',
|
||||
'Etc/Greenwich' => 'UTC',
|
||||
'Etc/UCT' => 'UTC',
|
||||
'Etc/Universal' => 'UTC',
|
||||
'Etc/UTC' => 'UTC',
|
||||
'Etc/Zulu' => 'UTC',
|
||||
'Factory' => 'UTC',
|
||||
'GMT' => 'UTC',
|
||||
'GMT+0' => 'UTC',
|
||||
'GMT-0' => 'UTC',
|
||||
'GMT0' => 'UTC',
|
||||
'Hongkong' => 'Asia/Hong_Kong',
|
||||
'HST' => 'Pacific/Honolulu',
|
||||
'Iceland' => 'Atlantic/Reykjavik',
|
||||
'Iran' => 'Asia/Tehran',
|
||||
'Israel' => 'Asia/Tel_Aviv',
|
||||
'Jamaica' => 'America/Jamaica',
|
||||
'Japan' => 'Asia/Tokyo',
|
||||
'Kwajalein' => 'Pacific/Kwajalein',
|
||||
'Libya' => 'Africa/Tunis',
|
||||
'MET' => 'Europe/Budapest',
|
||||
'Mexico/BajaNorte' => 'America/Tijuana',
|
||||
'Mexico/BajaSur' => 'America/Mazatlan',
|
||||
'Mexico/General' => 'America/Mexico_City',
|
||||
'MST' => 'America/Boise',
|
||||
'MST7MDT' => 'America/Boise',
|
||||
'Navajo' => 'America/Phoenix',
|
||||
'NZ' => 'Pacific/Auckland',
|
||||
'NZ-CHAT' => 'Pacific/Chatham',
|
||||
'Poland' => 'Europe/Warsaw',
|
||||
'Portugal' => 'Europe/Lisbon',
|
||||
'PRC' => 'Asia/Chongqing',
|
||||
'PST8PDT' => 'America/Los_Angeles',
|
||||
'ROC' => 'Asia/Taipei',
|
||||
'ROK' => 'Asia/Seoul',
|
||||
'Singapore' => 'Asia/Singapore',
|
||||
'Turkey' => 'Europe/Istanbul',
|
||||
'US/Alaska' => 'America/Anchorage',
|
||||
'US/Aleutian' => 'America/Adak',
|
||||
'US/Arizona' => 'America/Phoenix',
|
||||
'US/Central' => 'America/Chicago',
|
||||
'US/East-Indiana' => 'America/Indianapolis',
|
||||
'US/Eastern' => 'America/New_York',
|
||||
'US/Hawaii' => 'Pacific/Honolulu',
|
||||
'US/Indiana-Starke' => 'America/Indiana/Knox',
|
||||
'US/Michigan' => 'America/Detroit',
|
||||
'US/Mountain' => 'America/Boise',
|
||||
'US/Pacific' => 'America/Los_Angeles',
|
||||
'US/Pacific-New' => 'America/Los_Angeles',
|
||||
'US/Samoa' => 'Pacific/Samoa',
|
||||
'W-SU' => 'Europe/Moscow',
|
||||
'WET' => 'Europe/Paris',
|
||||
);
|
||||
if (array_key_exists($old, $replace)) {
|
||||
return $replace[$old];
|
||||
}
|
||||
else {
|
||||
return $old;
|
||||
}
|
||||
}
|
||||
17
sites/all/modules/contrib/fields/date/date_api/date_api.info
Normal file
17
sites/all/modules/contrib/fields/date/date_api/date_api.info
Normal file
@@ -0,0 +1,17 @@
|
||||
name = Date API
|
||||
description = A Date API that can be used by other modules.
|
||||
package = Date/Time
|
||||
core = 7.x
|
||||
php = 5.2
|
||||
|
||||
stylesheets[all][] = date.css
|
||||
|
||||
files[] = date_api.module
|
||||
files[] = date_api_sql.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-08-13
|
||||
version = "7.x-2.6"
|
||||
core = "7.x"
|
||||
project = "date"
|
||||
datestamp = "1344850024"
|
||||
|
||||
252
sites/all/modules/contrib/fields/date/date_api/date_api.install
Normal file
252
sites/all/modules/contrib/fields/date/date_api/date_api.install
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the date_api module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper function for setting Date variables.
|
||||
*/
|
||||
function date_api_set_variables() {
|
||||
// Set absolute minimum and maximum year for dates on this site.
|
||||
// There is actually no maximum and minimum year in PHP 5, but a date with
|
||||
// a year less than 0 would result in negative ISO and DATETIME dates,
|
||||
// like -1250-01-01T00:00:00, which probably won't make sense or work
|
||||
// correctly anywhere.
|
||||
// The odd construct of using variable_get() instead of variable_set()
|
||||
// is so we don't accidentally write over an existing value. If
|
||||
// no value is set, variable_get() will set it.
|
||||
variable_get('date_max_year', 4000);
|
||||
variable_get('date_min_year', 1);
|
||||
variable_get('date_php_min_year', 1901);
|
||||
|
||||
// Set an API version in a way that other modules can test for compatibility.
|
||||
variable_set('date_api_version', '7.2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function date_api_requirements($phase) {
|
||||
$requirements = array();
|
||||
|
||||
if ($phase == 'runtime') {
|
||||
$t = get_t();
|
||||
module_load_include('module', 'date_api');
|
||||
$messages = date_api_status();
|
||||
$error_messages = !empty($messages['errors']) ? $messages['errors'] : array();
|
||||
$success_messages = !empty($messages['success']) ? $messages['success'] : array();
|
||||
|
||||
if (!empty($error_messages)) {
|
||||
$requirements['date'] = array(
|
||||
'title' => $t('Date API'),
|
||||
'value' => $t('Missing system date settings'),
|
||||
'description' => implode(' ', array_merge($error_messages, $success_messages)),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
);
|
||||
}
|
||||
else {
|
||||
$requirements['date'] = array(
|
||||
'title' => $t('Date API'),
|
||||
'value' => $t('System date settings'),
|
||||
'description' => implode(' ', $success_messages),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function date_api_install() {
|
||||
// Only set the message if Drupal itself is already installed.
|
||||
if (variable_get('install_task') == 'done') {
|
||||
// Ensure translations don't break at install time.
|
||||
$t = get_t();
|
||||
|
||||
// date_api_set_variables can install date_timezone. The
|
||||
// date_timezone_install() function does a module_enable('date_api'). This
|
||||
// means that date_api_enable() can be called before date_api_install()
|
||||
// finishes! So the date_api schema needs to be installed before this line!
|
||||
date_api_set_variables();
|
||||
|
||||
$message = $t('The Date API requires that you set up the <a href="@regional_settings">site timezone and first day of week settings</a> and the <a href="@regional_date_time">date format settings</a> to function correctly.', array('@regional_settings' => url('admin/config/regional/settings'), '@regional_date_time' => url('admin/config/regional/date-time')));
|
||||
drupal_set_message(filter_xss_admin($message), 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_enable().
|
||||
*/
|
||||
function date_api_enable() {
|
||||
date_api_set_variables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function date_api_uninstall() {
|
||||
cache_clear_all('date_timezone_identifiers_list', 'cache');
|
||||
$variables = array(
|
||||
'date_api_version',
|
||||
'date_min_year',
|
||||
'date_max_year',
|
||||
'date_php_min_year',
|
||||
'date_db_tz_support',
|
||||
'date_api_use_iso8601',
|
||||
);
|
||||
foreach ($variables as $variable) {
|
||||
variable_del($variable);
|
||||
}
|
||||
|
||||
if (db_table_exists('views_display')) {
|
||||
$displays = array(
|
||||
'date_nav',
|
||||
);
|
||||
db_query("DELETE FROM {views_display} WHERE display_plugin IN ('" . implode("','", $displays) . "')");
|
||||
db_query("DELETE FROM {cache_views}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function date_api_update_last_removed() {
|
||||
return 6005;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move old date format data to new date format tables, and delete the old
|
||||
* tables. Insert only values that don't already exist in the new tables, in
|
||||
* case new version of those custom values have already been created.
|
||||
*/
|
||||
function date_api_update_7000() {
|
||||
// Move format data from the old 'date_format_types' table to the new
|
||||
// 'date_format_type' table.
|
||||
if (db_table_exists('date_format_types')) {
|
||||
// Find all the custom entries in the D6 table.
|
||||
$result = db_select('date_format_types', 'old')
|
||||
->fields('old', array('type', 'title', 'locked'))
|
||||
->condition('locked', 0)
|
||||
->execute()
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Iterate over all the old values.
|
||||
foreach ($result as $row) {
|
||||
// See if this value already exists in the new table
|
||||
// (it might have been added manually before this update got run).
|
||||
$count = db_select('date_format_type', 'new')
|
||||
->condition('type', $row['type'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// If the value is missing, insert it.
|
||||
// Do nothing if it already exists, assume the value in the
|
||||
// new table trumps the old values.
|
||||
if (empty($count)) {
|
||||
db_insert('date_format_type')
|
||||
->fields(array(
|
||||
'type' => $row['type'],
|
||||
'title' => $row['title'],
|
||||
'locked' => $row['locked'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the old table.
|
||||
db_drop_table('date_format_types');
|
||||
|
||||
}
|
||||
|
||||
// Move format data from the old 'date_formats' table (which was renamed to
|
||||
// 'd6_date_formats') to the new 'date_formats' table.
|
||||
if (db_table_exists('d6_date_formats')) {
|
||||
// Find all the custom entries in the D6 table.
|
||||
$result = db_select('d6_date_formats', 'old')
|
||||
->fields('old', array('format', 'type', 'locked'))
|
||||
->condition('type', 'custom')
|
||||
->execute()
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Iterate over all the old values.
|
||||
foreach ($result as $row) {
|
||||
// See if this value already exists in the new table (it might have been
|
||||
// added manually before this update got run).
|
||||
$count = db_select('date_formats', 'new')
|
||||
->condition('format', $row['format'])
|
||||
->condition('type', $row['type'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// If the value is missing, insert it. Do nothing if it already exists,
|
||||
// assume the value in the new table trumps the old values.
|
||||
if (empty($count)) {
|
||||
db_insert('date_formats')
|
||||
->fields(array(
|
||||
'format' => $row['format'],
|
||||
'type' => $row['type'],
|
||||
'locked' => $row['locked'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the old table.
|
||||
db_drop_table('d6_date_formats');
|
||||
}
|
||||
|
||||
// Move format data from the old 'date_format_locale' table (which was renamed
|
||||
// to 'd6_date_format_locale') to the new 'date_format_locale' table.
|
||||
if (db_table_exists('d6_date_format_locale')) {
|
||||
// Find all the custom entries in the D6 table.
|
||||
$result = db_select('d6_date_format_locale', 'old')
|
||||
->fields('old', array('format', 'type', 'language'))
|
||||
->condition('type', 'custom')
|
||||
->execute()
|
||||
->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Iterate over all the old values.
|
||||
foreach ($result as $row) {
|
||||
// See if this value already exists in the new table (it might have been
|
||||
// added manually before this update got run).
|
||||
$count = db_select('date_format_locale', 'new')
|
||||
->condition('format', $row['format'])
|
||||
->condition('type', $row['type'])
|
||||
->condition('language', $row['language'])
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
// If the value is missing, insert it.
|
||||
// Do nothing if it already exists, assume the value in the
|
||||
// new table trumps the old values.
|
||||
if (empty($count)) {
|
||||
db_insert('date_format_locale')
|
||||
->fields(array(
|
||||
'format' => $row['format'],
|
||||
'type' => $row['type'],
|
||||
'language' => $row['language'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the old table.
|
||||
db_drop_table('d6_date_format_locale');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drop D6 timezone_name field on {users} after upgrading to D7.
|
||||
*/
|
||||
function date_api_update_7001() {
|
||||
if (db_field_exists('users', 'timezone_name')) {
|
||||
db_drop_field('users', 'timezone_name');
|
||||
}
|
||||
}
|
||||
2707
sites/all/modules/contrib/fields/date/date_api/date_api.module
Normal file
2707
sites/all/modules/contrib/fields/date/date_api/date_api.module
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,752 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Date API elements themes and validation.
|
||||
* This file is only included during the edit process to reduce memory usage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*
|
||||
* Parameters for date form elements, designed to have sane defaults so any
|
||||
* or all can be omitted.
|
||||
*
|
||||
* Fill the element #default_value with a date in datetime format,
|
||||
* (YYYY-MM-DD HH:MM:SS), adjusted to the proper local timezone.
|
||||
*
|
||||
* NOTE - Converting a date stored in the database from UTC to the local zone
|
||||
* and converting it back to UTC before storing it is not handled by this
|
||||
* element and must be done in pre-form and post-form processing!!
|
||||
*
|
||||
* The date_select element will create a collection of form elements, with a
|
||||
* separate select or textfield for each date part. The whole collection will
|
||||
* get reformatted back to a date value of the requested type during validation.
|
||||
*
|
||||
* The date_text element will create a textfield that can contain a whole
|
||||
* date or any part of a date as text. The user input value will be re-formatted
|
||||
* back into a date value of the requested type during validation.
|
||||
*
|
||||
* The date_timezone element will create a drop-down selector to pick a
|
||||
* timezone name.
|
||||
*
|
||||
* The date_year_range element will create two textfields (for users with
|
||||
* JavaScript enabled they will appear as drop-down selectors with an option
|
||||
* for custom text entry) to pick a range of years that will be passed to form
|
||||
* submit handlers as a single string (e.g., -3:+3).
|
||||
*
|
||||
* #date_timezone
|
||||
* The local timezone to be used to create this date.
|
||||
*
|
||||
* #date_format
|
||||
* A format string that describes the format and order of date parts to
|
||||
* display in the edit form for this element. This makes it possible
|
||||
* to show date parts in a custom order, or to leave some of them out.
|
||||
* Be sure to add 'A' or 'a' to get an am/pm selector. Defaults to the
|
||||
* short site default format.
|
||||
*
|
||||
* #date_label_position
|
||||
* Handling option for date part labels, like 'Year', 'Month', and 'Day',
|
||||
* can be 'above' the date part, 'within' it, or 'none', default is 'above' .
|
||||
* The 'within' option shows the label as the first option in a select list
|
||||
* or the default value for an empty textfield, taking up less screen space.
|
||||
*
|
||||
* #date_increment
|
||||
* Increment minutes and seconds by this amount, default is 1.
|
||||
*
|
||||
* #date_year_range
|
||||
* The number of years to go back and forward in a year selector,
|
||||
* default is -3:+3 (3 back and 3 forward).
|
||||
*
|
||||
* #date_text_parts
|
||||
* Array of date parts that should use textfields instead of selects
|
||||
* i.e. array('year') will format the year as a textfield and other
|
||||
* date parts as drop-down selects.
|
||||
*/
|
||||
function _date_api_element_info() {
|
||||
$date_base = array(
|
||||
'#input' => TRUE, '#tree' => TRUE,
|
||||
'#date_timezone' => date_default_timezone(),
|
||||
'#date_flexible' => 0,
|
||||
'#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'),
|
||||
'#date_text_parts' => array(),
|
||||
'#date_increment' => 1,
|
||||
'#date_year_range' => '-3:+3',
|
||||
'#date_label_position' => 'above',
|
||||
);
|
||||
if (module_exists('ctools')) {
|
||||
$date_base['#pre_render'] = array('ctools_dependent_pre_render');
|
||||
}
|
||||
$type['date_select'] = array_merge($date_base, array(
|
||||
'#process' => array('date_select_element_process'),
|
||||
'#theme_wrappers' => array('date_select'),
|
||||
'#value_callback' => 'date_select_element_value_callback',
|
||||
));
|
||||
$type['date_text'] = array_merge($date_base, array(
|
||||
'#process' => array('date_text_element_process'),
|
||||
'#theme_wrappers' => array('date_text'),
|
||||
'#value_callback' => 'date_text_element_value_callback',
|
||||
));
|
||||
$type['date_timezone'] = array(
|
||||
'#input' => TRUE, '#tree' => TRUE,
|
||||
'#process' => array('date_timezone_element_process'),
|
||||
'#theme_wrappers' => array('date_text'),
|
||||
'#value_callback' => 'date_timezone_element_value_callback',
|
||||
);
|
||||
$type['date_year_range'] = array(
|
||||
'#input' => TRUE,
|
||||
'#process' => array('date_year_range_element_process'),
|
||||
'#value_callback' => 'date_year_range_element_value_callback',
|
||||
'#element_validate' => array('date_year_range_validate'),
|
||||
);
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a date object from a datetime string value.
|
||||
*/
|
||||
function date_default_date($element) {
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$default_value = $element['#default_value'];
|
||||
$format = DATE_FORMAT_DATETIME;
|
||||
|
||||
// The text and popup widgets might return less than a full datetime string.
|
||||
if (strlen($element['#default_value']) < 19) {
|
||||
switch (strlen($element['#default_value'])) {
|
||||
case 16:
|
||||
$format = 'Y-m-d H:i';
|
||||
break;
|
||||
case 13:
|
||||
$format = 'Y-m-d H';
|
||||
break;
|
||||
case 10:
|
||||
$format = 'Y-m-d';
|
||||
break;
|
||||
case 7:
|
||||
$format = 'Y-m';
|
||||
break;
|
||||
case 4:
|
||||
$format = 'Y';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$date = new DateObject($default_value, $element['#date_timezone'], $format);
|
||||
if (is_object($date)) {
|
||||
$date->limitGranularity($granularity);
|
||||
if ($date->validGranularity($granularity, $element['#date_flexible'])) {
|
||||
date_increment_round($date, $element['#date_increment']);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process callback which creates a date_year_range form element.
|
||||
*/
|
||||
function date_year_range_element_process($element, &$form_state, $form) {
|
||||
// Year range is stored in the -3:+3 format, but collected as two separate
|
||||
// textfields.
|
||||
$element['years_back'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Starting year'),
|
||||
'#default_value' => $element['#value']['years_back'],
|
||||
'#size' => 10,
|
||||
'#maxsize' => 10,
|
||||
'#attributes' => array('class' => array('select-list-with-custom-option', 'back')),
|
||||
'#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
|
||||
);
|
||||
$element['years_forward'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Ending year'),
|
||||
'#default_value' => $element['#value']['years_forward'],
|
||||
'#size' => 10,
|
||||
'#maxsize' => 10,
|
||||
'#attributes' => array('class' => array('select-list-with-custom-option', 'forward')),
|
||||
'#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
|
||||
);
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#attached']['js'][] = drupal_get_path('module', 'date_api') . '/date_year_range.js';
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_year_range_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for the date_year_range form element.
|
||||
*/
|
||||
function date_year_range_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
// Convert the element's default value from a string to an array (to match
|
||||
// what we will get from the two textfields when the form is submitted).
|
||||
if ($input === FALSE) {
|
||||
list($years_back, $years_forward) = explode(':', $element['#default_value']);
|
||||
return array(
|
||||
'years_back' => $years_back,
|
||||
'years_forward' => $years_forward,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Element validation function for the date_year_range form element.
|
||||
*/
|
||||
function date_year_range_validate(&$element, &$form_state) {
|
||||
// Recombine the two submitted form values into the -3:+3 format we will
|
||||
// validate and save.
|
||||
$year_range_submitted = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
|
||||
$year_range = $year_range_submitted['years_back'] . ':' . $year_range_submitted['years_forward'];
|
||||
drupal_array_set_nested_value($form_state['values'], $element['#parents'], $year_range);
|
||||
if (!date_range_valid($year_range)) {
|
||||
form_error($element['years_back'], t('Starting year must be in the format -9, or an absolute year such as 1980.'));
|
||||
form_error($element['years_forward'], t('Ending year must be in the format +9, or an absolute year such as 2030.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for date_timezone element.
|
||||
*/
|
||||
function date_timezone_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
$return = '';
|
||||
if ($input !== FALSE) {
|
||||
$return = $input;
|
||||
}
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$return = array('timezone' => $element['#default_value']);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a timezone form element.
|
||||
*
|
||||
* @param array $element
|
||||
* The timezone form element.
|
||||
*
|
||||
* @return array
|
||||
* the timezone form element
|
||||
*/
|
||||
function date_timezone_element_process($element, &$form_state, $form) {
|
||||
if (date_hidden_element($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$label = theme('date_part_label_timezone', array('part_type' => 'select', 'element' => $element));
|
||||
$element['timezone'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $element['#date_label_position'] == 'above' ? $label : '',
|
||||
'#options' => date_timezone_names($element['#required']),
|
||||
'#value' => $element['#value'],
|
||||
'#weight' => $element['#weight'],
|
||||
'#required' => $element['#required'],
|
||||
'#theme' => 'date_select_element',
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
);
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_push($element['#element_validate'], 'date_timezone_validate');
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = array('date_timezone_validate');
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_timezone_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for timezone input
|
||||
*
|
||||
* Move the timezone value from the nested field back to the original field.
|
||||
*/
|
||||
function date_timezone_validate($element, &$form_state) {
|
||||
if (date_hidden_element($element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
form_set_value($element, $element['#value']['timezone'], $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for date_text element.
|
||||
*/
|
||||
function date_text_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
$return = array('date' => '');
|
||||
$date = NULL;
|
||||
|
||||
// Normal input from submitting the form element.
|
||||
// Check is_array() to skip the string input values created by Views pagers.
|
||||
// Those string values, if present, should be interpreted as empty input.
|
||||
if ($input != FALSE && is_array($input)) {
|
||||
$return = $input;
|
||||
$date = date_text_input_date($element, $input);
|
||||
}
|
||||
// No input? Try the default value.
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$date = date_default_date($element);
|
||||
}
|
||||
if (date_is_date($date)) {
|
||||
$return['date'] = date_format_date($date, 'custom', $element['#date_format']);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text date input form.
|
||||
*
|
||||
* Display all or part of a date in a single textfield.
|
||||
*
|
||||
* The exact parts displayed in the field are those in #date_granularity.
|
||||
* The display of each part comes from #date_format.
|
||||
*
|
||||
*/
|
||||
function date_text_element_process($element, &$form_state, $form) {
|
||||
if (date_hidden_element($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#theme_wrappers'] = array('date_text');
|
||||
$element['date']['#value'] = $element['#value']['date'];
|
||||
$element['date']['#type'] = 'textfield';
|
||||
$element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
|
||||
$element['date']['#attributes'] = array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-date') : array('date-date'));
|
||||
$now = date_example_date();
|
||||
$element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_format_date(date_example_date(), 'custom', $element['#date_format'])));
|
||||
$element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
|
||||
|
||||
// Keep the system from creating an error message for the sub-element.
|
||||
// We'll set our own message on the parent element.
|
||||
// $element['date']['#required'] = $element['#required'];
|
||||
$element['date']['#theme'] = 'date_textfield_element';
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_push($element['#element_validate'], 'date_text_validate');
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = array('date_text_validate');
|
||||
}
|
||||
if (!empty($element['#force_value'])) {
|
||||
$element['date']['#value'] = $element['date']['#default_value'];
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_text_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for text input.
|
||||
*
|
||||
* When used as a Views widget, the validation step always gets triggered,
|
||||
* even with no form submission. Before form submission $element['#value']
|
||||
* contains a string, after submission it contains an array.
|
||||
*
|
||||
*/
|
||||
function date_text_validate($element, &$form_state) {
|
||||
if (date_hidden_element($element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($element['#value'])) {
|
||||
return;
|
||||
}
|
||||
$input_exists = NULL;
|
||||
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
|
||||
|
||||
drupal_alter('date_text_pre_validate', $element, $form_state, $input);
|
||||
|
||||
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
|
||||
$date = date_text_input_date($element, $input);
|
||||
|
||||
// If the field has errors, display them.
|
||||
// If something was input but there is no date, the date is invalid.
|
||||
// If the field is empty and required, set error message and return.
|
||||
$error_field = implode('][', $element['#parents']);
|
||||
if (empty($date) || !empty($date->errors)) {
|
||||
if (is_object($date) && !empty($date->errors)) {
|
||||
$message = t('The value input for field %field is invalid:', array('%field' => $label));
|
||||
$message .= '<br />' . implode('<br />', $date->errors);
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
if (!empty($element['#required'])) {
|
||||
$message = t('A valid date is required for %title.', array('%title' => $label));
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
// Fall through, some other error.
|
||||
if (!empty($input['date'])) {
|
||||
form_error($element, t('%title is invalid.', array('%title' => $label)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
$value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
|
||||
form_set_value($element, $value, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating a date object out of user input.
|
||||
*/
|
||||
function date_text_input_date($element, $input) {
|
||||
if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
|
||||
return NULL;
|
||||
}
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$date = new DateObject($input['date'], $element['#date_timezone'], $element['#date_format']);
|
||||
if (is_object($date)) {
|
||||
$date->limitGranularity($granularity);
|
||||
if ($date->validGranularity($granularity, $element['#date_flexible'])) {
|
||||
date_increment_round($date, $element['#date_increment']);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element value callback for date_select element.
|
||||
*/
|
||||
function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
|
||||
$return = array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
|
||||
$date = NULL;
|
||||
if ($input !== FALSE) {
|
||||
$return = $input;
|
||||
$date = date_select_input_date($element, $input);
|
||||
}
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$date = date_default_date($element);
|
||||
}
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
|
||||
foreach ($granularity as $field) {
|
||||
if ($field != 'timezone') {
|
||||
$return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flexible date/time drop-down selector.
|
||||
*
|
||||
* Splits date into a collection of date and time sub-elements, one
|
||||
* for each date part. Each sub-element can be either a textfield or a
|
||||
* select, based on the value of ['#date_settings']['text_fields'].
|
||||
*
|
||||
* The exact parts displayed in the field are those in #date_granularity.
|
||||
* The display of each part comes from ['#date_settings']['format'].
|
||||
*
|
||||
*/
|
||||
function date_select_element_process($element, &$form_state, $form) {
|
||||
if (date_hidden_element($element)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$date = NULL;
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
|
||||
if (is_array($element['#default_value'])) {
|
||||
$date = date_select_input_date($element, $element['#default_value']);
|
||||
}
|
||||
elseif (!empty($element['#default_value'])) {
|
||||
$date = date_default_date($element);
|
||||
}
|
||||
|
||||
$element['#tree'] = TRUE;
|
||||
$element['#theme_wrappers'] = array('date_select');
|
||||
|
||||
$element += (array) date_parts_element($element, $date, $element['#date_format']);
|
||||
|
||||
// Store a hidden value for all date parts not in the current display.
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
$formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
|
||||
foreach (date_nongranularity($granularity) as $field) {
|
||||
if ($field != 'timezone') {
|
||||
$element[$field] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (isset($element['#element_validate'])) {
|
||||
array_push($element['#element_validate'], 'date_select_validate');
|
||||
}
|
||||
else {
|
||||
$element['#element_validate'] = array('date_select_validate');
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_select_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates form elements for one or more date parts.
|
||||
*
|
||||
* Get the order of date elements from the provided format.
|
||||
* If the format order omits any date parts in the granularity, alter the
|
||||
* granularity array to match the format, then flip the $order array
|
||||
* to get the position for each element. Then iterate through the
|
||||
* elements and create a sub-form for each part.
|
||||
*
|
||||
* @param array $element
|
||||
* The date element.
|
||||
* @param object $date
|
||||
* The date object.
|
||||
* @param string $format
|
||||
* A date format string.
|
||||
*
|
||||
* @return array
|
||||
* The form array for the submitted date parts.
|
||||
*/
|
||||
function date_parts_element($element, $date, $format) {
|
||||
$granularity = date_format_order($format);
|
||||
$sub_element = array('#granularity' => $granularity);
|
||||
$order = array_flip($granularity);
|
||||
|
||||
$hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
|
||||
$month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
|
||||
$count = 0;
|
||||
$increment = min(intval($element['#date_increment']), 1);
|
||||
|
||||
// Allow empty value as option if date is not required or there is no date.
|
||||
$part_required = (bool) $element['#required'] && is_object($date);
|
||||
foreach ($granularity as $field) {
|
||||
$part_type = in_array($field, $element['#date_text_parts']) ? 'textfield' : 'select';
|
||||
$sub_element[$field] = array(
|
||||
'#weight' => $order[$field],
|
||||
'#required' => $part_required,
|
||||
'#attributes' => array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-' . $field) : array('date-' . $field)),
|
||||
'#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
|
||||
);
|
||||
switch ($field) {
|
||||
case 'year':
|
||||
$range = date_range_years($element['#date_year_range'], $date);
|
||||
$min_year = $range[0];
|
||||
$max_year = $range[1];
|
||||
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('Y') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
|
||||
}
|
||||
break;
|
||||
case 'month':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('n') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = $month_function($part_required);
|
||||
}
|
||||
break;
|
||||
case 'day':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('j') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
|
||||
}
|
||||
break;
|
||||
case 'hour':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format($hours_format) : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_hours($hours_format, $part_required));
|
||||
}
|
||||
$sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
|
||||
break;
|
||||
case 'minute':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('i') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_minutes('i', $part_required, $element['#date_increment']));
|
||||
}
|
||||
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
|
||||
break;
|
||||
case 'second':
|
||||
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('s') : '';
|
||||
if ($part_type == 'select') {
|
||||
$sub_element[$field]['#options'] = drupal_map_assoc(date_seconds('s', $part_required, $element['#date_increment']));
|
||||
}
|
||||
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add handling for the date part label.
|
||||
$label = theme('date_part_label_' . $field, array('part_type' => $part_type, 'element' => $element));
|
||||
if (in_array($field, $element['#date_text_parts'])) {
|
||||
$sub_element[$field]['#type'] = 'textfield';
|
||||
$sub_element[$field]['#theme'] = 'date_textfield_element';
|
||||
$sub_element[$field]['#size'] = 7;
|
||||
if ($element['#date_label_position'] == 'within') {
|
||||
if (!empty($sub_element[$field]['#options']) && is_array($sub_element[$field]['#options'])) {
|
||||
$sub_element[$field]['#options'] = array(
|
||||
'-' . $label => '-' . $label) + $sub_element[$field]['#options'];
|
||||
}
|
||||
if (empty($sub_element[$field]['#default_value'])) {
|
||||
$sub_element[$field]['#default_value'] = '-' . $label;
|
||||
}
|
||||
}
|
||||
elseif ($element['#date_label_position'] != 'none') {
|
||||
$sub_element[$field]['#title'] = $label;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$sub_element[$field]['#type'] = 'select';
|
||||
$sub_element[$field]['#theme'] = 'date_select_element';
|
||||
if ($element['#date_label_position'] == 'within') {
|
||||
$sub_element[$field]['#options'] = array(
|
||||
'' => '-' . $label) + $sub_element[$field]['#options'];
|
||||
}
|
||||
elseif ($element['#date_label_position'] != 'none') {
|
||||
$sub_element[$field]['#title'] = $label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Views exposed filters are treated as submitted even if not,
|
||||
// so force the #default value in that case. Make sure we set
|
||||
// a default that is in the option list.
|
||||
if (!empty($element['#force_value'])) {
|
||||
$options = $sub_element[$field]['#options'];
|
||||
$default = !empty($sub_element[$field]['#default_value']) ? $sub_element[$field]['#default_value'] : array_shift($options);
|
||||
$sub_element[$field]['#value'] = $default;
|
||||
}
|
||||
|
||||
if (($hours_format == 'g' || $hours_format == 'h') && date_has_time($granularity)) {
|
||||
$sub_element['ampm'] = array(
|
||||
'#type' => 'select',
|
||||
'#theme' => 'date_select_element',
|
||||
'#default_value' => is_object($date) ? (date_format($date, 'G') >= 12 ? 'pm' : 'am') : '',
|
||||
'#options' => drupal_map_assoc(date_ampm($part_required)),
|
||||
'#required' => $part_required,
|
||||
'#weight' => 8,
|
||||
'#attributes' => array('class' => array('date-ampm')),
|
||||
);
|
||||
if ($element['#date_label_position'] == 'within') {
|
||||
$sub_element['ampm']['#options'] = array('' => '-' . theme('date_part_label_ampm', array('part_type' => 'ampm', 'eleement' => $element))) + $sub_element['ampm']['#options'];
|
||||
}
|
||||
elseif ($element['#date_label_position'] != 'none') {
|
||||
$sub_element['ampm']['#title'] = theme('date_part_label_ampm', array('part_type' => 'ampm', 'element' => $element));
|
||||
}
|
||||
}
|
||||
|
||||
return $sub_element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation function for date selector.
|
||||
*
|
||||
* When used as a Views widget, the validation step always gets triggered,
|
||||
* even with no form submission. Before form submission $element['#value']
|
||||
* contains a string, after submission it contains an array.
|
||||
*/
|
||||
function date_select_validate($element, &$form_state) {
|
||||
if (date_hidden_element($element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($element['#value'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$input_exists = NULL;
|
||||
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
|
||||
|
||||
// Strip field labels out of the results.
|
||||
foreach ($element['#value'] as $field => $field_value) {
|
||||
if (substr($field_value, 0, 1) == '-') {
|
||||
$input[$field] = '';
|
||||
}
|
||||
}
|
||||
|
||||
drupal_alter('date_select_pre_validate', $element, $form_state, $input);
|
||||
|
||||
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
|
||||
if (isset($input['ampm'])) {
|
||||
if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
|
||||
$input['hour'] += 12;
|
||||
}
|
||||
elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
|
||||
$input['hour'] -= 12;
|
||||
}
|
||||
}
|
||||
unset($input['ampm']);
|
||||
$date = date_select_input_date($element, $input);
|
||||
|
||||
// If the field has errors, display them.
|
||||
$error_field = implode('][', $element['#parents']);
|
||||
$entered = array_values(array_filter($input));
|
||||
if (empty($date) || !empty($date->errors)) {
|
||||
// The input created a date but it has errors.
|
||||
if (is_object($date) && !empty($date->errors)) {
|
||||
$message = t('The value input for field %field is invalid:', array('%field' => $label));
|
||||
$message .= '<br />' . implode('<br />', $date->errors);
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
// Nothing was entered but the date is required.
|
||||
elseif (empty($entered) && $element['#required']) {
|
||||
$message = t('A valid date is required for %title.', array('%title' => $label));
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
// Something was input but it wasn't enough to create a valid date.
|
||||
elseif (!empty($entered)) {
|
||||
$message = t('The value input for field %field is invalid.', array('%field' => $label));
|
||||
form_set_error($error_field, $message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
|
||||
form_set_value($element, $value, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating a date object out of user input.
|
||||
*/
|
||||
function date_select_input_date($element, $input) {
|
||||
|
||||
// Was anything entered? If not, we have no date.
|
||||
if (!is_array($input)) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
$entered = array_values(array_filter($input));
|
||||
if (empty($entered)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
$granularity = date_format_order($element['#date_format']);
|
||||
if (isset($input['ampm'])) {
|
||||
if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
|
||||
$input['hour'] += 12;
|
||||
}
|
||||
elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
|
||||
$input['hour'] -= 12;
|
||||
}
|
||||
}
|
||||
unset($input['ampm']);
|
||||
|
||||
// Make the input match the granularity.
|
||||
foreach (date_nongranularity($granularity) as $part) {
|
||||
unset($input[$part]);
|
||||
}
|
||||
|
||||
$date = new DateObject($input, $element['#date_timezone']);
|
||||
if (is_object($date)) {
|
||||
$date->limitGranularity($granularity);
|
||||
if ($date->validGranularity($granularity, $element['#date_flexible'])) {
|
||||
date_increment_round($date, $element['#date_increment']);
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
803
sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
Normal file
803
sites/all/modules/contrib/fields/date/date_api/date_api_ical.inc
Normal file
@@ -0,0 +1,803 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Parse iCal data.
|
||||
*
|
||||
* This file must be included when these functions are needed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return an array of iCalendar information from an iCalendar file.
|
||||
*
|
||||
* No timezone adjustment is performed in the import since the timezone
|
||||
* conversion needed will vary depending on whether the value is being
|
||||
* imported into the database (when it needs to be converted to UTC), is being
|
||||
* viewed on a site that has user-configurable timezones (when it needs to be
|
||||
* converted to the user's timezone), if it needs to be converted to the
|
||||
* site timezone, or if it is a date without a timezone which should not have
|
||||
* any timezone conversion applied.
|
||||
*
|
||||
* Properties that have dates and times are converted to sub-arrays like:
|
||||
* 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted
|
||||
* 'all_day' => whether this is an all-day event
|
||||
* 'tz' => the timezone of the date, could be blank for absolute
|
||||
* times that should get no timezone conversion.
|
||||
*
|
||||
* Exception dates can have muliple values and are returned as arrays
|
||||
* like the above for each exception date.
|
||||
*
|
||||
* Most other properties are returned as PROPERTY => VALUE.
|
||||
*
|
||||
* Each item in the VCALENDAR will return an array like:
|
||||
* [0] => Array (
|
||||
* [TYPE] => VEVENT
|
||||
* [UID] => 104
|
||||
* [SUMMARY] => An example event
|
||||
* [URL] => http://example.com/node/1
|
||||
* [DTSTART] => Array (
|
||||
* [datetime] => 1997-09-07 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [DTEND] => Array (
|
||||
* [datetime] => 1997-09-07 11:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [RRULE] => Array (
|
||||
* [FREQ] => Array (
|
||||
* [0] => MONTHLY
|
||||
* )
|
||||
* [BYDAY] => Array (
|
||||
* [0] => 1SU
|
||||
* [1] => -1SU
|
||||
* )
|
||||
* )
|
||||
* [EXDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* [RDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @todo
|
||||
* figure out how to handle this if subgroups are nested,
|
||||
* like a VALARM nested inside a VEVENT.
|
||||
*
|
||||
* @param string $filename
|
||||
* Location (local or remote) of a valid iCalendar file.
|
||||
*
|
||||
* @return array
|
||||
* An array with all the elements from the ical.
|
||||
*/
|
||||
function date_ical_import($filename) {
|
||||
// Fetch the iCal data. If file is a URL, use drupal_http_request. fopen
|
||||
// isn't always configured to allow network connections.
|
||||
if (substr($filename, 0, 4) == 'http') {
|
||||
// Fetch the ical data from the specified network location.
|
||||
$icaldatafetch = drupal_http_request($filename);
|
||||
// Check the return result.
|
||||
if ($icaldatafetch->error) {
|
||||
watchdog('date ical', 'HTTP Request Error importing %filename: @error', array('%filename' => $filename, '@error' => $icaldatafetch->error));
|
||||
return FALSE;
|
||||
}
|
||||
// Break the return result into one array entry per lines.
|
||||
$icaldatafolded = explode("\n", $icaldatafetch->data);
|
||||
}
|
||||
else {
|
||||
$icaldatafolded = @file($filename, FILE_IGNORE_NEW_LINES);
|
||||
if ($icaldatafolded === FALSE) {
|
||||
watchdog('date ical', 'Failed to open file: %filename', array('%filename' => $filename));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// Verify this is iCal data.
|
||||
if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
|
||||
watchdog('date ical', 'Invalid calendar file: %filename', array('%filename' => $filename));
|
||||
return FALSE;
|
||||
}
|
||||
return date_ical_parse($icaldatafolded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of iCalendar information from an iCalendar file.
|
||||
*
|
||||
* As date_ical_import() but different param.
|
||||
*
|
||||
* @param array $icaldatafolded
|
||||
* An array of lines from an ical feed.
|
||||
*
|
||||
* @return array
|
||||
* An array with all the elements from the ical.
|
||||
*/
|
||||
function date_ical_parse($icaldatafolded = array()) {
|
||||
$items = array();
|
||||
|
||||
// Verify this is iCal data.
|
||||
if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
|
||||
watchdog('date ical', 'Invalid calendar file.');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// "Unfold" wrapped lines.
|
||||
$icaldata = array();
|
||||
foreach ($icaldatafolded as $line) {
|
||||
$out = array();
|
||||
// See if this looks like the beginning of a new property or value. If not,
|
||||
// it is a continuation of the previous line. The regex is to ensure that
|
||||
// wrapped QUOTED-PRINTABLE data is kept intact.
|
||||
if (!preg_match('/([A-Z]+)[:;](.*)/', $line, $out)) {
|
||||
// Trim up to 1 leading space from wrapped line per iCalendar standard.
|
||||
$line = array_pop($icaldata) . (ltrim(substr($line, 0, 1)) . substr($line, 1));
|
||||
}
|
||||
$icaldata[] = $line;
|
||||
}
|
||||
unset($icaldatafolded);
|
||||
|
||||
// Parse the iCal information.
|
||||
$parents = array();
|
||||
$subgroups = array();
|
||||
$vcal = '';
|
||||
foreach ($icaldata as $line) {
|
||||
$line = trim($line);
|
||||
$vcal .= $line . "\n";
|
||||
// Deal with begin/end tags separately.
|
||||
if (preg_match('/(BEGIN|END):V(\S+)/', $line, $matches)) {
|
||||
$closure = $matches[1];
|
||||
$type = 'V' . $matches[2];
|
||||
if ($closure == 'BEGIN') {
|
||||
array_push($parents, $type);
|
||||
array_push($subgroups, array());
|
||||
}
|
||||
elseif ($closure == 'END') {
|
||||
end($subgroups);
|
||||
$subgroup = &$subgroups[key($subgroups)];
|
||||
switch ($type) {
|
||||
case 'VCALENDAR':
|
||||
if (prev($subgroups) == FALSE) {
|
||||
$items[] = array_pop($subgroups);
|
||||
}
|
||||
else {
|
||||
$parent[array_pop($parents)][] = array_pop($subgroups);
|
||||
}
|
||||
break;
|
||||
// Add the timezones in with their index their TZID.
|
||||
case 'VTIMEZONE':
|
||||
$subgroup = end($subgroups);
|
||||
$id = $subgroup['TZID'];
|
||||
unset($subgroup['TZID']);
|
||||
|
||||
// Append this subgroup onto the one above it.
|
||||
prev($subgroups);
|
||||
$parent = &$subgroups[key($subgroups)];
|
||||
|
||||
$parent[$type][$id] = $subgroup;
|
||||
|
||||
array_pop($subgroups);
|
||||
array_pop($parents);
|
||||
break;
|
||||
// Do some fun stuff with durations and all_day events and then append
|
||||
// to parent.
|
||||
case 'VEVENT':
|
||||
case 'VALARM':
|
||||
case 'VTODO':
|
||||
case 'VJOURNAL':
|
||||
case 'VVENUE':
|
||||
case 'VFREEBUSY':
|
||||
default:
|
||||
// Can't be sure whether DTSTART is before or after DURATION, so
|
||||
// parse DURATION at the end.
|
||||
if (isset($subgroup['DURATION'])) {
|
||||
date_ical_parse_duration($subgroup, 'DURATION');
|
||||
}
|
||||
// Add a top-level indication for the 'All day' condition. Leave it
|
||||
// in the individual date components, too, so it is always available
|
||||
// even when you are working with only a portion of the VEVENT
|
||||
// array, like in Feed API parsers.
|
||||
$subgroup['all_day'] = FALSE;
|
||||
|
||||
// iCal spec states 'The "DTEND" property for a "VEVENT" calendar
|
||||
// component specifies the non-inclusive end of the event'. Adjust
|
||||
// multi-day events to remove the extra day because the Date code
|
||||
// assumes the end date is inclusive.
|
||||
if (!empty($subgroup['DTEND']) && (!empty($subgroup['DTEND']['all_day']))) {
|
||||
// Make the end date one day earlier.
|
||||
$date = new DateObject ($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
|
||||
date_modify($date, '-1 day');
|
||||
$subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
|
||||
}
|
||||
// If a start datetime is defined AND there is no definition for
|
||||
// the end datetime THEN make the end datetime equal the start
|
||||
// datetime and if it is an all day event define the entire event
|
||||
// as a single all day event.
|
||||
if (!empty($subgroup['DTSTART']) &&
|
||||
(empty($subgroup['DTEND']) && empty($subgroup['RRULE']) && empty($subgroup['RRULE']['COUNT']))) {
|
||||
$subgroup['DTEND'] = $subgroup['DTSTART'];
|
||||
}
|
||||
// Add this element to the parent as an array under the component
|
||||
// name.
|
||||
if (!empty($subgroup['DTSTART']['all_day'])) {
|
||||
$subgroup['all_day'] = TRUE;
|
||||
}
|
||||
// Add this element to the parent as an array under the
|
||||
prev($subgroups);
|
||||
$parent = &$subgroups[key($subgroups)];
|
||||
|
||||
$parent[$type][] = $subgroup;
|
||||
|
||||
array_pop($subgroups);
|
||||
array_pop($parents);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle all other possibilities.
|
||||
else {
|
||||
// Grab current subgroup.
|
||||
end($subgroups);
|
||||
$subgroup = &$subgroups[key($subgroups)];
|
||||
|
||||
// Split up the line into nice pieces for PROPERTYNAME,
|
||||
// PROPERTYATTRIBUTES, and PROPERTYVALUE.
|
||||
preg_match('/([^;:]+)(?:;([^:]*))?:(.+)/', $line, $matches);
|
||||
$name = !empty($matches[1]) ? strtoupper(trim($matches[1])) : '';
|
||||
$field = !empty($matches[2]) ? $matches[2] : '';
|
||||
$data = !empty($matches[3]) ? $matches[3] : '';
|
||||
$parse_result = '';
|
||||
switch ($name) {
|
||||
// Keep blank lines out of the results.
|
||||
case '':
|
||||
break;
|
||||
|
||||
// Lots of properties have date values that must be parsed out.
|
||||
case 'CREATED':
|
||||
case 'LAST-MODIFIED':
|
||||
case 'DTSTART':
|
||||
case 'DTEND':
|
||||
case 'DTSTAMP':
|
||||
case 'FREEBUSY':
|
||||
case 'DUE':
|
||||
case 'COMPLETED':
|
||||
$parse_result = date_ical_parse_date($field, $data);
|
||||
break;
|
||||
|
||||
case 'EXDATE':
|
||||
case 'RDATE':
|
||||
$parse_result = date_ical_parse_exceptions($field, $data);
|
||||
break;
|
||||
|
||||
case 'TRIGGER':
|
||||
// A TRIGGER can either be a date or in the form -PT1H.
|
||||
if (!empty($field)) {
|
||||
$parse_result = date_ical_parse_date($field, $data);
|
||||
}
|
||||
else {
|
||||
$parse_result = array('DATA' => $data);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DURATION':
|
||||
// Can't be sure whether DTSTART is before or after DURATION in
|
||||
// the VEVENT, so store the data and parse it at the end.
|
||||
$parse_result = array('DATA' => $data);
|
||||
break;
|
||||
|
||||
case 'RRULE':
|
||||
case 'EXRULE':
|
||||
$parse_result = date_ical_parse_rrule($field, $data);
|
||||
break;
|
||||
|
||||
case 'STATUS':
|
||||
case 'SUMMARY':
|
||||
case 'DESCRIPTION':
|
||||
$parse_result = date_ical_parse_text($field, $data);
|
||||
break;
|
||||
|
||||
case 'LOCATION':
|
||||
$parse_result = date_ical_parse_location($field, $data);
|
||||
break;
|
||||
|
||||
// For all other properties, just store the property and the value.
|
||||
// This can be expanded on in the future if other properties should
|
||||
// be given special treatment.
|
||||
default:
|
||||
$parse_result = $data;
|
||||
break;
|
||||
}
|
||||
|
||||
// Store the result of our parsing.
|
||||
$subgroup[$name] = $parse_result;
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a ical date element.
|
||||
*
|
||||
* Possible formats to parse include:
|
||||
* PROPERTY:YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* PROPERTY;VALUE=DATE:YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* PROPERTY;VALUE=DATE-TIME:YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* PROPERTY;TZID=XXXXXXXX;VALUE=DATE:YYYYMMDD[T][HH][MM][SS]
|
||||
* PROPERTY;TZID=XXXXXXXX:YYYYMMDD[T][HH][MM][SS]
|
||||
*
|
||||
* The property and the colon before the date are removed in the import
|
||||
* process above and we are left with $field and $data.
|
||||
*
|
||||
* @param string $field
|
||||
* The text before the colon and the date, i.e.
|
||||
* ';VALUE=DATE:', ';VALUE=DATE-TIME:', ';TZID='
|
||||
* @param string $data
|
||||
* The date itself, after the colon, in the format YYYYMMDD[T][HH][MM][SS][Z]
|
||||
* 'Z', if supplied, means the date is in UTC.
|
||||
*
|
||||
* @return array
|
||||
* $items array, consisting of:
|
||||
* 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted
|
||||
* 'all_day' => whether this is an all-day event with no time
|
||||
* 'tz' => the timezone of the date, could be blank if the ical
|
||||
* has no timezone; the ical specs say no timezone
|
||||
* conversion should be done if no timezone info is
|
||||
* supplied
|
||||
* @todo
|
||||
* Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
|
||||
* period may include a duration, or a date and a duration, or two dates, so
|
||||
* would have to be split into parts and run through date_ical_parse_date()
|
||||
* and date_ical_parse_duration(). This is not commonly used, so ignored for
|
||||
* now. It will take more work to figure how to support that.
|
||||
*/
|
||||
function date_ical_parse_date($field, $data) {
|
||||
|
||||
$items = array('datetime' => '', 'all_day' => '', 'tz' => '');
|
||||
if (empty($data)) {
|
||||
return $items;
|
||||
}
|
||||
// Make this a little more whitespace independent.
|
||||
$data = trim($data);
|
||||
|
||||
// Turn the properties into a nice indexed array of
|
||||
// array(PROPERTYNAME => PROPERTYVALUE);
|
||||
$field_parts = preg_split('/[;:]/', $field);
|
||||
$properties = array();
|
||||
foreach ($field_parts as $part) {
|
||||
if (strpos($part, '=') !== FALSE) {
|
||||
$tmp = explode('=', $part);
|
||||
$properties[$tmp[0]] = $tmp[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Make this a little more whitespace independent.
|
||||
$data = trim($data);
|
||||
|
||||
// Record if a time has been found.
|
||||
$has_time = FALSE;
|
||||
|
||||
// If a format is specified, parse it according to that format.
|
||||
if (isset($properties['VALUE'])) {
|
||||
switch ($properties['VALUE']) {
|
||||
case 'DATE':
|
||||
preg_match(DATE_REGEX_ICAL_DATE, $data, $regs);
|
||||
// Date.
|
||||
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
|
||||
break;
|
||||
case 'DATE-TIME':
|
||||
preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
|
||||
// Date.
|
||||
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
|
||||
// Time.
|
||||
$datetime .= ' ' . date_pad($regs[4]) . ':' . date_pad($regs[5]) . ':' . date_pad($regs[6]);
|
||||
$has_time = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If no format is specified, attempt a loose match.
|
||||
else {
|
||||
preg_match(DATE_REGEX_LOOSE, $data, $regs);
|
||||
if (!empty($regs) && count($regs) > 2) {
|
||||
// Date.
|
||||
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
|
||||
if (isset($regs[4])) {
|
||||
$has_time = TRUE;
|
||||
// Time.
|
||||
$datetime .= ' ' . (!empty($regs[5]) ? date_pad($regs[5]) : '00') .
|
||||
':' . (!empty($regs[6]) ? date_pad($regs[6]) : '00') .
|
||||
':' . (!empty($regs[7]) ? date_pad($regs[7]) : '00');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use timezone if explicitly declared.
|
||||
if (isset($properties['TZID'])) {
|
||||
$tz = $properties['TZID'];
|
||||
// Fix alternatives like US-Eastern which should be US/Eastern.
|
||||
$tz = str_replace('-', '/', $tz);
|
||||
// Unset invalid timezone names.
|
||||
module_load_include('inc', 'date_api', 'date_api.admin');
|
||||
$tz = _date_timezone_replacement($tz);
|
||||
if (!date_timezone_is_valid($tz)) {
|
||||
$tz = '';
|
||||
}
|
||||
}
|
||||
// If declared as UTC with terminating 'Z', use that timezone.
|
||||
elseif (strpos($data, 'Z') !== FALSE) {
|
||||
$tz = 'UTC';
|
||||
}
|
||||
// Otherwise this date is floating.
|
||||
else {
|
||||
$tz = '';
|
||||
}
|
||||
|
||||
$items['datetime'] = $datetime;
|
||||
$items['all_day'] = $has_time ? FALSE : TRUE;
|
||||
$items['tz'] = $tz;
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an ical repeat rule.
|
||||
*
|
||||
* @return array
|
||||
* Array in the form of PROPERTY => array(VALUES)
|
||||
* PROPERTIES include FREQ, INTERVAL, COUNT, BYDAY, BYMONTH, BYYEAR, UNTIL
|
||||
*/
|
||||
function date_ical_parse_rrule($field, $data) {
|
||||
$data = preg_replace("/RRULE.*:/", '', $data);
|
||||
$items = array('DATA' => $data);
|
||||
$rrule = explode(';', $data);
|
||||
foreach ($rrule as $key => $value) {
|
||||
$param = explode('=', $value);
|
||||
// Must be some kind of invalid data.
|
||||
if (count($param) != 2) {
|
||||
continue;
|
||||
}
|
||||
if ($param[0] == 'UNTIL') {
|
||||
$values = date_ical_parse_date('', $param[1]);
|
||||
}
|
||||
else {
|
||||
$values = explode(',', $param[1]);
|
||||
}
|
||||
// Treat items differently if they have multiple or single values.
|
||||
if (in_array($param[0], array('FREQ', 'INTERVAL', 'COUNT', 'WKST'))) {
|
||||
$items[$param[0]] = $param[1];
|
||||
}
|
||||
else {
|
||||
$items[$param[0]] = $values;
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse exception dates (can be multiple values).
|
||||
*
|
||||
* @return array
|
||||
* an array of date value arrays.
|
||||
*/
|
||||
function date_ical_parse_exceptions($field, $data) {
|
||||
$data = str_replace($field . ':', '', $data);
|
||||
$items = array('DATA' => $data);
|
||||
$ex_dates = explode(',', $data);
|
||||
foreach ($ex_dates as $ex_date) {
|
||||
$items[] = date_ical_parse_date('', $ex_date);
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the duration of the event.
|
||||
*
|
||||
* Example:
|
||||
* DURATION:PT1H30M
|
||||
* DURATION:P1Y2M
|
||||
*
|
||||
* @param array $subgroup
|
||||
* Array of other values in the vevent so we can check for DTSTART.
|
||||
*/
|
||||
function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
|
||||
$items = $subgroup[$field];
|
||||
$data = $items['DATA'];
|
||||
preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
|
||||
$items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
|
||||
$items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
|
||||
$items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
|
||||
$items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
|
||||
$items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
|
||||
$items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
|
||||
$items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
|
||||
$start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
|
||||
$timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone');
|
||||
if (empty($timezone)) {
|
||||
$timezone = 'UTC';
|
||||
}
|
||||
$date = new DateObject($start_date, $timezone);
|
||||
$date2 = clone($date);
|
||||
foreach ($items as $item => $count) {
|
||||
if ($count > 0) {
|
||||
date_modify($date2, '+' . $count . ' ' . $item);
|
||||
}
|
||||
}
|
||||
$format = isset($subgroup['DTSTART']['type']) && $subgroup['DTSTART']['type'] == 'DATE' ? 'Y-m-d' : 'Y-m-d H:i:s';
|
||||
$subgroup['DTEND'] = array(
|
||||
'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
|
||||
'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
|
||||
'tz' => $timezone,
|
||||
);
|
||||
$duration = date_format($date2, 'U') - date_format($date, 'U');
|
||||
$subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and clean up ical text elements.
|
||||
*/
|
||||
function date_ical_parse_text($field, $data) {
|
||||
if (strstr($field, 'QUOTED-PRINTABLE')) {
|
||||
$data = quoted_printable_decode($data);
|
||||
}
|
||||
// Strip line breaks within element.
|
||||
$data = str_replace(array("\r\n ", "\n ", "\r "), '', $data);
|
||||
// Put in line breaks where encoded.
|
||||
$data = str_replace(array("\\n", "\\N"), "\n", $data);
|
||||
// Remove other escaping.
|
||||
$data = stripslashes($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse location elements.
|
||||
*
|
||||
* Catch situations like the upcoming.org feed that uses
|
||||
* LOCATION;VENUE-UID="http://upcoming.yahoo.com/venue/104/":111 First Street...
|
||||
* or more normal LOCATION;UID=123:111 First Street...
|
||||
* Upcoming feed would have been improperly broken on the ':' in http://
|
||||
* so we paste the $field and $data back together first.
|
||||
*
|
||||
* Use non-greedy check for ':' in case there are more of them in the address.
|
||||
*/
|
||||
function date_ical_parse_location($field, $data) {
|
||||
if (preg_match('/UID=[?"](.+)[?"][*?:](.+)/', $field . ':' . $data, $matches)) {
|
||||
$location = array();
|
||||
$location['UID'] = $matches[1];
|
||||
$location['DESCRIPTION'] = stripslashes($matches[2]);
|
||||
return $location;
|
||||
}
|
||||
else {
|
||||
// Remove other escaping.
|
||||
$location = stripslashes($data);
|
||||
return $location;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a date object for the ical date, adjusted to its local timezone.
|
||||
*
|
||||
* @param array $ical_date
|
||||
* An array of ical date information created in the ical import.
|
||||
* @param string $to_tz
|
||||
* The timezone to convert the date's value to.
|
||||
*
|
||||
* @return object
|
||||
* A timezone-adjusted date object.
|
||||
*/
|
||||
function date_ical_date($ical_date, $to_tz = FALSE) {
|
||||
|
||||
// If the ical date has no timezone, must assume it is stateless
|
||||
// so treat it as a local date.
|
||||
if (empty($ical_date['datetime'])) {
|
||||
return NULL;
|
||||
}
|
||||
elseif (empty($ical_date['tz'])) {
|
||||
$from_tz = date_default_timezone();
|
||||
}
|
||||
else {
|
||||
$from_tz = $ical_date['tz'];
|
||||
}
|
||||
if (strlen($ical_date['datetime']) < 11) {
|
||||
$ical_date['datetime'] .= ' 00:00:00';
|
||||
}
|
||||
$date = new DateObject($ical_date['datetime'], new DateTimeZone($from_tz));
|
||||
|
||||
if ($to_tz && $ical_date['tz'] != '' && $to_tz != $ical_date['tz']) {
|
||||
date_timezone_set($date, timezone_open($to_tz));
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape #text elements for safe iCal use.
|
||||
*
|
||||
* @param string $text
|
||||
* Text to escape
|
||||
*
|
||||
* @return string
|
||||
* Escaped text
|
||||
*
|
||||
*/
|
||||
function date_ical_escape_text($text) {
|
||||
$text = drupal_html_to_text($text);
|
||||
$text = trim($text);
|
||||
// TODO Per #38130 the iCal specs don't want : and " escaped
|
||||
// but there was some reason for adding this in. Need to watch
|
||||
// this and see if anything breaks.
|
||||
// $text = str_replace('"', '\"', $text);
|
||||
// $text = str_replace(":", "\:", $text);
|
||||
$text = preg_replace("/\\\b/", "\\\\", $text);
|
||||
$text = str_replace(",", "\,", $text);
|
||||
$text = str_replace(";", "\;", $text);
|
||||
$text = str_replace("\n", "\\n ", $text);
|
||||
return trim($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an iCal RULE from $form_values.
|
||||
*
|
||||
* @param array $form_values
|
||||
* An array constructed like the one created by date_ical_parse_rrule().
|
||||
* [RRULE] => Array (
|
||||
* [FREQ] => Array (
|
||||
* [0] => MONTHLY
|
||||
* )
|
||||
* [BYDAY] => Array (
|
||||
* [0] => 1SU
|
||||
* [1] => -1SU
|
||||
* )
|
||||
* [UNTIL] => Array (
|
||||
* [datetime] => 1997-21-31 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* [EXDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
* [RDATE] => Array (
|
||||
* [0] = Array (
|
||||
* [datetime] => 1997-09-21 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* [1] = Array (
|
||||
* [datetime] => 1997-10-05 09:00:00
|
||||
* [all_day] => 0
|
||||
* [tz] => US/Eastern
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
function date_api_ical_build_rrule($form_values) {
|
||||
$RRULE = '';
|
||||
if (empty($form_values) || !is_array($form_values)) {
|
||||
return $RRULE;
|
||||
}
|
||||
|
||||
// Grab the RRULE data and put them into iCal RRULE format.
|
||||
$RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
|
||||
$RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
|
||||
|
||||
// Unset the empty 'All' values.
|
||||
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
|
||||
unset($form_values['BYDAY']['']);
|
||||
}
|
||||
if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
|
||||
unset($form_values['BYMONTH']['']);
|
||||
}
|
||||
if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
|
||||
unset($form_values['BYMONTHDAY']['']);
|
||||
}
|
||||
|
||||
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
|
||||
$RRULE .= ';BYDAY=' . $BYDAY;
|
||||
}
|
||||
if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
|
||||
$RRULE .= ';BYMONTH=' . $BYMONTH;
|
||||
}
|
||||
if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
|
||||
$RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
|
||||
}
|
||||
// The UNTIL date is supposed to always be expressed in UTC.
|
||||
// The input date values may already have been converted to a date object on a
|
||||
// previous pass, so check for that.
|
||||
if (array_key_exists('UNTIL', $form_values) && array_key_exists('datetime', $form_values['UNTIL']) && !empty($form_values['UNTIL']['datetime'])) {
|
||||
// We only collect a date for UNTIL, but we need it to be inclusive, so
|
||||
// force it to a full datetime element at the last second of the day.
|
||||
if (!is_object($form_values['UNTIL']['datetime'])) {
|
||||
// If this is a date without time, give it time.
|
||||
if (strlen($form_values['UNTIL']['datetime']) < 11) {
|
||||
$form_values['UNTIL']['datetime'] .= ' 23:59:59';
|
||||
$form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
|
||||
$form_values['UNTIL']['all_day'] = FALSE;
|
||||
}
|
||||
$until = date_ical_date($form_values['UNTIL'], 'UTC');
|
||||
}
|
||||
else {
|
||||
$until = $form_values['UNTIL']['datetime'];
|
||||
}
|
||||
$RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
|
||||
}
|
||||
// Our form doesn't allow a value for COUNT, but it may be needed by
|
||||
// modules using the API, so add it to the rule.
|
||||
if (array_key_exists('COUNT', $form_values)) {
|
||||
$RRULE .= ';COUNT=' . $form_values['COUNT'];
|
||||
}
|
||||
|
||||
// iCal rules presume the week starts on Monday unless otherwise specified,
|
||||
// so we'll specify it.
|
||||
if (array_key_exists('WKST', $form_values)) {
|
||||
$RRULE .= ';WKST=' . $form_values['WKST'];
|
||||
}
|
||||
else {
|
||||
$RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
|
||||
}
|
||||
|
||||
// Exceptions dates go last, on their own line.
|
||||
// The input date values may already have been converted to a date
|
||||
// object on a previous pass, so check for that.
|
||||
if (isset($form_values['EXDATE']) && is_array($form_values['EXDATE'])) {
|
||||
$ex_dates = array();
|
||||
foreach ($form_values['EXDATE'] as $value) {
|
||||
if (!empty($value['datetime'])) {
|
||||
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
|
||||
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
|
||||
if (!empty($ex_date)) {
|
||||
$ex_dates[] = $ex_date;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($ex_dates)) {
|
||||
sort($ex_dates);
|
||||
$RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
|
||||
}
|
||||
}
|
||||
elseif (!empty($form_values['EXDATE'])) {
|
||||
$RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
|
||||
}
|
||||
|
||||
// Exceptions dates go last, on their own line.
|
||||
if (isset($form_values['RDATE']) && is_array($form_values['RDATE'])) {
|
||||
$ex_dates = array();
|
||||
foreach ($form_values['RDATE'] as $value) {
|
||||
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
|
||||
$ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
|
||||
if (!empty($ex_date)) {
|
||||
$ex_dates[] = $ex_date;
|
||||
}
|
||||
}
|
||||
if (!empty($ex_dates)) {
|
||||
sort($ex_dates);
|
||||
$RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
|
||||
}
|
||||
}
|
||||
elseif (!empty($form_values['RDATE'])) {
|
||||
$RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
|
||||
}
|
||||
|
||||
return $RRULE;
|
||||
}
|
||||
1156
sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
Normal file
1156
sites/all/modules/contrib/fields/date/date_api/date_api_sql.inc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,223 @@
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.dateYearRange = {};
|
||||
|
||||
Drupal.behaviors.dateYearRange.attach = function (context, settings) {
|
||||
var $textfield, $textfields, i;
|
||||
|
||||
// Turn the years back and forward fieldsets into dropdowns.
|
||||
$textfields = $('input.select-list-with-custom-option', context).once('date-year-range');
|
||||
for (i = 0; i < $textfields.length; i++) {
|
||||
$textfield = $($textfields[i]);
|
||||
new Drupal.dateYearRange.SelectListWithCustomOption($textfield);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Drupal.dateYearRange = {};
|
||||
|
||||
/**
|
||||
* Constructor for the SelectListWithCustomOption object.
|
||||
*
|
||||
* This object is responsible for turning the years back and forward textfields
|
||||
* into dropdowns with an 'other' option that lets the user enter a custom
|
||||
* value.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption = function ($textfield) {
|
||||
this.$textfield = $textfield;
|
||||
this.$description = $textfield.next('div.description');
|
||||
this.defaultValue = $textfield.val();
|
||||
this.$dropdown = this.createDropdown();
|
||||
this.$dropdown.insertBefore($textfield);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of the textfield as it existed on page load.
|
||||
*
|
||||
* @param {String} type
|
||||
* The type of the variable to be returned. Defaults to string.
|
||||
* @return
|
||||
* The original value of the textfield. Returned as an integer, if the type
|
||||
* parameter was 'int'.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getOriginal = function (type) {
|
||||
var original;
|
||||
if (type === 'int') {
|
||||
original = parseInt(this.defaultValue, 10);
|
||||
if (window.isNaN(original)) {
|
||||
original = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
original = this.defaultValue;
|
||||
}
|
||||
return original;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the correct first value for the dropdown.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getStartValue = function () {
|
||||
var direction = this.getDirection();
|
||||
var start;
|
||||
switch (direction) {
|
||||
case 'back':
|
||||
// For the 'years back' dropdown, the first option should be -10, unless
|
||||
// the default value of the textfield is even smaller than that.
|
||||
start = Math.min(this.getOriginal('int'), -10);
|
||||
break;
|
||||
case 'forward':
|
||||
start = 0;
|
||||
break;
|
||||
}
|
||||
return start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the correct last value for the dropdown.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getEndValue = function () {
|
||||
var direction = this.getDirection();
|
||||
var end;
|
||||
var originalString = this.getOriginal();
|
||||
switch (direction) {
|
||||
case 'back':
|
||||
end = 0;
|
||||
break;
|
||||
case 'forward':
|
||||
// If the original value of the textfield is an absolute year such as
|
||||
// 2020, don't try to include it in the dropdown.
|
||||
if (originalString.indexOf('+') === -1) {
|
||||
end = 10;
|
||||
}
|
||||
// If the original value is a relative value (+x), we want it to be
|
||||
// included in the possible dropdown values.
|
||||
else {
|
||||
end = Math.max(this.getOriginal('int'), 10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a dropdown select list with the correct options for this textfield.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.createDropdown = function () {
|
||||
var $dropdown = $('<select>').addClass('form-select date-year-range-select');
|
||||
var $option, i, value;
|
||||
var start = this.getStartValue();
|
||||
var end = this.getEndValue();
|
||||
var direction = this.getDirection();
|
||||
for (i = start; i <= end; i++) {
|
||||
// Make sure we include the +/- sign in the option value.
|
||||
value = i;
|
||||
if (i > 0) {
|
||||
value = '+' + i;
|
||||
}
|
||||
// Zero values must have a + or - in front.
|
||||
if (i === 0) {
|
||||
if (direction === 'back') {
|
||||
value = '-' + i;
|
||||
}
|
||||
else {
|
||||
value = '+' + i;
|
||||
}
|
||||
}
|
||||
$option = $('<option>' + Drupal.formatPlural(value, '@count year from now', '@count years from now') + '</option>').val(value);
|
||||
$dropdown.append($option);
|
||||
}
|
||||
// Create an 'Other' option.
|
||||
$option = $('<option class="custom-option">' + Drupal.t('Other') + '</option>').val('');
|
||||
$dropdown.append($option);
|
||||
|
||||
// When the user changes the selected option in the dropdown, perform
|
||||
// appropriate actions (such as showing or hiding the textfield).
|
||||
$dropdown.bind('change', $.proxy(this.handleDropdownChange, this));
|
||||
|
||||
// Set the initial value of the dropdown.
|
||||
this._setInitialDropdownValue($dropdown);
|
||||
return $dropdown;
|
||||
};
|
||||
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype._setInitialDropdownValue = function ($dropdown) {
|
||||
var textfieldValue = this.getOriginal();
|
||||
// Determine whether the original textfield value exists in the dropdown.
|
||||
var possible = $dropdown.find('option[value="' + textfieldValue + '"]');
|
||||
// If the original textfield value is one of the dropdown options, preselect
|
||||
// it and hide the 'other' textfield.
|
||||
if (possible.length) {
|
||||
$dropdown.val(textfieldValue);
|
||||
this.hideTextfield();
|
||||
}
|
||||
// If the original textfield value isn't one of the dropdown options, choose
|
||||
// the 'Other' option in the dropdown.
|
||||
else {
|
||||
$dropdown.val('');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether this is the "years back" or "years forward" textfield.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getDirection = function () {
|
||||
if (this.direction) {
|
||||
return this.direction;
|
||||
}
|
||||
var direction;
|
||||
if (this.$textfield.hasClass('back')) {
|
||||
direction = 'back';
|
||||
}
|
||||
else if (this.$textfield.hasClass('forward')) {
|
||||
direction = 'forward';
|
||||
}
|
||||
this.direction = direction;
|
||||
return direction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change handler for the dropdown, to modify the textfield as appropriate.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.handleDropdownChange = function () {
|
||||
// Since the dropdown changed, we need to make the content of the textfield
|
||||
// match the (new) selected option.
|
||||
this.syncTextfield();
|
||||
|
||||
// Show the textfield if the 'Other' option was selected, and hide it if one
|
||||
// of the preset options was selected.
|
||||
if ($(':selected', this.$dropdown).hasClass('custom-option')) {
|
||||
this.revealTextfield();
|
||||
}
|
||||
else {
|
||||
this.hideTextfield();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display the textfield and its description.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.revealTextfield = function () {
|
||||
this.$textfield.show();
|
||||
this.$description.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the textfield and its description.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.hideTextfield = function () {
|
||||
this.$textfield.hide();
|
||||
this.$description.hide();
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy the selected value of the dropdown to the textfield.
|
||||
*
|
||||
* FAPI doesn't know about the JS-only dropdown, so the textfield needs to
|
||||
* reflect the value of the dropdown.
|
||||
*/
|
||||
Drupal.dateYearRange.SelectListWithCustomOption.prototype.syncTextfield = function () {
|
||||
var value = this.$dropdown.val();
|
||||
this.$textfield.val(value);
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 440 B |
Binary file not shown.
|
After Width: | Height: | Size: 357 B |
229
sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
Normal file
229
sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Theme files for Date API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns HTML for a date timezone element.
|
||||
*/
|
||||
function theme_date_timezone($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = $element['#attributes'];
|
||||
$wrapper_attributes = array();
|
||||
// Add an wrapper to mimic the way a single value field works, for ease in
|
||||
// using #states.
|
||||
if (isset($element['#children'])) {
|
||||
$element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
|
||||
}
|
||||
return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date select element.
|
||||
*/
|
||||
function theme_date_select($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
|
||||
$attributes['class'][] = 'container-inline-date';
|
||||
$wrapper_attributes = array('class' => array('date-padding'));
|
||||
$wrapper_attributes['class'][] = 'clearfix';
|
||||
// Add an wrapper to mimic the way a single value field works, for ease in
|
||||
// using #states.
|
||||
if (isset($element['#children'])) {
|
||||
$element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
|
||||
}
|
||||
return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date text element.
|
||||
*/
|
||||
function theme_date_text($variables) {
|
||||
$element = $variables['element'];
|
||||
$attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
|
||||
$attributes['class'][] = 'container-inline-date';
|
||||
// If there is no description, the floating date elements need some extra
|
||||
// padding below them.
|
||||
$wrapper_attributes = array('class' => array('date-padding'));
|
||||
if (empty($element['date']['#description'])) {
|
||||
$wrapper_attributes['class'][] = 'clearfix';
|
||||
}
|
||||
// Add an wrapper to mimic the way a single value field works, for ease in
|
||||
// using #states.
|
||||
if (isset($element['#children'])) {
|
||||
$element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
|
||||
}
|
||||
return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date select input form element.
|
||||
*/
|
||||
function theme_date_select_element($variables) {
|
||||
$element = $variables['element'];
|
||||
$parents = $element['#parents'];
|
||||
$part = array_pop($parents);
|
||||
return '<div class="date-' . $part . '">' . theme('select', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date textfield input form element.
|
||||
*/
|
||||
function theme_date_textfield_element($variables) {
|
||||
$element = $variables['element'];
|
||||
$parents = $element['#parents'];
|
||||
$part = array_pop($parents);
|
||||
return '<div class="date-' . $part . '">' . theme('textfield', $element) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a 'hour' date part prefix.
|
||||
*/
|
||||
function theme_date_part_hour_prefix($variables) {
|
||||
$element = $variables['element'];
|
||||
if ($element['#date_label_position'] != 'above') {
|
||||
return '<span class="form-item date-spacer"> - </span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a 'minutes and seconds' date part prefix.
|
||||
*/
|
||||
function theme_date_part_minsec_prefix($variables) {
|
||||
$element = $variables['element'];
|
||||
if ($element['#date_label_position'] != 'above') {
|
||||
return '<span class="form-item date-spacer">:</span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'year' label.
|
||||
*/
|
||||
function theme_date_part_label_year($variables) {
|
||||
return t('Year', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'month' label.
|
||||
*/
|
||||
function theme_date_part_label_month($variables) {
|
||||
return t('Month', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'day' label.
|
||||
*/
|
||||
function theme_date_part_label_day($variables) {
|
||||
return t('Day', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'hour' label.
|
||||
*/
|
||||
function theme_date_part_label_hour($variables) {
|
||||
return t('Hour', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'minute' label.
|
||||
*/
|
||||
function theme_date_part_label_minute($variables) {
|
||||
return t('Minute', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'second' label.
|
||||
*/
|
||||
function theme_date_part_label_second($variables) {
|
||||
return t('Second', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'ampm' label.
|
||||
*/
|
||||
function theme_date_part_label_ampm($variables) {
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'timezone' label.
|
||||
*/
|
||||
function theme_date_part_label_timezone($variables) {
|
||||
return t('Timezone');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'date' label.
|
||||
*/
|
||||
function theme_date_part_label_date($variables) {
|
||||
return t('Date', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date_select 'time' label.
|
||||
*/
|
||||
function theme_date_part_label_time($variables) {
|
||||
return t('Time', array(), array('context' => 'datetime'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns HTML for a date block that looks like a mini calendar day.
|
||||
*
|
||||
* Pass in a date object already set to the right timezone, format as a calendar
|
||||
* page date. The calendar styling is created in CSS.
|
||||
*/
|
||||
function theme_date_calendar_day($variables) {
|
||||
$output = '';
|
||||
$date = $variables['date'];
|
||||
if (!empty($date)) {
|
||||
$output .= '<div class="date-calendar-day">';
|
||||
$output .= '<span class="month">' . date_format_date($date, 'custom', 'M') . '</span>';
|
||||
$output .= '<span class="day">' . date_format_date($date, 'custom', 'j') . '</span>';
|
||||
$output .= '<span class="year">' . date_format_date($date, 'custom', 'Y') . '</span>';
|
||||
$output .= '</div>';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML for a date in the format 'time ago'.
|
||||
*/
|
||||
function theme_date_time_ago($variables) {
|
||||
$start_date = $variables['start_date'];
|
||||
$end_date = $variables['end_date'];
|
||||
$interval = !empty($variables['interval']) ? $variables['interval'] : 2;
|
||||
$display = isset($variables['interval_display']) ? $variables['interval_display'] : 'time ago';
|
||||
|
||||
// If no date is sent, then return nothing.
|
||||
if (empty($start_date) || empty($end_date)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Time to compare dates to.
|
||||
$now = date_format(date_now(), DATE_FORMAT_UNIX);
|
||||
$start = date_format($start_date, DATE_FORMAT_UNIX);
|
||||
|
||||
// will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
|
||||
$time_diff = $now - $start;
|
||||
|
||||
// Uses the same options used by Views format_interval.
|
||||
switch ($display) {
|
||||
case 'raw time ago':
|
||||
return format_interval($time_diff, $interval);
|
||||
case 'time ago':
|
||||
return t('%time ago', array('%time' => format_interval($time_diff, $interval)));
|
||||
case 'raw time hence':
|
||||
return format_interval(-$time_diff, $interval);
|
||||
case 'time hence':
|
||||
return t('%time hence', array('%time' => format_interval(-$time_diff, $interval)));
|
||||
case 'raw time span':
|
||||
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
|
||||
case 'inverse time span':
|
||||
return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
|
||||
case 'time span':
|
||||
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), $interval)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
name = Date Context
|
||||
description = Adds an option to the Context module to set a context condition based on the value of a date field.
|
||||
package = Date/Time
|
||||
core = 7.x
|
||||
|
||||
dependencies[] = date
|
||||
dependencies[] = context
|
||||
|
||||
files[] = date_context.module
|
||||
files[] = plugins/date_context_date_condition.inc
|
||||
; Information added by drupal.org packaging script on 2012-08-13
|
||||
version = "7.x-2.6"
|
||||
core = "7.x"
|
||||
project = "date"
|
||||
datestamp = "1344850024"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* @TODO
|
||||
*
|
||||
* Currently only implemented for nodes. Need to add $plugin->execute()
|
||||
* for any other entities that might be supported.
|
||||
*
|
||||
* Cache the date processing, perhaps cache the formatted, timezone-adjusted
|
||||
* date strings for each entity (would have to be cached differently for each
|
||||
* timezone, based on the tz_handling method for the date).
|
||||
*
|
||||
* Add an option to set/not set the context on forms vs views.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_context_node_condition_alter().
|
||||
*/
|
||||
function date_context_context_node_condition_alter($node, $op) {
|
||||
if ($plugin = context_get_plugin('condition', 'date_context_date_condition')) {
|
||||
$plugin->execute($node, $op);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_context_plugins()
|
||||
*/
|
||||
function date_context_context_plugins() {
|
||||
$plugins = array();
|
||||
$plugins['date_context_date_condition'] = array(
|
||||
'handler' => array(
|
||||
'class' => 'date_context_date_condition',
|
||||
'parent' => 'context_condition_node',
|
||||
'path' => drupal_get_path('module', 'date_context') . '/plugins',
|
||||
'file' => 'date_context_date_condition.inc',
|
||||
),
|
||||
);
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_context_registry()
|
||||
*/
|
||||
function date_context_context_registry() {
|
||||
return array(
|
||||
'conditions' => array(
|
||||
'date_context_date_condition' => array(
|
||||
'title' => t('Date'),
|
||||
'description' => t('Set a condition based on the value of a date field'),
|
||||
'plugin' => 'date_context_date_condition',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Expose term views/term forms by vocabulary as a context condition.
|
||||
*/
|
||||
class date_context_date_condition extends context_condition_node {
|
||||
function condition_values() {
|
||||
$values = array();
|
||||
$fields = field_info_fields();
|
||||
foreach ($fields as $field_name => $field) {
|
||||
if (in_array($field['type'], array('date', 'datetime', 'datestamp'))) {
|
||||
$values[$field_name] = $field_name;
|
||||
}
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
function options_form($context) {
|
||||
$defaults = $this->fetch_from_context($context, 'options');
|
||||
$options = array(
|
||||
'<' => t('Is less than'),
|
||||
'<=' => t('Is less than or equal to'),
|
||||
'>=' => t('Is greater than or equal to'),
|
||||
'>' => t('Is greater than'),
|
||||
'=' => t('Is equal to'),
|
||||
'!=' => t('Is not equal to'),
|
||||
'empty' => t('Is empty'),
|
||||
'not empty' => t('Is not Empty'),
|
||||
);
|
||||
$form['operation'] = array(
|
||||
'#title' => t('Operation'),
|
||||
'#type' => 'select',
|
||||
'#options' => $options,
|
||||
'#description' => t('The comparison to perform to determine if the date field meets the condition. For multiple value date fields, all values will be checked to see if any meet the condition.'),
|
||||
'#default_value' => isset($defaults['operation']) ? $defaults['operation'] : '',
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['value'] = array(
|
||||
'#title' => t('Value'),
|
||||
'#type' => 'textfield',
|
||||
'#description' => t("The value the field should contain to meet the condition. This can either be an absolute date in ISO format (YYYY-MM-DDTHH:MM:SS) or a relative string like '12AM today'. Examples: 2011-12-31T00:00:00, now, now +1 day, 12AM today, Monday next week. <a href=\"@relative_format\">More examples of relative date formats in the PHP documentation</a>.", array('@relative_format' => 'http://www.php.net/manual/en/datetime.formats.relative.php')),
|
||||
'#default_value' => isset($defaults['value']) ? $defaults['value'] : '',
|
||||
'#process' => array('ctools_dependent_process'),
|
||||
'#dependency' => array(':input[name="conditions[plugins][date_context_date_condition][options][operation]"]' => array('<', '<=', '>', '>=', '=', '!=')),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
function execute($entity, $op) {
|
||||
if (in_array($op, array('view', 'form'))) {
|
||||
foreach ($this->get_contexts() as $context) {
|
||||
$options = $this->fetch_from_context($context, 'options');
|
||||
$fields = $this->fetch_from_context($context, 'values');
|
||||
|
||||
foreach ($fields as $field_name => $label) {
|
||||
|
||||
// If this field does not exist on this entity, just move along.
|
||||
if (empty($entity->{$field_name})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$items = field_get_items('node', $entity, $field_name);
|
||||
|
||||
// If there are no values, nothing to do unless we were looking for 'empty' or '!='.
|
||||
if (empty($items)) {
|
||||
if ($options['operation'] == '!=' || $options['operation'] == 'empty') {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have to construct the date values if we're just testing for 'not empty'.
|
||||
elseif ($options['operation'] == 'not empty') {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
|
||||
// All other operations need to retrieve the date values for comparision.
|
||||
else {
|
||||
$field = field_info_field($field_name);
|
||||
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
foreach ($items as $delta => $item) {
|
||||
$timezone = date_get_timezone($field['settings']['tz_handling'], $item['timezone']);
|
||||
$date = new DateObject($item['value'], $timezone_db);
|
||||
date_timezone_set($date, timezone_open($timezone));
|
||||
$date1 = $date->format(DATE_FORMAT_DATETIME);
|
||||
if (empty($item['value2'])) {
|
||||
$item['value2'] = $item['value'];
|
||||
}
|
||||
$date = new DateObject($item['value2'], $timezone_db);
|
||||
date_timezone_set($date, timezone_open($timezone));
|
||||
$date2 = $date->format(DATE_FORMAT_DATETIME);
|
||||
str_replace('now', 'today', $options['value']);
|
||||
$date = date_create($options['value'], date_default_timezone_object());
|
||||
$compdate = $date->format(DATE_FORMAT_DATETIME);
|
||||
switch($options['operation']) {
|
||||
case '=':
|
||||
if ($date2 >= $compdate && $date1 <= $compdate) {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if ($date1 > $compdate) {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
break;
|
||||
case '>=':
|
||||
if ($date1 >= $compdate) {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if ($date2 < $compdate) {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
break;
|
||||
case '<=':
|
||||
if ($date2 <= $compdate) {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
break;
|
||||
case '!=':
|
||||
if ($date1 < $compdate || $date2 > $compdate) {
|
||||
$this->condition_met($context, $field_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
660
sites/all/modules/contrib/fields/date/date_elements.inc
Normal file
660
sites/all/modules/contrib/fields/date/date_elements.inc
Normal file
@@ -0,0 +1,660 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Date forms and form themes and validation.
|
||||
*
|
||||
* All code used in form editing and processing is in this file,
|
||||
* included only during form editing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Private implementation of hook_widget().
|
||||
*
|
||||
* The widget builds out a complex date element in the following way:
|
||||
*
|
||||
* - A field is pulled out of the database which is comprised of one or
|
||||
* more collections of start/end dates.
|
||||
*
|
||||
* - The dates in this field are all converted from the UTC values stored
|
||||
* in the database back to the local time. This is done in #process
|
||||
* to avoid making this change to dates that are not being processed,
|
||||
* like those hidden with #access.
|
||||
*
|
||||
* - If values are empty, the field settings rules are used to determine
|
||||
* if the default_values should be empty, now, the same, or use strtotime.
|
||||
*
|
||||
* - Each start/end combination is created using the date_combo element type
|
||||
* defined by the date module. If the timezone is date-specific, a
|
||||
* timezone selector is added to the first combo element.
|
||||
*
|
||||
* - The date combo element creates two individual date elements, one each
|
||||
* for the start and end field, using the appropriate individual Date API
|
||||
* date elements, like selects, textfields, or popups.
|
||||
*
|
||||
* - In the individual element validation, the data supplied by the user is
|
||||
* used to update the individual date values.
|
||||
*
|
||||
* - In the combo date validation, the timezone is updated, if necessary,
|
||||
* then the user input date values are used with that timezone to create
|
||||
* date objects, which are used update combo date timezone and offset values.
|
||||
*
|
||||
* - In the field's submission processing, the new date values, which are in
|
||||
* the local timezone, are converted back to their UTC values and stored.
|
||||
*
|
||||
*/
|
||||
function date_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
|
||||
|
||||
$element = $base;
|
||||
$field_name = $field['field_name'];
|
||||
$entity_type = $instance['entity_type'];
|
||||
|
||||
// If this is a new entity, populate the field with the right default values.
|
||||
// This happens early so even fields later hidden with #access get those values.
|
||||
// We should only add default values to new entities, to avoid over-writing
|
||||
// a value that has already been set. This means we can't just check to see
|
||||
// if $items is empty, because it might have been set that way on purpose.
|
||||
// @see date_field_widget_properties_alter() where we flagged if this is a new entity.
|
||||
|
||||
// We check !isset($items[$delta]['value']) because entity translation may create
|
||||
// a new translation entity for an existing entity and we don't want to clobber
|
||||
// values that were already set in that case.
|
||||
// @see http://drupal.org/node/1478848.
|
||||
|
||||
$is_default = FALSE;
|
||||
if (!empty($instance['widget']['is_new']) && !isset($items[$delta]['value'])) {
|
||||
$items = date_default_value($field, $instance, $langcode);
|
||||
$is_default = TRUE;
|
||||
}
|
||||
|
||||
// @TODO Repeating dates should probably be made into their own field type and completely separated out.
|
||||
// That will have to wait for a new branch since it may break other things, including other modules
|
||||
// that have an expectation of what the date field types are.
|
||||
|
||||
// Since repeating dates cannot use the default Add more button, we have to handle our own behaviors here.
|
||||
// Return only the first multiple value for repeating dates, then clean up the 'Add more' bits in #after_build.
|
||||
// The repeating values will be re-generated when the repeat widget form is validated.
|
||||
// At this point we can't tell if this form element is going to be hidden by #access, and we're going to
|
||||
// lose all but the first value by doing this, so store the original values in case we need to replace them later.
|
||||
if (!empty($field['settings']['repeat'])) {
|
||||
if ($delta == 0) {
|
||||
$form['#after_build'] = array('date_repeat_after_build');
|
||||
$form_state['storage']['repeat_fields'][$field_name] = array_merge($form['#parents'], array($field_name));
|
||||
$form_state['storage']['date_items'][$field_name][$langcode] = $items;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
module_load_include('inc', 'date_api', 'date_api_elements');
|
||||
$timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[0]['timezone']) ? $items[0]['timezone'] : date_default_timezone());
|
||||
|
||||
// TODO see if there's a way to keep the timezone element from ever being
|
||||
// nested as array('timezone' => 'timezone' => value)). After struggling
|
||||
// with this a while, I can find no way to get it displayed in the form
|
||||
// correctly and get it to use the timezone element without ending up
|
||||
// with nesting.
|
||||
if (is_array($timezone)) {
|
||||
$timezone = $timezone['timezone'];
|
||||
}
|
||||
|
||||
$element += array(
|
||||
'#type' => 'date_combo',
|
||||
'#theme_wrappers' => array('date_combo'),
|
||||
'#weight' => $delta,
|
||||
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
|
||||
'#date_timezone' => $timezone,
|
||||
'#element_validate' => array('date_combo_validate'),
|
||||
'#date_is_default' => $is_default,
|
||||
|
||||
// Store the original values, for use with disabled and hidden fields.
|
||||
'#date_items' => isset($items[$delta]) ? $items[$delta] : '',
|
||||
);
|
||||
|
||||
$element['#title'] = $instance['label'];
|
||||
|
||||
if ($field['settings']['tz_handling'] == 'date') {
|
||||
$element['timezone'] = array(
|
||||
'#type' => 'date_timezone',
|
||||
'#theme_wrappers' => array('date_timezone'),
|
||||
'#delta' => $delta,
|
||||
'#default_value' => $timezone,
|
||||
'#weight' => $instance['widget']['weight'] + 1,
|
||||
'#attributes' => array('class' => array('date-no-float')),
|
||||
'#date_label_position' => $instance['widget']['settings']['label_position'],
|
||||
);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create local date object.
|
||||
*
|
||||
* Create a date object set to local time from the field and
|
||||
* widget settings and item values. Default values for new entities
|
||||
* are set by the default value callback, so don't need to be accounted for here.
|
||||
*/
|
||||
function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
|
||||
|
||||
$value = $item[$part];
|
||||
|
||||
// If the value is empty, don't try to create a date object because it will
|
||||
// end up being the current day.
|
||||
if (empty($value)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// @TODO Figure out how to replace date_fuzzy_datetime() function.
|
||||
// Special case for ISO dates to create a valid date object for formatting.
|
||||
// Is this still needed?
|
||||
/*
|
||||
if ($field['type'] == DATE_ISO) {
|
||||
$value = date_fuzzy_datetime($value);
|
||||
}
|
||||
else {
|
||||
$db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$value = date_convert($value, $field['type'], DATE_DATETIME, $db_timezone);
|
||||
}
|
||||
*/
|
||||
|
||||
$date = new DateObject($value, date_get_timezone_db($field['settings']['tz_handling']));
|
||||
$date->limitGranularity($field['settings']['granularity']);
|
||||
if (empty($date)) {
|
||||
return NULL;
|
||||
}
|
||||
date_timezone_set($date, timezone_open($timezone));
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback for setting a default value for an empty date field.
|
||||
*/
|
||||
function date_default_value($field, $instance, $langcode) {
|
||||
$item = array();
|
||||
$db_format = date_type_format($field['type']);
|
||||
$date = date_default_value_part($item, $field, $instance, $langcode, 'value');
|
||||
$item[0]['value'] = is_object($date) ? date_format($date, $db_format) : '';
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$date = date_default_value_part($item, $field, $instance, $langcode, 'value2');
|
||||
$item[0]['value2'] = is_object($date) ? date_format($date, $db_format) : '';
|
||||
}
|
||||
|
||||
// Make sure the default value has the same construct as a loaded field value
|
||||
// to avoid errors if the default value is used on a hidden element.
|
||||
$item[0]['timezone'] = date_get_timezone($field['settings']['tz_handling']);
|
||||
$item[0]['timezone_db'] = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$item[0]['date_type'] = $field['type'];
|
||||
if (!isset($item[0]['value2'])) {
|
||||
$item[0]['value2'] = $item[0]['value'];
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for the date default value callback to set
|
||||
* either 'value' or 'value2' to its default value.
|
||||
*/
|
||||
function date_default_value_part($item, $field, $instance, $langcode, $part = 'value') {
|
||||
$timezone = date_get_timezone($field['settings']['tz_handling']);
|
||||
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$date = NULL;
|
||||
if ($part == 'value') {
|
||||
$default_value = $instance['settings']['default_value'];
|
||||
$default_value_code = $instance['settings']['default_value_code'];
|
||||
}
|
||||
else {
|
||||
$default_value = $instance['settings']['default_value2'];
|
||||
$default_value_code = $instance['settings']['default_value_code2'];
|
||||
}
|
||||
if (empty($default_value) || $default_value == 'blank') {
|
||||
return NULL;
|
||||
}
|
||||
elseif ($default_value == 'strtotime' && !empty($default_value_code)) {
|
||||
$date = new DateObject($default_value_code, date_default_timezone());
|
||||
}
|
||||
elseif ($part == 'value2' && $default_value == 'same') {
|
||||
if ($instance['settings']['default_value'] == 'blank' || empty($item[0]['value'])) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
// The date stored in 'value' has already been switched to the db timezone.
|
||||
$date = new DateObject($item[0]['value'], $timezone_db, DATE_FORMAT_DATETIME);
|
||||
}
|
||||
}
|
||||
// Special case for 'now' when using dates with no timezone,
|
||||
// make sure 'now' isn't adjusted to UTC value of 'now' .
|
||||
elseif ($field['settings']['tz_handling'] == 'none') {
|
||||
$date = date_now();
|
||||
}
|
||||
else {
|
||||
$date = date_now($timezone);
|
||||
}
|
||||
// The default value needs to be in the database timezone.
|
||||
date_timezone_set($date, timezone_open($timezone_db));
|
||||
$date->limitGranularity($field['settings']['granularity']);
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an individual date element.
|
||||
*/
|
||||
function date_combo_element_process($element, &$form_state, $form) {
|
||||
|
||||
if (date_hidden_element($element)) {
|
||||
// A hidden value for a new entity that had its end date set to blank
|
||||
// will not get processed later to populate the end date, so set it here.
|
||||
if (isset($element['#value']['value2']) && empty($element['#value']['value2'])) {
|
||||
$element['#value']['value2'] = $element['#value']['value'];
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
$field_name = $element['#field_name'];
|
||||
$delta = $element['#delta'];
|
||||
$bundle = $element['#bundle'];
|
||||
$entity_type = $element['#entity_type'];
|
||||
$langcode = $element['#language'];
|
||||
$date_is_default = $element['#date_is_default'];
|
||||
|
||||
$field = field_widget_field($element, $form_state);
|
||||
$instance = field_widget_instance($element, $form_state);
|
||||
|
||||
// Figure out how many items are in the form, including new ones added by ajax.
|
||||
$field_state = field_form_get_state($element['#field_parents'], $field_name, $element['#language'], $form_state);
|
||||
$items_count = $field_state['items_count'];
|
||||
|
||||
$columns = $element['#columns'];
|
||||
if (isset($columns['rrule'])) {
|
||||
unset($columns['rrule']);
|
||||
}
|
||||
$from_field = 'value';
|
||||
$to_field = 'value2';
|
||||
$tz_field = 'timezone';
|
||||
$offset_field = 'offset';
|
||||
$offset_field2 = 'offset2';
|
||||
|
||||
// Convert UTC dates to their local values in DATETIME format,
|
||||
// and adjust the default values as specified in the field settings.
|
||||
|
||||
// It would seem to make sense to do this conversion when the data
|
||||
// is loaded instead of when the form is created, but the loaded
|
||||
// field data is cached and we can't cache dates that have been converted
|
||||
// to the timezone of an individual user, so we cache the UTC values
|
||||
// instead and do our conversion to local dates in the form and
|
||||
// in the formatters.
|
||||
$process = date_process_values($field, $instance);
|
||||
foreach ($process as $processed) {
|
||||
if (!isset($element['#default_value'][$processed])) {
|
||||
$element['#default_value'][$processed] = '';
|
||||
}
|
||||
$date = date_local_date($element['#default_value'], $element['#date_timezone'], $field, $instance, $processed);
|
||||
$element['#default_value'][$processed] = is_object($date) ? date_format($date, DATE_FORMAT_DATETIME) : '';
|
||||
}
|
||||
|
||||
// Blank out the end date for optional end dates that match the start date,
|
||||
// except when this is a new node that has default values that should be honored.
|
||||
if (!$date_is_default && $field['settings']['todate'] != 'required'
|
||||
&& !empty($element['#default_value'][$to_field])
|
||||
&& $element['#default_value'][$to_field] == $element['#default_value'][$from_field]) {
|
||||
unset($element['#default_value'][$to_field]);
|
||||
}
|
||||
|
||||
$show_todate = !empty($form_state['values']['show_todate']) || !empty($element['#default_value'][$to_field]) || $field['settings']['todate'] == 'required';
|
||||
$element['show_todate'] = array(
|
||||
'#title' => t('Show End Date'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $show_todate,
|
||||
'#weight' => -20,
|
||||
'#access' => $field['settings']['todate'] == 'optional',
|
||||
'#prefix' => '<div class="date-float">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
$parents = $element['#parents'];
|
||||
$first_parent = array_shift($parents);
|
||||
$show_id = $first_parent . '[' . implode('][', $parents) . '][show_todate]';
|
||||
|
||||
$element[$from_field] = array(
|
||||
'#field' => $field,
|
||||
'#instance' => $instance,
|
||||
'#weight' => $instance['widget']['weight'],
|
||||
'#required' => ($instance['required'] && $delta == 0) ? 1 : 0,
|
||||
'#default_value' => isset($element['#default_value'][$from_field]) ? $element['#default_value'][$from_field] : '',
|
||||
'#delta' => $delta,
|
||||
'#date_timezone' => $element['#date_timezone'],
|
||||
'#date_format' => date_limit_format(date_input_format($element, $field, $instance), $field['settings']['granularity']),
|
||||
'#date_text_parts' => (array) $instance['widget']['settings']['text_parts'],
|
||||
'#date_increment' => $instance['widget']['settings']['increment'],
|
||||
'#date_year_range' => $instance['widget']['settings']['year_range'],
|
||||
'#date_label_position' => $instance['widget']['settings']['label_position'],
|
||||
);
|
||||
|
||||
$description = !empty($instance['description']) ? t($instance['description']) : '';
|
||||
|
||||
// Give this element the right type, using a Date API
|
||||
// or a Date Popup element type.
|
||||
$element[$from_field]['#attributes'] = array('class' => array('date-clear'));
|
||||
$element[$from_field]['#wrapper_attributes'] = array('class' => array());
|
||||
$element[$from_field]['#wrapper_attributes']['class'][] = 'date-no-float';
|
||||
|
||||
switch ($instance['widget']['type']) {
|
||||
case 'date_select':
|
||||
$element[$from_field]['#type'] = 'date_select';
|
||||
$element[$from_field]['#theme_wrappers'] = array('date_select');
|
||||
$element['#attached']['js'][] = drupal_get_path('module', 'date') . '/date.js';
|
||||
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
|
||||
break;
|
||||
case 'date_popup':
|
||||
$element[$from_field]['#type'] = 'date_popup';
|
||||
$element[$from_field]['#theme_wrappers'] = array('date_popup');
|
||||
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
|
||||
break;
|
||||
default:
|
||||
$element[$from_field]['#type'] = 'date_text';
|
||||
$element[$from_field]['#theme_wrappers'] = array('date_text');
|
||||
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
// If this field uses the 'End', add matching element
|
||||
// for the 'End' date, and adapt titles to make it clear which
|
||||
// is the 'Start' and which is the 'End' .
|
||||
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$element[$from_field]['#title'] = '';
|
||||
$element[$to_field] = $element[$from_field];
|
||||
$element[$to_field]['#title'] = t('to:');
|
||||
$element[$from_field]['#wrapper_attributes']['class'][] = 'start-date-wrapper';
|
||||
$element[$to_field]['#wrapper_attributes']['class'][] = 'end-date-wrapper';
|
||||
$element[$to_field]['#default_value'] = isset($element['#default_value'][$to_field]) ? $element['#default_value'][$to_field] : '';
|
||||
$element[$to_field]['#required'] = ($element[$from_field]['#required'] && $field['settings']['todate'] == 'required');
|
||||
$element[$to_field]['#weight'] += .2;
|
||||
$element[$to_field]['#prefix'] = '';
|
||||
// Users with JS enabled will never see initially blank values for the end
|
||||
// date (see Drupal.date.EndDateHandler()), so hide the message for them.
|
||||
$description .= '<span class="js-hide"> ' . t("Empty 'End date' values will use the 'Start date' values.") . '</span>';
|
||||
$element['#fieldset_description'] = $description;
|
||||
if ($field['settings']['todate'] == 'optional') {
|
||||
$element[$to_field]['#states'] = array(
|
||||
'visible' => array(
|
||||
'input[name="' . $show_id . '"]' => array('checked' => TRUE),
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element[$from_field]['#description'] = $description;
|
||||
}
|
||||
|
||||
// Create label for error messages that make sense in multiple values
|
||||
// and when the title field is left blank.
|
||||
if ($field['cardinality'] <> 1 && empty($field['settings']['repeat'])) {
|
||||
$element[$from_field]['#date_title'] = t('@field_name Start date value #@delta', array('@field_name' => $instance['label'], '@delta' => $delta + 1));
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$element[$to_field]['#date_title'] = t('@field_name End date value #@delta', array('@field_name' => $instance['label'], '@delta' => $delta + 1));
|
||||
}
|
||||
}
|
||||
elseif (!empty($field['settings']['todate'])) {
|
||||
$element[$from_field]['#date_title'] = t('@field_name Start date', array('@field_name' => $instance['label']));
|
||||
$element[$to_field]['#date_title'] = t('@field_name End date', array('@field_name' => $instance['label']));
|
||||
}
|
||||
else {
|
||||
$element[$from_field]['#date_title'] = $instance['label'];
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'form' => $form,
|
||||
);
|
||||
drupal_alter('date_combo_process', $element, $form_state, $context);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
function date_element_empty($element, &$form_state) {
|
||||
$item = array();
|
||||
$item['value'] = NULL;
|
||||
$item['value2'] = NULL;
|
||||
$item['timezone'] = NULL;
|
||||
$item['offset'] = NULL;
|
||||
$item['offset2'] = NULL;
|
||||
$item['rrule'] = NULL;
|
||||
form_set_value($element, $item, $form_state);
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and update a combo element.
|
||||
* Don't try this if there were errors before reaching this point.
|
||||
*/
|
||||
function date_combo_validate($element, &$form_state) {
|
||||
|
||||
// Disabled and hidden elements won't have any input and don't need validation,
|
||||
// we just need to re-save the original values, from before they were processed into
|
||||
// widget arrays and timezone-adjusted.
|
||||
if (date_hidden_element($element) || !empty($element['#disabled'])) {
|
||||
form_set_value($element, $element['#date_items'], $form_state);
|
||||
return;
|
||||
}
|
||||
|
||||
$field_name = $element['#field_name'];
|
||||
$delta = $element['#delta'];
|
||||
$langcode = $element['#language'];
|
||||
|
||||
$form_values = drupal_array_get_nested_value($form_state['values'], $element['#field_parents']);
|
||||
$form_input = drupal_array_get_nested_value($form_state['input'], $element['#field_parents']);
|
||||
|
||||
// If the whole field is empty and that's OK, stop now.
|
||||
if (empty($form_input[$field_name]) && !$element['#required']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$item = $form_values[$field_name][$langcode][$delta];
|
||||
$posted = $form_input[$field_name][$langcode][$delta];
|
||||
|
||||
$field = field_widget_field($element, $form_state);
|
||||
$instance = field_widget_instance($element, $form_state);
|
||||
|
||||
$context = array(
|
||||
'field' => $field,
|
||||
'instance' => $instance,
|
||||
'item' => $item,
|
||||
);
|
||||
|
||||
drupal_alter('date_combo_pre_validate', $element, $form_state, $context);
|
||||
|
||||
$from_field = 'value';
|
||||
$to_field = 'value2';
|
||||
$tz_field = 'timezone';
|
||||
$offset_field = 'offset';
|
||||
$offset_field2 = 'offset2';
|
||||
|
||||
// Check for empty 'Start date', which could either be an empty
|
||||
// value or an array of empty values, depending on the widget.
|
||||
$empty = TRUE;
|
||||
if (!empty($item[$from_field])) {
|
||||
if (!is_array($item[$from_field])) {
|
||||
$empty = FALSE;
|
||||
}
|
||||
else {
|
||||
foreach ($item[$from_field] as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
$empty = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An 'End' date without a 'Start' date is a validation error.
|
||||
if ($empty && !empty($item[$to_field])) {
|
||||
if (!is_array($item[$to_field])) {
|
||||
form_error($element, t("A 'Start date' date is required if an 'end date' is supplied for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])));
|
||||
$empty = FALSE;
|
||||
}
|
||||
else {
|
||||
foreach ($item[$to_field] as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
form_error($element, t("A 'Start date' date is required if an 'End date' is supplied for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])));
|
||||
$empty = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user chose the option to not show the end date, just swap in the
|
||||
// start date as that value so the start and end dates are the same.
|
||||
if ($field['settings']['todate'] == 'optional' && empty($item['show_todate'])) {
|
||||
$item[$to_field] = $item[$from_field];
|
||||
$posted[$to_field] = $posted[$from_field];
|
||||
}
|
||||
|
||||
if ($empty) {
|
||||
$item = date_element_empty($element, $form_state);
|
||||
if (!$element['#required']) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Don't look for further errors if errors are already flagged
|
||||
// because otherwise we'll show errors on the nested elements
|
||||
// more than once.
|
||||
elseif (!form_get_errors()) {
|
||||
|
||||
$timezone = !empty($item[$tz_field]) ? $item[$tz_field] : $element['#date_timezone'];
|
||||
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
|
||||
$element[$from_field]['#date_timezone'] = $timezone;
|
||||
$from_date = date_input_date($field, $instance, $element[$from_field], $posted[$from_field]);
|
||||
|
||||
if (!empty($field['settings']['todate'])) {
|
||||
$element[$to_field]['#date_timezone'] = $timezone;
|
||||
$to_date = date_input_date($field, $instance, $element[$to_field], $posted[$to_field]);
|
||||
}
|
||||
else {
|
||||
$to_date = $from_date;
|
||||
}
|
||||
|
||||
// Neither the start date nor the end date should be empty at this point
|
||||
// unless they held values that couldn't be evaluated.
|
||||
|
||||
if (!$instance['required'] && (!date_is_date($from_date) || !date_is_date($to_date))) {
|
||||
$item = date_element_empty($element, $form_state);
|
||||
$errors[] = t('The dates are invalid.');
|
||||
}
|
||||
elseif (!empty($field['settings']['todate']) && $from_date > $to_date) {
|
||||
form_set_value($element[$to_field], $to_date, $form_state);
|
||||
$errors[] = t('The End date must be greater than the Start date.');
|
||||
}
|
||||
else {
|
||||
// Convert input dates back to their UTC values and re-format to ISO
|
||||
// or UNIX instead of the DATETIME format used in element processing.
|
||||
$item[$tz_field] = $timezone;
|
||||
|
||||
// Update the context for changes in the $item, and allow other modules to
|
||||
// alter the computed local dates.
|
||||
$context['item'] = $item;
|
||||
// We can only pass two additional values to drupal_alter, so $element
|
||||
// needs to be included in $context.
|
||||
$context['element'] = $element;
|
||||
drupal_alter('date_combo_validate_date_start', $from_date, $form_state, $context);
|
||||
drupal_alter('date_combo_validate_date_end', $to_date, $form_state, $context);
|
||||
|
||||
$item[$offset_field] = date_offset_get($from_date);
|
||||
|
||||
$test_from = date_format($from_date, 'r');
|
||||
$test_to = date_format($to_date, 'r');
|
||||
|
||||
$item[$offset_field2] = date_offset_get($to_date);
|
||||
date_timezone_set($from_date, timezone_open($timezone_db));
|
||||
date_timezone_set($to_date, timezone_open($timezone_db));
|
||||
$item[$from_field] = date_format($from_date, date_type_format($field['type']));
|
||||
$item[$to_field] = date_format($to_date, date_type_format($field['type']));
|
||||
if (isset($form_values[$field_name]['rrule'])) {
|
||||
$item['rrule'] = $form_values[$field['field_name']]['rrule'];
|
||||
}
|
||||
|
||||
// If the db timezone is not the same as the display timezone
|
||||
// and we are using a date with time granularity,
|
||||
// test a roundtrip back to the original timezone to catch
|
||||
// invalid dates, like 2AM on the day that spring daylight savings
|
||||
// time begins in the US.
|
||||
$granularity = date_format_order($element[$from_field]['#date_format']);
|
||||
if ($timezone != $timezone_db && date_has_time($granularity)) {
|
||||
date_timezone_set($from_date, timezone_open($timezone));
|
||||
date_timezone_set($to_date, timezone_open($timezone));
|
||||
|
||||
if ($test_from != date_format($from_date, 'r')) {
|
||||
$errors[] = t('The Start date is invalid.');
|
||||
}
|
||||
if ($test_to != date_format($to_date, 'r')) {
|
||||
$errors[] = t('The End date is invalid.');
|
||||
}
|
||||
}
|
||||
if (empty($errors)) {
|
||||
form_set_value($element, $item, $form_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($errors)) {
|
||||
if ($field['cardinality']) {
|
||||
form_error($element, t('There are errors in @field_name value #@delta:', array('@field_name' => $instance['label'], '@delta' => $delta + 1)) . theme('item_list', array('items' => $errors)));
|
||||
}
|
||||
else {
|
||||
form_error($element, t('There are errors in @field_name:', array('@field_name' => $instance['label'])) . theme('item_list', array('items' => $errors)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the input format for this element.
|
||||
*/
|
||||
function date_input_format($element, $field, $instance) {
|
||||
if (!empty($instance['widget']['settings']['input_format_custom'])) {
|
||||
return $instance['widget']['settings']['input_format_custom'];
|
||||
}
|
||||
elseif (!empty($instance['widget']['settings']['input_format']) && $instance['widget']['settings']['input_format'] != 'site-wide') {
|
||||
return $instance['widget']['settings']['input_format'];
|
||||
}
|
||||
return variable_get('date_format_short', 'm/d/Y - H:i');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_date_select_pre_validate_alter().
|
||||
*/
|
||||
function date_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
date_empty_end_date($element, $form_state, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_text_pre_validate_alter().
|
||||
*/
|
||||
function date_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
date_empty_end_date($element, $form_state, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_date_popup_pre_validate_alter().
|
||||
*/
|
||||
function date_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
|
||||
date_empty_end_date($element, $form_state, $input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to clear out end date when not being used.
|
||||
*/
|
||||
function date_empty_end_date(&$element, &$form_state, &$input) {
|
||||
// If this is the end date and the option to show an end date has not been selected,
|
||||
// empty the end date to surpress validation errors and stop further processing.
|
||||
$parents = $element['#parents'];
|
||||
$parent = array_pop($parents);
|
||||
if ($parent == 'value2') {
|
||||
$parent_values = drupal_array_get_nested_value($form_state['values'], $parents);
|
||||
if (isset($parent_values['show_todate']) && $parent_values['show_todate'] != 1) {
|
||||
$input = array();
|
||||
form_set_value($element, NULL, $form_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Support for migration into Date fields.
|
||||
*/
|
||||
|
||||
class DateMigrateFieldHandler extends MigrateFieldHandler {
|
||||
|
||||
/**
|
||||
* Declares the types of fields used.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->registerTypes(array('date', 'datestamp', 'datetime'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for a date field migration.
|
||||
*
|
||||
* @param string $timezone
|
||||
* Timezone (such as UTC, America/New_York, etc.) to apply.
|
||||
* @param string $timezone_db
|
||||
* Timezone_db value for the field.
|
||||
* @param string $rrule
|
||||
* Rule string for a repeating date field.
|
||||
* @param string $language
|
||||
* Language of the text (defaults to destination language)
|
||||
*
|
||||
* @return array
|
||||
* An array of the defined variables in this scope.
|
||||
*/
|
||||
static function arguments($timezone = 'UTC', $timezone_db = 'UTC', $rrule = NULL, $language = NULL) {
|
||||
return get_defined_vars();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts incoming data into the proper field arrays for Date fields.
|
||||
*
|
||||
* @param object $entity
|
||||
* The destination entity which will hold the field arrays.
|
||||
* @param array $field_info
|
||||
* Metadata for the date field being populated.
|
||||
* @param array $instance
|
||||
* Metadata for this instance of the date field being populated.
|
||||
* @param array $values
|
||||
* Array of date values to be fielded.
|
||||
*
|
||||
* @return array|null
|
||||
* An array of date fields.
|
||||
*/
|
||||
public function prepare($entity, array $field_info, array $instance, array $values) {
|
||||
if (isset($values['arguments'])) {
|
||||
$arguments = $values['arguments'];
|
||||
unset($values['arguments']);
|
||||
}
|
||||
else {
|
||||
$arguments = array();
|
||||
}
|
||||
|
||||
if (isset($arguments['timezone'])) {
|
||||
$default_timezone = $arguments['timezone'];
|
||||
}
|
||||
else {
|
||||
$default_timezone = 'UTC';
|
||||
}
|
||||
if (isset($arguments['timezone_db'])) {
|
||||
$default_timezone_db = $arguments['timezone_db'];
|
||||
}
|
||||
else {
|
||||
$default_timezone_db = NULL;
|
||||
}
|
||||
if (isset($arguments['rrule'])) {
|
||||
$default_rrule = $arguments['rrule'];
|
||||
}
|
||||
else {
|
||||
$default_rrule = NULL;
|
||||
}
|
||||
$language = $this->getFieldLanguage($entity, $field_info, $arguments);
|
||||
|
||||
// Setup the standard Field API array for saving.
|
||||
$delta = 0;
|
||||
foreach ($values as $from) {
|
||||
// Set defaults.
|
||||
$to = NULL;
|
||||
$timezone = $default_timezone;
|
||||
$timezone_db = $default_timezone_db;
|
||||
$rrule = $default_rrule;
|
||||
|
||||
// Is the value a straight datetime value, or JSON containing a set of
|
||||
// properties?
|
||||
if (!empty($from) && $from{0} == '{') {
|
||||
$properties = drupal_json_decode($from);
|
||||
$from = $properties['from'];
|
||||
// Properties passed in with the date override any set via arguments.
|
||||
if (!empty($properties['to'])) {
|
||||
$to = $properties['to'];
|
||||
}
|
||||
if (!empty($properties['timezone'])) {
|
||||
$timezone = $properties['timezone'];
|
||||
}
|
||||
if (!empty($properties['timezone_db'])) {
|
||||
$timezone_db = $properties['timezone_db'];
|
||||
}
|
||||
if (!empty($properties['rrule'])) {
|
||||
$rrule = $properties['rrule'];
|
||||
}
|
||||
}
|
||||
|
||||
// Missing data? Create an empty value and return;
|
||||
// Don't try to turn the empty value into a bogus
|
||||
// timestamp for 'now'.
|
||||
if (empty($from)) {
|
||||
$return[$language][$delta]['value'] = NULL;
|
||||
if (!empty($field_info['settings']['todate'])) {
|
||||
$return[$language][$delta]['value2'] = NULL;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
// If there is no 'to' date, just use the 'from' date.
|
||||
if (!empty($field_info['settings']['todate']) && empty($to)) {
|
||||
$to = $from;
|
||||
}
|
||||
|
||||
// If we have a value, work from a timestamp.
|
||||
$from = MigrationBase::timestamp($from);
|
||||
if ($to) {
|
||||
$to = MigrationBase::timestamp($to);
|
||||
}
|
||||
|
||||
// What does the destination field expect?
|
||||
switch ($field_info['type']) {
|
||||
case 'datestamp':
|
||||
// Already done.
|
||||
break;
|
||||
case 'datetime':
|
||||
// YYYY-MM-DD HH:MM:SS.
|
||||
$from = format_date($from, 'custom', 'Y-m-d H:i:s', $timezone);
|
||||
if ($to) {
|
||||
$to = format_date($to, 'custom', 'Y-m-d H:i:s', $timezone);
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
// ISO date: YYYY-MM-DDTHH:MM:SS.
|
||||
$from = format_date($from, 'custom', 'Y-m-d\TH:i:s', $timezone);
|
||||
if ($to) {
|
||||
$to = format_date($to, 'custom', 'Y-m-d\TH:i:s', $timezone);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle repeats, coming in as RRULEs. Many field instances may be
|
||||
// created.
|
||||
if (function_exists('date_repeat_build_dates') && !empty($field_info['settings']['repeat']) && $rrule) {
|
||||
include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc';
|
||||
$item = array('value' => $from, 'value2' => $to, 'timezone' => $timezone);
|
||||
// Can be de-uglified when http://drupal.org/node/1159404 is committed.
|
||||
$return[$language] = date_repeat_build_dates(NULL, date_ical_parse_rrule($field_info, $rrule), $field_info, $item);
|
||||
}
|
||||
else {
|
||||
$return[$language][$delta]['value'] = $from;
|
||||
if (!empty($to)) {
|
||||
$return[$language][$delta]['value2'] = $to;
|
||||
}
|
||||
}
|
||||
$delta++;
|
||||
}
|
||||
if (!isset($return)) {
|
||||
$return = NULL;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
name = Date Migration
|
||||
description = Provides support for importing into date fields with the Migrate module.
|
||||
core = 7.x
|
||||
package = Date/Time
|
||||
|
||||
dependencies[] = migrate
|
||||
dependencies[] = date
|
||||
files[] = date.migrate.inc
|
||||
files[] = date_migrate.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-08-13
|
||||
version = "7.x-2.6"
|
||||
core = "7.x"
|
||||
project = "date"
|
||||
datestamp = "1344850024"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Migration integration for Date Migrate.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_migrate_api().
|
||||
*/
|
||||
function date_migrate_migrate_api() {
|
||||
$api = array(
|
||||
'api' => 2,
|
||||
);
|
||||
return $api;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user