New module 'Token'
This commit is contained in:
parent
ae2a2d8417
commit
0e730eca64
25 changed files with 3967 additions and 0 deletions
132
sites/all/modules/token/API.txt
Normal file
132
sites/all/modules/token/API.txt
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
Overview
|
||||
========
|
||||
In many cases, it's useful to allow users to define patterns or large
|
||||
chunks of text that contain programmatically derived values. For example,
|
||||
form email messages addressed to a given user, or url path aliases
|
||||
containing the title of a given node. Both examples require bits of data
|
||||
that vary each time the text is generated -- node titles, user ids, and
|
||||
so on. Rather than forcing users to embed ugly snippets of PHP, or creating
|
||||
elaborate and bizarre UIs for configuring the patterns via the browser,
|
||||
it's most useful to give users a set of 'placeholder' tokens to place in
|
||||
their text.
|
||||
|
||||
Token.module provides a shared API for exposing and using placeholder
|
||||
tokens and their appropriate replacement values. It does nothing *by
|
||||
itself* -- other modules can use it to avoid reinventing the wheel.
|
||||
|
||||
Using Token Replacement
|
||||
=======================
|
||||
To apply token replacement to a chunk of text, you have two options. The
|
||||
first, and simplest, is:
|
||||
|
||||
token_replace($original, $type = 'global', $object = NULL,
|
||||
$leading = '[', $trailing = ']')
|
||||
|
||||
$original is the source text to perform substitutions on: it can be either
|
||||
a simple string, or an array of multiple strings.
|
||||
|
||||
$type and $object are to be used when performing substitution based on a
|
||||
particular Drupal object. Replacing tokens in an email with values from
|
||||
a particular user account, or replacing tokens in a path alias pattern with
|
||||
values from the node being aliased, are two examples.
|
||||
|
||||
$type should contain the general object type (node, comment, user, etc.)
|
||||
while $object should contain the object itself.
|
||||
|
||||
$leading and $trailing can be used to override the default token style.
|
||||
For example, to replace tokens using %this style, pass in '%' and '' for
|
||||
the $leading and $trailing values. Note that passing in a leading but NOT
|
||||
trailing value can lead to false positives if two tokens are named in a
|
||||
similar fashion (%node_term and %node_term_id, for example).
|
||||
|
||||
|
||||
|
||||
Altering The Replacement Values
|
||||
===============================
|
||||
If your module needs to perform additional cleanup work on the replacement
|
||||
values before doing the actual substitutions (cleaning replacement values
|
||||
to make them appropriate for path aliasing, truncating them to a particular
|
||||
length, etc.) you can manually retrieve the list of tokens and replacement
|
||||
values, then call str_replace() yourself.
|
||||
|
||||
token_get_values($type = 'global', $object = NULL)
|
||||
|
||||
Pass in the $type and $object as you would with the simpler token_replace()
|
||||
function. The return value will be an object containing one array of tokens
|
||||
and one array of values as in this example:
|
||||
|
||||
stdClass Object {
|
||||
[tokens] => array(
|
||||
[0] => mytoken1,
|
||||
[1] => mytoken2
|
||||
),
|
||||
[values] => array(
|
||||
[0] => value1,
|
||||
[1] => value2,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
Providing Placeholder Tokens
|
||||
============================
|
||||
Token.module provides a small set of default placeholders for global values
|
||||
like the name of the currently logged in user, the site's URL, and so on.
|
||||
Any module can provide additional tokens by implementing two hooks.
|
||||
|
||||
Security note: For tokens which include user input, users and modules
|
||||
expect to see both a ['token-name'] and a ['token-name-raw'] value.
|
||||
|
||||
|
||||
hook_token_values($type, $object = NULL)
|
||||
========================================
|
||||
This function should return a keyed array of placeholders, and their
|
||||
replacement values. $type contains the current context -- 'node', 'user',
|
||||
'global', etc. $object contains the specific node, user, etc. that
|
||||
should be used as the basis for the replacements. *Only* generate and
|
||||
return replacement tokens when $type is something that your module can
|
||||
really deal with. That helps keep things speedy and avoid needlessly
|
||||
searching for jillions of replacement tokens. The $options array can
|
||||
contain additional options (exact use is dynamic and not easily documented).
|
||||
|
||||
For example:
|
||||
|
||||
function my_user_token_values($type, $object = NULL, $options = array()) {
|
||||
if ($type == 'user') {
|
||||
$user = $object;
|
||||
$tokens['name'] = $user->name;
|
||||
$tokens['mail'] = $user->mail;
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hook_token_list($type = 'all')
|
||||
==============================
|
||||
This function is used to provide help and inline documentation for all
|
||||
of the possible replacement tokens.
|
||||
|
||||
As with hook_token_values, $type indicates the context that token help
|
||||
is being generated for. Unlike hook_token_values however, you should
|
||||
show ALL tokens at the same time if $type is 'all'. As such, the help
|
||||
text should be keyed by the $type context your module will use when
|
||||
doing the actual replacements. For example:
|
||||
|
||||
function my_user_token_list($type = 'all') {
|
||||
if ($type == 'user' || $type == 'all') {
|
||||
$tokens['user']['name'] = t("The user's name");
|
||||
$tokens['user']['mail'] = t("The user's email address");
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
||||
Examples of more elaborate token replacement setups can be found in the
|
||||
token_node.inc file that's bundled with token.module.
|
||||
|
||||
Security Note
|
||||
========
|
||||
If use any of the tokens in the ['raw'] sub-array then please note that these
|
||||
are unfiltered values which could conceivably contain XSS attacks or other
|
||||
malicious data. Your module should then provide it's own filtering to ensure the
|
||||
safety of site users.
|
339
sites/all/modules/token/LICENSE.txt
Normal file
339
sites/all/modules/token/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.
|
30
sites/all/modules/token/README.txt
Normal file
30
sites/all/modules/token/README.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
Description
|
||||
===========
|
||||
Token module provides a centralized API for text substitution. Unless
|
||||
you're installing another Drupal module that requires it, this software
|
||||
is probably unnecessary.
|
||||
|
||||
For more information on tokens see http://groups.drupal.org/tokens
|
||||
|
||||
Benefits
|
||||
========
|
||||
If you're a Drupal developer, check out API.txt for detailed instructions
|
||||
on using the Token API. It allows every module to announce the placeholder
|
||||
tokens they can handle, uses simple caching to prevent duplicated work in
|
||||
a given page-view, and is pretty lightweight. It's nice. You'll like it.
|
||||
|
||||
tokenSTARTER
|
||||
============
|
||||
Want to add your own custom tokens to a site? Not sure how to write a
|
||||
module? Worry no more, it's now quite easy.
|
||||
|
||||
1. Copy and rename the tokenSTARTER.info and tokenSTARTER.module replacing
|
||||
every instance of STARTER with a descriptive, appropriate word.
|
||||
|
||||
2. Edit the .module file and change hook_token_list and hook_token_values
|
||||
to provide whatever additional tokens or logic your site needs.
|
||||
|
||||
3. Enable the module and enjoy!
|
||||
|
||||
You should also want to read the API.txt.
|
BIN
sites/all/modules/token/arrow-down.png
Normal file
BIN
sites/all/modules/token/arrow-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 B |
BIN
sites/all/modules/token/arrow-right.png
Normal file
BIN
sites/all/modules/token/arrow-right.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 127 B |
44
sites/all/modules/token/jquery.treeTable.css
Normal file
44
sites/all/modules/token/jquery.treeTable.css
Normal file
|
@ -0,0 +1,44 @@
|
|||
|
||||
/* jQuery TreeTable Core 2.0 stylesheet
|
||||
*
|
||||
* This file contains styles that are used to display the tree table. Each tree
|
||||
* table is assigned the +treeTable+ class.
|
||||
* ========================================================================= */
|
||||
|
||||
/* jquery.treeTable.collapsible
|
||||
* ------------------------------------------------------------------------- */
|
||||
.treeTable tr td .expander {
|
||||
background-position: left center;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
zoom: 1; /* IE7 Hack */
|
||||
}
|
||||
|
||||
.treeTable tr.collapsed td .expander {
|
||||
background-image: url(arrow-right.png);
|
||||
}
|
||||
|
||||
.treeTable tr.expanded td .expander {
|
||||
background-image: url(arrow-down.png);
|
||||
}
|
||||
|
||||
/* jquery.treeTable.sortable
|
||||
* ------------------------------------------------------------------------- */
|
||||
.treeTable tr.selected, .treeTable tr.accept {
|
||||
background-color: #3875d7;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.treeTable tr.collapsed.selected td .expander, .treeTable tr.collapsed.accept td .expander {
|
||||
background-image: url(../images/toggle-expand-light.png);
|
||||
}
|
||||
|
||||
.treeTable tr.expanded.selected td .expander, .treeTable tr.expanded.accept td .expander {
|
||||
background-image: url(../images/toggle-collapse-light.png);
|
||||
}
|
||||
|
||||
.treeTable .ui-draggable-dragging {
|
||||
color: #000;
|
||||
z-index: 1;
|
||||
}
|
220
sites/all/modules/token/jquery.treeTable.js
Normal file
220
sites/all/modules/token/jquery.treeTable.js
Normal file
|
@ -0,0 +1,220 @@
|
|||
|
||||
/*
|
||||
* jQuery treeTable Plugin 2.3.0
|
||||
* http://ludo.cubicphuse.nl/jquery-plugins/treeTable/
|
||||
*
|
||||
* Copyright 2010, Ludo van den Boom
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*/
|
||||
(function($) {
|
||||
// Helps to make options available to all functions
|
||||
// TODO: This gives problems when there are both expandable and non-expandable
|
||||
// trees on a page. The options shouldn't be global to all these instances!
|
||||
var options;
|
||||
var defaultPaddingLeft;
|
||||
|
||||
$.fn.treeTable = function(opts) {
|
||||
options = $.extend({}, $.fn.treeTable.defaults, opts);
|
||||
|
||||
return this.each(function() {
|
||||
$(this).addClass("treeTable").find("tbody tr").each(function() {
|
||||
// Initialize root nodes only if possible
|
||||
if(!options.expandable || $(this)[0].className.search(options.childPrefix) == -1) {
|
||||
// To optimize performance of indentation, I retrieve the padding-left
|
||||
// value of the first root node. This way I only have to call +css+
|
||||
// once.
|
||||
if (isNaN(defaultPaddingLeft)) {
|
||||
defaultPaddingLeft = parseInt($($(this).children("td")[options.treeColumn]).css('padding-left'), 10);
|
||||
}
|
||||
|
||||
initialize($(this));
|
||||
} else if(options.initialState == "collapsed") {
|
||||
this.style.display = "none"; // Performance! $(this).hide() is slow...
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.treeTable.defaults = {
|
||||
childPrefix: "child-of-",
|
||||
clickableNodeNames: false,
|
||||
expandable: true,
|
||||
indent: 19,
|
||||
initialState: "collapsed",
|
||||
treeColumn: 0
|
||||
};
|
||||
|
||||
// Recursively hide all node's children in a tree
|
||||
$.fn.collapse = function() {
|
||||
$(this).addClass("collapsed");
|
||||
|
||||
childrenOf($(this)).each(function() {
|
||||
if(!$(this).hasClass("collapsed")) {
|
||||
$(this).collapse();
|
||||
}
|
||||
|
||||
this.style.display = "none"; // Performance! $(this).hide() is slow...
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Recursively show all node's children in a tree
|
||||
$.fn.expand = function() {
|
||||
$(this).removeClass("collapsed").addClass("expanded");
|
||||
|
||||
childrenOf($(this)).each(function() {
|
||||
initialize($(this));
|
||||
|
||||
if($(this).is(".expanded.parent")) {
|
||||
$(this).expand();
|
||||
}
|
||||
|
||||
// this.style.display = "table-row"; // Unfortunately this is not possible with IE :-(
|
||||
$(this).show();
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Reveal a node by expanding all ancestors
|
||||
$.fn.reveal = function() {
|
||||
$(ancestorsOf($(this)).reverse()).each(function() {
|
||||
initialize($(this));
|
||||
$(this).expand().show();
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Add an entire branch to +destination+
|
||||
$.fn.appendBranchTo = function(destination) {
|
||||
var node = $(this);
|
||||
var parent = parentOf(node);
|
||||
|
||||
var ancestorNames = $.map(ancestorsOf($(destination)), function(a) { return a.id; });
|
||||
|
||||
// Conditions:
|
||||
// 1: +node+ should not be inserted in a location in a branch if this would
|
||||
// result in +node+ being an ancestor of itself.
|
||||
// 2: +node+ should not have a parent OR the destination should not be the
|
||||
// same as +node+'s current parent (this last condition prevents +node+
|
||||
// from being moved to the same location where it already is).
|
||||
// 3: +node+ should not be inserted as a child of +node+ itself.
|
||||
if($.inArray(node[0].id, ancestorNames) == -1 && (!parent || (destination.id != parent[0].id)) && destination.id != node[0].id) {
|
||||
indent(node, ancestorsOf(node).length * options.indent * -1); // Remove indentation
|
||||
|
||||
if(parent) { node.removeClass(options.childPrefix + parent[0].id); }
|
||||
|
||||
node.addClass(options.childPrefix + destination.id);
|
||||
move(node, destination); // Recursively move nodes to new location
|
||||
indent(node, ancestorsOf(node).length * options.indent);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Add reverse() function from JS Arrays
|
||||
$.fn.reverse = function() {
|
||||
return this.pushStack(this.get().reverse(), arguments);
|
||||
};
|
||||
|
||||
// Toggle an entire branch
|
||||
$.fn.toggleBranch = function() {
|
||||
if($(this).hasClass("collapsed")) {
|
||||
$(this).expand();
|
||||
} else {
|
||||
$(this).removeClass("expanded").collapse();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// === Private functions
|
||||
|
||||
function ancestorsOf(node) {
|
||||
var ancestors = [];
|
||||
while(node = parentOf(node)) {
|
||||
ancestors[ancestors.length] = node[0];
|
||||
}
|
||||
return ancestors;
|
||||
};
|
||||
|
||||
function childrenOf(node) {
|
||||
return $(node).siblings("tr." + options.childPrefix + node[0].id);
|
||||
};
|
||||
|
||||
function getPaddingLeft(node) {
|
||||
var paddingLeft = parseInt(node[0].style.paddingLeft, 10);
|
||||
return (isNaN(paddingLeft)) ? defaultPaddingLeft : paddingLeft;
|
||||
}
|
||||
|
||||
function indent(node, value) {
|
||||
var cell = $(node.children("td")[options.treeColumn]);
|
||||
cell[0].style.paddingLeft = getPaddingLeft(cell) + value + "px";
|
||||
|
||||
childrenOf(node).each(function() {
|
||||
indent($(this), value);
|
||||
});
|
||||
};
|
||||
|
||||
function initialize(node) {
|
||||
if(!node.hasClass("initialized")) {
|
||||
node.addClass("initialized");
|
||||
|
||||
var childNodes = childrenOf(node);
|
||||
|
||||
if(!node.hasClass("parent") && childNodes.length > 0) {
|
||||
node.addClass("parent");
|
||||
}
|
||||
|
||||
if(node.hasClass("parent")) {
|
||||
var cell = $(node.children("td")[options.treeColumn]);
|
||||
var padding = getPaddingLeft(cell) + options.indent;
|
||||
|
||||
childNodes.each(function() {
|
||||
$(this).children("td")[options.treeColumn].style.paddingLeft = padding + "px";
|
||||
});
|
||||
|
||||
if(options.expandable) {
|
||||
cell.prepend('<span style="margin-left: -' + options.indent + 'px; padding-left: ' + options.indent + 'px" class="expander"></span>');
|
||||
$(cell[0].firstChild).click(function() { node.toggleBranch(); });
|
||||
|
||||
if(options.clickableNodeNames) {
|
||||
cell[0].style.cursor = "pointer";
|
||||
$(cell).click(function(e) {
|
||||
// Don't double-toggle if the click is on the existing expander icon
|
||||
if (e.target.className != 'expander') {
|
||||
node.toggleBranch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Check for a class set explicitly by the user, otherwise set the default class
|
||||
if(!(node.hasClass("expanded") || node.hasClass("collapsed"))) {
|
||||
node.addClass(options.initialState);
|
||||
}
|
||||
|
||||
if(node.hasClass("expanded")) {
|
||||
node.expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function move(node, destination) {
|
||||
node.insertAfter(destination);
|
||||
childrenOf(node).reverse().each(function() { move($(this), node[0]); });
|
||||
};
|
||||
|
||||
function parentOf(node) {
|
||||
var classNames = node[0].className.split(' ');
|
||||
|
||||
for(key in classNames) {
|
||||
if(classNames[key].match(options.childPrefix)) {
|
||||
return $(node).siblings("#" + classNames[key].substring(options.childPrefix.length));
|
||||
}
|
||||
}
|
||||
};
|
||||
})(jQuery);
|
100
sites/all/modules/token/token.api.php
Normal file
100
sites/all/modules/token/token.api.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the token module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provide metadata about available placeholder tokens and token types.
|
||||
*
|
||||
* @param $type
|
||||
* The type of tokens to list (e.g. 'global', 'node', or 'user'). To list all
|
||||
* tokens, use 'all'.
|
||||
*
|
||||
* @return
|
||||
* An associative array of available tokens. The base array is keys of token
|
||||
* types and an array of its tokens. The token arrays are keys containing the
|
||||
* raw name of the token and values containing its user-friendly name.
|
||||
*/
|
||||
function hook_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'global' || $type == 'all') {
|
||||
$tokens['global']['random-number'] = t('A randomly generated number.');
|
||||
|
||||
}
|
||||
if ($type == 'node' || $type == 'all') {
|
||||
$tokens['node']['node-random-nid'] = t("A randomly generated number between one and the node's unique ID.");
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide replacement values for placeholder tokens.
|
||||
*
|
||||
* @param $type
|
||||
* The type of token being replaced (e.g. 'global', 'node', or 'user').
|
||||
* @param $data
|
||||
* (optional) An object to be used when generating replacement values.
|
||||
* @param $options
|
||||
* (optional) A associative array of options to control the token replacement
|
||||
* process.
|
||||
*
|
||||
* @return
|
||||
* An associative array of replacement values, keyed by the original 'raw'
|
||||
* tokens that were found in the source text. For example:
|
||||
* $values['title-raw'] = 'My new node';
|
||||
*
|
||||
* @see hook_token_values_alter()
|
||||
*/
|
||||
function hook_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
|
||||
if ($type == 'global') {
|
||||
$values['random-number'] = mt_rand();
|
||||
}
|
||||
|
||||
if ($type == 'node' && !empty($object)) {
|
||||
$values['node-random-nid'] = mt_rand(1, $object->nid);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter replacement values for placeholder tokens.
|
||||
*
|
||||
* @param $replacements
|
||||
* An associative array of replacements returned by hook_token_values().
|
||||
* @param $context
|
||||
* The context in which hook_token_values() was called. An associative array
|
||||
* with the following keys, which have the same meaning as the corresponding
|
||||
* parameters of hook_token_values():
|
||||
* - 'type'
|
||||
* - 'object'
|
||||
* - 'options'
|
||||
*
|
||||
* @see hook_token_values()
|
||||
*/
|
||||
function hook_token_values_alter(&$replacements, $context) {
|
||||
if ($context['type'] == 'node' && !empty($context['object'])) {
|
||||
$node = $context['object'];
|
||||
|
||||
if (isset($replacements['title-raw']) && !empty($node->field_title[0]['value'])) {
|
||||
$title = $node->field_title[0]['value'];
|
||||
$replacements['title-raw'] = $title;
|
||||
$replacements['title'] = check_plain($title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
23
sites/all/modules/token/token.css
Normal file
23
sites/all/modules/token/token.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
.token-tree {
|
||||
font-size: 0.85em;
|
||||
margin-left: 19px;
|
||||
}
|
||||
|
||||
.token-tree td, .token-tree th {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.token-group {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.js .token-group {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* Prevent the token columns from being wrapped. */
|
||||
.token-tree td.token-key {
|
||||
white-space: nowrap;
|
||||
}
|
10
sites/all/modules/token/token.info
Normal file
10
sites/all/modules/token/token.info
Normal file
|
@ -0,0 +1,10 @@
|
|||
name = Token
|
||||
description = Provides a shared API for replacement of textual placeholders with actual data.
|
||||
core = 6.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-09-12
|
||||
version = "6.x-1.19"
|
||||
core = "6.x"
|
||||
project = "token"
|
||||
datestamp = "1347470077"
|
||||
|
43
sites/all/modules/token/token.install
Normal file
43
sites/all/modules/token/token.install
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The install and update code for the token module.
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function token_requirements($phase = 'runtime') {
|
||||
$requirements = array();
|
||||
$t = get_t();
|
||||
|
||||
// Check for duplicate tokens.
|
||||
if ($phase == 'runtime') {
|
||||
if ($duplicate_tokens = token_find_duplicate_tokens()) {
|
||||
foreach ($duplicate_tokens as $token => $modules) {
|
||||
$duplicate_tokens[$token] = $t('@token (defined by modules: @modules)', array('@token' => $token, '@modules' => implode(', ', $modules)));
|
||||
}
|
||||
$requirements['token_duplicates'] = array(
|
||||
'title' => $t('Duplicate tokens'),
|
||||
'value' => $t('The following tokens are defined by multiple modules and may cause problems when performing token replacement.'),
|
||||
'severity' => REQUIREMENT_WARNING,
|
||||
'description' => theme('item_list', $duplicate_tokens),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
function token_install() {
|
||||
db_query("UPDATE {system} SET weight = 10 WHERE name = 'token'");
|
||||
}
|
||||
|
||||
function token_update_1() {
|
||||
$ret = array();
|
||||
$ret[] = update_sql("UPDATE {system} SET weight = 10 WHERE name = 'token'");
|
||||
return $ret;
|
||||
}
|
51
sites/all/modules/token/token.js
Normal file
51
sites/all/modules/token/token.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.tokenTree = function() {
|
||||
$('table.token-tree').each(function() {
|
||||
$(this).treeTable();
|
||||
});
|
||||
};
|
||||
|
||||
Drupal.behaviors.tokenInsert = function() {
|
||||
// Keep track of which textfield was last selected/focused.
|
||||
$('textarea, input[type="text"]').focus(function() {
|
||||
Drupal.settings.tokenFocusedField = this;
|
||||
});
|
||||
|
||||
$('.token-click-insert .token-key').each(function() {
|
||||
var newThis = $('<a href="javascript:void(0);" title="' + Drupal.t('Insert this token into your form') + '">' + $(this).html() + '</a>').click(function(){
|
||||
if (typeof Drupal.settings.tokenFocusedField == 'undefined') {
|
||||
alert(Drupal.t('First click a text field to insert your tokens into.'));
|
||||
}
|
||||
else {
|
||||
var myField = Drupal.settings.tokenFocusedField;
|
||||
var myValue = $(this).text();
|
||||
|
||||
//IE support
|
||||
if (document.selection) {
|
||||
myField.focus();
|
||||
sel = document.selection.createRange();
|
||||
sel.text = myValue;
|
||||
}
|
||||
|
||||
//MOZILLA/NETSCAPE support
|
||||
else if (myField.selectionStart || myField.selectionStart == '0') {
|
||||
var startPos = myField.selectionStart;
|
||||
var endPos = myField.selectionEnd;
|
||||
myField.value = myField.value.substring(0, startPos)
|
||||
+ myValue
|
||||
+ myField.value.substring(endPos, myField.value.length);
|
||||
} else {
|
||||
myField.value += myValue;
|
||||
}
|
||||
|
||||
$('html,body').animate({scrollTop: $(myField).offset().top}, 500);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$(this).html(newThis);
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|
960
sites/all/modules/token/token.module
Normal file
960
sites/all/modules/token/token.module
Normal file
|
@ -0,0 +1,960 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The Token API module.
|
||||
*
|
||||
* The Token module provides an API for providing tokens to other modules.
|
||||
* Tokens are small bits of text that can be placed into larger documents
|
||||
* via simple placeholders, like %site-name or [user].
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* The default token prefix string.
|
||||
*/
|
||||
define('TOKEN_PREFIX', '[');
|
||||
|
||||
/**
|
||||
* The default token suffix string.
|
||||
*/
|
||||
define('TOKEN_SUFFIX', ']');
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function token_help($path, $arg) {
|
||||
if ($path == 'admin/help#token') {
|
||||
$output = '<dl>';
|
||||
$output .= '<dt>' . t('List of the currently available tokens on this site') . '</dt>';
|
||||
$output .= '<dd>' . theme('token_tree', 'all', TRUE, FALSE) . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of the core modules supported by token.module.
|
||||
*/
|
||||
function _token_core_supported_modules() {
|
||||
return array('node', 'user', 'taxonomy', 'comment', 'menu', 'book');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function token_menu() {
|
||||
$items = array();
|
||||
|
||||
// Devel token pages.
|
||||
if (module_exists('devel')) {
|
||||
$items['node/%node/devel/token'] = array(
|
||||
'title' => 'Tokens',
|
||||
'page callback' => 'token_devel_token_object',
|
||||
'page arguments' => array('node', 1),
|
||||
'access arguments' => array('access devel information'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'token.pages.inc',
|
||||
'weight' => 5,
|
||||
);
|
||||
$items['user/%user/devel/token'] = array(
|
||||
'title' => 'Tokens',
|
||||
'page callback' => 'token_devel_token_object',
|
||||
'page arguments' => array('user', 1),
|
||||
'access arguments' => array('access devel information'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'token.pages.inc',
|
||||
'weight' => 5,
|
||||
);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function token_theme() {
|
||||
return array(
|
||||
'token_help' => array(
|
||||
'arguments' => array('type' => 'all', 'prefix' => TOKEN_PREFIX, 'suffix' => TOKEN_SUFFIX),
|
||||
'file' => 'token.pages.inc',
|
||||
),
|
||||
'token_tree' => array(
|
||||
'arguments' => array('token_types' => array(), 'global_types' => TRUE , 'click_insert' => TRUE),
|
||||
'file' => 'token.pages.inc',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_values().
|
||||
*/
|
||||
function token_token_values($type, $object = NULL) {
|
||||
global $user;
|
||||
$values = array();
|
||||
|
||||
switch ($type) {
|
||||
case 'global':
|
||||
// Current user tokens.
|
||||
$values['user-name'] = $user->uid ? $user->name : variable_get('anonymous', t('Anonymous'));
|
||||
$values['user-id'] = $user->uid ? $user->uid : 0;
|
||||
$values['user-mail'] = $user->uid ? $user->mail : '';
|
||||
|
||||
// Site information tokens.
|
||||
$values['site-url'] = url('<front>', array('absolute' => TRUE));
|
||||
$values['site-name'] = check_plain(variable_get('site_name', t('Drupal')));
|
||||
$values['site-slogan'] = check_plain(variable_get('site_slogan', ''));
|
||||
$values['site-mission'] = filter_xss_admin(variable_get('site_mission', ''));
|
||||
$values['site-mail'] = variable_get('site_mail', '');
|
||||
$values += token_get_date_token_values(NULL, 'site-date-');
|
||||
|
||||
// Current page tokens.
|
||||
$values['current-page-title'] = drupal_get_title();
|
||||
$alias = drupal_get_path_alias($_GET['q']);
|
||||
$values['current-page-path-raw'] = $alias;
|
||||
$values['current-page-path'] = check_plain($alias);
|
||||
$values['current-page-url'] = url($_GET['q'], array('absolute' => TRUE));
|
||||
|
||||
$page = isset($_GET['page']) ? $_GET['page'] : '';
|
||||
$pager_page_array = explode(',', $page);
|
||||
$page = $pager_page_array[0];
|
||||
$values['current-page-number'] = (int) $page + 1;
|
||||
|
||||
// Backwards compatability for renamed tokens.
|
||||
$values['site-date'] = $values['site-date-small'];
|
||||
$values['page-number'] = $values['current-page-number'];
|
||||
|
||||
break;
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_list().
|
||||
*/
|
||||
function token_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'global' || $type == 'all') {
|
||||
// Current user tokens.
|
||||
$tokens['global']['user-name'] = t('The name of the currently logged in user.');
|
||||
$tokens['global']['user-id'] = t('The user ID of the currently logged in user.');
|
||||
$tokens['global']['user-mail'] = t('The email address of the currently logged in user.');
|
||||
|
||||
// Site information tokens.
|
||||
$tokens['global']['site-url'] = t("The URL of the site's front page.");
|
||||
$tokens['global']['site-name'] = t('The name of the site.');
|
||||
$tokens['global']['site-slogan'] = t('The slogan of the site.');
|
||||
$tokens['global']['site-mission'] = t("The optional 'mission' of the site.");
|
||||
$tokens['global']['site-mail'] = t('The administrative email address for the site.');
|
||||
$tokens['global'] += token_get_date_token_info(t('The current'), 'site-date-');
|
||||
|
||||
// Current page tokens.
|
||||
$tokens['global']['current-page-title'] = t('The title of the current page.');
|
||||
$tokens['global']['current-page-path'] = t('The URL alias of the current page.');
|
||||
$tokens['global']['current-page-path-raw'] = t('The URL alias of the current page.');
|
||||
$tokens['global']['current-page-url'] = t('The URL of the current page.');
|
||||
$tokens['global']['current-page-number'] = t('The page number of the current page when viewing paged lists.');
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* General function to include the files that token relies on for the real work.
|
||||
*/
|
||||
function token_include() {
|
||||
static $run = FALSE;
|
||||
|
||||
if (!$run) {
|
||||
$run = TRUE;
|
||||
$modules_enabled = array_keys(module_list());
|
||||
$modules = array_intersect(_token_core_supported_modules(), $modules_enabled);
|
||||
foreach ($modules as $module) {
|
||||
module_load_include('inc', 'token', "token_$module");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all tokens in a given string with appropriate values.
|
||||
*
|
||||
* @param $text
|
||||
* A string potentially containing replaceable tokens.
|
||||
* @param $type
|
||||
* (optional) A flag indicating the class of substitution tokens to use. If
|
||||
* an object is passed in the second param, 'type' should contain the
|
||||
* object's type. For example, 'node', 'comment', or 'user'. If no type is
|
||||
* specified, only 'global' site-wide substitution tokens are built.
|
||||
* @param $object
|
||||
* (optional) An object to use for building substitution values (e.g. a node
|
||||
* comment, or user object).
|
||||
* @param $leading
|
||||
* (optional) Character(s) to prepend to the token key before searching for
|
||||
* matches. Defaults to TOKEN_PREFIX.
|
||||
* @param $trailing
|
||||
* (optional) Character(s) to append to the token key before searching for
|
||||
* matches. Defaults to TOKEN_SUFFIX.
|
||||
* @param $options
|
||||
* (optional) A keyed array of settings and flags to control the token
|
||||
* generation and replacement process. Supported options are:
|
||||
* - clear: A boolean flag indicating that tokens should be removed from the
|
||||
* final text if no replacement value can be generated.
|
||||
* @param $flush
|
||||
* (optional) A flag indicating whether or not to flush the token cache.
|
||||
* Useful for processes that need to slog through huge numbers of tokens
|
||||
* in a single execution cycle. Flushing it will keep them from burning
|
||||
* through memory. Defaults to FALSE.
|
||||
*
|
||||
* @return
|
||||
* Text with tokens replaced.
|
||||
*/
|
||||
function token_replace($text, $type = 'global', $object = NULL, $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX, $options = array(), $flush = FALSE) {
|
||||
return token_replace_multiple($text, array($type => $object), $leading, $trailing, $options, $flush);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all tokens in a given string with appropriate values.
|
||||
*
|
||||
* Contrary to token_replace() this function supports replacing multiple types.
|
||||
*
|
||||
* @param $text
|
||||
* A string potentially containing replaceable tokens.
|
||||
* @param $types
|
||||
* (optional) An array of substitution classes and optional objects. The key
|
||||
* is a flag indicating the class of substitution tokens to use. If an object
|
||||
* is passed as value, the key should contain the object's type. For example,
|
||||
* 'node', 'comment', or 'user'. The object will be used for building
|
||||
* substitution values. If no type is specified, only 'global' site-wide
|
||||
* substitution tokens are built.
|
||||
* @param $leading
|
||||
* (optional) Character(s) to prepend to the token key before searching for
|
||||
* matches. Defaults to TOKEN_PREFIX.
|
||||
* @param $trailing
|
||||
* (optional) Character(s) to append to the token key before searching for
|
||||
* matches. Defaults to TOKEN_SUFFIX.
|
||||
* @param $options
|
||||
* (optional) A keyed array of settings and flags to control the token
|
||||
* generation and replacement process. Supported options are:
|
||||
* - clear: A boolean flag indicating that tokens should be removed from the
|
||||
* final text if no replacement value can be generated.
|
||||
* @param $flush
|
||||
* (optional) A flag indicating whether or not to flush the token cache.
|
||||
* Useful for processes that need to slog through huge numbers of tokens
|
||||
* in a single execution cycle. Flushing it will keep them from burning
|
||||
* through memory. Defaults to FALSE.
|
||||
*
|
||||
* @return
|
||||
* Text with tokens replaced.
|
||||
*/
|
||||
function token_replace_multiple($text, $types = array('global' => NULL), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX, $options = array(), $flush = FALSE) {
|
||||
// Ensure that the $text parameter is a string and not an array which is an
|
||||
// invalid input.
|
||||
if (is_array($text)) {
|
||||
foreach ($text as $key => $value) {
|
||||
$text[$key] = token_replace_multiple($value, $types, $leading, $trailing, $options, $flush);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
// If there are no tokens to replace, just return the text.
|
||||
$text_tokens = token_scan($text, $leading, $trailing);
|
||||
if (empty($text_tokens)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$full = new stdClass();
|
||||
$full->tokens = $full->values = array();
|
||||
|
||||
// Allow global token replacement by default.
|
||||
if (empty($types) || !is_array($types)) {
|
||||
$types = array('global' => NULL);
|
||||
}
|
||||
|
||||
foreach ($types as $type => $object) {
|
||||
$temp = token_get_values($type, $object, $flush, $options);
|
||||
$full->tokens = array_merge($full->tokens, $temp->tokens);
|
||||
$full->values = array_merge($full->values, $temp->values);
|
||||
}
|
||||
|
||||
// Support clearing out tokens that would not be replaced.
|
||||
if (!empty($options['clear'])) {
|
||||
foreach ($text_tokens as $token) {
|
||||
if (!in_array($token, $full->tokens)) {
|
||||
$full->tokens[] = $token;
|
||||
$full->values[] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tokens = token_prepare_tokens($full->tokens, $leading, $trailing);
|
||||
return str_replace($tokens, $full->values, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of valid substitution tokens and their values for
|
||||
* the specified type.
|
||||
*
|
||||
* @param $type
|
||||
* (optional) A flag indicating the class of substitution tokens to use. If an
|
||||
* object is passed in the second param, 'type' should contain the
|
||||
* object's type. For example, 'node', 'comment', or 'user'. If no
|
||||
* type is specified, only 'global' site-wide substitution tokens are
|
||||
* built.
|
||||
* @param $object
|
||||
* (optional) An object to use for building substitution values (e.g. a node
|
||||
* comment, or user object).
|
||||
* @param $flush
|
||||
* (optional) A flag indicating whether or not to flush the token cache.
|
||||
* Useful for processes that need to slog through huge numbers of tokens
|
||||
* in a single execution cycle. Flushing it will keep them from burning
|
||||
* through memory. Defaults to FALSE.
|
||||
* @param $options
|
||||
* (optional) A keyed array of settings and flags to control the token
|
||||
* generation process.
|
||||
*
|
||||
* @return
|
||||
* An object with two properties:
|
||||
* - tokens: All the possible tokens names generated.
|
||||
* - values: The corresponding values for the tokens.
|
||||
*
|
||||
* Note that before performing actual token replacement that the token names
|
||||
* should be run through token_prepare_tokens().
|
||||
*/
|
||||
function token_get_values($type = 'global', $object = NULL, $flush = FALSE, $options = array()) {
|
||||
static $tokens = array();
|
||||
static $running = FALSE;
|
||||
|
||||
// Simple recursion check. This is to avoid content_view()'s potential
|
||||
// for endless looping when a filter uses tokens, which load the content
|
||||
// view, which calls the filter, which uses tokens, which...
|
||||
if ($running) {
|
||||
// We'll allow things to get two levels deep, but bail out after that
|
||||
// without performing any substitutions.
|
||||
$result = new stdClass();
|
||||
$result->tokens = array();
|
||||
$result->values = array();
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
$running = TRUE;
|
||||
}
|
||||
|
||||
// Flush the static token cache. Useful for processes that need to slog
|
||||
// through huge numbers of tokens in a single execution cycle. Flushing it
|
||||
// will keep them from burning through memory.
|
||||
if ($flush || !empty($options['reset'])) {
|
||||
$tokens = array();
|
||||
}
|
||||
|
||||
// Allow simple resets of the static values.
|
||||
if ($type === 'reset') {
|
||||
$tokens = array();
|
||||
$running = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
// Neutralize options that do not affect token replacement.
|
||||
$serialized_options = $options;
|
||||
unset($serialized_options['clear']);
|
||||
|
||||
// Store the token cache by object ID and serialized options.
|
||||
$cid = _token_get_id($type, $object) . ':' . md5(serialize($serialized_options));
|
||||
if ($type != 'global' && !isset($tokens[$type][$cid])) {
|
||||
token_include();
|
||||
$tokens[$type][$cid] = module_invoke_all('token_values', $type, $object, $options);
|
||||
}
|
||||
|
||||
// Special-case global tokens, as we always want to be able to process
|
||||
// those substitutions.
|
||||
if (!isset($tokens['global'][$cid])) {
|
||||
token_include();
|
||||
$tokens['global'][$cid] = module_invoke_all('token_values', 'global', NULL, $options);
|
||||
}
|
||||
|
||||
$all = $tokens['global'][$cid];
|
||||
if ($type != 'global') {
|
||||
// Avoid using array_merge() if only global tokens were requested.
|
||||
$all = array_merge($all, $tokens[$type][$cid]);
|
||||
}
|
||||
|
||||
// Allow other modules to alter the replacements.
|
||||
$context = array(
|
||||
'type' => $type,
|
||||
'object' => $object,
|
||||
'options' => $options,
|
||||
);
|
||||
drupal_alter('token_values', $all, $context);
|
||||
|
||||
$result = new stdClass();
|
||||
$result->tokens = array_keys($all);
|
||||
$result->values = array_values($all);
|
||||
|
||||
$running = FALSE;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function that retrieves all currently exposed tokens,
|
||||
* and merges them recursively. This is only necessary when building
|
||||
* the token listing -- during actual value replacement, only tokens
|
||||
* in a particular domain are requested and a normal array_marge() is
|
||||
* sufficient.
|
||||
*
|
||||
* @param $types
|
||||
* A flag indicating the class of substitution tokens to use. If an
|
||||
* object is passed in the second param, 'types' should contain the
|
||||
* object's type. For example, 'node', 'comment', or 'user'. 'types'
|
||||
* may also be an array of types of the form array('node','user'). If no
|
||||
* type is specified, only 'global' site-wide substitution tokens are
|
||||
* built.
|
||||
*
|
||||
* @return
|
||||
* The array of usable tokens and their descriptions, organized by
|
||||
* token type.
|
||||
*/
|
||||
function token_get_list($types = 'all') {
|
||||
token_include();
|
||||
$return = array();
|
||||
settype($types, 'array');
|
||||
foreach (module_implements('token_list') as $module) {
|
||||
foreach ($types as $type) {
|
||||
$module_token_list = module_invoke($module, 'token_list', $type);
|
||||
if (isset($module_token_list) && is_array($module_token_list)) {
|
||||
foreach ($module_token_list as $category => $tokens) {
|
||||
foreach ($tokens as $token => $title) {
|
||||
// Automatically append a raw token warning.
|
||||
if (substr($token, -4) === '-raw' && strpos($title, t('raw user input')) === FALSE && strpos($title, t('UNIX timestamp format')) === FALSE) {
|
||||
$title .= ' <em>' . t('Warning: Token value contains raw user input.') . '</em>';
|
||||
}
|
||||
$return[$category][$token] = $title;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort the tokens by name.
|
||||
foreach (array_keys($return) as $category) {
|
||||
ksort($return[$category]);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to prepare raw tokens for replacement.
|
||||
*
|
||||
* @param $tokens
|
||||
* The array of tokens names with no delimiting characters.
|
||||
* @param $leading
|
||||
* String to prepend to the token. Default is TOKEN_PREFIX.
|
||||
* @param $trailing
|
||||
* String to append to the token. Default is TOKEN_SUFFIX.
|
||||
*
|
||||
* @return
|
||||
* An array of the formatted tokens.
|
||||
*/
|
||||
function token_prepare_tokens($tokens = array(), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) {
|
||||
foreach ($tokens as $key => $value) {
|
||||
$tokens[$key] = $leading . $value . $trailing;
|
||||
}
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to return an object's ID for use in static caching.
|
||||
*/
|
||||
function _token_get_id($type = 'global', $object = NULL) {
|
||||
if (!isset($object)) {
|
||||
return "default";
|
||||
}
|
||||
switch ($type) {
|
||||
case 'node':
|
||||
return isset($object->vid) ? $object->vid : (isset($object->nid) ? $object->nid : 0);
|
||||
case 'comment':
|
||||
return isset($object->cid) ? $object->cid : 0;
|
||||
case 'user':
|
||||
return isset($object->uid) ? $object->uid : 0;
|
||||
case 'taxonomy':
|
||||
return isset($object->tid) ? $object->tid : 0;
|
||||
default:
|
||||
return crc32(serialize($object));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of common date tokens for use in hook_token_list().
|
||||
*
|
||||
* @param $description
|
||||
*/
|
||||
function token_get_date_token_info($description, $token_prefix = '') {
|
||||
$time = time();
|
||||
$tokens[$token_prefix . 'small'] = t("!description date in 'small' format. (%date)", array('!description' => $description, '%date' => format_date($time, 'small')));
|
||||
$tokens[$token_prefix . 'yyyy'] = t("!description year (four digit)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'yy'] = t("!description year (two digit)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'month'] = t("!description month (full word)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'mon'] = t("!description month (abbreviated)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'mm'] = t("!description month (two digits with leading zeros)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'm'] = t("!description month (one or two digits without leading zeros)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'ww'] = t("!description week (two digits with leading zeros)", array('!description' => $description));
|
||||
if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
|
||||
$tokens[$token_prefix . 'date'] = t("!description date (numeric representation of the day of the week)", array('!description' => $description));
|
||||
}
|
||||
$tokens[$token_prefix . 'day'] = t("!description day (full word)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'ddd'] = t("!description day (abbreviation)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'dd'] = t("!description day (two digits with leading zeros)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'd'] = t("!description day (one or two digits without leading zeros)", array('!description' => $description));
|
||||
$tokens[$token_prefix . 'raw'] = t("!description in UNIX timestamp format (%date)", array('!description' => $description, '%date' => $time));
|
||||
$tokens[$token_prefix . 'since'] = t("!description in 'time-since' format. (%date)", array('!description' => $description, '%date' => format_interval($time - 360, 2)));
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of common date tokens for use in hook_token_values().
|
||||
*/
|
||||
function token_get_date_token_values($timestamp = NULL, $token_prefix = '', $langcode = NULL) {
|
||||
static $formats;
|
||||
|
||||
if (!isset($formats)) {
|
||||
$formats = array();
|
||||
$formats['small'] = variable_get('date_format_short', 'm/d/Y - H:i');
|
||||
$formats['yyyy'] = 'Y';
|
||||
$formats['yy'] = 'y';
|
||||
$formats['month'] = 'F';
|
||||
$formats['mon'] = 'M';
|
||||
$formats['mm'] = 'm';
|
||||
$formats['m'] = 'n';
|
||||
$formats['ww'] = 'W';
|
||||
if (version_compare(PHP_VERSION, '5.1.0', '>=')) {
|
||||
$formats['date'] = 'N';
|
||||
}
|
||||
$formats['day'] = 'l';
|
||||
$formats['ddd'] = 'D';
|
||||
$formats['dd'] = 'd';
|
||||
$formats['d'] = 'j';
|
||||
}
|
||||
|
||||
$time = time();
|
||||
if (!isset($timestamp)) {
|
||||
$timestamp = $time;
|
||||
}
|
||||
|
||||
$tokens = array();
|
||||
foreach ($formats as $token => $format) {
|
||||
$tokens[$token_prefix . $token] = token_format_date($timestamp, 'custom', $format, NULL, $langcode);
|
||||
}
|
||||
$tokens[$token_prefix . 'raw'] = $timestamp;
|
||||
$tokens[$token_prefix . 'since'] = format_interval($time - $timestamp, 2, $langcode);
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* A copy of format_date() that supports the 'N' date format character.
|
||||
*
|
||||
* @see format_date()
|
||||
*/
|
||||
function token_format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
|
||||
global $user;
|
||||
static $timezones = array();
|
||||
|
||||
// Statically cache each user's timezone so it doesn't need to be re-fetched
|
||||
// ever call.
|
||||
if (!isset($timezones[$user->uid])) {
|
||||
if (!empty($user->uid) && variable_get('configurable_timezones', 1) && strlen($user->timezone)) {
|
||||
$timezones[$user->uid] = $user->timezone;
|
||||
}
|
||||
else {
|
||||
$timezones[$user->uid] = variable_get('date_default_timezone', 0);
|
||||
}
|
||||
}
|
||||
|
||||
$timestamp += $timezones[$user->uid];
|
||||
|
||||
switch ($type) {
|
||||
case 'custom':
|
||||
// No change to format.
|
||||
break;
|
||||
case 'small':
|
||||
$format = variable_get('date_format_short', 'm/d/Y - H:i');
|
||||
break;
|
||||
case 'large':
|
||||
$format = variable_get('date_format_long', 'l, F j, Y - H:i');
|
||||
break;
|
||||
case 'medium':
|
||||
default:
|
||||
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
|
||||
}
|
||||
|
||||
$max = strlen($format);
|
||||
$date = '';
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
$c = $format[$i];
|
||||
if (strpos('AaDlM', $c) !== FALSE) {
|
||||
$date .= t(gmdate($c, $timestamp), array(), $langcode);
|
||||
}
|
||||
elseif ($c == 'F') {
|
||||
// Special treatment for long month names: May is both an abbreviation
|
||||
// and a full month name in English, but other languages have
|
||||
// different abbreviations.
|
||||
$date .= trim(t('!long-month-name ' . gmdate($c, $timestamp), array('!long-month-name' => ''), $langcode));
|
||||
}
|
||||
elseif (strpos('BdgGhHiIjLmnNsStTUwWYyz', $c) !== FALSE) {
|
||||
// This condition was modified to allow the 'N' date format character.
|
||||
$date .= gmdate($c, $timestamp);
|
||||
}
|
||||
elseif ($c == 'r') {
|
||||
$date .= token_format_date($timestamp - $timezone, 'custom', 'D, d M Y H:i:s O', $timezone, $langcode);
|
||||
}
|
||||
elseif ($c == 'O') {
|
||||
$date .= sprintf('%s%02d%02d', ($timezone < 0 ? '-' : '+'), abs($timezone / 3600), abs($timezone % 3600) / 60);
|
||||
}
|
||||
elseif ($c == 'Z') {
|
||||
$date .= $timezone;
|
||||
}
|
||||
elseif ($c == '\\') {
|
||||
$date .= $format[++$i];
|
||||
}
|
||||
else {
|
||||
$date .= $c;
|
||||
}
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an tokens in raw text based on possible contexts.
|
||||
*
|
||||
* @param $value
|
||||
* A string with the raw text containing the raw tokens, or an array of
|
||||
* tokens from token_scan().
|
||||
* @param $valid_types
|
||||
* An array of token types to validage against.
|
||||
* @param $leading
|
||||
* Character(s) to prepend to the token key before searching for
|
||||
* matches. Defaults to TOKEN_PREFIX.
|
||||
* @param $trailing
|
||||
* Character(s) to append to the token key before searching for
|
||||
* matches. Defaults to TOKEN_SUFFIX.
|
||||
*
|
||||
* @return
|
||||
* An array with the invalid tokens in their original raw forms.
|
||||
*/
|
||||
function token_get_invalid_tokens_by_context($value, $valid_types = array(), $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) {
|
||||
if (in_array('all', $valid_types)) {
|
||||
$valid_types = array('all');
|
||||
}
|
||||
else {
|
||||
// Add the token types that are always valid in global context.
|
||||
$valid_types[] = 'global';
|
||||
}
|
||||
|
||||
$invalid_tokens = array();
|
||||
$valid_tokens = array();
|
||||
$value_tokens = is_string($value) ? token_scan($value, $leading, $trailing) : $value;
|
||||
|
||||
foreach (token_get_list($valid_types) as $category => $tokens) {
|
||||
$valid_tokens += $tokens;
|
||||
}
|
||||
|
||||
foreach ($value_tokens as $token) {
|
||||
if (isset($valid_tokens[$token])) {
|
||||
continue;
|
||||
}
|
||||
elseif (preg_match('/^(.*[_-])([^-_])+$/', $token, $matches)) {
|
||||
// Allow tokens that do not have a direct match to tokens listed in
|
||||
// hook_token_info() to be matched against a 'wildcard' token name.
|
||||
if (isset($valid_tokens[$matches[1] . '?'])) {
|
||||
// [token-name-?] wildcards.
|
||||
continue;
|
||||
}
|
||||
elseif (isset($valid_tokens[$matches[1] . '????'])) {
|
||||
// [token-name-????] wildcards.
|
||||
continue;
|
||||
}
|
||||
elseif (is_numeric($matches[2]) && isset($valid_tokens[$matches[1] . 'N'])) {
|
||||
// [token-name-N] wildcards if N is a numeric value.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$invalid_tokens[] = $token;
|
||||
}
|
||||
|
||||
array_unique($invalid_tokens);
|
||||
$invalid_tokens = token_prepare_tokens($invalid_tokens, $leading, $trailing);
|
||||
return $invalid_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of all token-like patterns that appear in the text.
|
||||
*
|
||||
* @param $text
|
||||
* The text to be scanned for possible tokens.
|
||||
* @param $leading
|
||||
* Character(s) to prepend to the token key before searching for
|
||||
* matches. Defaults to TOKEN_PREFIX.
|
||||
* @param $trailing
|
||||
* Character(s) to append to the token key before searching for
|
||||
* matches. Defaults to TOKEN_SUFFIX.
|
||||
*
|
||||
* @return
|
||||
* An array of discovered tokens.
|
||||
*/
|
||||
function token_scan($text, $leading = TOKEN_PREFIX, $trailing = TOKEN_SUFFIX) {
|
||||
$leadingregex = preg_quote($leading, '/');
|
||||
$trailingregex = preg_quote($trailing, '/');
|
||||
|
||||
$regex = '/' . $leadingregex;
|
||||
$regex .= '([^\s';
|
||||
if (drupal_strlen($leading) == 1) {
|
||||
// Only add the leading string as a non-match if it is a single character.
|
||||
$regex .= $leadingregex;
|
||||
}
|
||||
if (drupal_strlen($trailing) == 1) {
|
||||
// Only add the trailing string as a non-match if it is a single character.
|
||||
$regex .= $trailingregex;
|
||||
}
|
||||
$regex .= ']+)' . $trailingregex . '/x';
|
||||
|
||||
preg_match_all($regex, $text, $matches);
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a form element that should have tokens in it.
|
||||
*
|
||||
* Form elements that want to add this validation should have the #token_types
|
||||
* parameter defined.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* $form['my_node_text_element'] = array(
|
||||
* '#type' => 'textfield',
|
||||
* '#title' => t('Some text to token-ize that has a node context.'),
|
||||
* '#default_value' => 'The title of this node is [title].',
|
||||
* '#element_validate' => array('token_element_validate'),
|
||||
* '#token_types' => array('node'),
|
||||
* '#min_tokens' => 1,
|
||||
* '#max_tokens' => 10,
|
||||
* );
|
||||
* @endcode
|
||||
*/
|
||||
function token_element_validate(&$element, &$form_state) {
|
||||
$value = isset($element['#value']) ? $element['#value'] : $element['#default_value'];
|
||||
|
||||
if (!drupal_strlen($value)) {
|
||||
// Empty value needs no further validation since the element should depend
|
||||
// on using the '#required' FAPI property.
|
||||
return $element;
|
||||
}
|
||||
|
||||
$tokens = token_scan($value);
|
||||
$title = empty($element['#title']) ? $element['#parents'][0] : $element['#title'];
|
||||
|
||||
// Validate if an element must have a minimum number of tokens.
|
||||
if (isset($element['#min_tokens']) && count($tokens) < $element['#min_tokens']) {
|
||||
// @todo Change this error message to include the minimum number.
|
||||
$error = format_plural($element['#min_tokens'], 'The %element-title cannot contain fewer than one token.', 'The %element-title must contain at least @count tokens.', array('%element-title' => $title));
|
||||
form_error($element, $error);
|
||||
}
|
||||
|
||||
// Validate if an element must have a maximum number of tokens.
|
||||
if (isset($element['#max_tokens']) && count($tokens) > $element['#max_tokens']) {
|
||||
// @todo Change this error message to include the maximum number.
|
||||
$error = format_plural($element['#max_tokens'], 'The %element-title must contain as most one token.', 'The %element-title must contain at most @count tokens.', array('%element-title' => $title));
|
||||
form_error($element, $error);
|
||||
}
|
||||
|
||||
// Check if the field defines specific token types.
|
||||
if (!empty($element['#token_types'])) {
|
||||
$invalid_tokens = token_get_invalid_tokens_by_context($tokens, $element['#token_types']);
|
||||
if ($invalid_tokens) {
|
||||
form_error($element, t('The %element-title is using the following invalid tokens: @invalid-tokens.', array('%element-title' => $title, '@invalid-tokens' => implode(', ', $invalid_tokens))));
|
||||
}
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use token_element_validate() instead.
|
||||
*/
|
||||
function token_element_validate_token_context(&$element, &$form_state) {
|
||||
return token_element_validate($element, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tokens that have been declared twice by different modules.
|
||||
*/
|
||||
function token_find_duplicate_tokens() {
|
||||
token_include();
|
||||
$all_tokens = array();
|
||||
|
||||
foreach (module_implements('token_list') as $module) {
|
||||
$module_token_list = module_invoke($module, 'token_list', 'all');
|
||||
if (!isset($module_token_list) || !is_array($module_token_list)) {
|
||||
// Skip modules that do not return an array as that is a valid return
|
||||
// value.
|
||||
continue;
|
||||
}
|
||||
if (in_array($module, _token_core_supported_modules())) {
|
||||
$module = 'token';
|
||||
}
|
||||
foreach ($module_token_list as $type => $tokens) {
|
||||
foreach (array_keys($tokens) as $token) {
|
||||
$all_tokens[$type . ':' . $token][] = $module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($all_tokens as $token => $modules) {
|
||||
if (count($modules) < 2) {
|
||||
unset($all_tokens[$token]);
|
||||
}
|
||||
}
|
||||
|
||||
return $all_tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a translated menu link by its mlid, without access checking.
|
||||
*
|
||||
* This function is a copy of menu_link_load() but with its own cache and a
|
||||
* simpler query to load the link. This also skips normal menu link access
|
||||
* checking by using _token_menu_link_translate().
|
||||
*
|
||||
* @param $mlid
|
||||
* The mlid of the menu item.
|
||||
*
|
||||
* @return
|
||||
* A menu link translated for rendering.
|
||||
*
|
||||
* @see menu_link_load()
|
||||
* @see _token_menu_link_translate()
|
||||
*/
|
||||
function token_menu_link_load($mlid) {
|
||||
static $cache = array();
|
||||
|
||||
if (!is_numeric($mlid)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!isset($cache[$mlid])) {
|
||||
$item = db_fetch_array(db_query("SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid));
|
||||
if (!empty($item)) {
|
||||
_token_menu_link_translate($item);
|
||||
}
|
||||
$cache[$mlid] = $item;
|
||||
}
|
||||
|
||||
return $cache[$mlid];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a translated book menu link by its mlid, without access checking.
|
||||
*
|
||||
* This function is a copy of book_link_load() but with its own cache and a
|
||||
* simpler query to load the link. This also skips normal menu link access
|
||||
* checking by using _token_menu_link_translate().
|
||||
*
|
||||
* @param $mlid
|
||||
* The mlid of the book menu item.
|
||||
*
|
||||
* @return
|
||||
* A book menu link translated for rendering.
|
||||
*
|
||||
* @see book_link_load()
|
||||
* @see _token_menu_link_translate()
|
||||
*/
|
||||
function token_book_link_load($mlid) {
|
||||
static $cache = array();
|
||||
|
||||
if (!is_numeric($mlid)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!isset($cache[$mlid])) {
|
||||
$item = db_fetch_array(db_query("SELECT * FROM {menu_links} ml INNER JOIN {book} b ON b.mlid = ml.mlid LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid));
|
||||
if (!empty($item)) {
|
||||
_token_menu_link_translate($item);
|
||||
}
|
||||
$cache[$mlid] = $item;
|
||||
}
|
||||
|
||||
return $cache[$mlid];
|
||||
}
|
||||
|
||||
function _token_menu_link_translate(&$item) {
|
||||
$map = array();
|
||||
|
||||
if (!is_array($item['options'])) {
|
||||
$item['options'] = unserialize($item['options']);
|
||||
}
|
||||
|
||||
if ($item['external']) {
|
||||
$item['access'] = 1;
|
||||
$item['href'] = $item['link_path'];
|
||||
$item['title'] = $item['link_title'];
|
||||
$item['localized_options'] = $item['options'];
|
||||
}
|
||||
else {
|
||||
$map = explode('/', $item['link_path']);
|
||||
_menu_link_map_translate($map, $item['to_arg_functions']);
|
||||
$item['href'] = implode('/', $map);
|
||||
|
||||
// Note - skip callbacks without real values for their arguments.
|
||||
if (strpos($item['href'], '%') !== FALSE) {
|
||||
$item['access'] = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$item['access'] = TRUE;
|
||||
_menu_item_localize($item, $map, TRUE);
|
||||
}
|
||||
|
||||
// Allow other customizations - e.g. adding a page-specific query string to the
|
||||
// options array. For performance reasons we only invoke this hook if the link
|
||||
// has the 'alter' flag set in the options array.
|
||||
if (!empty($item['options']['alter'])) {
|
||||
drupal_alter('translated_menu_link', $item, $map);
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all ancestors of a given menu link ID.
|
||||
*
|
||||
* @param $mlid
|
||||
* A menu link ID.
|
||||
*
|
||||
* @return
|
||||
* An array of menu links from token_menu_link_load() with the root link
|
||||
* first, and the menu link with ID $mlid last.
|
||||
*/
|
||||
function token_menu_link_get_parents_all($mlid) {
|
||||
$parents = array();
|
||||
|
||||
while (!empty($mlid)) {
|
||||
$link = token_menu_link_load($mlid);
|
||||
array_unshift($parents, $link);
|
||||
$mlid = $link['plid'];
|
||||
}
|
||||
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use the raw return value of token_menu_link_get_parents_all() instead.
|
||||
*/
|
||||
function _menu_titles($menu_link, $nid) {
|
||||
$titles = array();
|
||||
$parents = token_menu_link_get_parents_all($menu_link['mlid']);
|
||||
foreach ($parents as $mlid => $parent) {
|
||||
$titles[] = $parent['title'];
|
||||
}
|
||||
return $titles;
|
||||
}
|
158
sites/all/modules/token/token.pages.inc
Normal file
158
sites/all/modules/token/token.pages.inc
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* User page callbacks for the token module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* For a given context, builds a formatted list of tokens and descriptions
|
||||
* of their replacement values.
|
||||
*
|
||||
* @param types
|
||||
* The token types to display documentation for. Can be either a single
|
||||
* string or an array of token types. Defaults to 'all'.
|
||||
* @param prefix
|
||||
* The prefix your module will use when parsing tokens. Defaults to '['
|
||||
* @param suffix
|
||||
* The suffix your module will use when parsing tokens. Defaults to ']'
|
||||
* @return An HTML table containing the formatting docs.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_token_help($types = 'all', $prefix = TOKEN_PREFIX, $suffix = TOKEN_SUFFIX) {
|
||||
token_include();
|
||||
$full_list = token_get_list($types);
|
||||
|
||||
$headers = array(t('Token'), t('Replacement value'));
|
||||
$rows = array();
|
||||
foreach ($full_list as $key => $category) {
|
||||
$rows[] = array(array('data' => t('@type tokens', array('@type' => drupal_ucfirst($key))), 'class' => 'region', 'colspan' => 2));
|
||||
foreach ($category as $token => $description) {
|
||||
$row = array();
|
||||
$row[] = $prefix . $token . $suffix;
|
||||
$row[] = $description;
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$output = theme('table', $headers, $rows, array('class' => 'description'));
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a 'tree' display of nested tokens.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_token_tree($token_types = array(), $global_types = TRUE, $click_insert = TRUE) {
|
||||
if ($token_types == 'all' || !is_array($token_types) || in_array('all', $token_types)) {
|
||||
$token_types = array('all');
|
||||
}
|
||||
elseif ($global_types) {
|
||||
$token_types[] = 'global';
|
||||
}
|
||||
else {
|
||||
$global_key = array_search('global', $token_types);
|
||||
if ($global_key !== FALSE) {
|
||||
unset($token_types[$global_key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for token type validity and sort.
|
||||
$token_types = array_unique($token_types);
|
||||
$info = token_get_list($token_types);
|
||||
//$token_types = array_intersect($token_types, array_keys($info));
|
||||
$token_types = array_keys($info);
|
||||
sort($token_types);
|
||||
|
||||
$header = array(
|
||||
t('Token'),
|
||||
t('Description'),
|
||||
);
|
||||
$rows = array();
|
||||
|
||||
foreach ($token_types as $type) {
|
||||
$parent = NULL;
|
||||
|
||||
if (count($token_types) > 1) {
|
||||
$rows[] = _token_token_tree_format_row($type, array(), TRUE);
|
||||
$parent = $type;
|
||||
}
|
||||
|
||||
foreach ($info[$type] as $token => $description) {
|
||||
$rows[] = _token_token_tree_format_row("[$token]", array('description' => $description, 'parent' => $parent));
|
||||
}
|
||||
}
|
||||
|
||||
if (count($rows)) {
|
||||
drupal_add_js(drupal_get_path('module', 'token') . '/jquery.treeTable.js');
|
||||
drupal_add_css(drupal_get_path('module', 'token') . '/jquery.treeTable.css');
|
||||
drupal_add_js(drupal_get_path('module', 'token') . '/token.js');
|
||||
drupal_add_css(drupal_get_path('module', 'token') . '/token.css');
|
||||
}
|
||||
else {
|
||||
$rows[] = array(array(
|
||||
'data' => t('No tokens available.'),
|
||||
'colspan' => 2,
|
||||
));
|
||||
}
|
||||
|
||||
$table_options = array(
|
||||
'attributes' => array('class' => 'token-tree'),
|
||||
'caption' => '',
|
||||
);
|
||||
if ($click_insert) {
|
||||
$table_options['caption'] = t('Click a token to insert it into the field you\'ve last clicked.');
|
||||
$table_options['attributes']['class'] .= ' token-click-insert';
|
||||
}
|
||||
return theme('table', $header, $rows, $table_options['attributes'], $table_options['caption']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a row in the token tree.
|
||||
*/
|
||||
function _token_token_tree_format_row($token, $token_info = array(), $is_group = FALSE) {
|
||||
$row = array(
|
||||
'id' => _token_clean_css_identifier($token),
|
||||
'class' => array(),
|
||||
'data' => array(
|
||||
'token' => '',
|
||||
'description' => !empty($token_info['description']) ? $token_info['description'] : '',
|
||||
),
|
||||
);
|
||||
|
||||
if ($is_group) {
|
||||
// This is a token type/group.
|
||||
$row['data']['token'] = drupal_ucfirst($token);
|
||||
$row['class'][] = 'token-group';
|
||||
$row['id'] .= '-group';
|
||||
}
|
||||
else {
|
||||
// This is a token.
|
||||
$row['data']['token'] = array(
|
||||
'data' => $token,
|
||||
'class' => 'token-key',
|
||||
);
|
||||
if (!empty($token_info['parent'])) {
|
||||
$row['class'][] = 'child-of-' . _token_clean_css_identifier($token_info['parent']) . '-group';
|
||||
}
|
||||
}
|
||||
|
||||
$row['class'] = implode(' ', $row['class']);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
function _token_clean_css_identifier($id) {
|
||||
return 'token-' . rtrim(str_replace(array('][', '_', ' ', ':'), '-', trim($id, '[]')), '-');
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; prints the available tokens and values for an object.
|
||||
*/
|
||||
function token_devel_token_object($entity, $object) {
|
||||
$tokens = token_get_values($entity, $object);
|
||||
$tokens = array_combine($tokens->tokens, $tokens->values);
|
||||
return kdevel_print_object($tokens);
|
||||
}
|
120
sites/all/modules/token/token.rules.inc
Normal file
120
sites/all/modules/token/token.rules.inc
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Rules integration for the token module.
|
||||
*
|
||||
* This provides a token input evaluator, so that token replacements can be used
|
||||
* in every rules action.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_rules_evaluator().
|
||||
*/
|
||||
function token_rules_evaluator() {
|
||||
return array(
|
||||
'token_rules_input_evaluator' => array(
|
||||
'label' => t('Token replacement patterns'),
|
||||
'weight' => -5,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the evalution.
|
||||
*
|
||||
* @param $string
|
||||
* The string to evaluate later.
|
||||
* @param $variables
|
||||
* An array of available variables.
|
||||
* @return
|
||||
* Arbitrary data, which is passed to the evaluator on evaluation.
|
||||
* If NULL is returned the input evaluator will be skipped later.
|
||||
*/
|
||||
function token_rules_input_evaluator_prepare($string, $variables) {
|
||||
$used_vars = array();
|
||||
foreach ($variables as $name => $info) {
|
||||
if (strpos($string, TOKEN_PREFIX. $name .':') !== FALSE) {
|
||||
$used_vars[] = $name;
|
||||
}
|
||||
}
|
||||
// Using ':global' instead of 'global' to avoid potential namespace conflicts
|
||||
// See http://drupal.org/node/932460#comment-3884866
|
||||
$used_vars[] = ':global';
|
||||
return $used_vars ? $used_vars : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the input evaluator.
|
||||
*
|
||||
* @param $text
|
||||
* The string for which tokens should be replaced.
|
||||
* @param $used_vars
|
||||
* The used variables as returned from preparation.
|
||||
* @param $state
|
||||
* The current evaluation state of rules.
|
||||
*/
|
||||
function token_rules_input_evaluator_apply($text, $used_vars, &$state) {
|
||||
static $token_cache = array();
|
||||
|
||||
if ($used_vars) {
|
||||
$vars = rules_get_variables(drupal_map_assoc(array_diff($used_vars, array(':global'))), $state);
|
||||
if ($vars === FALSE) {
|
||||
//there not all needed variables available!
|
||||
return FALSE;
|
||||
}
|
||||
$vars[':global'] = ':global';
|
||||
|
||||
foreach ($used_vars as $name) {
|
||||
$type = ($name == ':global') ? 'global' : _token_rules_map_type($state['variables'][$name]->info['type']);
|
||||
if ($type) {
|
||||
$token_id = _token_get_id($type, $vars[$name]);
|
||||
if (isset($token_cache[$token_id]) && $token_cache[$token_id] != $name) {
|
||||
// this is the same variable in another state
|
||||
// so we need to flush the token cache to get the fresh values
|
||||
token_get_values('reset');
|
||||
}
|
||||
|
||||
$text = token_replace($text, $type, $vars[$name], TOKEN_PREFIX. $name .':', TOKEN_SUFFIX);
|
||||
|
||||
// remember that this variable has been used and got cached
|
||||
$token_cache[$token_id] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map rules types to corresponding token types
|
||||
*/
|
||||
function _token_rules_map_type($type) {
|
||||
if (($data_type = rules_get_data_types($type)) && isset($data_type['token type'])) {
|
||||
return $data_type['token type'];
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some token replacement help for the condition/action edit form.
|
||||
*/
|
||||
function token_rules_input_evaluator_help($variables) {
|
||||
|
||||
$variables[':global'] = array('type' => 'global', 'label' => t('global token'),);
|
||||
|
||||
foreach ($variables as $name => $info) {
|
||||
$type = _token_rules_map_type($info['type']);
|
||||
if ($type) {
|
||||
$form[$name] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Replacement patterns for @name', array('@name' => $info['label'])),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
);
|
||||
$form[$name]['content'] = array(
|
||||
'#value' => theme('token_help', $type, TOKEN_PREFIX. $name . ':', TOKEN_SUFFIX),
|
||||
);
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
690
sites/all/modules/token/token.test
Normal file
690
sites/all/modules/token/token.test
Normal file
|
@ -0,0 +1,690 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for the token module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper test class with some added functions for testing.
|
||||
*/
|
||||
class TokenTestHelper extends DrupalWebTestCase {
|
||||
function setUp(array $modules = array()) {
|
||||
$modules[] = 'path';
|
||||
$modules[] = 'token';
|
||||
$modules[] = 'token_test';
|
||||
parent::setUp($modules);
|
||||
|
||||
// Clear the token static cache.
|
||||
token_get_values('reset');
|
||||
}
|
||||
|
||||
function assertToken($type, $object, $token, $expected, array $options = array()) {
|
||||
$this->assertTokens($type, $object, array($token => $expected), $options);
|
||||
}
|
||||
|
||||
function assertTokens($type, $object, array $tokens, array $options = array()) {
|
||||
$values = token_get_values($type, $object, FALSE, $options);
|
||||
$values = array_combine($values->tokens, $values->values);
|
||||
foreach ($tokens as $token => $expected) {
|
||||
if (!isset($expected)) {
|
||||
$this->assertTrue(!isset($values[$token]), t("Token value for [@token] was not generated.", array('@token' => $token)));
|
||||
}
|
||||
elseif (!isset($values[$token])) {
|
||||
$this->fail(t("Token value for [@token] was not generated.", array('@token' => $token)));
|
||||
}
|
||||
else {
|
||||
$this->assertIdentical($values[$token], $expected, t("Token value for [@token] was '@actual', expected value '@expected'.", array('@token' => $token, '@actual' => $values[$token], '@expected' => $expected)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a page request and test for token generation.
|
||||
*/
|
||||
function assertPageTokens($url, array $tokens, array $data = array('global' => NULL), array $options = array()) {
|
||||
if (empty($tokens)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
$token_page_tokens = array(
|
||||
'tokens' => $tokens,
|
||||
'data' => $data,
|
||||
'options' => $options,
|
||||
);
|
||||
variable_set('token_page_tokens', $token_page_tokens);
|
||||
|
||||
$options += array('url_options' => array());
|
||||
$this->drupalGet($url, $options['url_options']);
|
||||
$this->refreshVariables();
|
||||
$result = variable_get('token_page_tokens', array());
|
||||
|
||||
if (!isset($result['values']) || !is_array($result['values'])) {
|
||||
return $this->fail('Failed to generate tokens.');
|
||||
}
|
||||
|
||||
foreach ($tokens as $token => $expected) {
|
||||
if (!isset($expected)) {
|
||||
$this->assertTrue(!isset($result['values'][$token]) || $result['values'][$token] === $token, t("Token value for @token was not generated.", array('@token' => $token)));
|
||||
}
|
||||
elseif (!isset($result['values'][$token])) {
|
||||
$this->fail(t('Failed to generate token @token.', array('@token' => $token)));
|
||||
}
|
||||
else {
|
||||
$this->assertIdentical($result['values'][$token], (string) $expected, t("Token value for @token was '@actual', expected value '@expected'.", array('@token' => $token, '@actual' => $result['values'][$token], '@expected' => $expected)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TokenUnitTestCase extends TokenTestHelper {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Token unit tests',
|
||||
'description' => 'Test basic, low-level token functions.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test token_get_invalid_tokens() and token_get_invalid_tokens_by_context().
|
||||
*/
|
||||
public function testGetInvalidTokens() {
|
||||
$tests = array();
|
||||
$tests[] = array(
|
||||
'valid tokens' => array(
|
||||
'[title-raw]',
|
||||
'[yyyy]',
|
||||
'[mod-yyyy]',
|
||||
'[site-name]',
|
||||
'[site-slogan]',
|
||||
'[user-id]',
|
||||
),
|
||||
'invalid tokens' => array(
|
||||
'[title-invalid]',
|
||||
'[invalid]',
|
||||
'[mod-invalid]',
|
||||
'[invalid-title]',
|
||||
'[site-invalid]',
|
||||
'[uid]',
|
||||
'[comment-cid]',
|
||||
),
|
||||
'types' => array('node'),
|
||||
);
|
||||
$tests[] = array(
|
||||
'valid tokens' => array(
|
||||
'[title-raw]',
|
||||
'[yyyy]',
|
||||
'[mod-yyyy]',
|
||||
'[site-name]',
|
||||
'[site-slogan]',
|
||||
'[user-id]',
|
||||
'[uid]',
|
||||
'[comment-cid]',
|
||||
),
|
||||
'invalid tokens' => array(
|
||||
'[title-invalid]',
|
||||
'[invalid]',
|
||||
'[mod-invalid]',
|
||||
'[invalid-title]',
|
||||
'[site-invalid]',
|
||||
),
|
||||
'types' => array('all'),
|
||||
);
|
||||
$tests[] = array(
|
||||
'valid tokens' => array(
|
||||
'[alpha]',
|
||||
'[beta-1]',
|
||||
'[beta-2]',
|
||||
'[gamma_A]',
|
||||
'[delta-extra]',
|
||||
'[epsilon-zeta-A]',
|
||||
),
|
||||
'invalid tokens' => array(
|
||||
'[alpha-plus]',
|
||||
'[beta]',
|
||||
'[beta-]',
|
||||
'[beta_]',
|
||||
'[beta_1]',
|
||||
'[beta-A]',
|
||||
'[gamma]',
|
||||
'[gamma_]',
|
||||
'[gamma-A]',
|
||||
'[delta]',
|
||||
'[epsilon-zeta-]',
|
||||
),
|
||||
'types' => array('all'),
|
||||
);
|
||||
|
||||
foreach ($tests as $test) {
|
||||
$tokens = array_merge($test['valid tokens'], $test['invalid tokens']);
|
||||
shuffle($tokens);
|
||||
|
||||
$invalid_tokens = token_get_invalid_tokens_by_context(implode(' ', $tokens), $test['types']);
|
||||
|
||||
sort($invalid_tokens);
|
||||
sort($test['invalid tokens']);
|
||||
$this->assertEqual($invalid_tokens, $test['invalid tokens'], 'Invalid tokens detected properly: ' . implode(', ', $invalid_tokens));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the $options['clear'] parameter for token_replace().
|
||||
*/
|
||||
public function testClearOption() {
|
||||
$tests[] = array(
|
||||
'input' => 'Foo [site-name][invalid-token] bar [another-invalid-token] [invalid-token]',
|
||||
'output' => 'Foo Drupal bar ',
|
||||
'options' => array('clear' => TRUE),
|
||||
);
|
||||
$tests[] = array(
|
||||
'input' => 'Foo [site-name][invalid-token] bar [another-invalid-token] [invalid-token]',
|
||||
'output' => 'Foo Drupal[invalid-token] bar [another-invalid-token] [invalid-token]',
|
||||
'options' => array(),
|
||||
);
|
||||
|
||||
foreach ($tests as $test) {
|
||||
$output = token_replace($test['input'], 'global', NULL, TOKEN_PREFIX, TOKEN_SUFFIX, $test['options']);
|
||||
$this->assertIdentical($output, $test['output']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether token-replacement works in various contexts.
|
||||
*
|
||||
* @see http://drupal.org/node/733192
|
||||
*/
|
||||
function testSystemTokenRecognition() {
|
||||
global $language;
|
||||
|
||||
// Generate prefixes and suffixes for the token context.
|
||||
$tests = array(
|
||||
array('prefix' => 'this is the ', 'suffix' => ' site'),
|
||||
array('prefix' => 'this is the', 'suffix' => 'site'),
|
||||
array('prefix' => '[', 'suffix' => ']'),
|
||||
array('prefix' => '', 'suffix' => ']]]'),
|
||||
array('prefix' => '[[[', 'suffix' => ''),
|
||||
array('prefix' => ':[:', 'suffix' => '--]'),
|
||||
array('prefix' => '-[-', 'suffix' => ':]:'),
|
||||
array('prefix' => '[:', 'suffix' => ']'),
|
||||
array('prefix' => '[site:', 'suffix' => ':name]'),
|
||||
array('prefix' => '[site:', 'suffix' => ']'),
|
||||
);
|
||||
|
||||
// Check if the token is recognized in each of the contexts.
|
||||
foreach ($tests as $test) {
|
||||
$input = $test['prefix'] . '[site-name]' . $test['suffix'];
|
||||
$expected = $test['prefix'] . 'Drupal' . $test['suffix'];
|
||||
$output = token_replace($input);
|
||||
$this->assertEqual($output, $expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test token caching.
|
||||
*/
|
||||
function testTokenCaching() {
|
||||
// Run global tokens once so that the cache is primed.
|
||||
$tokens = array(
|
||||
'option-foo' => '',
|
||||
);
|
||||
$this->assertTokens('global', NULL, $tokens);
|
||||
|
||||
// Run global tokens again with different options. This should return a
|
||||
// different value for the [option-foo] token.
|
||||
$tokens = array(
|
||||
'option-foo' => 'bar',
|
||||
);
|
||||
$this->assertTokens('global', NULL, $tokens, array('foo' => 'bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the token_scan() function.
|
||||
*/
|
||||
function testTokenScan() {
|
||||
$tests = array(
|
||||
array('text' => 'Test [foo] [[bar]] test.', 'tokens' => array('foo', 'bar')),
|
||||
array('text' => 'Test [foo] [] test.', 'tokens' => array('foo')),
|
||||
array('text' => 'Test [foo][] test.', 'tokens' => array('foo')),
|
||||
array('text' => 'Test [foo][bar] test.', 'tokens' => array('foo', 'bar')),
|
||||
// Test the e-mail token syntax.
|
||||
array('text' => 'Test %foo %%bar test.', 'tokens' => array('foo', 'bar'), 'leading' => '%', 'trailing' => ''),
|
||||
array('text' => 'Test %foo % test.', 'tokens' => array('foo'), 'leading' => '%', 'trailing' => ''),
|
||||
array('text' => 'Test %foo% test.', 'tokens' => array('foo'), 'leading' => '%', 'trailing' => ''),
|
||||
array('text' => 'Test %foo%%bar test.', 'tokens' => array('foo', 'bar'), 'leading' => '%', 'trailing' => ''),
|
||||
// Test the rules token syntax.
|
||||
array('text' => 'Test [global:foo] [global:bar] test.', 'tokens' => array('foo', 'bar'), 'leading' => '[global:'),
|
||||
array('text' => 'Test [node:foo] [node:] test.', 'tokens' => array('foo'), 'leading' => '[node:'),
|
||||
array('text' => 'Test [node:foo][node:] test.', 'tokens' => array('foo'), 'leading' => '[node:'),
|
||||
array('text' => 'Test [node:foo][node:bar] test.', 'tokens' => array('foo', 'bar'), 'leading' => '[node:'),
|
||||
);
|
||||
foreach ($tests as $test) {
|
||||
$test += array('leading' => TOKEN_PREFIX, 'trailing' => TOKEN_SUFFIX);
|
||||
$this->assertEqual(token_scan($test['text'], $test['leading'], $test['trailing']), $test['tokens']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TokenNodeTestCase extends TokenTestHelper {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Node token tests',
|
||||
'description' => 'Test the node tokens.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
function testNodeTokens() {
|
||||
$time = time();
|
||||
$created = gmmktime(0, 0, 0, 11, 19, 1978);
|
||||
$changed = gmmktime(0, 0, 0, 7, 4, 1984);
|
||||
$node = $this->drupalCreateNode(array(
|
||||
'type' => 'page',
|
||||
'language' => 'und',
|
||||
'created' => $created,
|
||||
'log' => '<blink>' . $this->randomName() . '</blink>',
|
||||
));
|
||||
$node->changed = $changed;
|
||||
path_set_alias('node/' . $node->nid, 'content/first-node');
|
||||
|
||||
$tokens = array(
|
||||
'nid' => $node->nid,
|
||||
'type' => 'page',
|
||||
'type-name' => 'Page',
|
||||
'language' => 'und',
|
||||
'node-path' => 'content/first-node',
|
||||
'node-url' => url('node/' . $node->nid, array('absolute' => TRUE)),
|
||||
'small' => '11/19/1978 - 00:00',
|
||||
'yyyy' => '1978',
|
||||
'yy' => '78',
|
||||
'month' => 'November',
|
||||
'mon' => 'Nov',
|
||||
'mm' => '11',
|
||||
'm' => '11',
|
||||
'ww' => '46',
|
||||
'date' => '7',
|
||||
'day' => 'Sunday',
|
||||
'ddd' => 'Sun',
|
||||
'dd' => '19',
|
||||
'd' => '19',
|
||||
'raw' => 280281600,
|
||||
'since' => format_interval($time - 280281600),
|
||||
'mod-small' => '07/04/1984 - 00:00',
|
||||
'mod-yyyy' => '1984',
|
||||
'mod-yy' => '84',
|
||||
'mod-month' => 'July',
|
||||
'mod-mon' => 'Jul',
|
||||
'mod-mm' => '07',
|
||||
'mod-m' => '7',
|
||||
'mod-ww' => '27',
|
||||
'mod-date' => '3',
|
||||
'mod-day' => 'Wednesday',
|
||||
'mod-ddd' => 'Wed',
|
||||
'mod-dd' => '04',
|
||||
'mod-d' => '4',
|
||||
'mod-raw' => 457747200,
|
||||
'mod-since' => format_interval($time - 457747200),
|
||||
'log' => filter_xss($node->log),
|
||||
'log-raw' => $node->log,
|
||||
);
|
||||
$this->assertTokens('node', $node, $tokens);
|
||||
|
||||
// Check that a new revision of a node returns different tokens.
|
||||
$node->revision = TRUE;
|
||||
$node->title = 'New revision';
|
||||
node_save($node);
|
||||
$this->assertTokens('node', $node, array('title' => 'New revision'));
|
||||
}
|
||||
}
|
||||
|
||||
class TokenCommentTestCase extends TokenTestHelper {
|
||||
protected $node;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Comment token tests',
|
||||
'description' => 'Test the comment tokens.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp(array $modules = array()) {
|
||||
$modules[] = 'comment';
|
||||
parent::setUp($modules);
|
||||
$this->node = $this->drupalCreateNode(array('comment' => 2));
|
||||
}
|
||||
|
||||
function loadComment($cid) {
|
||||
return db_fetch_object(db_query('SELECT c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data, c.status FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d', $cid));
|
||||
}
|
||||
|
||||
function createComment(array $comment) {
|
||||
$comment += array(
|
||||
'cid' => 0,
|
||||
'nid' => $this->node->nid,
|
||||
'pid' => 0,
|
||||
'uid' => 0,
|
||||
'subject' => $this->randomName(),
|
||||
'comment' => $this->randomName(64),
|
||||
'format' => 1,
|
||||
'timestamp' => gmmktime(0, 0, 0, 7, 4, 1984),
|
||||
'status' => COMMENT_PUBLISHED,
|
||||
);
|
||||
|
||||
$cid = comment_save($comment);
|
||||
return $this->loadComment($cid);
|
||||
}
|
||||
|
||||
function testCommentTokens() {
|
||||
$time = time();
|
||||
$comment = $this->createComment(array(
|
||||
'timestamp' => gmmktime(0, 0, 0, 7, 4, 1984),
|
||||
));
|
||||
|
||||
$tokens = array(
|
||||
'comment-cid' => $comment->cid,
|
||||
'comment-nid' => $this->node->nid,
|
||||
'comment-yyyy' => '1984',
|
||||
'comment-yy' => '84',
|
||||
'comment-month' => 'July',
|
||||
'comment-mon' => 'Jul',
|
||||
'comment-mm' => '07',
|
||||
'comment-m' => '7',
|
||||
'comment-ww' => '27',
|
||||
'comment-date' => '3',
|
||||
'comment-day' => 'Wednesday',
|
||||
'comment-ddd' => 'Wed',
|
||||
'comment-dd' => '04',
|
||||
'comment-d' => '4',
|
||||
'comment-raw' => '457747200',
|
||||
'comment-since' => format_interval($time - 457747200),
|
||||
'comment-node-title' => check_plain($this->node->title),
|
||||
'comment-node-title-raw' => $this->node->title,
|
||||
);
|
||||
$this->assertTokens('comment', $comment, $tokens);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class TokenTaxonomyTestCase extends TokenTestHelper {
|
||||
protected $vocabulary;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Taxonomy and vocabulary token tests',
|
||||
'description' => 'Test the taxonomy tokens.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp(array $modules = array()) {
|
||||
$modules[] = 'taxonomy';
|
||||
parent::setUp($modules);
|
||||
// Reset the static taxonomy.module caches.
|
||||
taxonomy_vocabulary_load(0, TRUE);
|
||||
taxonomy_get_term(0, TRUE);
|
||||
}
|
||||
|
||||
function addVocabulary(array $vocabulary = array()) {
|
||||
$vocabulary += array(
|
||||
'name' => drupal_strtolower($this->randomName(5)),
|
||||
'nodes' => array('story' => 'story'),
|
||||
);
|
||||
taxonomy_save_vocabulary($vocabulary);
|
||||
return (object) $vocabulary;
|
||||
}
|
||||
|
||||
function addTerm(stdClass $vocabulary, array $term = array()) {
|
||||
$term += array(
|
||||
'name' => drupal_strtolower($this->randomName(5)),
|
||||
'vid' => $vocabulary->vid,
|
||||
);
|
||||
taxonomy_save_term($term);
|
||||
return (object) $term;
|
||||
}
|
||||
|
||||
function testTaxonomyTokens() {
|
||||
$vocabulary = $this->addVocabulary(array(
|
||||
'name' => '<blink>Vocab Name</blink>',
|
||||
'description' => '<blink>Vocab Description</blink>',
|
||||
));
|
||||
$term = $this->addTerm($vocabulary, array(
|
||||
'name' => '<blink>Term Name</blink>',
|
||||
'description' => '<blink>Term Description</blink>',
|
||||
));
|
||||
|
||||
$tokens = array(
|
||||
'tid' => $term->tid,
|
||||
'cat' => check_plain($term->name),
|
||||
'cat-raw' => $term->name,
|
||||
'cat-description' => 'Term Description',
|
||||
'vid' => $vocabulary->vid,
|
||||
'vocab' => check_plain($vocabulary->name),
|
||||
'vocab-raw' => $vocabulary->name,
|
||||
'vocab-description' => 'Vocab Description',
|
||||
'vocab-description-raw' => $vocabulary->description,
|
||||
);
|
||||
$this->assertTokens('taxonomy', $term, $tokens);
|
||||
|
||||
$tokens = array(
|
||||
'vocabulary-vid' => $vocabulary->vid,
|
||||
'vocabulary-name' => check_plain($vocabulary->name),
|
||||
'vocabulary-name-raw' => $vocabulary->name,
|
||||
'vocabulary-description' => 'Vocab Description',
|
||||
'vocabulary-description-raw' => $vocabulary->description,
|
||||
);
|
||||
$this->assertTokens('vocabulary', $vocabulary, $tokens);
|
||||
}
|
||||
}
|
||||
|
||||
class TokenMenuTestCase extends TokenTestHelper {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Menu token tests',
|
||||
'description' => 'Test the menu tokens.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp(array $modules = array()) {
|
||||
$modules[] = 'menu';
|
||||
parent::setUp($modules);
|
||||
}
|
||||
|
||||
function testMenuTokens() {
|
||||
$root_link = array(
|
||||
'link_path' => 'root',
|
||||
'link_title' => 'Root link',
|
||||
'menu_name' => 'primary-links',
|
||||
);
|
||||
menu_link_save($root_link);
|
||||
|
||||
// Add another link with the root link as the parent
|
||||
$parent_link = array(
|
||||
'link_path' => 'root/parent',
|
||||
'link_title' => 'Parent link',
|
||||
'menu_name' => 'primary-links',
|
||||
'plid' => $root_link['mlid'],
|
||||
);
|
||||
menu_link_save($parent_link);
|
||||
|
||||
$node_link = array(
|
||||
'enabled' => TRUE,
|
||||
'link_title' => 'Node link',
|
||||
'plid' => $parent_link['mlid'],
|
||||
'customized' => 0,
|
||||
);
|
||||
$node = $this->drupalCreateNode(array('menu' => $node_link));
|
||||
|
||||
// Test [node:menu] tokens.
|
||||
$tokens = array(
|
||||
'menu' => 'Primary links',
|
||||
'menu-raw' => 'Primary links',
|
||||
'menupath' => 'Root link/Parent link/Node link',
|
||||
'menupath-raw' => 'Root link/Parent link/Node link',
|
||||
'menu-link-title' => 'Node link',
|
||||
'menu-link-title-raw' => 'Node link',
|
||||
'menu-link-mlid' => $node->menu['mlid'],
|
||||
'menu-link-plid' => $node->menu['plid'],
|
||||
'menu-link-plid' => $parent_link['mlid'],
|
||||
'menu-link-parent-path' => 'root/parent',
|
||||
'menu-link-parent-path-raw' => 'root/parent',
|
||||
);
|
||||
$this->assertTokens('node', $node, $tokens);
|
||||
|
||||
// Reload the node which will not have $node->menu defined and re-test.
|
||||
$loaded_node = node_load($node->nid);
|
||||
// We have to reset the token static cache because tokens are cached by
|
||||
// node ID only and not if the node object has changed.
|
||||
$this->assertTokens('node', $loaded_node, $tokens, array('reset' => TRUE));
|
||||
|
||||
// Regression test for http://drupal.org/node/1317926 to ensure the
|
||||
// original node object is not changed when calling menu_node_prepare().
|
||||
$this->assertTrue(!isset($loaded_node->menu), t('The $node->menu property was not modified during token replacement.'), 'Regression');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unit tests for the book tokens provided by Pathauto.
|
||||
*/
|
||||
class TokenBookTestCase extends TokenTestHelper {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Book tokens',
|
||||
'description' => 'Tests the book tokens.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp(array $modules = array()) {
|
||||
$modules[] = 'book';
|
||||
$modules[] = 'menu';
|
||||
parent::setUp($modules);
|
||||
|
||||
variable_set('book_allowed_types', array('book', 'page'));
|
||||
}
|
||||
|
||||
function testBookTokens() {
|
||||
// Add a non-book node.
|
||||
$non_book_node = $this->drupalCreateNode(array('type' => 'book'));
|
||||
$tokens = array(
|
||||
'book' => '',
|
||||
'book-raw' => '',
|
||||
'book_id' => '',
|
||||
'bookpath' => '',
|
||||
'bookpath-raw' => '',
|
||||
);
|
||||
$this->assertTokens('node', $non_book_node, $tokens);
|
||||
|
||||
// Add a root book page.
|
||||
$parent_node = $this->drupalCreateNode(array(
|
||||
'type' => 'book',
|
||||
'title' => 'Root',
|
||||
'book' => array('bid' => 'new') + _book_link_defaults('new'),
|
||||
));
|
||||
$tokens = array(
|
||||
'book' => 'Root',
|
||||
'book-raw' => 'Root',
|
||||
'book_id' => $parent_node->book['bid'],
|
||||
'bookpath' => '',
|
||||
'bookpath-raw' => '',
|
||||
// Check that even those book menu links have been created for this node,
|
||||
// that the menu links still return nothing.
|
||||
'menu' => '',
|
||||
'menupath' => '',
|
||||
'menu-link-title' => '',
|
||||
'menu-link-title-raw' => '',
|
||||
'menu-link-mlid' => '',
|
||||
'menu-link-plid' => '',
|
||||
'menu-link-parent-path' => '',
|
||||
);
|
||||
$this->assertTokens('node', $parent_node, $tokens);
|
||||
|
||||
// Add a first child page.
|
||||
$child_node1 = $this->drupalCreateNode(array(
|
||||
'type' => 'book',
|
||||
'title' => 'Sub page1',
|
||||
'book' => array(
|
||||
'bid' => $parent_node->book['bid'],
|
||||
'plid' => $parent_node->book['mlid'],
|
||||
) + _book_link_defaults('new'),
|
||||
));
|
||||
$tokens = array(
|
||||
'book' => 'Root',
|
||||
'book-raw' => 'Root',
|
||||
'book_id' => $parent_node->book['bid'],
|
||||
'bookpath' => 'Root',
|
||||
'bookpath-raw' => 'Root',
|
||||
);
|
||||
$this->assertTokens('node', $child_node1, $tokens);
|
||||
|
||||
// Add a second child page.
|
||||
$child_node2 = $this->drupalCreateNode(array(
|
||||
'type' => 'book',
|
||||
'title' => 'Sub page2',
|
||||
'book' => array(
|
||||
'bid' => $parent_node->book['bid'],
|
||||
'plid' => $parent_node->book['mlid'],
|
||||
) + _book_link_defaults('new'),
|
||||
));
|
||||
$tokens = array(
|
||||
'book' => 'Root',
|
||||
'book-raw' => 'Root',
|
||||
'book_id' => $parent_node->book['bid'],
|
||||
'bookpath' => 'Root',
|
||||
'bookpath-raw' => 'Root',
|
||||
);
|
||||
$this->assertTokens('node', $child_node2, $tokens);
|
||||
|
||||
// Add a child page on an existing child page.
|
||||
$sub_child_node1 = $this->drupalCreateNode(array(
|
||||
'type' => 'page',
|
||||
'title' => 'Sub-sub Page1',
|
||||
'book' => array(
|
||||
'bid' => $parent_node->book['bid'],
|
||||
'plid' => $child_node1->book['mlid'],
|
||||
) + _book_link_defaults('new'),
|
||||
));
|
||||
$tokens = array(
|
||||
'book' => 'Root',
|
||||
'book-raw' => 'Root',
|
||||
'book_id' => $parent_node->book['bid'],
|
||||
'bookpath' => 'Root/Sub page1',
|
||||
'bookpath-raw' => 'Root/Sub page1',
|
||||
);
|
||||
$this->assertTokens('node', $sub_child_node1, $tokens);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the current page tokens.
|
||||
*/
|
||||
class TokenCurrentPageTestCase extends TokenTestHelper {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Current page token tests',
|
||||
'description' => 'Test the current page tokens.',
|
||||
'group' => 'Token',
|
||||
);
|
||||
}
|
||||
|
||||
function testCurrentPageTokens() {
|
||||
$tokens = array(
|
||||
'[current-page-title]' => '',
|
||||
'[current-page-path]' => 'node',
|
||||
'[current-page-url]' => url('node', array('absolute' => TRUE)),
|
||||
'[current-page-number]' => 1,
|
||||
);
|
||||
$this->assertPageTokens('', $tokens);
|
||||
|
||||
$node = $this->drupalCreateNode(array('title' => 'Node title', 'path' => 'node-alias'));
|
||||
$tokens = array(
|
||||
'[current-page-title]' => 'Node title',
|
||||
'[current-page-path]' => 'node-alias',
|
||||
'[current-page-url]' => url("node/{$node->nid}", array('absolute' => TRUE)),
|
||||
'[current-page-number]' => 1,
|
||||
);
|
||||
$this->assertPageTokens("node/{$node->nid}", $tokens);
|
||||
}
|
||||
}
|
11
sites/all/modules/token/tokenSTARTER.info
Normal file
11
sites/all/modules/token/tokenSTARTER.info
Normal file
|
@ -0,0 +1,11 @@
|
|||
name = TokenSTARTER
|
||||
description = Provides additional tokens and a base on which to build your own tokens.
|
||||
dependencies[] = token
|
||||
core = 6.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-09-12
|
||||
version = "6.x-1.19"
|
||||
core = "6.x"
|
||||
project = "token"
|
||||
datestamp = "1347470077"
|
||||
|
68
sites/all/modules/token/tokenSTARTER.module
Normal file
68
sites/all/modules/token/tokenSTARTER.module
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The Token API module.
|
||||
*
|
||||
* The Token module provides an API for providing tokens to other modules.
|
||||
* Tokens are small bits of text that can be placed into larger documents
|
||||
* via simple placeholders, like %site-name or [user].
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_token_list().
|
||||
*/
|
||||
function tokenSTARTER_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'global' || $type == 'all') {
|
||||
$tokens['global']['random-sha1'] = t("A randomly generated SHA1 hash.");
|
||||
$tokens['global']['site-date-timestamp'] = t('The current timestamp in seconds past January 1, 1970.');
|
||||
$tokens['global']['random-num-1'] = t('A randomly generated single-digit number.');
|
||||
$tokens['global']['random-num-3'] = t('A randomly generated three-digit number.');
|
||||
$tokens['global']['random-num-10'] = t('A randomly generated ten-digit number.');
|
||||
$tokens['global']['random-alpha-1'] = t('Randomly generated single-digit letter.');
|
||||
$tokens['global']['random-alpha-3'] = t('Randomly generated three-digit letters.');
|
||||
$tokens['global']['random-alpha-10'] = t('Randomly generated ten-digit letters.');
|
||||
}
|
||||
if ($type == 'node' || $type == 'all') {
|
||||
// Node tokens here.
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_token_values().
|
||||
*/
|
||||
function tokenSTARTER_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
switch ($type) {
|
||||
case 'global':
|
||||
$values['random-sha1'] = sha1(rand());
|
||||
// Create random numbers.
|
||||
$values['random-num-1'] = mt_rand(0, 9);
|
||||
$values['random-num-3'] = mt_rand(100, 999);
|
||||
$values['random-num-10'] = mt_rand(10000, 99999) . mt_rand(10000, 99999);
|
||||
// Create random letters.
|
||||
$letters = range('a', 'z');
|
||||
$values['random-alpha-1'] = $letters[array_rand($letters, 1)];
|
||||
shuffle($letters);
|
||||
$values['random-alpha-3'] = implode('', array_slice($letters, 0, 3));
|
||||
shuffle($letters);
|
||||
$values['random-alpha-10'] = implode('', array_slice($letters, 0, 10));
|
||||
// Create a UNIX timestamp token.
|
||||
$time = time();
|
||||
$tz = variable_get('date_default_timezone', 0);
|
||||
$values['site-date-timestamp'] = format_date($time, 'custom', 'Y', $tz);
|
||||
|
||||
break;
|
||||
case 'node':
|
||||
// Node tokens here.
|
||||
break;
|
||||
}
|
||||
return $values;
|
||||
}
|
11
sites/all/modules/token/token_actions.info
Normal file
11
sites/all/modules/token/token_actions.info
Normal file
|
@ -0,0 +1,11 @@
|
|||
name = Token actions
|
||||
description = Provides enhanced versions of core Drupal actions using the Token module.
|
||||
dependencies[] = token
|
||||
core = 6.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-09-12
|
||||
version = "6.x-1.19"
|
||||
core = "6.x"
|
||||
project = "token"
|
||||
datestamp = "1347470077"
|
||||
|
300
sites/all/modules/token/token_actions.module
Normal file
300
sites/all/modules/token/token_actions.module
Normal file
|
@ -0,0 +1,300 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The Token Actions module.
|
||||
*
|
||||
* The Token Actions module provides ways to use tokens inside of actions.
|
||||
* Currently it provides the ability to show users a message, send a token-ized
|
||||
* mail, or redirect a user to a tokenized URL.
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_action_info().
|
||||
*/
|
||||
function token_actions_action_info() {
|
||||
return array(
|
||||
'token_actions_message_action' => array(
|
||||
'type' => 'system',
|
||||
'description' => t('Display a tokenized message to the user'),
|
||||
'configurable' => TRUE,
|
||||
'hooks' => array(
|
||||
'nodeapi' => array('view', 'insert', 'update', 'delete'),
|
||||
'comment' => array('view', 'insert', 'update', 'delete'),
|
||||
'user' => array('view', 'insert', 'update', 'delete', 'login'),
|
||||
'taxonomy' => array('insert', 'update', 'delete'),
|
||||
),
|
||||
),
|
||||
'token_actions_send_email_action' => array(
|
||||
'description' => t('Send tokenized e-mail'),
|
||||
'type' => 'system',
|
||||
'configurable' => TRUE,
|
||||
'hooks' => array(
|
||||
'nodeapi' => array('view', 'insert', 'update', 'delete'),
|
||||
'comment' => array('view', 'insert', 'update', 'delete'),
|
||||
'user' => array('view', 'insert', 'update', 'delete', 'login'),
|
||||
'taxonomy' => array('insert', 'update', 'delete'),
|
||||
)
|
||||
),
|
||||
'token_actions_goto_action' => array(
|
||||
'description' => t('Redirect to a tokenized URL'),
|
||||
'type' => 'system',
|
||||
'configurable' => TRUE,
|
||||
'hooks' => array(
|
||||
'nodeapi' => array('view', 'insert', 'update', 'delete'),
|
||||
'comment' => array('view', 'insert', 'update', 'delete'),
|
||||
'user' => array('view', 'insert', 'update', 'delete', 'login'),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_mail().
|
||||
*/
|
||||
function token_actions_mail($key, &$message, $params) {
|
||||
$message['subject'] = $params['subject'];
|
||||
$message['body'][] = $params['body'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Action callback to send a tokenized e-mail.
|
||||
*
|
||||
* @see token_actions_send_email_action_form()
|
||||
* @see token_actions_send_email_action_submit()
|
||||
*/
|
||||
function token_actions_send_email_action($object, $context) {
|
||||
token_normalize_context($context);
|
||||
$params['from'] = variable_get('site_mail', ini_get('sendmail_from'));
|
||||
$recipient = token_replace_multiple($context['recipient'], $context);
|
||||
$params['subject'] = str_replace(array("\r", "\n"), '', token_replace_multiple($context['subject'], $context));
|
||||
$params['body'] = token_replace_multiple($context['message'], $context);
|
||||
|
||||
if (drupal_mail('token_actions', 'action_send_email', $recipient, language_default(), $params)) {
|
||||
watchdog('action', 'Sent email to %recipient', array('%recipient' => $recipient));
|
||||
}
|
||||
else {
|
||||
watchdog('error', 'Unable to send email to %recipient', array('%recipient' => $recipient));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder; Prepare a form for a tokenized e-mail action.
|
||||
*
|
||||
* @see token_actions_send_email_action()
|
||||
* @see token_actions_send_email_action_validate()
|
||||
* @see token_actions_send_email_action_submit()
|
||||
*/
|
||||
function token_actions_send_email_action_form($context) {
|
||||
// Set default values for form.
|
||||
$context += array(
|
||||
'recipient' => '',
|
||||
'subject' => '',
|
||||
'message' => '',
|
||||
);
|
||||
|
||||
$form['recipient'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Recipient'),
|
||||
'#default_value' => $context['recipient'],
|
||||
'#required' => TRUE,
|
||||
'#size' => '20',
|
||||
'#maxlength' => '254',
|
||||
'#description' => t('The email address to which the message should be sent.'),
|
||||
'#element_validate' => array('token_element_validate'),
|
||||
'#token_types' => array('all'),
|
||||
);
|
||||
$form['subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Subject'),
|
||||
'#default_value' => $context['subject'],
|
||||
'#size' => '20',
|
||||
'#maxlength' => '254',
|
||||
'#description' => t('The subject of the message.'),
|
||||
'#element_validate' => array('token_element_validate'),
|
||||
'#token_types' => array('all'),
|
||||
);
|
||||
$form['message'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Message'),
|
||||
'#default_value' => $context['message'],
|
||||
'#required' => TRUE,
|
||||
'#cols' => '80',
|
||||
'#rows' => '20',
|
||||
'#description' => t('The message that should be sent.'),
|
||||
'#element_validate' => array('token_element_validate'),
|
||||
'#token_types' => array('all'),
|
||||
);
|
||||
|
||||
$form['help'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#title' => t('Placeholder tokens'),
|
||||
'#description' => t("The following placeholder tokens can be used in to generate the URL path. Some tokens may not be available, depending on the context in which the action is triggered."),
|
||||
);
|
||||
$form['help']['tokens'] = array(
|
||||
'#value' => theme('token_tree', 'all'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate token_actions_send_email_action form submissions.
|
||||
*
|
||||
* @see token_actions_send_email_action()
|
||||
* @see token_actions_send_email_action_form()
|
||||
* @see token_actions_send_email_action_submit()
|
||||
*/
|
||||
function token_actions_send_email_action_validate($form, $form_state) {
|
||||
$form_values = $form_state['values'];
|
||||
if (!valid_email_address($form_values['recipient']) && strpos($form_values['recipient'], 'mail') === FALSE) {
|
||||
// We want the literal %mail placeholder to be emphasized in the error message.
|
||||
form_set_error('recipient', t('Enter a valid email address or use a token e-mail address such as %mail.', array('%mail' => '[mail]')));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process token_actions_send_email_action form submissions.
|
||||
*
|
||||
* @see token_actions_send_email_action()
|
||||
* @see token_actions_send_email_action_form()
|
||||
* @see token_actions_send_email_action_validate()
|
||||
*/
|
||||
function token_actions_send_email_action_submit($form, $form_state) {
|
||||
return array(
|
||||
'recipient' => $form_state['values']['recipient'],
|
||||
'subject' => $form_state['values']['subject'],
|
||||
'message' => $form_state['values']['message'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action callback to send a message to the current user's screen.
|
||||
*
|
||||
* @see token_actions_message_action_form()
|
||||
* @see token_actions_message_action_submit()
|
||||
*/
|
||||
function token_actions_message_action(&$object, $context = array()) {
|
||||
token_normalize_context($context);
|
||||
$context['message'] = token_replace_multiple($context['message'], $context);
|
||||
drupal_set_message($context['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder; Prepare a form for a tokenized message action.
|
||||
*
|
||||
* @see token_actions_message_action()
|
||||
* @see token_actions_message_action_submit()
|
||||
*/
|
||||
function token_actions_message_action_form($context) {
|
||||
$context += array('message' => '');
|
||||
|
||||
$form['message'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Message'),
|
||||
'#default_value' => $context['message'],
|
||||
'#required' => TRUE,
|
||||
'#rows' => '8',
|
||||
'#description' => t('The message to be displayed to the current user.'),
|
||||
'#element_validate' => array('token_element_validate'),
|
||||
'#token_types' => array('all'),
|
||||
);
|
||||
|
||||
$form['help'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#title' => t('Placeholder tokens'),
|
||||
'#description' => t("The following placeholder tokens can be used in the custom message text. Some tokens may not be available, depending on the context in which the action is triggered."),
|
||||
);
|
||||
$form['help']['tokens'] = array(
|
||||
'#value' => theme('token_tree', 'all'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process token_actions_message_action form submissions.
|
||||
*
|
||||
* @see token_actions_message_action()
|
||||
* @see token_actions_message_action_form()
|
||||
*/
|
||||
function token_actions_message_action_submit($form, $form_state) {
|
||||
return array('message' => $form_state['values']['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action callback to redirect the user to a tokenized URL.
|
||||
*
|
||||
* @see token_actions_goto_action_form()
|
||||
* @see token_actions_goto_action_submit()
|
||||
*/
|
||||
function token_actions_goto_action($object, $context) {
|
||||
token_normalize_context($context);
|
||||
drupal_goto(token_replace_multiple($context['url'], $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder; Prepare a form for a tokenized redirect action.
|
||||
*
|
||||
* @see token_actions_goto_action()
|
||||
* @see token_actions_goto_action_submit()
|
||||
*/
|
||||
function token_actions_goto_action_form($context) {
|
||||
$context += array('url' => '');
|
||||
|
||||
$form['url'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('URL'),
|
||||
'#description' => t('The URL to which the user should be redirected. This can be an internal URL like node/1234 or an external URL like http://drupal.org.'),
|
||||
'#default_value' => $context['url'],
|
||||
'#required' => TRUE,
|
||||
'#element_validate' => array('token_element_validate'),
|
||||
'#token_types' => array('all'),
|
||||
);
|
||||
|
||||
$form['help'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#title' => t('Placeholder tokens'),
|
||||
'#description' => t("The following placeholder tokens can be used in the URL path. Some tokens may not be available, depending on the context in which the action is triggered."),
|
||||
);
|
||||
$form['help']['tokens'] = array(
|
||||
'#value' => theme('token_tree', 'all'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process token_actions_goto_action form submissions.
|
||||
*
|
||||
* @see token_actions_goto_action()
|
||||
* @see token_actions_goto_action_form()
|
||||
*/
|
||||
function token_actions_goto_action_submit($form, $form_state) {
|
||||
return array('url' => $form_state['values']['url']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an action context for use with token_replace_multiple().
|
||||
*/
|
||||
function token_normalize_context(&$context) {
|
||||
$context['global'] = NULL;
|
||||
|
||||
if (empty($context['user']) && !empty($context['node'])) {
|
||||
$context['user'] = user_load(array('uid' => $context['node']->uid));
|
||||
}
|
||||
if (empty($context['node']) && !empty($context['comment']) && !empty($context['comment']->nid)) {
|
||||
$context['node'] = node_load($context['comment']->nid);
|
||||
}
|
||||
if (empty($context['user']) && !empty($context['account'])) {
|
||||
$context['user'] = $context['account'];
|
||||
}
|
||||
}
|
79
sites/all/modules/token/token_actions.test
Normal file
79
sites/all/modules/token/token_actions.test
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for the token_actions module.
|
||||
*/
|
||||
|
||||
class TokenActionsTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Token action tests'),
|
||||
'description' => t('Test some of the token actions and tokens.'),
|
||||
'group' => t('Token'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('token', 'token_actions', 'trigger');
|
||||
$user = $this->drupalCreateUser(array('administer actions', 'administer site configuration', 'administer users'));
|
||||
$this->drupalLogin($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user actions and triggers.
|
||||
*/
|
||||
function testUserActions() {
|
||||
$insert_action = $this->createAction('token_actions_message_action', array(
|
||||
'message' => 'Yay [site-name] has a new user [user] with an ID of [uid] and e-mail address of [mail]!',
|
||||
));
|
||||
$this->assignTriggerAction('user', 'insert', $insert_action);
|
||||
|
||||
// Create a user to trigger the action.
|
||||
$edit = array();
|
||||
$edit['name'] = $this->randomName();
|
||||
$edit['mail'] = $edit['name'] .'@example.com';
|
||||
$edit['pass[pass1]'] = $this->randomName();
|
||||
$edit['pass[pass2]'] = $edit['pass[pass1]'];
|
||||
|
||||
$this->drupalPost('admin/user/user/create', $edit, t('Create new account'));
|
||||
$account = user_load(array('name' => $edit['name']));
|
||||
$this->assertText("Yay Drupal has a new user {$account->name} with an ID of {$account->uid} and e-mail address of {$account->mail}!", 'Tokenized message displays');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an action.
|
||||
*
|
||||
* @param $action
|
||||
* The machine name of the action.
|
||||
* @param $edit
|
||||
* An optional array to pass onto drupalPost() for configuring the action.
|
||||
*
|
||||
* @return
|
||||
* The created action object.
|
||||
*/
|
||||
function createAction($action, $edit = array()) {
|
||||
$edit += array(
|
||||
'actions_description' => $this->randomName(),
|
||||
);
|
||||
$this->drupalPost('admin/settings/actions/configure/'. md5($action), $edit, t('Save'));
|
||||
$this->assertText('The action has been successfully saved.');
|
||||
return db_fetch_object(db_query("SELECT * FROM {actions} WHERE type = 'system' AND callback = '%s' AND description = '%s'", $action, $edit['actions_description']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an action to a trigger.
|
||||
*
|
||||
* @param $type
|
||||
* The trigger type.
|
||||
* @param $trigger
|
||||
* The trigger.
|
||||
* @param $action
|
||||
* The action object.
|
||||
*/
|
||||
function assignTriggerAction($type, $trigger, $action) {
|
||||
$edit['aid'] = md5($action->aid);
|
||||
$this->drupalPost("admin/build/trigger/{$type}", $edit, 'Assign', array(), array(), "trigger-{$type}-{$trigger}-assign-form");
|
||||
return $this->assertLinkByHref("admin/build/trigger/unassign/{$type}/{$trigger}/{$edit['aid']}", 0, t('Action assigned to @type @trigger trigger.', array('@type' => $type, '@trigger' => $trigger)));
|
||||
}
|
||||
}
|
91
sites/all/modules/token/token_comment.inc
Normal file
91
sites/all/modules/token/token_comment.inc
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementations of token module hooks for the core comment module.
|
||||
*
|
||||
* The token module requires specific hooks to be added to modules
|
||||
* so that those modules can return data about their objects to the
|
||||
* token API. Until and unless token becomes a part of core, the
|
||||
* implementations of the token hooks for core modules are provided
|
||||
* in the token module itself.
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_list() on behalf of comment.module.
|
||||
*/
|
||||
function comment_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'comment' || $type == 'all') {
|
||||
$tokens['comment']['comment-cid'] = t('The unique ID of the comment.');
|
||||
$tokens['comment']['comment-nid'] = t('The unique ID of the node the comment was posted to.');
|
||||
$tokens['comment']['comment-title'] = t('The title of the comment.');
|
||||
$tokens['comment']['comment-title-raw'] = t('The title of the comment.');
|
||||
$tokens['comment']['comment-body'] = t('The formatted content of the comment itself.');
|
||||
$tokens['comment']['comment-body-raw'] = t('The formatted content of the comment itself.');
|
||||
|
||||
$tokens['comment']['comment-author-uid'] = t('The unique ID of the author of the comment.');
|
||||
$tokens['comment']['comment-author-name'] = t('The name left by the comment author.');
|
||||
$tokens['comment']['comment-author-name-raw'] = t('The name left by the comment author.');
|
||||
$tokens['comment']['comment-author-homepage'] = t('The home page URL left by the comment author.');
|
||||
|
||||
$tokens['comment']['comment-author-mail'] = t('The email address left by the comment author.');
|
||||
$tokens['comment']['comment-author-mail-raw'] = t('The email address left by the comment author.');
|
||||
|
||||
$tokens['comment'] += token_get_date_token_info(t('Comment creation'), 'comment-');
|
||||
|
||||
$tokens['comment']['comment-node-title'] = t('The title of the node the comment was posted to.');
|
||||
$tokens['comment']['comment-node-title-raw'] = t('The title of the node the comment was posted to.');
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_values() on behalf of comment.module.
|
||||
*/
|
||||
function comment_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
|
||||
if ($type == 'comment' && !empty($object)) {
|
||||
// Cast to an object just in case fussy Drupal gave us an array
|
||||
$comment = (object) $object;
|
||||
|
||||
$values['comment-cid'] = $comment->cid;
|
||||
$values['comment-nid'] = $comment->nid;
|
||||
$values['comment-title'] = check_plain($comment->subject);
|
||||
$values['comment-body'] = check_markup($comment->comment, $comment->format, FALSE);
|
||||
$values['comment-author-name'] = check_plain($comment->name);
|
||||
$values['comment-author-uid'] = $comment->uid;
|
||||
$values['comment-author-homepage'] = check_url($comment->homepage);
|
||||
|
||||
// Raw counterparts of user supplied data.
|
||||
$values['comment-title-raw'] = $comment->subject;
|
||||
$values['comment-body-raw'] = $comment->comment;
|
||||
$values['comment-author-name-raw'] = $comment->name;
|
||||
|
||||
if (!empty($comment->mail)) {
|
||||
$account_mail = $comment->mail;
|
||||
}
|
||||
elseif (!empty($comment->uid)) {
|
||||
$account_mail = db_result(db_query("SELECT mail FROM {users} WHERE uid = %d", $comment->uid));
|
||||
}
|
||||
else {
|
||||
$account_mail = '';
|
||||
}
|
||||
$values['comment-author-mail'] = check_plain($account_mail);
|
||||
$values['comment-author-mail-raw'] = $account_mail;
|
||||
|
||||
// Included in case a consuming module wants to format the body
|
||||
$values['comment-body-format'] = $comment->format;
|
||||
|
||||
$values += token_get_date_token_values($comment->timestamp, 'comment-');
|
||||
|
||||
$values['comment-node-title-raw'] = db_result(db_query("SELECT title FROM {node} WHERE nid = %d", $comment->nid));
|
||||
$values['comment-node-title'] = check_plain($values['comment-node-title-raw']);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
328
sites/all/modules/token/token_node.inc
Normal file
328
sites/all/modules/token/token_node.inc
Normal file
|
@ -0,0 +1,328 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementations of token module hooks for the core node and book modules.
|
||||
*
|
||||
* The token module requires specific hooks to be added to modules
|
||||
* so that those modules can return data about their objects to the
|
||||
* token API. Until and unless token becomes a part of core, the
|
||||
* implementations of the token hooks for core modules are provided
|
||||
* in the token module itself.
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_list() on behalf of node.module.
|
||||
*/
|
||||
function node_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'node' || $type == 'all') {
|
||||
$tokens['node']['nid'] = t('The unique ID of the content item, or "node".');
|
||||
$tokens['node']['type'] = t('The type of the node.');
|
||||
$tokens['node']['type-name'] = t('The human-readable name of the node type.');
|
||||
$tokens['node']['language'] = t('The language the node is written in.');
|
||||
$tokens['node']['title'] = t('The title of the node.');
|
||||
$tokens['node']['title-raw'] = t('The title of the node.');
|
||||
$tokens['node']['node-path'] = t('The URL alias of the node.');
|
||||
$tokens['node']['node-path-raw'] = t('The URL alias of the node.');
|
||||
$tokens['node']['node-url'] = t('The URL of the node.');
|
||||
|
||||
$tokens['node']['author-uid'] = t("The unique ID of the author of the node.");
|
||||
$tokens['node']['author-name'] = t("The login name of the author of the node.");
|
||||
$tokens['node']['author-name-raw'] = t("The login name of the author of the node.");
|
||||
$tokens['node']['author-mail'] = t("The email address of the author of the node.");
|
||||
$tokens['node']['author-mail-raw'] = t("The email address of the author of the node.");
|
||||
|
||||
$tokens['node']['log'] = t('The explanation of the most recent changes made to the node.');
|
||||
$tokens['node']['log-raw'] = t('The explanation of the most recent changes made to the node.');
|
||||
|
||||
$tokens['node'] += token_get_date_token_info(t('Node creation'));
|
||||
$tokens['node'] += token_get_date_token_info(t('Node modification'), 'mod-');
|
||||
|
||||
if (module_exists('comment')) {
|
||||
$tokens['node']['node_comment_count'] = t("The number of comments posted on a node.");
|
||||
$tokens['node']['unread_comment_count'] = t("The number of comments posted on a node since the reader last viewed it.");
|
||||
}
|
||||
|
||||
if (module_exists('taxonomy')) {
|
||||
$tokens['node']['term'] = t("Name of top taxonomy term");
|
||||
$tokens['node']['term-raw'] = t("Unfiltered name of top taxonomy term.");
|
||||
$tokens['node']['term-id'] = t("ID of top taxonomy term");
|
||||
$tokens['node']['vocab'] = t("Name of top term's vocabulary");
|
||||
$tokens['node']['vocab-raw'] = t("Unfiltered name of top term's vocabulary.");
|
||||
$tokens['node']['vocab-id'] = t("ID of top term's vocabulary");
|
||||
// Temporarily disabled -- see notes in node_token_values.
|
||||
// $tokens['node']['catpath'] = t("Full taxonomy tree for the topmost term");
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_values() on behalf of node.module.
|
||||
*/
|
||||
function node_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
|
||||
if ($type == 'node' && !empty($object)) {
|
||||
$node = $object;
|
||||
$account = db_fetch_object(db_query("SELECT name, mail FROM {users} WHERE uid = %d", $node->uid));
|
||||
|
||||
// Adjust for the anonymous user name.
|
||||
if (!$node->uid && !$account->name) {
|
||||
$account->name = variable_get('anonymous', t('Anonymous'));
|
||||
}
|
||||
|
||||
$values['nid'] = $node->nid;
|
||||
$values['type'] = $node->type;
|
||||
$values['type-name'] = node_get_types('name', $node->type);
|
||||
$values['language'] = check_plain($node->language);
|
||||
$values['title'] = check_plain($node->title);
|
||||
$values['title-raw'] = $node->title;
|
||||
$values['node-path-raw'] = drupal_get_path_alias('node/'. $node->nid);
|
||||
$values['node-path'] = check_plain($values['node-path-raw']);
|
||||
$values['node-url'] = url('node/' . $node->nid, array('absolute' => TRUE));
|
||||
$values['author-uid'] = $node->uid;
|
||||
$values['author-name'] = check_plain($account->name);
|
||||
$values['author-name-raw'] = $account->name;
|
||||
$values['author-mail'] = check_plain($account->mail);
|
||||
$values['author-mail-raw'] = $account->mail;
|
||||
|
||||
$values['log-raw'] = isset($node->log) ? $node->log : '';
|
||||
$values['log'] = filter_xss($values['log-raw']);
|
||||
|
||||
if (module_exists('comment')) {
|
||||
$values['node_comment_count'] = isset($node->comment_count) ? $node->comment_count : 0;
|
||||
$values['unread_comment_count'] = comment_num_new($node->nid);
|
||||
}
|
||||
else {
|
||||
$values['node_comment_count'] = 0;
|
||||
$values['unread_comment_count'] = 0;
|
||||
}
|
||||
|
||||
if (isset($node->created)) {
|
||||
$values += token_get_date_token_values($node->created, '');
|
||||
}
|
||||
|
||||
if (isset($node->changed)) {
|
||||
$values += token_get_date_token_values($node->changed, 'mod-');
|
||||
}
|
||||
|
||||
// And now taxonomy, which is a bit more work. This code is adapted from
|
||||
// pathauto's handling code; it's intended for compatibility with it.
|
||||
if (module_exists('taxonomy') && !empty($node->taxonomy) && is_array($node->taxonomy)) {
|
||||
foreach ($node->taxonomy as $term) {
|
||||
$original_term = $term;
|
||||
if ((object)$term) {
|
||||
// With free-tagging it's somewhat hard to get the tid, vid, name values
|
||||
// Rather than duplicating taxonomy.module code here you should make sure your calling module
|
||||
// has a weight of at least 1 which will run after taxonomy has saved the data which allows us to
|
||||
// pull it out of the db here.
|
||||
if (!isset($term->name) || !isset($term->tid)) {
|
||||
$vid = db_result(db_query_range("SELECT t.vid FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.nid = %d ORDER BY v.weight, t.weight, t.name", $object->nid, 0, 1));
|
||||
if (!$vid) {
|
||||
continue;
|
||||
}
|
||||
$term = db_fetch_object(db_query_range("SELECT t.tid, t.name FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.vid = %d ORDER BY t.weight", $vid, $object->vid, 0, 1));
|
||||
$term->vid = $vid;
|
||||
}
|
||||
|
||||
// Ok, if we still don't have a term name maybe this is a pre-taxonomy submit node
|
||||
// So if it's a number we can get data from it
|
||||
if (!isset($term->name) && is_array($original_term)) {
|
||||
$tid = array_shift($original_term);
|
||||
if (is_numeric($tid)) {
|
||||
$term = taxonomy_get_term($tid);
|
||||
}
|
||||
}
|
||||
$values['term'] = check_plain($term->name);
|
||||
$values['term-raw'] = $term->name;
|
||||
$values['term-id'] = $term->tid;
|
||||
$vid = $term->vid;
|
||||
|
||||
if (!empty($vid)) {
|
||||
$vocabulary = taxonomy_vocabulary_load($vid);
|
||||
$values['vocab'] = check_plain($vocabulary->name);
|
||||
$values['vocab-raw'] = $vocabulary->name;
|
||||
$values['vocab-id'] = $vocabulary->vid;
|
||||
}
|
||||
|
||||
// The 'catpath' (and 'cat') tokens have been removed, as they caused quite a bit of confusion,
|
||||
// and the catpath was a relatively expensive query when the taxonomy tree was deep.
|
||||
//
|
||||
// It existed only to provide forward-compatability with pathauto module, and
|
||||
// for most uses of token.module, it was a relatively useless token -- it exposed
|
||||
// a list of term names formatted as a URL/path string. Once pathauto supports
|
||||
// tokens, *it* should handle this catpath alias as it's the primary consumer.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// It's possible to leave that block and still not have good data.
|
||||
// So, we test for these and if not set, set them.
|
||||
if (!isset($values['term'])) {
|
||||
$values['term'] = '';
|
||||
$values['term-raw'] = '';
|
||||
$values['term-id'] = '';
|
||||
$values['vocab'] = '';
|
||||
$values['vocab-raw'] = '';
|
||||
$values['vocab-id'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_list() on behalf of menu.module.
|
||||
*/
|
||||
function menu_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'node' || $type == 'all') {
|
||||
$tokens['node']['menu'] = t("The name of the menu the node belongs to.");
|
||||
$tokens['node']['menu-raw'] = t("The name of the menu the node belongs to.");
|
||||
$tokens['node']['menupath'] = t("The menu path (as reflected in the breadcrumb), not including Home or [menu]. Separated by /.");
|
||||
$tokens['node']['menupath-raw'] = t("The unfiltered menu path (as reflected in the breadcrumb), not including Home or [menu]. Separated by /.");
|
||||
$tokens['node']['menu-link-title'] = t("The text used in the menu as link text for this item.");
|
||||
$tokens['node']['menu-link-title-raw'] = t("The unfiltered text used in the menu as link text for this item.");
|
||||
$tokens['node']['menu-link-mlid'] = t("The unique ID of the node's menu link.");
|
||||
$tokens['node']['menu-link-plid'] = t("The unique ID of the node's menu link parent.");
|
||||
$tokens['node']['menu-link-parent-path'] = t('The URL alias of the parent menu link of the node.');
|
||||
$tokens['node']['menu-link-parent-path-raw'] = t('The URL alias of the parent menu link of the node.');
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_values() on behalf of menu.module.
|
||||
*/
|
||||
function menu_token_values($type, $object = NULL, $options = array()) {
|
||||
static $menus;
|
||||
|
||||
$values = array();
|
||||
|
||||
// Statically cache menu_get_menus() since this causes a database query
|
||||
// every time it is called, and is not likely to change in the same page
|
||||
// request.
|
||||
if (!isset($menus)) {
|
||||
$menus = menu_get_menus();
|
||||
}
|
||||
|
||||
if ($type == 'node' && !empty($object)) {
|
||||
$node = $object;
|
||||
|
||||
// Initialize tokens to empty strings.
|
||||
$values['menu'] = '';
|
||||
$values['menu-raw'] = '';
|
||||
$values['menupath'] = '';
|
||||
$values['menupath-raw'] = '';
|
||||
$values['menu-link-title'] = '';
|
||||
$values['menu-link-title-raw'] = '';
|
||||
$values['menu-link-mlid'] = '';
|
||||
$values['menu-link-plid'] = '';
|
||||
$values['menu-link-parent-path'] = '';
|
||||
$values['menu-link-parent-path-raw'] = '';
|
||||
|
||||
if (!isset($node->menu)) {
|
||||
// We need to clone the node as menu_nodeapi($node, 'prepare') may cause data loss.
|
||||
// @see http://drupal.org/node/1317926
|
||||
$node = drupal_clone($node);
|
||||
// Nodes do not have their menu links loaded via menu_nodeapi($node, 'load').
|
||||
menu_nodeapi($node, 'prepare');
|
||||
}
|
||||
|
||||
// Now get the menu related information.
|
||||
if (!empty($node->menu['mlid'])) {
|
||||
$link = token_menu_link_load($node->menu['mlid']);
|
||||
|
||||
if (isset($menus[$link['menu_name']])) {
|
||||
$values['menu-raw'] = $menus[$link['menu_name']];
|
||||
$values['menu'] = check_plain($values['menu-raw']);
|
||||
}
|
||||
|
||||
$parents = token_menu_link_get_parents_all($link['mlid']);
|
||||
$trail_raw = array();
|
||||
foreach ($parents as $parent) {
|
||||
$trail_raw[] = $parent['title'];
|
||||
}
|
||||
$trail = array_map('check_plain', $trail_raw);
|
||||
|
||||
$values['menupath'] = !empty($options['pathauto']) ? $trail : implode('/', $trail);
|
||||
$values['menupath-raw'] = !empty($options['pathauto']) ? $trail_raw : implode('/', $trail_raw);
|
||||
$values['menu-link-title'] = check_plain($link['title']);
|
||||
$values['menu-link-title-raw'] = $link['title'];
|
||||
$values['menu-link-mlid'] = $link['mlid'];
|
||||
|
||||
if (!empty($link['plid']) && $parent = token_menu_link_load($link['plid'])) {
|
||||
$values['menu-link-plid'] = $parent['mlid'];
|
||||
$values['menu-link-parent-path-raw'] = drupal_get_path_alias($parent['href']);
|
||||
$values['menu-link-parent-path'] = check_plain($values['menu-link-parent-path-raw']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_list() on behalf of book.module.
|
||||
*/
|
||||
function book_token_list($type) {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'node' || $type == 'all') {
|
||||
$tokens['book']['book'] = t("The title of the node's book parent.");
|
||||
$tokens['book']['book-raw'] = t("The title of the node's book parent.");
|
||||
$tokens['book']['book_id'] = t("The id of the node's book parent.");
|
||||
$tokens['book']['bookpath'] = t("The titles of all parents in the node's book hierarchy.");
|
||||
$tokens['book']['bookpath-raw'] = t("The titles of all parents in the node's book hierarchy.");
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_values() on behalf of book.module.
|
||||
*/
|
||||
function book_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
|
||||
if ($type == 'node' && !empty($object)) {
|
||||
$node = $object;
|
||||
|
||||
// Initialize tokens to empty strings.
|
||||
$values['book'] = '';
|
||||
$values['book-raw'] = '';
|
||||
$values['book_id'] = '';
|
||||
$values['bookpath'] = '';
|
||||
$values['bookpath-raw'] = '';
|
||||
|
||||
if (!empty($node->book['mlid'])) {
|
||||
// Exclude the current node's title from the book path trail (start with
|
||||
// the book link's plid rather than mlid).
|
||||
$parents = token_menu_link_get_parents_all($node->book['plid']);
|
||||
$trail_raw = array();
|
||||
foreach ($parents as $parent) {
|
||||
$trail_raw[] = $parent['title'];
|
||||
}
|
||||
$trail = array_map('check_plain', $trail_raw);
|
||||
|
||||
// Load the root book page.
|
||||
$root = token_menu_link_load($node->book['p1']);
|
||||
|
||||
$values['book'] = check_plain($root['title']);
|
||||
$values['book-raw'] = $root['title'];
|
||||
$values['book_id'] = $node->book['bid'];
|
||||
$values['bookpath'] = !empty($options['pathauto']) ? $trail : implode('/', $trail);
|
||||
$values['bookpath-raw'] = !empty($options['pathauto']) ? $trail_raw : implode('/', $trail_raw);
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
81
sites/all/modules/token/token_taxonomy.inc
Normal file
81
sites/all/modules/token/token_taxonomy.inc
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementations of token module hooks for the core taxonomy module.
|
||||
*
|
||||
* The token module requires specific hooks to be added to modules
|
||||
* so that those modules can return data about their objects to the
|
||||
* token API. Until and unless token becomes a part of core, the
|
||||
* implementations of the token hooks for core modules are provided
|
||||
* in the token module itself.
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_list().
|
||||
*/
|
||||
function taxonomy_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
// Taxonomy term tokens.
|
||||
if ($type == 'taxonomy' || $type == 'all') {
|
||||
$tokens['taxonomy']['tid'] = t('The unique ID of the taxonomy term.');
|
||||
$tokens['taxonomy']['cat'] = t('The name of the taxonomy term.');
|
||||
$tokens['taxonomy']['cat-raw'] = t('The name of the taxonomy term.');
|
||||
$tokens['taxonomy']['cat-description'] = t('The optional description of the taxonomy term.');
|
||||
$tokens['taxonomy']['vid'] = t("The unique ID of the taxonomy vocabulary the taxonomy term belongs to.");
|
||||
$tokens['taxonomy']['vocab'] = t("The name of the taxonomy vocabulary the taxonomy term belongs to.");
|
||||
$tokens['taxonomy']['vocab-raw'] = t("The name of the taxonomy vocabulary the taxonomy term belongs to.");
|
||||
$tokens['taxonomy']['vocab-description'] = t('The optional description of the taxonomy vocabulary the taxonomy term belongs to.');
|
||||
$tokens['taxonomy']['vocab-description-raw'] = t('The optional description of the taxonomy vocabulary the taxonomy term belongs to.');
|
||||
}
|
||||
|
||||
// Vocabulary tokens.
|
||||
if ($type == 'vocabulary' || $type == 'all') {
|
||||
$tokens['vocabulary']['vocabulary-vid'] = t('The unique ID of the taxonomy vocabulary.');
|
||||
$tokens['vocabulary']['vocabulary-name'] = t('The name of the taxonomy vocabulary.');
|
||||
$tokens['vocabulary']['vocabulary-name-raw'] = t('The name of the taxonomy vocabulary.');
|
||||
$tokens['vocabulary']['vocabulary-description'] = t('The optional description of the taxonomy vocabulary.');
|
||||
$tokens['vocabulary']['vocabulary-description-raw'] = t('The optional description of the taxonomy vocabulary.');
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_token_values().
|
||||
*/
|
||||
function taxonomy_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
|
||||
// Taxonomy term tokens.
|
||||
if ($type == 'taxonomy' && !empty($object)) {
|
||||
$term = $object;
|
||||
$vocabulary = taxonomy_vocabulary_load($term->vid);
|
||||
|
||||
$values['tid'] = $term->tid;
|
||||
$values['cat'] = check_plain($term->name);
|
||||
$values['cat-raw'] = $term->name;
|
||||
$values['cat-description'] = filter_xss($term->description);
|
||||
$values['vid'] = $term->vid;
|
||||
$values['vocab'] = check_plain($vocabulary->name);
|
||||
$values['vocab-raw'] = $vocabulary->name;
|
||||
$values['vocab-description'] = filter_xss($vocabulary->description);
|
||||
$values['vocab-description-raw'] = $vocabulary->description;
|
||||
}
|
||||
|
||||
// Vocabulary tokens.
|
||||
if ($type == 'vocabulary' && !empty($object)) {
|
||||
$vocabulary = $object;
|
||||
|
||||
$values['vocabulary-vid'] = $vocabulary->vid;
|
||||
$values['vocabulary-name'] = check_plain($vocabulary->name);
|
||||
$values['vocabulary-name-raw'] = $vocabulary->name;
|
||||
$values['vocabulary-description'] = filter_xss($vocabulary->description);
|
||||
$values['vocabulary-description-raw'] = $vocabulary->description;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
78
sites/all/modules/token/token_user.inc
Normal file
78
sites/all/modules/token/token_user.inc
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementations of token module hooks for the core user module.
|
||||
*
|
||||
* The token module requires specific hooks to be added to modules
|
||||
* so that those modules can return data about their objects to the
|
||||
* token API. Until and unless token becomes a part of core, the
|
||||
* implementations of the token hooks for core modules are provided
|
||||
* in the token module itself.
|
||||
*
|
||||
* @ingroup token
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of hook_token_list().
|
||||
*/
|
||||
function user_token_list($type = 'all') {
|
||||
$tokens = array();
|
||||
|
||||
if ($type == 'user' || $type == 'all') {
|
||||
$tokens['user']['user'] = t("The login name of the user account.");
|
||||
$tokens['user']['user-raw'] = t("The login name of the user account.");
|
||||
$tokens['user']['uid'] = t("The unique ID of the user account.");
|
||||
$tokens['user']['mail'] = t("The email address of the user account.");
|
||||
|
||||
$tokens['user'] += token_get_date_token_info(t("User's registration"), 'user-created-');
|
||||
$tokens['user'] += token_get_date_token_info(t("User's last login"), 'user-last-login-');
|
||||
$tokens['user']['date-in-tz'] = t("The current date in the user's timezone.");
|
||||
|
||||
$tokens['user']['account-url'] = t("The URL of the account profile page.");
|
||||
$tokens['user']['account-edit-url'] = t("The URL of the account edit page.");
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_token_values().
|
||||
*/
|
||||
function user_token_values($type, $object = NULL, $options = array()) {
|
||||
$values = array();
|
||||
|
||||
if ($type == 'user') {
|
||||
// @todo Why do we all the current user object to be loaded?
|
||||
$account = !empty($object) ? $object : user_load(array('uid' => $GLOBALS['user']->uid));
|
||||
|
||||
// Adjust for the anonymous user name.
|
||||
if (!$account->uid && empty($account->name)) {
|
||||
$account_name = variable_get('anonymous', 'Anonymous');
|
||||
}
|
||||
else {
|
||||
$account_name = $account->name;
|
||||
}
|
||||
|
||||
$values['user'] = check_plain($account_name);
|
||||
$values['user-raw'] = $account_name;
|
||||
$values['uid'] = $account->uid;
|
||||
$values['mail'] = $account->uid ? $account->mail : '';
|
||||
|
||||
if ($account->uid) {
|
||||
$values += token_get_date_token_values($account->created, 'user-created-');
|
||||
$values += token_get_date_token_values($account->access, 'user-last-login-');
|
||||
$values['reg-date'] = $values['user-created-small'];
|
||||
$values['reg-since'] = $values['user-created-since'];
|
||||
$values['log-date'] = $values['user-last-login-small'];
|
||||
$values['log-since'] = $values['user-last-login-since'];
|
||||
$values['date-in-tz'] = $account->uid ? format_date(time(), 'small', '', $account->timezone) : '';
|
||||
}
|
||||
|
||||
$values['account-url'] = $account->uid ? url("user/$account->uid", array('absolute' => TRUE)) : '';
|
||||
$values['account-edit-url'] = $account->uid ? url("user/$account->uid/edit", array('absolute' => TRUE)) : '';
|
||||
$values['account-edit'] = $values['account-edit-url'];
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
Reference in a new issue